diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 7843dca6c87..ca9de90ba02 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -94,7 +94,6 @@ /apps/shorturl/ @grafana/sharing-squad /apps/secret/ @grafana/grafana-operator-experience-squad /apps/scope/ @grafana/grafana-operator-experience-squad -/apps/investigations/ @fcjack @matryer @svennergr /apps/advisor/ @grafana/plugins-platform-backend /apps/iam/ @grafana/access-squad /apps/sdk.mk @grafana/grafana-app-platform-squad @@ -441,6 +440,7 @@ i18next.config.ts @grafana/grafana-frontend-platform /e2e-playwright/dashboards/TestDashboard.json @grafana/dashboards-squad @grafana/grafana-search-navigate-organise /e2e-playwright/dashboards/TestV2Dashboard.json @grafana/dashboards-squad /e2e-playwright/dashboards/V2DashWithRepeats.json @grafana/dashboards-squad +/e2e-playwright/dashboards/V2DashWithRowRepeats.json @grafana/dashboards-squad /e2e-playwright/dashboards/V2DashWithTabRepeats.json @grafana/dashboards-squad /e2e-playwright/dashboards-suite/adhoc-filter-from-panel.spec.ts @grafana/datapro /e2e-playwright/dashboards-suite/dashboard-browse-nested.spec.ts @grafana/grafana-search-navigate-organise @@ -501,7 +501,6 @@ i18next.config.ts @grafana/grafana-frontend-platform /e2e-playwright/various-suite/filter-annotations.spec.ts @grafana/dashboards-squad /e2e-playwright/various-suite/frontend-sandbox-app.spec.ts @grafana/plugins-platform-frontend /e2e-playwright/various-suite/frontend-sandbox-datasource.spec.ts @grafana/plugins-platform-frontend -/e2e-playwright/various-suite/gauge.spec.ts @grafana/dataviz-squad /e2e-playwright/various-suite/grafana-datasource-random-walk.spec.ts @grafana/grafana-frontend-platform /e2e-playwright/various-suite/graph-auto-migrate.spec.ts @grafana/dataviz-squad /e2e-playwright/various-suite/inspect-drawer.spec.ts @grafana/dashboards-squad @@ -520,7 +519,7 @@ i18next.config.ts @grafana/grafana-frontend-platform /e2e-playwright/various-suite/solo-route.spec.ts @grafana/dashboards-squad /e2e-playwright/various-suite/trace-view-scrolling.spec.ts @grafana/observability-traces-and-profiling /e2e-playwright/various-suite/verify-i18n.spec.ts @grafana/grafana-frontend-platform -/e2e-playwright/various-suite/visualization-suggestions.spec.ts @grafana/dataviz-squad +/e2e-playwright/various-suite/visualization-suggestions*.spec.ts @grafana/dataviz-squad /e2e-playwright/various-suite/perf-test.spec.ts @grafana/grafana-frontend-platform # Packages @@ -1277,6 +1276,7 @@ embed.go @grafana/grafana-as-code /.github/workflows/i18n-crowdin-download.yml @grafana/grafana-frontend-platform /.github/workflows/i18n-crowdin-create-tasks.yml @grafana/grafana-frontend-platform /.github/workflows/i18n-verify.yml @grafana/grafana-frontend-platform +/.github/workflows/deploy-storybook.yml @grafana/grafana-frontend-platform /.github/workflows/deploy-storybook-preview.yml @grafana/grafana-frontend-platform /.github/workflows/scripts/crowdin/create-tasks.ts @grafana/grafana-frontend-platform /.github/workflows/scripts/publish-frontend-metrics.mts @grafana/grafana-frontend-platform diff --git a/.github/actions/change-detection/action.yml b/.github/actions/change-detection/action.yml index 2b8484d7cf6..1fd10ae5540 100644 --- a/.github/actions/change-detection/action.yml +++ b/.github/actions/change-detection/action.yml @@ -14,6 +14,9 @@ outputs: frontend: description: Whether the frontend or self has changed in any way value: ${{ steps.changed-files.outputs.frontend_any_changed || 'true' }} + frontend-packages: + description: Whether any frontend packages have changed + value: ${{ steps.changed-files.outputs.frontend_packages_any_changed || 'true' }} e2e: description: Whether the e2e tests or self have changed in any way value: ${{ steps.changed-files.outputs.e2e_any_changed == 'true' || @@ -97,6 +100,12 @@ runs: - '.yarn/**' - 'apps/dashboard/pkg/migration/**' - '${{ inputs.self }}' + frontend_packages: + - '.github/actions/checkout/**' + - '.github/actions/change-detection/**' + - 'packages/**' + - './scripts/validate-npm-packages.sh' + - '${{ inputs.self }}' e2e: - 'e2e/**' - 'e2e-playwright/**' @@ -153,6 +162,8 @@ runs: echo " --> ${{ steps.changed-files.outputs.backend_all_changed_files }}" echo "Frontend: ${{ steps.changed-files.outputs.frontend_any_changed || 'true' }}" echo " --> ${{ steps.changed-files.outputs.frontend_all_changed_files }}" + echo "Frontend packages: ${{ steps.changed-files.outputs.frontend_packages_any_changed || 'true' }}" + echo " --> ${{ steps.changed-files.outputs.frontend_packages_all_changed_files }}" echo "E2E: ${{ steps.changed-files.outputs.e2e_any_changed || 'true' }}" echo " --> ${{ steps.changed-files.outputs.e2e_all_changed_files }}" echo " --> ${{ steps.changed-files.outputs.backend_all_changed_files }}" diff --git a/.github/actions/setup-node/action.yml b/.github/actions/setup-node/action.yml index 5762389f83b..92ffd43593c 100644 --- a/.github/actions/setup-node/action.yml +++ b/.github/actions/setup-node/action.yml @@ -4,8 +4,8 @@ description: Sets up a node.js environment with presets for the Grafana reposito runs: using: "composite" steps: - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v6 with: node-version-file: '.nvmrc' cache: 'yarn' - cache-dependency-path: 'yarn.lock' \ No newline at end of file + cache-dependency-path: 'yarn.lock' diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 79987600b9a..6356a793b36 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -19,7 +19,6 @@ updates: - "/apps/dashboard" - "/apps/folder" - "/apps/iam" - - "/apps/investigations" - "/apps/playlist" - "/apps/plugins" - "/apps/preferences" diff --git a/.github/workflows/deploy-storybook.yml b/.github/workflows/deploy-storybook.yml new file mode 100644 index 00000000000..08bffaeb891 --- /dev/null +++ b/.github/workflows/deploy-storybook.yml @@ -0,0 +1,79 @@ +name: Deploy Storybook + +on: + workflow_dispatch: + # push: + # branches: + # - main + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: {} + +jobs: + detect-changes: + # Only run in grafana/grafana + if: github.repository == 'grafana/grafana' + name: Detect whether code changed + runs-on: ubuntu-latest + permissions: + contents: read + outputs: + changed-frontend-packages: ${{ steps.detect-changes.outputs.frontend-packages }} + steps: + - uses: actions/checkout@v5 + with: + persist-credentials: true # required to get more history in the changed-files action + fetch-depth: 2 + - name: Detect changes + id: detect-changes + uses: ./.github/actions/change-detection + with: + self: .github/workflows/deploy-storybook.yml + deploy-storybook: + name: Deploy Storybook + runs-on: ubuntu-latest + needs: detect-changes + # Only run in grafana/grafana + if: github.repository == 'grafana/grafana' && needs.detect-changes.outputs.changed-frontend-packages == 'true' + permissions: + contents: read + id-token: write + + env: + BUCKET_NAME: grafana-storybook + + steps: + - name: Checkout code + uses: actions/checkout@v5 + with: + persist-credentials: false + + - name: Setup Node.js + uses: ./.github/actions/setup-node + + - name: Install dependencies + run: yarn install --immutable + + - name: Build storybook + run: yarn storybook:build + + # Create the GCS folder name + # Right now, this just returns "canary" + # But we'll expand this to work for "latest" as well in the future + - name: Create deploy name + id: create-deploy-name + run: | + echo "deploy-name=canary" >> "$GITHUB_OUTPUT" + + - name: Upload Storybook + uses: grafana/shared-workflows/actions/push-to-gcs@main + with: + environment: prod + bucket: ${{ env.BUCKET_NAME }} + bucket_path: ${{ steps.create-deploy-name.outputs.deploy-name }} + path: packages/grafana-ui/dist/storybook + service_account: github-gf-storybook-deploy@grafanalabs-workload-identity.iam.gserviceaccount.com + parent: false diff --git a/.github/workflows/frontend-lint.yml b/.github/workflows/frontend-lint.yml index 02833d61149..539d57b1742 100644 --- a/.github/workflows/frontend-lint.yml +++ b/.github/workflows/frontend-lint.yml @@ -17,6 +17,7 @@ jobs: outputs: changed: ${{ steps.detect-changes.outputs.frontend }} prettier: ${{ steps.detect-changes.outputs.frontend == 'true' || steps.detect-changes.outputs.docs == 'true' }} + changed-frontend-packages: ${{ steps.detect-changes.outputs.frontend-packages }} steps: - uses: actions/checkout@v5 with: @@ -42,11 +43,8 @@ jobs: - uses: actions/checkout@v5 with: persist-credentials: false - - uses: actions/setup-node@v6 - with: - node-version-file: '.nvmrc' - cache: 'yarn' - cache-dependency-path: 'yarn.lock' + - name: Setup Node + uses: ./.github/actions/setup-node - run: yarn install --immutable --check-cache - run: yarn run prettier:check - run: yarn run lint @@ -63,11 +61,8 @@ jobs: - uses: actions/checkout@v5 with: persist-credentials: false - - uses: actions/setup-node@v6 - with: - node-version-file: '.nvmrc' - cache: 'yarn' - cache-dependency-path: 'yarn.lock' + - name: Setup Node + uses: ./.github/actions/setup-node - name: Setup Enterprise uses: ./.github/actions/setup-enterprise with: @@ -89,11 +84,8 @@ jobs: - uses: actions/checkout@v5 with: persist-credentials: false - - uses: actions/setup-node@v6 - with: - node-version-file: '.nvmrc' - cache: 'yarn' - cache-dependency-path: 'yarn.lock' + - name: Setup Node + uses: ./.github/actions/setup-node - run: yarn install --immutable --check-cache - run: yarn run typecheck lint-frontend-typecheck-enterprise: @@ -109,11 +101,8 @@ jobs: - uses: actions/checkout@v5 with: persist-credentials: false - - uses: actions/setup-node@v6 - with: - node-version-file: '.nvmrc' - cache: 'yarn' - cache-dependency-path: 'yarn.lock' + - name: Setup Node + uses: ./.github/actions/setup-node - name: Setup Enterprise uses: ./.github/actions/setup-enterprise with: @@ -133,11 +122,8 @@ jobs: - uses: actions/checkout@v5 with: persist-credentials: false - - uses: actions/setup-node@v6 - with: - node-version-file: '.nvmrc' - cache: 'yarn' - cache-dependency-path: 'yarn.lock' + - name: Setup Node + uses: ./.github/actions/setup-node - run: yarn install --immutable --check-cache - name: Generate API clients run: | @@ -164,11 +150,8 @@ jobs: - uses: actions/checkout@v5 with: persist-credentials: false - - uses: actions/setup-node@v6 - with: - node-version-file: '.nvmrc' - cache: 'yarn' - cache-dependency-path: 'yarn.lock' + - name: Setup Node + uses: ./.github/actions/setup-node - name: Setup Enterprise uses: ./.github/actions/setup-enterprise with: @@ -187,3 +170,26 @@ jobs: echo "${uncommited_error_message}" exit 1 fi + lint-frontend-packed-packages: + needs: detect-changes + permissions: + contents: read + id-token: write + if: github.event_name == 'pull_request' && needs.detect-changes.outputs.changed-frontend-packages == 'true' + name: Verify packed frontend packages + runs-on: ubuntu-latest + steps: + - name: Checkout build commit + uses: actions/checkout@v5 + with: + persist-credentials: false + - name: Setup Node + uses: ./.github/actions/setup-node + - name: Install dependencies + run: yarn install --immutable + - name: Build and pack packages + run: | + yarn run packages:build + yarn run packages:pack + - name: Validate packages + run: ./scripts/validate-npm-packages.sh diff --git a/.golangci.yml b/.golangci.yml index b52a986d435..069e88632ff 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -67,14 +67,6 @@ linters: deny: - pkg: github.com/grafana/grafana/pkg desc: apiserver is not allowed to import grafana core - apps-investigation: - list-mode: lax - files: - - ./apps/investigations/* - - ./apps/investigations/**/* - deny: - - pkg: github.com/grafana/grafana/pkg - desc: apps/investigations is not allowed to import grafana core apps-playlist: list-mode: lax files: diff --git a/.yarn/patches/@storybook-core-npm-8.6.2-8c752112c0.patch b/.yarn/patches/@storybook-core-npm-8.6.15-a468a35170.patch similarity index 73% rename from .yarn/patches/@storybook-core-npm-8.6.2-8c752112c0.patch rename to .yarn/patches/@storybook-core-npm-8.6.15-a468a35170.patch index 730ecce8fb2..f3b7cb48e98 100644 --- a/.yarn/patches/@storybook-core-npm-8.6.2-8c752112c0.patch +++ b/.yarn/patches/@storybook-core-npm-8.6.15-a468a35170.patch @@ -1,8 +1,8 @@ diff --git a/dist/builder-manager/index.js b/dist/builder-manager/index.js -index 3d7f9b213dae1801bda62b31db31b9113e382ccd..212501c63d20146c29db63fb0f6300c6779eecb5 100644 +index ac8ac6a5f6a3b7852c4064e93dc9acd3201289e6..34a0a5a5c38dd7fe525c9ebd382a10a451d4d4f3 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) => { +@@ -1974,7 +1974,7 @@ var pa = /^\/($|\?)/, G, C, xt = /* @__PURE__ */ o(async (e) => { bundle: !0, minify: !0, sourcemap: !1, diff --git a/Dockerfile b/Dockerfile index 2b16926a836..d3c2fc9ef5e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -91,6 +91,7 @@ COPY pkg/storage/unified/resource pkg/storage/unified/resource COPY pkg/storage/unified/resourcepb pkg/storage/unified/resourcepb COPY pkg/storage/unified/apistore pkg/storage/unified/apistore COPY pkg/semconv pkg/semconv +COPY pkg/plugins pkg/plugins COPY pkg/aggregator pkg/aggregator COPY apps/playlist apps/playlist COPY apps/quotas apps/quotas @@ -103,7 +104,6 @@ COPY apps/collections apps/collections COPY apps/provisioning apps/provisioning COPY apps/secret apps/secret COPY apps/scope apps/scope -COPY apps/investigations apps/investigations COPY apps/logsdrilldown apps/logsdrilldown COPY apps/advisor apps/advisor COPY apps/dashboard apps/dashboard diff --git a/Makefile b/Makefile index a5353e95567..e4a261acb4b 100644 --- a/Makefile +++ b/Makefile @@ -135,7 +135,7 @@ i18n-extract-enterprise: @echo "Skipping i18n extract for Enterprise: not enabled" else i18n-extract-enterprise: - @echo "Extracting i18n strings for Enterprise" + @echo "Extracting i18n strings for Enterprise" cd public/locales/enterprise && yarn run i18next-cli extract --sync-primary endif @@ -227,6 +227,10 @@ fix-cue: gen-jsonnet: go generate ./devenv/jsonnet +.PHONY: gen-themes +gen-themes: + go generate ./pkg/services/preference + .PHONY: update-workspace update-workspace: gen-go @echo "updating workspace" @@ -244,6 +248,7 @@ build-go-fast: ## Build all Go binaries without updating workspace. .PHONY: build-backend build-backend: ## Build Grafana backend. @echo "build backend" + $(MAKE) gen-themes $(GO) run build.go $(GO_BUILD_FLAGS) build-backend .PHONY: build-air diff --git a/apps/advisor/go.mod b/apps/advisor/go.mod index c1b2c7acd25..c65d5dacdc5 100644 --- a/apps/advisor/go.mod +++ b/apps/advisor/go.mod @@ -54,6 +54,7 @@ require ( github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0 // indirect github.com/BurntSushi/toml v1.5.0 // indirect + github.com/Machiel/slugify v1.0.1 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver v1.5.0 // indirect github.com/Masterminds/sprig/v3 v3.3.0 // indirect @@ -67,14 +68,14 @@ require ( github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/at-wat/mqtt-go v0.19.6 // indirect github.com/aws/aws-sdk-go v1.55.7 // indirect - github.com/aws/aws-sdk-go-v2 v1.39.1 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.18.14 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.8 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.8 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1 // indirect - 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/aws/aws-sdk-go-v2 v1.40.0 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.18.21 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.39.1 // indirect + github.com/aws/smithy-go v1.23.2 // indirect github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -157,18 +158,18 @@ require ( 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 - github.com/grafana/alerting v0.0.0-20251212143239-491433b332b7 // indirect + github.com/grafana/alerting v0.0.0-20251231150637-b7821017d69f // indirect github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f // indirect github.com/grafana/dataplane/sdata v0.0.9 // indirect github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 // indirect - github.com/grafana/grafana-aws-sdk v1.3.0 // indirect + github.com/grafana/grafana-aws-sdk v1.4.2 // indirect 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 + github.com/grafana/sqlds/v5 v5.0.3 // indirect github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 // indirect 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 diff --git a/apps/advisor/go.sum b/apps/advisor/go.sum index 760641a8857..c306b9fa889 100644 --- a/apps/advisor/go.sum +++ b/apps/advisor/go.sum @@ -115,6 +115,8 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapp github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0/go.mod h1:cSgYe11MCNYunTnRXrKiR/tHc0eoKjICUuWpNZoVCOo= github.com/IBM/pgxpoolprometheus v1.1.2 h1:sHJwxoL5Lw4R79Zt+H4Uj1zZ4iqXJLdk7XDE7TPs97U= github.com/IBM/pgxpoolprometheus v1.1.2/go.mod h1:+vWzISN6S9ssgurhUNmm6AlXL9XLah3TdWJktquKTR8= +github.com/Machiel/slugify v1.0.1 h1:EfWSlRWstMadsgzmiV7d0yVd2IFlagWH68Q+DcYCm4E= +github.com/Machiel/slugify v1.0.1/go.mod h1:fTFGn5uWEynW4CUMG7sWkYXOf1UgDxyTM3DbR6Qfg3k= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= @@ -171,44 +173,44 @@ github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/aws/aws-sdk-go v1.55.7 h1:UJrkFq7es5CShfBwlWAC8DA077vp8PyVbQd3lqLiztE= github.com/aws/aws-sdk-go v1.55.7/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= -github.com/aws/aws-sdk-go-v2 v1.39.1 h1:fWZhGAwVRK/fAN2tmt7ilH4PPAE11rDj7HytrmbZ2FE= -github.com/aws/aws-sdk-go-v2 v1.39.1/go.mod h1:sDioUELIUO9Znk23YVmIk86/9DOpkbyyVb1i/gUNFXY= +github.com/aws/aws-sdk-go-v2 v1.40.0 h1:/WMUA0kjhZExjOQN2z3oLALDREea1A7TobfuiBrKlwc= +github.com/aws/aws-sdk-go-v2 v1.40.0/go.mod h1:c9pm7VwuW0UPxAEYGyTmyurVcNrbF6Rt/wixFqDhcjE= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.11 h1:12SpdwU8Djs+YGklkinSSlcrPyj3H4VifVsKf78KbwA= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.11/go.mod h1:dd+Lkp6YmMryke+qxW/VnKyhMBDTYP41Q2Bb+6gNZgY= -github.com/aws/aws-sdk-go-v2/config v1.31.10 h1:7LllDZAegXU3yk41mwM6KcPu0wmjKGQB1bg99bNdQm4= -github.com/aws/aws-sdk-go-v2/config v1.31.10/go.mod h1:Ge6gzXPjqu4v0oHvgAwvGzYcK921GU0hQM25WF/Kl+8= -github.com/aws/aws-sdk-go-v2/credentials v1.18.14 h1:TxkI7QI+sFkTItN/6cJuMZEIVMFXeu2dI1ZffkXngKI= -github.com/aws/aws-sdk-go-v2/credentials v1.18.14/go.mod h1:12x4Uw/vijC11XkctTjy92TNCQ+UnNJkT7fzX0Yd93E= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.8 h1:gLD09eaJUdiszm7vd1btiQUYE0Hj+0I2b8AS+75z9AY= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.8/go.mod h1:4RW3oMPt1POR74qVOC4SbubxAwdP4pCT0nSw3jycOU4= +github.com/aws/aws-sdk-go-v2/config v1.31.17 h1:QFl8lL6RgakNK86vusim14P2k8BFSxjvUkcWLDjgz9Y= +github.com/aws/aws-sdk-go-v2/config v1.31.17/go.mod h1:V8P7ILjp/Uef/aX8TjGk6OHZN6IKPM5YW6S78QnRD5c= +github.com/aws/aws-sdk-go-v2/credentials v1.18.21 h1:56HGpsgnmD+2/KpG0ikvvR8+3v3COCwaF4r+oWwOeNA= +github.com/aws/aws-sdk-go-v2/credentials v1.18.21/go.mod h1:3YELwedmQbw7cXNaII2Wywd+YY58AmLPwX4LzARgmmA= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13 h1:T1brd5dR3/fzNFAQch/iBKeX07/ffu/cLu+q+RuzEWk= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13/go.mod h1:Peg/GBAQ6JDt+RoBf4meB1wylmAipb7Kg2ZFakZTlwk= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.84 h1:cTXRdLkpBanlDwISl+5chq5ui1d1YWg4PWMR9c3kXyw= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.84/go.mod h1:kwSy5X7tfIHN39uucmjQVs2LvDdXEjQucgQQEqCggEo= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.8 h1:6bgAZgRyT4RoFWhxS+aoGMFyE0cD1bSzFnEEi4bFPGI= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.8/go.mod h1:KcGkXFVU8U28qS4KvLEcPxytPZPBcRawaH2Pf/0jptE= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.8 h1:HhJYoES3zOz34yWEpGENqJvRVPqpmJyR3+AFg9ybhdY= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.8/go.mod h1:JnA+hPWeYAVbDssp83tv+ysAG8lTfLVXvSsyKg/7xNA= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14 h1:PZHqQACxYb8mYgms4RZbhZG0a7dPW06xOjmaH0EJC/I= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14/go.mod h1:VymhrMJUWs69D8u0/lZ7jSB6WgaG/NqHi3gX0aYf6U0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14 h1:bOS19y6zlJwagBfHxs0ESzr1XCOU2KXJCWcq3E2vfjY= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14/go.mod h1:1ipeGBMAxZ0xcTm6y6paC2C/J6f6OO7LBODV9afuAyM= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.36 h1:GMYy2EOWfzdP3wfVAGXBNKY5vK4K8vMET4sYOYltmqs= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.36/go.mod h1:gDhdAV6wL3PmPqBhiPbnlS447GoWs8HTTOYef9/9Inw= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1 h1:oegbebPEMA/1Jny7kvwejowCaHz1FWZAQ94WXFNCyTM= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1/go.mod h1:kemo5Myr9ac0U9JfSjMo9yHLtw+pECEHsFtJ9tqCEI8= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 h1:x2Ibm/Af8Fi+BH+Hsn9TXGdT+hKbDd5XOTZxTMxDk7o= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3/go.mod h1:IW1jwyrQgMdhisceG8fQLmQIydcT/jWY21rFhzgaKwo= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.4 h1:nAP2GYbfh8dd2zGZqFRSMlq+/F6cMPBUuCsGAMkN074= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.4/go.mod h1:LT10DsiGjLWh4GbjInf9LQejkYEhBgBCjLG5+lvk4EE= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.8 h1:M6JI2aGFEzYxsF6CXIuRBnkge9Wf9a2xU39rNeXgu10= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.8/go.mod h1:Fw+MyTwlwjFsSTE31mH211Np+CUslml8mzc0AFEG09s= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13 h1:kDqdFvMY4AtKoACfzIGD8A0+hbT41KTKF//gq7jITfM= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13/go.mod h1:lmKuogqSU3HzQCwZ9ZtcqOc5XGMqtDK7OIc2+DxiUEg= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.17 h1:qcLWgdhq45sDM9na4cvXax9dyLitn8EYBRl8Ak4XtG4= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.17/go.mod h1:M+jkjBFZ2J6DJrjMv2+vkBbuht6kxJYtJiwoVgX4p4U= github.com/aws/aws-sdk-go-v2/service/s3 v1.84.0 h1:0reDqfEN+tB+sozj2r92Bep8MEwBZgtAXTND1Kk9OXg= github.com/aws/aws-sdk-go-v2/service/s3 v1.84.0/go.mod h1:kUklwasNoCn5YpyAqC/97r6dzTA1SRKJfKq16SXeoDU= -github.com/aws/aws-sdk-go-v2/service/sso v1.29.4 h1:FTdEN9dtWPB0EOURNtDPmwGp6GGvMqRJCAihkSl/1No= -github.com/aws/aws-sdk-go-v2/service/sso v1.29.4/go.mod h1:mYubxV9Ff42fZH4kexj43gFPhgc/LyC7KqvUKt1watc= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.0 h1:I7ghctfGXrscr7r1Ga/mDqSJKm7Fkpl5Mwq79Z+rZqU= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.0/go.mod h1:Zo9id81XP6jbayIFWNuDpA6lMBWhsVy+3ou2jLa4JnA= -github.com/aws/aws-sdk-go-v2/service/sts v1.38.5 h1:+LVB0xBqEgjQoqr9bGZbRzvg212B0f17JdflleJRNR4= -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/aws/aws-sdk-go-v2/service/sso v1.30.1 h1:0JPwLz1J+5lEOfy/g0SURC9cxhbQ1lIMHMa+AHZSzz0= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.1/go.mod h1:fKvyjJcz63iL/ftA6RaM8sRCtN4r4zl4tjL3qw5ec7k= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.5 h1:OWs0/j2UYR5LOGi88sD5/lhN6TDLG6SfA7CqsQO9zF0= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.5/go.mod h1:klO+ejMvYsB4QATfEOIXk8WAEwN4N0aBfJpvC+5SZBo= +github.com/aws/aws-sdk-go-v2/service/sts v1.39.1 h1:mLlUgHn02ue8whiR4BmxxGJLR2gwU6s6ZzJ5wDamBUs= +github.com/aws/aws-sdk-go-v2/service/sts v1.39.1/go.mod h1:E19xDjpzPZC7LS2knI9E6BaRFDK43Eul7vd6rSq2HWk= +github.com/aws/smithy-go v1.23.2 h1:Crv0eatJUQhaManss33hS5r40CG3ZFH+21XSkqMrIUM= +github.com/aws/smithy-go v1.23.2/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df h1:GSoSVRLoBaFpOOds6QyY1L8AX7uoY+Ln3BHc22W40X0= @@ -619,8 +621,8 @@ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v1.5.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/alerting v0.0.0-20251212143239-491433b332b7 h1:ZzG/gCclEit9w0QUfQt9GURcOycAIGcsQAhY1u0AEX0= -github.com/grafana/alerting v0.0.0-20251212143239-491433b332b7/go.mod h1:l7v67cgP7x72ajB9UPZlumdrHqNztpKoqQ52cU8T3LU= +github.com/grafana/alerting v0.0.0-20251231150637-b7821017d69f h1:Br4SaUL3dnVopKKNhDavCLgehw60jdtl/sIxdfzmVts= +github.com/grafana/alerting v0.0.0-20251231150637-b7821017d69f/go.mod h1:l7v67cgP7x72ajB9UPZlumdrHqNztpKoqQ52cU8T3LU= github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f h1:Cbm6OKkOcJ+7CSZsGsEJzktC/SIa5bxVeYKQLuYK86o= github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f/go.mod h1:axY0cdOg3q0TZHwpHnIz5x16xZ8ZBxJHShsSHHXcHQg= github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4 h1:Muoy+FMGrHj3GdFbvsMzUT7eusgii9PKf9L1ZaXDDbY= @@ -635,8 +637,8 @@ github.com/grafana/grafana-app-sdk v0.48.7 h1:9mF7nqkqP0QUYYDlznoOt+GIyjzj45wGfU 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-aws-sdk v1.4.2 h1:GrUEoLbs46r8rG/GZL4L2b63Bo+rkIYKdtCT7kT5KkM= +github.com/grafana/grafana-aws-sdk v1.4.2/go.mod h1:1qnZdYs6gQzxxF0dDodaE7Rn9fiMzuhwvtaAZ7ySnhY= 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= @@ -653,8 +655,8 @@ github.com/grafana/pyroscope-go/godeltaprof v0.1.9 h1:c1Us8i6eSmkW+Ez05d3co8kasn github.com/grafana/pyroscope-go/godeltaprof v0.1.9/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU= github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248= github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk= -github.com/grafana/sqlds/v4 v4.2.7 h1:sFQhsS7DBakNMdxa++yOfJ9BVvkZwFJ0B95o57K0/XA= -github.com/grafana/sqlds/v4 v4.2.7/go.mod h1:BQRjUG8rOqrBI4NAaeoWrIMuoNgfi8bdhCJ+5cgEfLU= +github.com/grafana/sqlds/v5 v5.0.3 h1:+yUMUxfa0WANQsmS9xtTFSRX1Q55Iv1B9EjlrW4VlBU= +github.com/grafana/sqlds/v5 v5.0.3/go.mod h1:GKeTTiC+GeR1X0z3f0Iee+hZnNgN62uQpj5XVMx5Uew= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 h1:QGLs/O40yoNK9vmy4rhUGBVyMf1lISBGtXRpsu/Qu/o= diff --git a/apps/alerting/historian/go.mod b/apps/alerting/historian/go.mod index 0524e1a3852..9bce171ed16 100644 --- a/apps/alerting/historian/go.mod +++ b/apps/alerting/historian/go.mod @@ -4,7 +4,7 @@ go 1.25.5 require ( github.com/go-kit/log v0.2.1 - github.com/grafana/alerting v0.0.0-20251212143239-491433b332b7 + github.com/grafana/alerting v0.0.0-20260112172717-98a49ed9557f github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 github.com/grafana/grafana-app-sdk v0.48.7 github.com/grafana/grafana-app-sdk/logging v0.48.7 diff --git a/apps/alerting/historian/go.sum b/apps/alerting/historian/go.sum index 6e82a1dea7b..73b2a5c991b 100644 --- a/apps/alerting/historian/go.sum +++ b/apps/alerting/historian/go.sum @@ -243,8 +243,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/grafana/alerting v0.0.0-20251212143239-491433b332b7 h1:ZzG/gCclEit9w0QUfQt9GURcOycAIGcsQAhY1u0AEX0= -github.com/grafana/alerting v0.0.0-20251212143239-491433b332b7/go.mod h1:l7v67cgP7x72ajB9UPZlumdrHqNztpKoqQ52cU8T3LU= +github.com/grafana/alerting v0.0.0-20260112172717-98a49ed9557f h1:3bXOyht68qkfvD6Y8z8XoenFbytSSOIkr/s+AqRzj0o= +github.com/grafana/alerting v0.0.0-20260112172717-98a49ed9557f/go.mod h1:Ji0SfJChcwjgq8ljy6Y5CcYfHfAYKXjKYeysOoDS/6s= 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.7 h1:9mF7nqkqP0QUYYDlznoOt+GIyjzj45wGfUHB32u2ZMo= diff --git a/apps/alerting/historian/pkg/app/notification/lokireader.go b/apps/alerting/historian/pkg/app/notification/lokireader.go index c26519e59b4..636ae083d91 100644 --- a/apps/alerting/historian/pkg/app/notification/lokireader.go +++ b/apps/alerting/historian/pkg/app/notification/lokireader.go @@ -31,6 +31,10 @@ const ( maxLimit = 1000 Namespace = "grafana" Subsystem = "alerting" + + // LogQL field path for alert rule UID after JSON parsing. + // Loki flattens nested JSON fields with underscores: alert.labels.__alert_rule_uid__ -> alert_labels___alert_rule_uid__ + lokiAlertRuleUIDField = "alert_labels___alert_rule_uid__" ) var ( @@ -111,13 +115,13 @@ func buildQuery(query Query) (string, error) { fmt.Sprintf(`%s=%q`, historian.LabelFrom, historian.LabelFromValue), } - if query.RuleUID != nil { - selectors = append(selectors, - fmt.Sprintf(`%s=%q`, historian.LabelRuleUID, *query.RuleUID)) - } - logql := fmt.Sprintf(`{%s} | json`, strings.Join(selectors, `,`)) + // Add ruleUID filter as JSON line filter if specified. + if query.RuleUID != nil && *query.RuleUID != "" { + logql += fmt.Sprintf(` | %s = %q`, lokiAlertRuleUIDField, *query.RuleUID) + } + // Add receiver filter if specified. if query.Receiver != nil && *query.Receiver != "" { logql += fmt.Sprintf(` | receiver = %q`, *query.Receiver) @@ -211,16 +215,13 @@ func parseLokiEntry(s lokiclient.Sample) (Entry, error) { groupLabels = make(map[string]string) } - alerts := make([]EntryAlert, len(lokiEntry.Alerts)) - for i, a := range lokiEntry.Alerts { - alerts[i] = EntryAlert{ - Status: a.Status, - Labels: a.Labels, - Annotations: a.Annotations, - StartsAt: a.StartsAt, - EndsAt: a.EndsAt, - } - } + alerts := []EntryAlert{{ + Status: lokiEntry.Alert.Status, + Labels: lokiEntry.Alert.Labels, + Annotations: lokiEntry.Alert.Annotations, + StartsAt: lokiEntry.Alert.StartsAt, + EndsAt: lokiEntry.Alert.EndsAt, + }} return Entry{ Timestamp: s.T, diff --git a/apps/alerting/historian/pkg/app/notification/lokireader_test.go b/apps/alerting/historian/pkg/app/notification/lokireader_test.go index 708c9d10df1..c9c35cb1e62 100644 --- a/apps/alerting/historian/pkg/app/notification/lokireader_test.go +++ b/apps/alerting/historian/pkg/app/notification/lokireader_test.go @@ -7,6 +7,7 @@ import ( "testing" "time" + "github.com/grafana/alerting/models" "github.com/grafana/alerting/notify/historian" "github.com/grafana/alerting/notify/historian/lokiclient" "github.com/grafana/grafana-app-sdk/logging" @@ -133,9 +134,8 @@ func TestBuildQuery(t *testing.T) { query: Query{ RuleUID: stringPtr("test-rule-uid"), }, - expected: fmt.Sprintf(`{%s=%q,%s=%q} | json`, - historian.LabelFrom, historian.LabelFromValue, - historian.LabelRuleUID, "test-rule-uid"), + expected: fmt.Sprintf(`{%s=%q} | json | alert_labels___alert_rule_uid__ = "test-rule-uid"`, + historian.LabelFrom, historian.LabelFromValue), }, { name: "query with receiver filter", @@ -143,9 +143,8 @@ func TestBuildQuery(t *testing.T) { RuleUID: stringPtr("test-rule-uid"), Receiver: stringPtr("email-receiver"), }, - expected: fmt.Sprintf(`{%s=%q,%s=%q} | json | receiver = "email-receiver"`, - historian.LabelFrom, historian.LabelFromValue, - historian.LabelRuleUID, "test-rule-uid"), + expected: fmt.Sprintf(`{%s=%q} | json | alert_labels___alert_rule_uid__ = "test-rule-uid" | receiver = "email-receiver"`, + historian.LabelFrom, historian.LabelFromValue), }, { name: "query with status filter", @@ -153,9 +152,8 @@ func TestBuildQuery(t *testing.T) { RuleUID: stringPtr("test-rule-uid"), Status: createStatusPtr(v0alpha1.CreateNotificationqueryRequestNotificationStatusFiring), }, - expected: fmt.Sprintf(`{%s=%q,%s=%q} | json | status = "firing"`, - historian.LabelFrom, historian.LabelFromValue, - historian.LabelRuleUID, "test-rule-uid"), + expected: fmt.Sprintf(`{%s=%q} | json | alert_labels___alert_rule_uid__ = "test-rule-uid" | status = "firing"`, + historian.LabelFrom, historian.LabelFromValue), }, { name: "query with success outcome filter", @@ -163,9 +161,8 @@ func TestBuildQuery(t *testing.T) { RuleUID: stringPtr("test-rule-uid"), Outcome: outcomePtr(v0alpha1.CreateNotificationqueryRequestNotificationOutcomeSuccess), }, - expected: fmt.Sprintf(`{%s=%q,%s=%q} | json | error = ""`, - historian.LabelFrom, historian.LabelFromValue, - historian.LabelRuleUID, "test-rule-uid"), + expected: fmt.Sprintf(`{%s=%q} | json | alert_labels___alert_rule_uid__ = "test-rule-uid" | error = ""`, + historian.LabelFrom, historian.LabelFromValue), }, { name: "query with error outcome filter", @@ -173,9 +170,8 @@ func TestBuildQuery(t *testing.T) { RuleUID: stringPtr("test-rule-uid"), Outcome: outcomePtr(v0alpha1.CreateNotificationqueryRequestNotificationOutcomeError), }, - expected: fmt.Sprintf(`{%s=%q,%s=%q} | json | error != ""`, - historian.LabelFrom, historian.LabelFromValue, - historian.LabelRuleUID, "test-rule-uid"), + expected: fmt.Sprintf(`{%s=%q} | json | alert_labels___alert_rule_uid__ = "test-rule-uid" | error != ""`, + historian.LabelFrom, historian.LabelFromValue), }, { name: "query with many filters", @@ -185,9 +181,8 @@ func TestBuildQuery(t *testing.T) { Status: createStatusPtr(v0alpha1.CreateNotificationqueryRequestNotificationStatusResolved), Outcome: outcomePtr(v0alpha1.CreateNotificationqueryRequestNotificationOutcomeSuccess), }, - expected: fmt.Sprintf(`{%s=%q,%s=%q} | json | receiver = "email-receiver" | status = "resolved" | error = ""`, - historian.LabelFrom, historian.LabelFromValue, - historian.LabelRuleUID, "test-rule-uid"), + expected: fmt.Sprintf(`{%s=%q} | json | alert_labels___alert_rule_uid__ = "test-rule-uid" | receiver = "email-receiver" | status = "resolved" | error = ""`, + historian.LabelFrom, historian.LabelFromValue), }, { name: "query with group label matcher", @@ -277,19 +272,19 @@ func TestParseLokiEntry(t *testing.T) { GroupLabels: map[string]string{ "alertname": "test-alert", }, - Alerts: []historian.NotificationHistoryLokiEntryAlert{ - { - Status: "firing", - Labels: map[string]string{ - "severity": "critical", - }, - Annotations: map[string]string{ - "summary": "Test alert", - }, - StartsAt: now, - EndsAt: now.Add(1 * time.Hour), + Alert: historian.NotificationHistoryLokiEntryAlert{ + Status: "firing", + Labels: map[string]string{ + "severity": "critical", }, + Annotations: map[string]string{ + "summary": "Test alert", + }, + StartsAt: now, + EndsAt: now.Add(1 * time.Hour), }, + AlertIndex: 0, + AlertCount: 1, Retry: false, Duration: 100, PipelineTime: now, @@ -335,7 +330,9 @@ func TestParseLokiEntry(t *testing.T) { Error: "notification failed", GroupKey: "key:thing", GroupLabels: map[string]string{}, - Alerts: []historian.NotificationHistoryLokiEntryAlert{}, + Alert: historian.NotificationHistoryLokiEntryAlert{}, + AlertIndex: 0, + AlertCount: 1, PipelineTime: now, }), }, @@ -347,7 +344,7 @@ func TestParseLokiEntry(t *testing.T) { Outcome: OutcomeError, GroupKey: "key:thing", GroupLabels: map[string]string{}, - Alerts: []EntryAlert{}, + Alerts: []EntryAlert{{}}, Error: stringPtr("notification failed"), PipelineTime: now, }, @@ -365,7 +362,7 @@ func TestParseLokiEntry(t *testing.T) { Status: Status("firing"), Outcome: OutcomeSuccess, GroupLabels: map[string]string{}, - Alerts: []EntryAlert{}, + Alerts: []EntryAlert{{}}, PipelineTime: now, }, }, @@ -448,7 +445,9 @@ func TestLokiReader_RunQuery(t *testing.T) { Receiver: "receiver-1", Status: "firing", GroupLabels: map[string]string{}, - Alerts: []historian.NotificationHistoryLokiEntryAlert{}, + Alert: historian.NotificationHistoryLokiEntryAlert{}, + AlertIndex: 0, + AlertCount: 1, PipelineTime: now, }), }, @@ -459,7 +458,9 @@ func TestLokiReader_RunQuery(t *testing.T) { Receiver: "receiver-3", Status: "firing", GroupLabels: map[string]string{}, - Alerts: []historian.NotificationHistoryLokiEntryAlert{}, + Alert: historian.NotificationHistoryLokiEntryAlert{}, + AlertIndex: 0, + AlertCount: 1, PipelineTime: now, }), }, @@ -474,7 +475,9 @@ func TestLokiReader_RunQuery(t *testing.T) { Receiver: "receiver-2", Status: "firing", GroupLabels: map[string]string{}, - Alerts: []historian.NotificationHistoryLokiEntryAlert{}, + Alert: historian.NotificationHistoryLokiEntryAlert{}, + AlertIndex: 0, + AlertCount: 1, PipelineTime: now, }), }, @@ -546,19 +549,19 @@ func createMockLokiResponse(timestamp time.Time) lokiclient.QueryRes { GroupLabels: map[string]string{ "alertname": "test-alert", }, - Alerts: []historian.NotificationHistoryLokiEntryAlert{ - { - Status: "firing", - Labels: map[string]string{ - "severity": "critical", - }, - Annotations: map[string]string{ - "summary": "Test alert", - }, - StartsAt: timestamp, - EndsAt: timestamp.Add(1 * time.Hour), + Alert: historian.NotificationHistoryLokiEntryAlert{ + Status: "firing", + Labels: map[string]string{ + "severity": "critical", }, + Annotations: map[string]string{ + "summary": "Test alert", + }, + StartsAt: timestamp, + EndsAt: timestamp.Add(1 * time.Hour), }, + AlertIndex: 0, + AlertCount: 1, Retry: false, Duration: 100, PipelineTime: timestamp, @@ -587,10 +590,19 @@ func createLokiEntryJSONWithNilLabels(t *testing.T, timestamp time.Time) string "status": "firing", "error": "", "groupLabels": null, - "alerts": [], + "alert": {}, + "alertIndex": 0, + "alertCount": 1, "retry": false, "duration": 0, "pipelineTime": "%s" }`, timestamp.Format(time.RFC3339Nano)) return jsonStr } + +func TestRuleUIDLabelConstant(t *testing.T) { + // Verify that models.RuleUIDLabel has the expected value. + // If this changes in the alerting module, our LogQL field path constant will be incorrect + // and filtering for a single alert rule by its UID will break. + assert.Equal(t, "__alert_rule_uid__", models.RuleUIDLabel) +} diff --git a/apps/dashboard/kinds/v2alpha1/dashboard_spec.cue b/apps/dashboard/kinds/v2alpha1/dashboard_spec.cue index c13eb866c80..55094fe3447 100644 --- a/apps/dashboard/kinds/v2alpha1/dashboard_spec.cue +++ b/apps/dashboard/kinds/v2alpha1/dashboard_spec.cue @@ -129,7 +129,7 @@ DashboardLink: { placement?: DashboardLinkPlacement } -// Dashboard Link placement. Defines where the link should be displayed. +// Dashboard Link placement. Defines where the link should be displayed. // - "inControlsMenu" renders the link in bottom part of the dashboard controls dropdown menu DashboardLinkPlacement: "inControlsMenu" @@ -254,8 +254,18 @@ FieldConfig: { // custom is specified by the FieldConfig field // in panel plugin schemas. custom?: {...} + + // Calculate min max per field + fieldMinMax?: bool + + // How null values should be handled when calculating field stats + // "null" - Include null values, "connected" - Ignore nulls, "null as zero" - Treat nulls as zero + nullValueMode?: NullValueMode } +// How null values should be handled +NullValueMode: "null" | "connected" | "null as zero" + DynamicConfigValue: { id: string | *"" value?: _ @@ -932,6 +942,7 @@ CustomVariableSpec: { skipUrlSync: bool | *false description?: string allowCustomValue: bool | *true + valuesFormat?: "csv" | "json" } // Custom variable kind diff --git a/apps/dashboard/kinds/v2beta1/dashboard_spec.cue b/apps/dashboard/kinds/v2beta1/dashboard_spec.cue index bb833795354..0802430907e 100644 --- a/apps/dashboard/kinds/v2beta1/dashboard_spec.cue +++ b/apps/dashboard/kinds/v2beta1/dashboard_spec.cue @@ -250,8 +250,18 @@ FieldConfig: { // custom is specified by the FieldConfig field // in panel plugin schemas. custom?: {...} + + // Calculate min max per field + fieldMinMax?: bool + + // How null values should be handled when calculating field stats + // "null" - Include null values, "connected" - Ignore nulls, "null as zero" - Treat nulls as zero + nullValueMode?: NullValueMode } +// How null values should be handled +NullValueMode: "null" | "connected" | "null as zero" + DynamicConfigValue: { id: string | *"" value?: _ @@ -935,6 +945,7 @@ CustomVariableSpec: { skipUrlSync: bool | *false description?: string allowCustomValue: bool | *true + valuesFormat?: "csv" | "json" } // Custom variable kind diff --git a/apps/dashboard/pkg/apis/dashboard/v0alpha1/dashboard_kind.cue b/apps/dashboard/pkg/apis/dashboard/v0alpha1/dashboard_kind.cue index 8338c9e13c5..3c6c0e92355 100644 --- a/apps/dashboard/pkg/apis/dashboard/v0alpha1/dashboard_kind.cue +++ b/apps/dashboard/pkg/apis/dashboard/v0alpha1/dashboard_kind.cue @@ -222,8 +222,10 @@ lineage: schemas: [{ // Optional field, if you want to extract part of a series name or metric node segment. // Named capture groups can be used to separate the display text and value. regex?: string - // Determine whether regex applies to variable value or display text - regexApplyTo?: #VariableRegexApplyTo + // Optional, indicates whether a custom type variable uses CSV or JSON to define its values + valuesFormat?: "csv" | "json" | *"csv" + // Determine whether regex applies to variable value or display text + regexApplyTo?: #VariableRegexApplyTo // Additional static options for query variable staticOptions?: [...#VariableOption] // Ordering of static options in relation to options returned from data source for query variable diff --git a/apps/dashboard/pkg/apis/dashboard/v1beta1/dashboard_kind.cue b/apps/dashboard/pkg/apis/dashboard/v1beta1/dashboard_kind.cue index 8338c9e13c5..3c6c0e92355 100644 --- a/apps/dashboard/pkg/apis/dashboard/v1beta1/dashboard_kind.cue +++ b/apps/dashboard/pkg/apis/dashboard/v1beta1/dashboard_kind.cue @@ -222,8 +222,10 @@ lineage: schemas: [{ // Optional field, if you want to extract part of a series name or metric node segment. // Named capture groups can be used to separate the display text and value. regex?: string - // Determine whether regex applies to variable value or display text - regexApplyTo?: #VariableRegexApplyTo + // Optional, indicates whether a custom type variable uses CSV or JSON to define its values + valuesFormat?: "csv" | "json" | *"csv" + // Determine whether regex applies to variable value or display text + regexApplyTo?: #VariableRegexApplyTo // Additional static options for query variable staticOptions?: [...#VariableOption] // Ordering of static options in relation to options returned from data source for query variable diff --git a/apps/dashboard/pkg/apis/dashboard/v2alpha1/dashboard_spec.cue b/apps/dashboard/pkg/apis/dashboard/v2alpha1/dashboard_spec.cue index ec8d7eead87..293082ab82f 100644 --- a/apps/dashboard/pkg/apis/dashboard/v2alpha1/dashboard_spec.cue +++ b/apps/dashboard/pkg/apis/dashboard/v2alpha1/dashboard_spec.cue @@ -133,7 +133,7 @@ DashboardLink: { placement?: DashboardLinkPlacement } -// Dashboard Link placement. Defines where the link should be displayed. +// Dashboard Link placement. Defines where the link should be displayed. // - "inControlsMenu" renders the link in bottom part of the dashboard controls dropdown menu DashboardLinkPlacement: "inControlsMenu" @@ -258,8 +258,18 @@ FieldConfig: { // custom is specified by the FieldConfig field // in panel plugin schemas. custom?: {...} + + // Calculate min max per field + fieldMinMax?: bool + + // How null values should be handled when calculating field stats + // "null" - Include null values, "connected" - Ignore nulls, "null as zero" - Treat nulls as zero + nullValueMode?: NullValueMode } +// How null values should be handled +NullValueMode: "null" | "connected" | "null as zero" + DynamicConfigValue: { id: string | *"" value?: _ @@ -936,6 +946,7 @@ CustomVariableSpec: { skipUrlSync: bool | *false description?: string allowCustomValue: bool | *true + valuesFormat?: "csv" | "json" } // Custom variable kind diff --git a/apps/dashboard/pkg/apis/dashboard/v2alpha1/dashboard_spec_gen.go b/apps/dashboard/pkg/apis/dashboard/v2alpha1/dashboard_spec_gen.go index 883c5399663..f7ccfdd4925 100644 --- a/apps/dashboard/pkg/apis/dashboard/v2alpha1/dashboard_spec_gen.go +++ b/apps/dashboard/pkg/apis/dashboard/v2alpha1/dashboard_spec_gen.go @@ -419,6 +419,11 @@ type DashboardFieldConfig struct { // custom is specified by the FieldConfig field // in panel plugin schemas. Custom map[string]interface{} `json:"custom,omitempty"` + // Calculate min max per field + FieldMinMax *bool `json:"fieldMinMax,omitempty"` + // How null values should be handled when calculating field stats + // "null" - Include null values, "connected" - Ignore nulls, "null as zero" - Treat nulls as zero + NullValueMode *DashboardNullValueMode `json:"nullValueMode,omitempty"` } // NewDashboardFieldConfig creates a new DashboardFieldConfig object. @@ -745,6 +750,16 @@ func NewDashboardActionVariable() *DashboardActionVariable { // +k8s:openapi-gen=true const DashboardActionVariableType = "string" +// How null values should be handled +// +k8s:openapi-gen=true +type DashboardNullValueMode string + +const ( + DashboardNullValueModeNull DashboardNullValueMode = "null" + DashboardNullValueModeConnected DashboardNullValueMode = "connected" + DashboardNullValueModeNullAsZero DashboardNullValueMode = "null as zero" +) + // +k8s:openapi-gen=true type DashboardDynamicConfigValue struct { Id string `json:"id"` @@ -1703,18 +1718,19 @@ func NewDashboardCustomVariableKind() *DashboardCustomVariableKind { // Custom variable specification // +k8s:openapi-gen=true type DashboardCustomVariableSpec struct { - Name string `json:"name"` - Query string `json:"query"` - Current DashboardVariableOption `json:"current"` - Options []DashboardVariableOption `json:"options"` - Multi bool `json:"multi"` - IncludeAll bool `json:"includeAll"` - AllValue *string `json:"allValue,omitempty"` - Label *string `json:"label,omitempty"` - Hide DashboardVariableHide `json:"hide"` - SkipUrlSync bool `json:"skipUrlSync"` - Description *string `json:"description,omitempty"` - AllowCustomValue bool `json:"allowCustomValue"` + Name string `json:"name"` + Query string `json:"query"` + Current DashboardVariableOption `json:"current"` + Options []DashboardVariableOption `json:"options"` + Multi bool `json:"multi"` + IncludeAll bool `json:"includeAll"` + AllValue *string `json:"allValue,omitempty"` + Label *string `json:"label,omitempty"` + Hide DashboardVariableHide `json:"hide"` + SkipUrlSync bool `json:"skipUrlSync"` + Description *string `json:"description,omitempty"` + AllowCustomValue bool `json:"allowCustomValue"` + ValuesFormat *DashboardCustomVariableSpecValuesFormat `json:"valuesFormat,omitempty"` } // NewDashboardCustomVariableSpec creates a new DashboardCustomVariableSpec object. @@ -2098,6 +2114,14 @@ const ( DashboardQueryVariableSpecStaticOptionsOrderSorted DashboardQueryVariableSpecStaticOptionsOrder = "sorted" ) +// +k8s:openapi-gen=true +type DashboardCustomVariableSpecValuesFormat string + +const ( + DashboardCustomVariableSpecValuesFormatCsv DashboardCustomVariableSpecValuesFormat = "csv" + DashboardCustomVariableSpecValuesFormatJson DashboardCustomVariableSpecValuesFormat = "json" +) + // +k8s:openapi-gen=true type DashboardPanelKindOrLibraryPanelKind struct { PanelKind *DashboardPanelKind `json:"PanelKind,omitempty"` diff --git a/apps/dashboard/pkg/apis/dashboard/v2alpha1/zz_generated.openapi.go b/apps/dashboard/pkg/apis/dashboard/v2alpha1/zz_generated.openapi.go index d697aa4f8b9..926d50cb49d 100644 --- a/apps/dashboard/pkg/apis/dashboard/v2alpha1/zz_generated.openapi.go +++ b/apps/dashboard/pkg/apis/dashboard/v2alpha1/zz_generated.openapi.go @@ -1548,6 +1548,12 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardCustomVariableSpec(ref common.R Format: "", }, }, + "valuesFormat": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, }, Required: []string{"name", "query", "current", "options", "multi", "includeAll", "hide", "skipUrlSync", "allowCustomValue"}, }, @@ -2271,6 +2277,20 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardFieldConfig(ref common.Referenc }, }, }, + "fieldMinMax": { + SchemaProps: spec.SchemaProps{ + Description: "Calculate min max per field", + Type: []string{"boolean"}, + Format: "", + }, + }, + "nullValueMode": { + SchemaProps: spec.SchemaProps{ + Description: "How null values should be handled when calculating field stats \"null\" - Include null values, \"connected\" - Ignore nulls, \"null as zero\" - Treat nulls as zero", + Type: []string{"string"}, + Format: "", + }, + }, }, }, }, diff --git a/apps/dashboard/pkg/apis/dashboard/v2beta1/dashboard_spec.cue b/apps/dashboard/pkg/apis/dashboard/v2beta1/dashboard_spec.cue index 12d7bec351b..41ab7bc3fa7 100644 --- a/apps/dashboard/pkg/apis/dashboard/v2beta1/dashboard_spec.cue +++ b/apps/dashboard/pkg/apis/dashboard/v2beta1/dashboard_spec.cue @@ -254,8 +254,18 @@ FieldConfig: { // custom is specified by the FieldConfig field // in panel plugin schemas. custom?: {...} + + // Calculate min max per field + fieldMinMax?: bool + + // How null values should be handled when calculating field stats + // "null" - Include null values, "connected" - Ignore nulls, "null as zero" - Treat nulls as zero + nullValueMode?: NullValueMode } +// How null values should be handled +NullValueMode: "null" | "connected" | "null as zero" + DynamicConfigValue: { id: string | *"" value?: _ @@ -939,6 +949,7 @@ CustomVariableSpec: { skipUrlSync: bool | *false description?: string allowCustomValue: bool | *true + valuesFormat?: "csv" | "json" } // Custom variable kind diff --git a/apps/dashboard/pkg/apis/dashboard/v2beta1/dashboard_spec_gen.go b/apps/dashboard/pkg/apis/dashboard/v2beta1/dashboard_spec_gen.go index a8ec1537e38..06f1e1df599 100644 --- a/apps/dashboard/pkg/apis/dashboard/v2beta1/dashboard_spec_gen.go +++ b/apps/dashboard/pkg/apis/dashboard/v2beta1/dashboard_spec_gen.go @@ -423,6 +423,11 @@ type DashboardFieldConfig struct { // custom is specified by the FieldConfig field // in panel plugin schemas. Custom map[string]interface{} `json:"custom,omitempty"` + // Calculate min max per field + FieldMinMax *bool `json:"fieldMinMax,omitempty"` + // How null values should be handled when calculating field stats + // "null" - Include null values, "connected" - Ignore nulls, "null as zero" - Treat nulls as zero + NullValueMode *DashboardNullValueMode `json:"nullValueMode,omitempty"` } // NewDashboardFieldConfig creates a new DashboardFieldConfig object. @@ -749,6 +754,16 @@ func NewDashboardActionVariable() *DashboardActionVariable { // +k8s:openapi-gen=true const DashboardActionVariableType = "string" +// How null values should be handled +// +k8s:openapi-gen=true +type DashboardNullValueMode string + +const ( + DashboardNullValueModeNull DashboardNullValueMode = "null" + DashboardNullValueModeConnected DashboardNullValueMode = "connected" + DashboardNullValueModeNullAsZero DashboardNullValueMode = "null as zero" +) + // +k8s:openapi-gen=true type DashboardDynamicConfigValue struct { Id string `json:"id"` @@ -1707,18 +1722,19 @@ func NewDashboardCustomVariableKind() *DashboardCustomVariableKind { // Custom variable specification // +k8s:openapi-gen=true type DashboardCustomVariableSpec struct { - Name string `json:"name"` - Query string `json:"query"` - Current DashboardVariableOption `json:"current"` - Options []DashboardVariableOption `json:"options"` - Multi bool `json:"multi"` - IncludeAll bool `json:"includeAll"` - AllValue *string `json:"allValue,omitempty"` - Label *string `json:"label,omitempty"` - Hide DashboardVariableHide `json:"hide"` - SkipUrlSync bool `json:"skipUrlSync"` - Description *string `json:"description,omitempty"` - AllowCustomValue bool `json:"allowCustomValue"` + Name string `json:"name"` + Query string `json:"query"` + Current DashboardVariableOption `json:"current"` + Options []DashboardVariableOption `json:"options"` + Multi bool `json:"multi"` + IncludeAll bool `json:"includeAll"` + AllValue *string `json:"allValue,omitempty"` + Label *string `json:"label,omitempty"` + Hide DashboardVariableHide `json:"hide"` + SkipUrlSync bool `json:"skipUrlSync"` + Description *string `json:"description,omitempty"` + AllowCustomValue bool `json:"allowCustomValue"` + ValuesFormat *DashboardCustomVariableSpecValuesFormat `json:"valuesFormat,omitempty"` } // NewDashboardCustomVariableSpec creates a new DashboardCustomVariableSpec object. @@ -2133,6 +2149,14 @@ const ( DashboardQueryVariableSpecStaticOptionsOrderSorted DashboardQueryVariableSpecStaticOptionsOrder = "sorted" ) +// +k8s:openapi-gen=true +type DashboardCustomVariableSpecValuesFormat string + +const ( + DashboardCustomVariableSpecValuesFormatCsv DashboardCustomVariableSpecValuesFormat = "csv" + DashboardCustomVariableSpecValuesFormatJson DashboardCustomVariableSpecValuesFormat = "json" +) + // +k8s:openapi-gen=true type DashboardPanelKindOrLibraryPanelKind struct { PanelKind *DashboardPanelKind `json:"PanelKind,omitempty"` diff --git a/apps/dashboard/pkg/apis/dashboard/v2beta1/zz_generated.openapi.go b/apps/dashboard/pkg/apis/dashboard/v2beta1/zz_generated.openapi.go index 2b1fe573336..73c4d1f7349 100644 --- a/apps/dashboard/pkg/apis/dashboard/v2beta1/zz_generated.openapi.go +++ b/apps/dashboard/pkg/apis/dashboard/v2beta1/zz_generated.openapi.go @@ -1560,6 +1560,12 @@ func schema_pkg_apis_dashboard_v2beta1_DashboardCustomVariableSpec(ref common.Re Format: "", }, }, + "valuesFormat": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, }, Required: []string{"name", "query", "current", "options", "multi", "includeAll", "hide", "skipUrlSync", "allowCustomValue"}, }, @@ -2278,6 +2284,20 @@ func schema_pkg_apis_dashboard_v2beta1_DashboardFieldConfig(ref common.Reference }, }, }, + "fieldMinMax": { + SchemaProps: spec.SchemaProps{ + Description: "Calculate min max per field", + Type: []string{"boolean"}, + Format: "", + }, + }, + "nullValueMode": { + SchemaProps: spec.SchemaProps{ + Description: "How null values should be handled when calculating field stats \"null\" - Include null values, \"connected\" - Ignore nulls, \"null as zero\" - Treat nulls as zero", + Type: []string{"string"}, + Format: "", + }, + }, }, }, }, diff --git a/apps/dashboard/pkg/apis/dashboard_manifest.go b/apps/dashboard/pkg/apis/dashboard_manifest.go index c815e815e08..aee89730dc1 100644 --- a/apps/dashboard/pkg/apis/dashboard_manifest.go +++ b/apps/dashboard/pkg/apis/dashboard_manifest.go @@ -32,10 +32,10 @@ var ( rawSchemaDashboardv1beta1 = []byte(`{"ConversionStatus":{"additionalProperties":false,"description":"ConversionStatus is the status of the conversion of the dashboard.","properties":{"error":{"description":"The error message from the conversion.\nEmpty if the conversion has not failed.","type":"string"},"failed":{"description":"Whether from another version has failed.\nIf true, means that the dashboard is not valid,\nand the caller should instead fetch the stored version.","type":"boolean"},"source":{"additionalProperties":{},"description":"The original value map[string]any","type":"object"},"storedVersion":{"description":"The version which was stored when the dashboard was created / updated.\nFetching this version should always succeed.","type":"string"}},"required":["failed"],"type":"object"},"Dashboard":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"spec":{"additionalProperties":{"additionalProperties":{},"type":"object"},"type":"object"},"status":{"additionalProperties":false,"properties":{"conversion":{"$ref":"#/components/schemas/ConversionStatus","description":"Optional conversion status."}},"type":"object"}}`) versionSchemaDashboardv1beta1 app.VersionSchema _ = json.Unmarshal(rawSchemaDashboardv1beta1, &versionSchemaDashboardv1beta1) - rawSchemaDashboardv2alpha1 = []byte(`{"Action":{"additionalProperties":false,"properties":{"confirmation":{"type":"string"},"fetch":{"$ref":"#/components/schemas/FetchOptions"},"infinity":{"$ref":"#/components/schemas/InfinityOptions"},"oneClick":{"type":"boolean"},"style":{"additionalProperties":false,"properties":{"backgroundColor":{"type":"string"}},"type":"object"},"title":{"type":"string"},"type":{"$ref":"#/components/schemas/ActionType"},"variables":{"items":{"$ref":"#/components/schemas/ActionVariable"},"type":"array"}},"required":["type","title"],"type":"object"},"ActionType":{"enum":["fetch","infinity"],"type":"string"},"ActionVariable":{"additionalProperties":false,"properties":{"key":{"type":"string"},"name":{"type":"string"},"type":{"$ref":"#/components/schemas/ActionVariableType"}},"required":["key","name","type"],"type":"object"},"ActionVariableType":{"const":"string","description":"Action variable type","type":"string"},"AdHocFilterWithLabels":{"additionalProperties":false,"description":"Define the AdHocFilterWithLabels type","properties":{"condition":{"description":"@deprecated","type":"string"},"forceEdit":{"type":"boolean"},"key":{"type":"string"},"keyLabel":{"type":"string"},"operator":{"type":"string"},"origin":{"$ref":"#/components/schemas/FilterOrigin"},"value":{"type":"string"},"valueLabels":{"items":{"type":"string"},"type":"array"},"values":{"items":{"type":"string"},"type":"array"}},"required":["key","operator","value"],"type":"object"},"AdhocVariableKind":{"additionalProperties":false,"description":"Adhoc variable kind","properties":{"kind":{"const":"AdhocVariable","type":"string"},"spec":{"$ref":"#/components/schemas/AdhocVariableSpec"}},"required":["kind","spec"],"type":"object"},"AdhocVariableSpec":{"additionalProperties":false,"description":"Adhoc variable specification","properties":{"allowCustomValue":{"default":true,"type":"boolean"},"baseFilters":{"items":{"$ref":"#/components/schemas/AdHocFilterWithLabels"},"type":"array"},"datasource":{"$ref":"#/components/schemas/DataSourceRef"},"defaultKeys":{"items":{"$ref":"#/components/schemas/MetricFindValue"},"type":"array"},"description":{"type":"string"},"filters":{"items":{"$ref":"#/components/schemas/AdHocFilterWithLabels"},"type":"array"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"label":{"type":"string"},"name":{"default":"","type":"string"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","baseFilters","filters","defaultKeys","hide","skipUrlSync","allowCustomValue"],"type":"object"},"AnnotationEventFieldMapping":{"additionalProperties":false,"description":"Annotation event field mapping. Defines how to map a data frame field to an annotation event field.","properties":{"regex":{"description":"Regular expression to apply to the field value","type":"string"},"source":{"default":"field","description":"Source type for the field value","type":"string"},"value":{"description":"Constant value to use when source is \"text\"","type":"string"}},"type":"object"},"AnnotationPanelFilter":{"additionalProperties":false,"properties":{"exclude":{"default":false,"description":"Should the specified panels be included or excluded","type":"boolean"},"ids":{"description":"Panel IDs that should be included or excluded","items":{"type":"integer"},"type":"array"}},"required":["ids"],"type":"object"},"AnnotationQueryKind":{"additionalProperties":false,"properties":{"kind":{"const":"AnnotationQuery","type":"string"},"spec":{"$ref":"#/components/schemas/AnnotationQuerySpec"}},"required":["kind","spec"],"type":"object"},"AnnotationQuerySpec":{"additionalProperties":false,"properties":{"builtIn":{"default":false,"type":"boolean"},"datasource":{"$ref":"#/components/schemas/DataSourceRef"},"enable":{"type":"boolean"},"filter":{"$ref":"#/components/schemas/AnnotationPanelFilter"},"hide":{"type":"boolean"},"iconColor":{"type":"string"},"legacyOptions":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"Catch-all field for datasource-specific properties","type":"object"},"mappings":{"additionalProperties":{"$ref":"#/components/schemas/AnnotationEventFieldMapping"},"description":"Mappings define how to convert data frame fields to annotation event fields.","type":"object"},"name":{"type":"string"},"query":{"$ref":"#/components/schemas/DataQueryKind"}},"required":["enable","hide","iconColor","name"],"type":"object"},"AutoGridLayoutItemKind":{"additionalProperties":false,"properties":{"kind":{"const":"AutoGridLayoutItem","type":"string"},"spec":{"$ref":"#/components/schemas/AutoGridLayoutItemSpec"}},"required":["kind","spec"],"type":"object"},"AutoGridLayoutItemSpec":{"additionalProperties":false,"properties":{"conditionalRendering":{"$ref":"#/components/schemas/ConditionalRenderingGroupKind"},"element":{"$ref":"#/components/schemas/ElementReference"},"repeat":{"$ref":"#/components/schemas/AutoGridRepeatOptions"}},"required":["element"],"type":"object"},"AutoGridLayoutKind":{"additionalProperties":false,"properties":{"kind":{"const":"AutoGridLayout","type":"string"},"spec":{"$ref":"#/components/schemas/AutoGridLayoutSpec"}},"required":["kind","spec"],"type":"object"},"AutoGridLayoutSpec":{"additionalProperties":false,"properties":{"columnWidth":{"type":"number"},"columnWidthMode":{"default":"standard","enum":["narrow","standard","wide","custom"],"type":"string"},"fillScreen":{"default":false,"type":"boolean"},"items":{"items":{"$ref":"#/components/schemas/AutoGridLayoutItemKind"},"type":"array"},"maxColumnCount":{"default":3,"type":"number"},"rowHeight":{"type":"number"},"rowHeightMode":{"default":"standard","enum":["short","standard","tall","custom"],"type":"string"}},"required":["columnWidthMode","rowHeightMode","items"],"type":"object"},"AutoGridRepeatOptions":{"additionalProperties":false,"properties":{"mode":{"$ref":"#/components/schemas/RepeatMode"},"value":{"type":"string"}},"required":["mode","value"],"type":"object"},"ConditionalRenderingDataKind":{"additionalProperties":false,"properties":{"kind":{"const":"ConditionalRenderingData","type":"string"},"spec":{"$ref":"#/components/schemas/ConditionalRenderingDataSpec"}},"required":["kind","spec"],"type":"object"},"ConditionalRenderingDataSpec":{"additionalProperties":false,"properties":{"value":{"type":"boolean"}},"required":["value"],"type":"object"},"ConditionalRenderingGroupKind":{"additionalProperties":false,"properties":{"kind":{"const":"ConditionalRenderingGroup","type":"string"},"spec":{"$ref":"#/components/schemas/ConditionalRenderingGroupSpec"}},"required":["kind","spec"],"type":"object"},"ConditionalRenderingGroupSpec":{"additionalProperties":false,"properties":{"condition":{"enum":["and","or"],"type":"string"},"items":{"items":{"oneOf":[{"$ref":"#/components/schemas/ConditionalRenderingVariableKind"},{"$ref":"#/components/schemas/ConditionalRenderingDataKind"},{"$ref":"#/components/schemas/ConditionalRenderingTimeRangeSizeKind"}]},"type":"array"},"visibility":{"enum":["show","hide"],"type":"string"}},"required":["visibility","condition","items"],"type":"object"},"ConditionalRenderingTimeRangeSizeKind":{"additionalProperties":false,"properties":{"kind":{"const":"ConditionalRenderingTimeRangeSize","type":"string"},"spec":{"$ref":"#/components/schemas/ConditionalRenderingTimeRangeSizeSpec"}},"required":["kind","spec"],"type":"object"},"ConditionalRenderingTimeRangeSizeSpec":{"additionalProperties":false,"properties":{"value":{"type":"string"}},"required":["value"],"type":"object"},"ConditionalRenderingVariableKind":{"additionalProperties":false,"properties":{"kind":{"const":"ConditionalRenderingVariable","type":"string"},"spec":{"$ref":"#/components/schemas/ConditionalRenderingVariableSpec"}},"required":["kind","spec"],"type":"object"},"ConditionalRenderingVariableSpec":{"additionalProperties":false,"properties":{"operator":{"enum":["equals","notEquals","matches","notMatches"],"type":"string"},"value":{"type":"string"},"variable":{"type":"string"}},"required":["variable","operator","value"],"type":"object"},"ConstantVariableKind":{"additionalProperties":false,"description":"Constant variable kind","properties":{"kind":{"const":"ConstantVariable","type":"string"},"spec":{"$ref":"#/components/schemas/ConstantVariableSpec"}},"required":["kind","spec"],"type":"object"},"ConstantVariableSpec":{"additionalProperties":false,"description":"Constant variable specification","properties":{"current":{"$ref":"#/components/schemas/VariableOption","default":{"text":"","value":""}},"description":{"type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"label":{"type":"string"},"name":{"default":"","type":"string"},"query":{"default":"","type":"string"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","query","current","hide","skipUrlSync"],"type":"object"},"ConversionStatus":{"additionalProperties":false,"description":"ConversionStatus is the status of the conversion of the dashboard.","properties":{"error":{"description":"The error message from the conversion.\nEmpty if the conversion has not failed.","type":"string"},"failed":{"description":"Whether from another version has failed.\nIf true, means that the dashboard is not valid,\nand the caller should instead fetch the stored version.","type":"boolean"},"source":{"additionalProperties":{},"description":"The original value map[string]any","type":"object"},"storedVersion":{"description":"The version which was stored when the dashboard was created / updated.\nFetching this version should always succeed.","type":"string"}},"required":["failed"],"type":"object"},"CustomVariableKind":{"additionalProperties":false,"description":"Custom variable kind","properties":{"kind":{"const":"CustomVariable","type":"string"},"spec":{"$ref":"#/components/schemas/CustomVariableSpec"}},"required":["kind","spec"],"type":"object"},"CustomVariableSpec":{"additionalProperties":false,"description":"Custom variable specification","properties":{"allValue":{"type":"string"},"allowCustomValue":{"default":true,"type":"boolean"},"current":{"$ref":"#/components/schemas/VariableOption"},"description":{"type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"includeAll":{"default":false,"type":"boolean"},"label":{"type":"string"},"multi":{"default":false,"type":"boolean"},"name":{"default":"","type":"string"},"options":{"items":{"$ref":"#/components/schemas/VariableOption"},"type":"array"},"query":{"default":"","type":"string"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","query","current","options","multi","includeAll","hide","skipUrlSync","allowCustomValue"],"type":"object"},"Dashboard":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"DashboardCursorSync":{"description":"\"Off\" for no shared crosshair or tooltip (default).\n\"Crosshair\" for shared crosshair.\n\"Tooltip\" for shared crosshair AND shared tooltip.","enum":["Crosshair","Tooltip","Off"],"type":"string"},"DashboardLink":{"additionalProperties":false,"description":"Links with references to other dashboards or external resources","properties":{"asDropdown":{"default":false,"description":"If true, all dashboards links will be displayed in a dropdown. If false, all dashboards links will be displayed side by side. Only valid if the type is dashboards","type":"boolean"},"icon":{"description":"Icon name to be displayed with the link","type":"string"},"includeVars":{"default":false,"description":"If true, includes current template variables values in the link as query params","type":"boolean"},"keepTime":{"default":false,"description":"If true, includes current time range in the link as query params","type":"boolean"},"placement":{"$ref":"#/components/schemas/DashboardLinkPlacement","description":"Placement can be used to display the link somewhere else on the dashboard other than above the visualisations."},"tags":{"description":"List of tags to limit the linked dashboards. If empty, all dashboards will be displayed. Only valid if the type is dashboards","items":{"type":"string"},"type":"array"},"targetBlank":{"default":false,"description":"If true, the link will be opened in a new tab","type":"boolean"},"title":{"description":"Title to display with the link","type":"string"},"tooltip":{"description":"Tooltip to display when the user hovers their mouse over it","type":"string"},"type":{"$ref":"#/components/schemas/DashboardLinkType","description":"Link type. Accepted values are dashboards (to refer to another dashboard) and link (to refer to an external resource)\nFIXME: The type is generated as ` + "`" + `type: DashboardLinkType | dashboardLinkType.Link;` + "`" + ` but it should be ` + "`" + `type: DashboardLinkType` + "`" + `"},"url":{"description":"Link URL. Only required/valid if the type is link","type":"string"}},"required":["title","type","icon","tooltip","tags","asDropdown","targetBlank","includeVars","keepTime"],"type":"object"},"DashboardLinkPlacement":{"const":"inControlsMenu","description":"Dashboard Link placement. Defines where the link should be displayed.\n- \"inControlsMenu\" renders the link in bottom part of the dashboard controls dropdown menu","type":"string"},"DashboardLinkType":{"description":"Dashboard Link type. Accepted values are dashboards (to refer to another dashboard) and link (to refer to an external resource)","enum":["link","dashboards"],"type":"string"},"DataLink":{"additionalProperties":false,"properties":{"targetBlank":{"type":"boolean"},"title":{"type":"string"},"url":{"type":"string"}},"required":["title","url"],"type":"object"},"DataQueryKind":{"additionalProperties":false,"properties":{"kind":{"description":"The kind of a DataQueryKind is the datasource type","type":"string"},"spec":{"additionalProperties":{"additionalProperties":{},"type":"object"},"type":"object"}},"required":["kind","spec"],"type":"object"},"DataSourceRef":{"additionalProperties":false,"properties":{"type":{"description":"The plugin type-id","type":"string"},"uid":{"description":"Specific datasource instance","type":"string"}},"type":"object"},"DataTopic":{"description":"A topic is attached to DataFrame metadata in query results.\nThis specifies where the data should be used.","enum":["series","annotations","alertStates"],"type":"string"},"DataTransformerConfig":{"additionalProperties":false,"description":"Transformations allow to manipulate data returned by a query before the system applies a visualization.\nUsing transformations you can: rename fields, join time series data, perform mathematical operations across queries,\nuse the output of one transformation as the input to another transformation, etc.","properties":{"disabled":{"description":"Disabled transformations are skipped","type":"boolean"},"filter":{"$ref":"#/components/schemas/MatcherConfig","description":"Optional frame matcher. When missing it will be applied to all results"},"id":{"description":"Unique identifier of transformer","type":"string"},"options":{"additionalProperties":{},"description":"Options to be passed to the transformer\nValid options depend on the transformer id","type":"object"},"topic":{"$ref":"#/components/schemas/DataTopic","description":"Where to pull DataFrames from as input to transformation"}},"required":["id","options"],"type":"object"},"DatasourceVariableKind":{"additionalProperties":false,"description":"Datasource variable kind","properties":{"kind":{"const":"DatasourceVariable","type":"string"},"spec":{"$ref":"#/components/schemas/DatasourceVariableSpec"}},"required":["kind","spec"],"type":"object"},"DatasourceVariableSpec":{"additionalProperties":false,"description":"Datasource variable specification","properties":{"allValue":{"type":"string"},"allowCustomValue":{"default":true,"type":"boolean"},"current":{"$ref":"#/components/schemas/VariableOption","default":{"text":"","value":""}},"description":{"type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"includeAll":{"default":false,"type":"boolean"},"label":{"type":"string"},"multi":{"default":false,"type":"boolean"},"name":{"default":"","type":"string"},"options":{"items":{"$ref":"#/components/schemas/VariableOption"},"type":"array"},"pluginId":{"default":"","type":"string"},"refresh":{"$ref":"#/components/schemas/VariableRefresh","default":"never"},"regex":{"default":"","type":"string"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","pluginId","refresh","regex","current","options","multi","includeAll","hide","skipUrlSync","allowCustomValue"],"type":"object"},"DynamicConfigValue":{"additionalProperties":false,"properties":{"id":{"default":"","type":"string"},"value":{"additionalProperties":{},"type":"object"}},"required":["id"],"type":"object"},"Element":{"description":"Supported dashboard elements\n|* more element types in the future","oneOf":[{"$ref":"#/components/schemas/PanelKind"},{"$ref":"#/components/schemas/LibraryPanelKind"}]},"ElementReference":{"additionalProperties":false,"properties":{"kind":{"const":"ElementReference","type":"string"},"name":{"type":"string"}},"required":["kind","name"],"type":"object"},"FetchOptions":{"additionalProperties":false,"properties":{"body":{"type":"string"},"headers":{"items":{"items":{"type":"string"},"type":"array"},"type":"array"},"method":{"$ref":"#/components/schemas/HttpRequestMethod"},"queryParams":{"description":"These are 2D arrays of strings, each representing a key-value pair\nWe are defining them this way because we can't generate a go struct that\nthat would have exactly two strings in each sub-array","items":{"items":{"type":"string"},"type":"array"},"type":"array"},"url":{"type":"string"}},"required":["method","url"],"type":"object"},"FieldColor":{"additionalProperties":false,"description":"Map a field to a color.","properties":{"fixedColor":{"description":"The fixed color value for fixed or shades color modes.","type":"string"},"mode":{"$ref":"#/components/schemas/FieldColorModeId","description":"The main color scheme mode."},"seriesBy":{"$ref":"#/components/schemas/FieldColorSeriesByMode","description":"Some visualizations need to know how to assign a series color from by value color schemes."}},"required":["mode"],"type":"object"},"FieldColorModeId":{"description":"Color mode for a field. You can specify a single color, or select a continuous (gradient) color schemes, based on a value.\nContinuous color interpolates a color using the percentage of a value relative to min and max.\nAccepted values are:\n` + "`" + `thresholds` + "`" + `: From thresholds. Informs Grafana to take the color from the matching threshold\n` + "`" + `palette-classic` + "`" + `: Classic palette. Grafana will assign color by looking up a color in a palette by series index. Useful for Graphs and pie charts and other categorical data visualizations\n` + "`" + `palette-classic-by-name` + "`" + `: Classic palette (by name). Grafana will assign color by looking up a color in a palette by series name. Useful for Graphs and pie charts and other categorical data visualizations\n` + "`" + `continuous-viridis` + "`" + `: Continuous Viridis palette mode\n` + "`" + `continuous-magma` + "`" + `: Continuous Magma palette mode\n` + "`" + `continuous-plasma` + "`" + `: Continuous Plasma palette mode\n` + "`" + `continuous-inferno` + "`" + `: Continuous Inferno palette mode\n` + "`" + `continuous-cividis` + "`" + `: Continuous Cividis palette mode\n` + "`" + `continuous-GrYlRd` + "`" + `: Continuous Green-Yellow-Red palette mode\n` + "`" + `continuous-RdYlGr` + "`" + `: Continuous Red-Yellow-Green palette mode\n` + "`" + `continuous-BlYlRd` + "`" + `: Continuous Blue-Yellow-Red palette mode\n` + "`" + `continuous-YlRd` + "`" + `: Continuous Yellow-Red palette mode\n` + "`" + `continuous-BlPu` + "`" + `: Continuous Blue-Purple palette mode\n` + "`" + `continuous-YlBl` + "`" + `: Continuous Yellow-Blue palette mode\n` + "`" + `continuous-blues` + "`" + `: Continuous Blue palette mode\n` + "`" + `continuous-reds` + "`" + `: Continuous Red palette mode\n` + "`" + `continuous-greens` + "`" + `: Continuous Green palette mode\n` + "`" + `continuous-purples` + "`" + `: Continuous Purple palette mode\n` + "`" + `shades` + "`" + `: Shades of a single color. Specify a single color, useful in an override rule.\n` + "`" + `fixed` + "`" + `: Fixed color mode. Specify a single color, useful in an override rule.","enum":["thresholds","palette-classic","palette-classic-by-name","continuous-viridis","continuous-magma","continuous-plasma","continuous-inferno","continuous-cividis","continuous-GrYlRd","continuous-RdYlGr","continuous-BlYlRd","continuous-YlRd","continuous-BlPu","continuous-YlBl","continuous-blues","continuous-reds","continuous-greens","continuous-purples","fixed","shades"],"type":"string"},"FieldColorSeriesByMode":{"description":"Defines how to assign a series color from \"by value\" color schemes. For example for an aggregated data points like a timeseries, the color can be assigned by the min, max or last value.","enum":["min","max","last"],"type":"string"},"FieldConfig":{"additionalProperties":false,"description":"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.\nEach column within this structure is called a field. A field can represent a single time series or table column.\nField options allow you to change how the data is displayed in your visualizations.","properties":{"actions":{"description":"Define interactive HTTP requests that can be triggered from data visualizations.","items":{"$ref":"#/components/schemas/Action"},"type":"array"},"color":{"$ref":"#/components/schemas/FieldColor","description":"Panel color configuration"},"custom":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"custom is specified by the FieldConfig field\nin panel plugin schemas.","type":"object"},"decimals":{"description":"Specify the number of decimals Grafana includes in the rendered value.\nIf you leave this field blank, Grafana automatically truncates the number of decimals based on the value.\nFor example 1.1234 will display as 1.12 and 100.456 will display as 100.\nTo display all decimals, set the unit to ` + "`" + `String` + "`" + `.","type":"number"},"description":{"description":"Human readable field metadata","type":"string"},"displayName":{"description":"The display value for this field. This supports template variables blank is auto","type":"string"},"displayNameFromDS":{"description":"This can be used by data sources that return and explicit naming structure for values and labels\nWhen this property is configured, this value is used rather than the default naming strategy.","type":"string"},"filterable":{"description":"True if data source field supports ad-hoc filters","type":"boolean"},"links":{"description":"The behavior when clicking on a result","items":{"additionalProperties":{},"type":"object"},"type":"array"},"mappings":{"description":"Convert input values into a display string","items":{"$ref":"#/components/schemas/ValueMapping"},"type":"array"},"max":{"description":"The maximum value used in percentage threshold calculations. Leave blank for auto calculation based on all series and fields.","type":"number"},"min":{"description":"The minimum value used in percentage threshold calculations. Leave blank for auto calculation based on all series and fields.","type":"number"},"noValue":{"description":"Alternative to empty string","type":"string"},"path":{"description":"An explicit path to the field in the datasource. When the frame meta includes a path,\nThis will default to ` + "`" + `${frame.meta.path}/${field.name}\n\nWhen defined, this value can be used as an identifier within the datasource scope, and\nmay be used to update the results","type":"string"},"thresholds":{"$ref":"#/components/schemas/ThresholdsConfig","description":"Map numeric values to states"},"unit":{"description":"Unit a field should use. The unit you select is applied to all fields except time.\nYou can use the units ID availables in Grafana or a custom unit.\nAvailable units in Grafana: https://github.com/grafana/grafana/blob/main/packages/grafana-data/src/valueFormats/categories.ts\nAs custom unit, you can use the following formats:\n` + "`" + `suffix:\u003csuffix\u003e` + "`" + ` for custom unit that should go after value.\n` + "`" + `prefix:\u003cprefix\u003e` + "`" + ` for custom unit that should go before value.\n` + "`" + `time:\u003cformat\u003e` + "`" + ` For custom date time formats type for example ` + "`" + `time:YYYY-MM-DD` + "`" + `.\n` + "`" + `si:\u003cbase scale\u003e\u003cunit characters\u003e` + "`" + ` for custom SI units. For example: ` + "`" + `si: mF` + "`" + `. This one is a bit more advanced as you can specify both a unit and the source data scale. So if your source data is represented as milli (thousands of) something prefix the unit with that SI scale character.\n` + "`" + `count:\u003cunit\u003e` + "`" + ` for a custom count unit.\n` + "`" + `currency:\u003cunit\u003e` + "`" + ` for custom a currency unit.","type":"string"},"writeable":{"description":"True if data source can write a value to the path. Auth/authz are supported separately","type":"boolean"}},"type":"object"},"FieldConfigSource":{"additionalProperties":false,"description":"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.\nEach column within this structure is called a field. A field can represent a single time series or table column.\nField options allow you to change how the data is displayed in your visualizations.","properties":{"defaults":{"$ref":"#/components/schemas/FieldConfig","description":"Defaults are the options applied to all fields."},"overrides":{"description":"Overrides are the options applied to specific fields overriding the defaults.","items":{"additionalProperties":false,"properties":{"__systemRef":{"description":"Describes config override rules created when interacting with Grafana.","type":"string"},"matcher":{"$ref":"#/components/schemas/MatcherConfig"},"properties":{"items":{"$ref":"#/components/schemas/DynamicConfigValue"},"type":"array"}},"required":["matcher","properties"],"type":"object"},"type":"array"}},"required":["defaults","overrides"],"type":"object"},"FilterOrigin":{"const":"dashboard","description":"Determine the origin of the adhoc variable filter","type":"string"},"GridLayoutItemKind":{"additionalProperties":false,"properties":{"kind":{"const":"GridLayoutItem","type":"string"},"spec":{"$ref":"#/components/schemas/GridLayoutItemSpec"}},"required":["kind","spec"],"type":"object"},"GridLayoutItemSpec":{"additionalProperties":false,"properties":{"element":{"$ref":"#/components/schemas/ElementReference","description":"reference to a PanelKind from dashboard.spec.elements Expressed as JSON Schema reference"},"height":{"type":"integer"},"repeat":{"$ref":"#/components/schemas/RepeatOptions"},"width":{"type":"integer"},"x":{"type":"integer"},"y":{"type":"integer"}},"required":["x","y","width","height","element"],"type":"object"},"GridLayoutKind":{"additionalProperties":false,"properties":{"kind":{"const":"GridLayout","type":"string"},"spec":{"$ref":"#/components/schemas/GridLayoutSpec"}},"required":["kind","spec"],"type":"object"},"GridLayoutSpec":{"additionalProperties":false,"properties":{"items":{"items":{"$ref":"#/components/schemas/GridLayoutItemKind"},"type":"array"}},"required":["items"],"type":"object"},"GroupByVariableKind":{"additionalProperties":false,"description":"Group variable kind","properties":{"kind":{"const":"GroupByVariable","type":"string"},"spec":{"$ref":"#/components/schemas/GroupByVariableSpec"}},"required":["kind","spec"],"type":"object"},"GroupByVariableSpec":{"additionalProperties":false,"description":"GroupBy variable specification","properties":{"current":{"$ref":"#/components/schemas/VariableOption","default":{"text":"","value":""}},"datasource":{"$ref":"#/components/schemas/DataSourceRef"},"defaultValue":{"$ref":"#/components/schemas/VariableOption"},"description":{"type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"label":{"type":"string"},"multi":{"default":false,"type":"boolean"},"name":{"default":"","type":"string"},"options":{"items":{"$ref":"#/components/schemas/VariableOption"},"type":"array"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","current","options","multi","hide","skipUrlSync"],"type":"object"},"HttpRequestMethod":{"enum":["GET","PUT","POST","DELETE","PATCH"],"type":"string"},"InfinityOptions":{"additionalProperties":false,"properties":{"body":{"type":"string"},"datasourceUid":{"type":"string"},"headers":{"items":{"items":{"type":"string"},"type":"array"},"type":"array"},"method":{"$ref":"#/components/schemas/HttpRequestMethod"},"queryParams":{"description":"These are 2D arrays of strings, each representing a key-value pair\nWe are defining them this way because we can't generate a go struct that\nthat would have exactly two strings in each sub-array","items":{"items":{"type":"string"},"type":"array"},"type":"array"},"url":{"type":"string"}},"required":["method","url","datasourceUid"],"type":"object"},"IntervalVariableKind":{"additionalProperties":false,"description":"Interval variable kind","properties":{"kind":{"const":"IntervalVariable","type":"string"},"spec":{"$ref":"#/components/schemas/IntervalVariableSpec"}},"required":["kind","spec"],"type":"object"},"IntervalVariableSpec":{"additionalProperties":false,"description":"Interval variable specification","properties":{"auto":{"default":false,"type":"boolean"},"auto_count":{"default":0,"type":"integer"},"auto_min":{"default":"","type":"string"},"current":{"$ref":"#/components/schemas/VariableOption","default":{"text":"","value":""}},"description":{"type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"label":{"type":"string"},"name":{"default":"","type":"string"},"options":{"items":{"$ref":"#/components/schemas/VariableOption"},"type":"array"},"query":{"default":"","type":"string"},"refresh":{"$ref":"#/components/schemas/VariableRefresh","default":"never"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","query","current","options","auto","auto_min","auto_count","refresh","hide","skipUrlSync"],"type":"object"},"LibraryPanelKind":{"additionalProperties":false,"properties":{"kind":{"const":"LibraryPanel","type":"string"},"spec":{"$ref":"#/components/schemas/LibraryPanelKindSpec"}},"required":["kind","spec"],"type":"object"},"LibraryPanelKindSpec":{"additionalProperties":false,"properties":{"id":{"description":"Panel ID for the library panel in the dashboard","type":"number"},"libraryPanel":{"$ref":"#/components/schemas/LibraryPanelRef"},"title":{"description":"Title for the library panel in the dashboard","type":"string"}},"required":["id","title","libraryPanel"],"type":"object"},"LibraryPanelRef":{"additionalProperties":false,"description":"A library panel is a reusable panel that you can use in any dashboard.\nWhen you make a change to a library panel, that change propagates to all instances of where the panel is used.\nLibrary panels streamline reuse of panels across multiple dashboards.","properties":{"name":{"description":"Library panel name","type":"string"},"uid":{"description":"Library panel uid","type":"string"}},"required":["name","uid"],"type":"object"},"MappingType":{"description":"Supported value mapping types\n` + "`" + `value` + "`" + `: Maps text values to a color or different display text and color. For example, you can configure a value mapping so that all instances of the value 10 appear as Perfection! rather than the number.\n` + "`" + `range` + "`" + `: Maps numerical ranges to a display text and color. For example, if a value is within a certain range, you can configure a range value mapping to display Low or High rather than the number.\n` + "`" + `regex` + "`" + `: Maps regular expressions to replacement text and a color. For example, if a value is www.example.com, you can configure a regex value mapping so that Grafana displays www and truncates the domain.\n` + "`" + `special` + "`" + `: Maps special values like Null, NaN (not a number), and boolean values like true and false to a display text and color. See SpecialValueMatch to see the list of special values. For example, you can configure a special value mapping so that null values appear as N/A.","enum":["value","range","regex","special"],"type":"string"},"MatcherConfig":{"additionalProperties":false,"description":"Matcher is a predicate configuration. Based on the config a set of field(s) or values is filtered in order to apply override / transformation.\nIt comes with in id ( to resolve implementation from registry) and a configuration that’s specific to a particular matcher type.","properties":{"id":{"default":"","description":"The matcher id. This is used to find the matcher implementation from registry.","type":"string"},"options":{"additionalProperties":{},"description":"The matcher options. This is specific to the matcher implementation.","type":"object"}},"required":["id"],"type":"object"},"MetricFindValue":{"additionalProperties":false,"description":"Define the MetricFindValue type","properties":{"expandable":{"type":"boolean"},"group":{"type":"string"},"text":{"type":"string"},"value":{"oneOf":[{"type":"string"},{"type":"number"}]}},"required":["text"],"type":"object"},"PanelKind":{"additionalProperties":false,"properties":{"kind":{"const":"Panel","type":"string"},"spec":{"$ref":"#/components/schemas/PanelSpec"}},"required":["kind","spec"],"type":"object"},"PanelQueryKind":{"additionalProperties":false,"properties":{"kind":{"const":"PanelQuery","type":"string"},"spec":{"$ref":"#/components/schemas/PanelQuerySpec"}},"required":["kind","spec"],"type":"object"},"PanelQuerySpec":{"additionalProperties":false,"properties":{"datasource":{"$ref":"#/components/schemas/DataSourceRef"},"hidden":{"type":"boolean"},"query":{"$ref":"#/components/schemas/DataQueryKind"},"refId":{"type":"string"}},"required":["query","refId","hidden"],"type":"object"},"PanelSpec":{"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/QueryGroupKind"},"description":{"type":"string"},"id":{"type":"number"},"links":{"items":{"$ref":"#/components/schemas/DataLink"},"type":"array"},"title":{"type":"string"},"transparent":{"type":"boolean"},"vizConfig":{"$ref":"#/components/schemas/VizConfigKind"}},"required":["id","title","description","links","data","vizConfig"],"type":"object"},"QueryGroupKind":{"additionalProperties":false,"properties":{"kind":{"const":"QueryGroup","type":"string"},"spec":{"$ref":"#/components/schemas/QueryGroupSpec"}},"required":["kind","spec"],"type":"object"},"QueryGroupSpec":{"additionalProperties":false,"properties":{"queries":{"items":{"$ref":"#/components/schemas/PanelQueryKind"},"type":"array"},"queryOptions":{"$ref":"#/components/schemas/QueryOptionsSpec"},"transformations":{"items":{"$ref":"#/components/schemas/TransformationKind"},"type":"array"}},"required":["queries","transformations","queryOptions"],"type":"object"},"QueryOptionsSpec":{"additionalProperties":false,"properties":{"cacheTimeout":{"type":"string"},"hideTimeOverride":{"type":"boolean"},"interval":{"type":"string"},"maxDataPoints":{"type":"integer"},"queryCachingTTL":{"type":"integer"},"timeFrom":{"type":"string"},"timeShift":{"type":"string"}},"type":"object"},"QueryVariableKind":{"additionalProperties":false,"description":"Query variable kind","properties":{"kind":{"const":"QueryVariable","type":"string"},"spec":{"$ref":"#/components/schemas/QueryVariableSpec"}},"required":["kind","spec"],"type":"object"},"QueryVariableSpec":{"additionalProperties":false,"description":"Query variable specification","properties":{"allValue":{"type":"string"},"allowCustomValue":{"default":true,"type":"boolean"},"current":{"$ref":"#/components/schemas/VariableOption","default":{"text":"","value":""}},"datasource":{"$ref":"#/components/schemas/DataSourceRef"},"definition":{"type":"string"},"description":{"type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"includeAll":{"default":false,"type":"boolean"},"label":{"type":"string"},"multi":{"default":false,"type":"boolean"},"name":{"default":"","type":"string"},"options":{"items":{"$ref":"#/components/schemas/VariableOption"},"type":"array"},"placeholder":{"type":"string"},"query":{"$ref":"#/components/schemas/DataQueryKind"},"refresh":{"$ref":"#/components/schemas/VariableRefresh","default":"never"},"regex":{"default":"","type":"string"},"regexApplyTo":{"$ref":"#/components/schemas/VariableRegexApplyTo","default":"value"},"skipUrlSync":{"default":false,"type":"boolean"},"sort":{"$ref":"#/components/schemas/VariableSort"},"staticOptions":{"items":{"$ref":"#/components/schemas/VariableOption"},"type":"array"},"staticOptionsOrder":{"enum":["before","after","sorted"],"type":"string"}},"required":["name","current","hide","refresh","skipUrlSync","query","regex","sort","options","multi","includeAll","allowCustomValue"],"type":"object"},"RangeMap":{"additionalProperties":false,"description":"Maps numerical ranges to a display text and color.\nFor example, if a value is within a certain range, you can configure a range value mapping to display Low or High rather than the number.","properties":{"options":{"additionalProperties":false,"description":"Range to match against and the result to apply when the value is within the range","properties":{"from":{"description":"Min value of the range. It can be null which means -Infinity","type":"number"},"result":{"$ref":"#/components/schemas/ValueMappingResult","description":"Config to apply when the value is within the range"},"to":{"description":"Max value of the range. It can be null which means +Infinity","type":"number"}},"required":["from","to","result"],"type":"object"},"type":{"$ref":"#/components/schemas/MappingType"}},"required":["type","options"],"type":"object"},"RegexMap":{"additionalProperties":false,"description":"Maps regular expressions to replacement text and a color.\nFor example, if a value is www.example.com, you can configure a regex value mapping so that Grafana displays www and truncates the domain.","properties":{"options":{"additionalProperties":false,"description":"Regular expression to match against and the result to apply when the value matches the regex","properties":{"pattern":{"description":"Regular expression to match against","type":"string"},"result":{"$ref":"#/components/schemas/ValueMappingResult","description":"Config to apply when the value matches the regex"}},"required":["pattern","result"],"type":"object"},"type":{"$ref":"#/components/schemas/MappingType"}},"required":["type","options"],"type":"object"},"RepeatMode":{"const":"variable","description":"other repeat modes will be added in the future: label, frame","type":"string"},"RepeatOptions":{"additionalProperties":false,"properties":{"direction":{"enum":["h","v"],"type":"string"},"maxPerRow":{"type":"integer"},"mode":{"$ref":"#/components/schemas/RepeatMode"},"value":{"type":"string"}},"required":["mode","value"],"type":"object"},"RowRepeatOptions":{"additionalProperties":false,"properties":{"mode":{"$ref":"#/components/schemas/RepeatMode"},"value":{"type":"string"}},"required":["mode","value"],"type":"object"},"RowsLayoutKind":{"additionalProperties":false,"properties":{"kind":{"const":"RowsLayout","type":"string"},"spec":{"$ref":"#/components/schemas/RowsLayoutSpec"}},"required":["kind","spec"],"type":"object"},"RowsLayoutRowKind":{"additionalProperties":false,"properties":{"kind":{"const":"RowsLayoutRow","type":"string"},"spec":{"$ref":"#/components/schemas/RowsLayoutRowSpec"}},"required":["kind","spec"],"type":"object"},"RowsLayoutRowSpec":{"additionalProperties":false,"properties":{"collapse":{"type":"boolean"},"conditionalRendering":{"$ref":"#/components/schemas/ConditionalRenderingGroupKind"},"fillScreen":{"type":"boolean"},"hideHeader":{"type":"boolean"},"layout":{"oneOf":[{"$ref":"#/components/schemas/GridLayoutKind"},{"$ref":"#/components/schemas/AutoGridLayoutKind"},{"$ref":"#/components/schemas/TabsLayoutKind"},{"$ref":"#/components/schemas/RowsLayoutKind"}]},"repeat":{"$ref":"#/components/schemas/RowRepeatOptions"},"title":{"type":"string"}},"required":["layout"],"type":"object"},"RowsLayoutSpec":{"additionalProperties":false,"properties":{"rows":{"items":{"$ref":"#/components/schemas/RowsLayoutRowKind"},"type":"array"}},"required":["rows"],"type":"object"},"SpecialValueMap":{"additionalProperties":false,"description":"Maps special values like Null, NaN (not a number), and boolean values like true and false to a display text and color.\nSee SpecialValueMatch to see the list of special values.\nFor example, you can configure a special value mapping so that null values appear as N/A.","properties":{"options":{"additionalProperties":false,"properties":{"match":{"$ref":"#/components/schemas/SpecialValueMatch","description":"Special value to match against"},"result":{"$ref":"#/components/schemas/ValueMappingResult","description":"Config to apply when the value matches the special value"}},"required":["match","result"],"type":"object"},"type":{"$ref":"#/components/schemas/MappingType"}},"required":["type","options"],"type":"object"},"SpecialValueMatch":{"description":"Special value types supported by the ` + "`" + `SpecialValueMap` + "`" + `","enum":["true","false","null","nan","null+nan","empty"],"type":"string"},"SwitchVariableKind":{"additionalProperties":false,"properties":{"kind":{"const":"SwitchVariable","type":"string"},"spec":{"$ref":"#/components/schemas/SwitchVariableSpec"}},"required":["kind","spec"],"type":"object"},"SwitchVariableSpec":{"additionalProperties":false,"description":"Switch variable specification","properties":{"current":{"default":"false","type":"string"},"description":{"type":"string"},"disabledValue":{"default":"false","type":"string"},"enabledValue":{"default":"true","type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"label":{"type":"string"},"name":{"default":"","type":"string"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","current","enabledValue","disabledValue","hide","skipUrlSync"],"type":"object"},"TabRepeatOptions":{"additionalProperties":false,"properties":{"mode":{"$ref":"#/components/schemas/RepeatMode"},"value":{"type":"string"}},"required":["mode","value"],"type":"object"},"TabsLayoutKind":{"additionalProperties":false,"properties":{"kind":{"const":"TabsLayout","type":"string"},"spec":{"$ref":"#/components/schemas/TabsLayoutSpec"}},"required":["kind","spec"],"type":"object"},"TabsLayoutSpec":{"additionalProperties":false,"properties":{"tabs":{"items":{"$ref":"#/components/schemas/TabsLayoutTabKind"},"type":"array"}},"required":["tabs"],"type":"object"},"TabsLayoutTabKind":{"additionalProperties":false,"properties":{"kind":{"const":"TabsLayoutTab","type":"string"},"spec":{"$ref":"#/components/schemas/TabsLayoutTabSpec"}},"required":["kind","spec"],"type":"object"},"TabsLayoutTabSpec":{"additionalProperties":false,"properties":{"conditionalRendering":{"$ref":"#/components/schemas/ConditionalRenderingGroupKind"},"layout":{"oneOf":[{"$ref":"#/components/schemas/GridLayoutKind"},{"$ref":"#/components/schemas/RowsLayoutKind"},{"$ref":"#/components/schemas/AutoGridLayoutKind"},{"$ref":"#/components/schemas/TabsLayoutKind"}]},"repeat":{"$ref":"#/components/schemas/TabRepeatOptions"},"title":{"type":"string"}},"required":["layout"],"type":"object"},"TextVariableKind":{"additionalProperties":false,"description":"Text variable kind","properties":{"kind":{"const":"TextVariable","type":"string"},"spec":{"$ref":"#/components/schemas/TextVariableSpec"}},"required":["kind","spec"],"type":"object"},"TextVariableSpec":{"additionalProperties":false,"description":"Text variable specification","properties":{"current":{"$ref":"#/components/schemas/VariableOption","default":{"text":"","value":""}},"description":{"type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"label":{"type":"string"},"name":{"default":"","type":"string"},"query":{"default":"","type":"string"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","current","query","hide","skipUrlSync"],"type":"object"},"Threshold":{"additionalProperties":false,"properties":{"color":{"type":"string"},"value":{"description":"Value null means -Infinity","type":"number"}},"required":["value","color"],"type":"object"},"ThresholdsConfig":{"additionalProperties":false,"properties":{"mode":{"$ref":"#/components/schemas/ThresholdsMode"},"steps":{"items":{"$ref":"#/components/schemas/Threshold"},"type":"array"}},"required":["mode","steps"],"type":"object"},"ThresholdsMode":{"enum":["absolute","percentage"],"type":"string"},"TimeRangeOption":{"additionalProperties":false,"properties":{"display":{"default":"Last 6 hours","type":"string"},"from":{"default":"now-6h","type":"string"},"to":{"default":"now","type":"string"}},"required":["display","from","to"],"type":"object"},"TimeSettingsSpec":{"additionalProperties":false,"description":"Time configuration\nIt defines the default time config for the time picker, the refresh picker for the specific dashboard.","properties":{"autoRefresh":{"default":"","description":"Refresh rate of dashboard. Represented via interval string, e.g. \"5s\", \"1m\", \"1h\", \"1d\".\nv1: refresh","type":"string"},"autoRefreshIntervals":{"default":["5s","10s","30s","1m","5m","15m","30m","1h","2h","1d"],"description":"Interval options available in the refresh picker dropdown.\nv1: timepicker.refresh_intervals","items":{"type":"string"},"type":"array"},"fiscalYearStartMonth":{"default":0,"description":"The month that the fiscal year starts on. 0 = January, 11 = December","type":"integer"},"from":{"default":"now-6h","description":"Start time range for dashboard.\nAccepted values are relative time strings like \"now-6h\" or absolute time strings like \"2020-07-10T08:00:00.000Z\".","type":"string"},"hideTimepicker":{"default":false,"description":"Whether timepicker is visible or not.\nv1: timepicker.hidden","type":"boolean"},"nowDelay":{"description":"Override the now time by entering a time delay. Use this option to accommodate known delays in data aggregation to avoid null values.\nv1: timepicker.nowDelay","type":"string"},"quickRanges":{"description":"Selectable options available in the time picker dropdown. Has no effect on provisioned dashboard.\nv1: timepicker.quick_ranges , not exposed in the UI","items":{"$ref":"#/components/schemas/TimeRangeOption"},"type":"array"},"timezone":{"default":"browser","description":"Timezone of dashboard. Accepted values are IANA TZDB zone ID or \"browser\" or \"utc\".","type":"string"},"to":{"default":"now","description":"End time range for dashboard.\nAccepted values are relative time strings like \"now-6h\" or absolute time strings like \"2020-07-10T08:00:00.000Z\".","type":"string"},"weekStart":{"description":"Day when the week starts. Expressed by the name of the day in lowercase, e.g. \"monday\".","enum":["saturday","monday","sunday"],"type":"string"}},"required":["from","to","autoRefresh","autoRefreshIntervals","hideTimepicker","fiscalYearStartMonth"],"type":"object"},"TransformationKind":{"additionalProperties":false,"properties":{"kind":{"description":"The kind of a TransformationKind is the transformation ID","type":"string"},"spec":{"$ref":"#/components/schemas/DataTransformerConfig"}},"required":["kind","spec"],"type":"object"},"ValueMap":{"additionalProperties":false,"description":"Maps text values to a color or different display text and color.\nFor example, you can configure a value mapping so that all instances of the value 10 appear as Perfection! rather than the number.","properties":{"options":{"additionalProperties":{"$ref":"#/components/schemas/ValueMappingResult"},"description":"Map with \u003cvalue_to_match\u003e: ValueMappingResult. For example: { \"10\": { text: \"Perfection!\", color: \"green\" } }","type":"object"},"type":{"$ref":"#/components/schemas/MappingType"}},"required":["type","options"],"type":"object"},"ValueMapping":{"oneOf":[{"$ref":"#/components/schemas/ValueMap"},{"$ref":"#/components/schemas/RangeMap"},{"$ref":"#/components/schemas/RegexMap"},{"$ref":"#/components/schemas/SpecialValueMap"}]},"ValueMappingResult":{"additionalProperties":false,"description":"Result used as replacement with text and color when the value matches","properties":{"color":{"description":"Text to use when the value matches","type":"string"},"icon":{"description":"Icon to display when the value matches. Only specific visualizations.","type":"string"},"index":{"description":"Position in the mapping array. Only used internally.","type":"integer"},"text":{"description":"Text to display when the value matches","type":"string"}},"type":"object"},"VariableHide":{"description":"Determine if the variable shows on dashboard\nAccepted values are ` + "`" + `dontHide` + "`" + ` (show label and value), ` + "`" + `hideLabel` + "`" + ` (show value only), ` + "`" + `hideVariable` + "`" + ` (show nothing).","enum":["dontHide","hideLabel","hideVariable"],"type":"string"},"VariableKind":{"oneOf":[{"$ref":"#/components/schemas/QueryVariableKind"},{"$ref":"#/components/schemas/TextVariableKind"},{"$ref":"#/components/schemas/ConstantVariableKind"},{"$ref":"#/components/schemas/DatasourceVariableKind"},{"$ref":"#/components/schemas/IntervalVariableKind"},{"$ref":"#/components/schemas/CustomVariableKind"},{"$ref":"#/components/schemas/GroupByVariableKind"},{"$ref":"#/components/schemas/AdhocVariableKind"},{"$ref":"#/components/schemas/SwitchVariableKind"}]},"VariableOption":{"additionalProperties":false,"description":"Variable option specification","properties":{"selected":{"description":"Whether the option is selected or not","type":"boolean"},"text":{"description":"Text to be displayed for the option","oneOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"}]},"value":{"description":"Value of the option","oneOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"}]}},"required":["text","value"],"type":"object"},"VariableRefresh":{"description":"Options to config when to refresh a variable\n` + "`" + `never` + "`" + `: Never refresh the variable\n` + "`" + `onDashboardLoad` + "`" + `: Queries the data source every time the dashboard loads.\n` + "`" + `onTimeRangeChanged` + "`" + `: Queries the data source when the dashboard time range changes.","enum":["never","onDashboardLoad","onTimeRangeChanged"],"type":"string"},"VariableRegexApplyTo":{"description":"Determine whether regex applies to variable value or display text\nAccepted values are ` + "`" + `value` + "`" + ` (apply to value used in queries) or ` + "`" + `text` + "`" + ` (apply to display text shown to users)","enum":["value","text"],"type":"string"},"VariableSort":{"description":"Sort variable options\nAccepted values are:\n` + "`" + `disabled` + "`" + `: No sorting\n` + "`" + `alphabeticalAsc` + "`" + `: Alphabetical ASC\n` + "`" + `alphabeticalDesc` + "`" + `: Alphabetical DESC\n` + "`" + `numericalAsc` + "`" + `: Numerical ASC\n` + "`" + `numericalDesc` + "`" + `: Numerical DESC\n` + "`" + `alphabeticalCaseInsensitiveAsc` + "`" + `: Alphabetical Case Insensitive ASC\n` + "`" + `alphabeticalCaseInsensitiveDesc` + "`" + `: Alphabetical Case Insensitive DESC\n` + "`" + `naturalAsc` + "`" + `: Natural ASC\n` + "`" + `naturalDesc` + "`" + `: Natural DESC\nVariableSort enum with default value","enum":["disabled","alphabeticalAsc","alphabeticalDesc","numericalAsc","numericalDesc","alphabeticalCaseInsensitiveAsc","alphabeticalCaseInsensitiveDesc","naturalAsc","naturalDesc"],"type":"string"},"VizConfigKind":{"additionalProperties":false,"properties":{"kind":{"description":"The kind of a VizConfigKind is the plugin ID","type":"string"},"spec":{"$ref":"#/components/schemas/VizConfigSpec"}},"required":["kind","spec"],"type":"object"},"VizConfigSpec":{"additionalProperties":false,"description":"--- Kinds ---","properties":{"fieldConfig":{"$ref":"#/components/schemas/FieldConfigSource"},"options":{"additionalProperties":{"additionalProperties":{},"type":"object"},"type":"object"},"pluginVersion":{"type":"string"}},"required":["pluginVersion","options","fieldConfig"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"annotations":{"items":{"$ref":"#/components/schemas/AnnotationQueryKind"},"type":"array"},"cursorSync":{"$ref":"#/components/schemas/DashboardCursorSync","default":"Off","description":"Configuration of dashboard cursor sync behavior.\n\"Off\" for no shared crosshair or tooltip (default).\n\"Crosshair\" for shared crosshair.\n\"Tooltip\" for shared crosshair AND shared tooltip."},"description":{"description":"Description of dashboard.","type":"string"},"editable":{"default":true,"description":"Whether a dashboard is editable or not.","type":"boolean"},"elements":{"additionalProperties":{"$ref":"#/components/schemas/Element"},"type":"object"},"layout":{"oneOf":[{"$ref":"#/components/schemas/GridLayoutKind"},{"$ref":"#/components/schemas/RowsLayoutKind"},{"$ref":"#/components/schemas/AutoGridLayoutKind"},{"$ref":"#/components/schemas/TabsLayoutKind"}]},"links":{"description":"Links with references to other dashboards or external websites.","items":{"$ref":"#/components/schemas/DashboardLink"},"type":"array"},"liveNow":{"description":"When set to true, the dashboard will redraw panels at an interval matching the pixel width.\nThis will keep data \"moving left\" regardless of the query refresh rate. This setting helps\navoid dashboards presenting stale live data.","type":"boolean"},"preload":{"default":false,"description":"When set to true, the dashboard will load all panels in the dashboard when it's loaded.","type":"boolean"},"revision":{"description":"Plugins only. The version of the dashboard installed together with the plugin.\nThis is used to determine if the dashboard should be updated when the plugin is updated.","type":"integer"},"tags":{"description":"Tags associated with dashboard.","items":{"type":"string"},"type":"array"},"timeSettings":{"$ref":"#/components/schemas/TimeSettingsSpec"},"title":{"description":"Title of dashboard.","type":"string"},"variables":{"description":"Configured template variables.","items":{"$ref":"#/components/schemas/VariableKind"},"type":"array"}},"required":["annotations","cursorSync","elements","layout","links","preload","tags","timeSettings","title","variables"],"type":"object"},"status":{"additionalProperties":false,"properties":{"conversion":{"$ref":"#/components/schemas/ConversionStatus","description":"Optional conversion status."}},"type":"object"}}`) + rawSchemaDashboardv2alpha1 = []byte(`{"Action":{"additionalProperties":false,"properties":{"confirmation":{"type":"string"},"fetch":{"$ref":"#/components/schemas/FetchOptions"},"infinity":{"$ref":"#/components/schemas/InfinityOptions"},"oneClick":{"type":"boolean"},"style":{"additionalProperties":false,"properties":{"backgroundColor":{"type":"string"}},"type":"object"},"title":{"type":"string"},"type":{"$ref":"#/components/schemas/ActionType"},"variables":{"items":{"$ref":"#/components/schemas/ActionVariable"},"type":"array"}},"required":["type","title"],"type":"object"},"ActionType":{"enum":["fetch","infinity"],"type":"string"},"ActionVariable":{"additionalProperties":false,"properties":{"key":{"type":"string"},"name":{"type":"string"},"type":{"$ref":"#/components/schemas/ActionVariableType"}},"required":["key","name","type"],"type":"object"},"ActionVariableType":{"const":"string","description":"Action variable type","type":"string"},"AdHocFilterWithLabels":{"additionalProperties":false,"description":"Define the AdHocFilterWithLabels type","properties":{"condition":{"description":"@deprecated","type":"string"},"forceEdit":{"type":"boolean"},"key":{"type":"string"},"keyLabel":{"type":"string"},"operator":{"type":"string"},"origin":{"$ref":"#/components/schemas/FilterOrigin"},"value":{"type":"string"},"valueLabels":{"items":{"type":"string"},"type":"array"},"values":{"items":{"type":"string"},"type":"array"}},"required":["key","operator","value"],"type":"object"},"AdhocVariableKind":{"additionalProperties":false,"description":"Adhoc variable kind","properties":{"kind":{"const":"AdhocVariable","type":"string"},"spec":{"$ref":"#/components/schemas/AdhocVariableSpec"}},"required":["kind","spec"],"type":"object"},"AdhocVariableSpec":{"additionalProperties":false,"description":"Adhoc variable specification","properties":{"allowCustomValue":{"default":true,"type":"boolean"},"baseFilters":{"items":{"$ref":"#/components/schemas/AdHocFilterWithLabels"},"type":"array"},"datasource":{"$ref":"#/components/schemas/DataSourceRef"},"defaultKeys":{"items":{"$ref":"#/components/schemas/MetricFindValue"},"type":"array"},"description":{"type":"string"},"filters":{"items":{"$ref":"#/components/schemas/AdHocFilterWithLabels"},"type":"array"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"label":{"type":"string"},"name":{"default":"","type":"string"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","baseFilters","filters","defaultKeys","hide","skipUrlSync","allowCustomValue"],"type":"object"},"AnnotationEventFieldMapping":{"additionalProperties":false,"description":"Annotation event field mapping. Defines how to map a data frame field to an annotation event field.","properties":{"regex":{"description":"Regular expression to apply to the field value","type":"string"},"source":{"default":"field","description":"Source type for the field value","type":"string"},"value":{"description":"Constant value to use when source is \"text\"","type":"string"}},"type":"object"},"AnnotationPanelFilter":{"additionalProperties":false,"properties":{"exclude":{"default":false,"description":"Should the specified panels be included or excluded","type":"boolean"},"ids":{"description":"Panel IDs that should be included or excluded","items":{"type":"integer"},"type":"array"}},"required":["ids"],"type":"object"},"AnnotationQueryKind":{"additionalProperties":false,"properties":{"kind":{"const":"AnnotationQuery","type":"string"},"spec":{"$ref":"#/components/schemas/AnnotationQuerySpec"}},"required":["kind","spec"],"type":"object"},"AnnotationQuerySpec":{"additionalProperties":false,"properties":{"builtIn":{"default":false,"type":"boolean"},"datasource":{"$ref":"#/components/schemas/DataSourceRef"},"enable":{"type":"boolean"},"filter":{"$ref":"#/components/schemas/AnnotationPanelFilter"},"hide":{"type":"boolean"},"iconColor":{"type":"string"},"legacyOptions":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"Catch-all field for datasource-specific properties","type":"object"},"mappings":{"additionalProperties":{"$ref":"#/components/schemas/AnnotationEventFieldMapping"},"description":"Mappings define how to convert data frame fields to annotation event fields.","type":"object"},"name":{"type":"string"},"query":{"$ref":"#/components/schemas/DataQueryKind"}},"required":["enable","hide","iconColor","name"],"type":"object"},"AutoGridLayoutItemKind":{"additionalProperties":false,"properties":{"kind":{"const":"AutoGridLayoutItem","type":"string"},"spec":{"$ref":"#/components/schemas/AutoGridLayoutItemSpec"}},"required":["kind","spec"],"type":"object"},"AutoGridLayoutItemSpec":{"additionalProperties":false,"properties":{"conditionalRendering":{"$ref":"#/components/schemas/ConditionalRenderingGroupKind"},"element":{"$ref":"#/components/schemas/ElementReference"},"repeat":{"$ref":"#/components/schemas/AutoGridRepeatOptions"}},"required":["element"],"type":"object"},"AutoGridLayoutKind":{"additionalProperties":false,"properties":{"kind":{"const":"AutoGridLayout","type":"string"},"spec":{"$ref":"#/components/schemas/AutoGridLayoutSpec"}},"required":["kind","spec"],"type":"object"},"AutoGridLayoutSpec":{"additionalProperties":false,"properties":{"columnWidth":{"type":"number"},"columnWidthMode":{"default":"standard","enum":["narrow","standard","wide","custom"],"type":"string"},"fillScreen":{"default":false,"type":"boolean"},"items":{"items":{"$ref":"#/components/schemas/AutoGridLayoutItemKind"},"type":"array"},"maxColumnCount":{"default":3,"type":"number"},"rowHeight":{"type":"number"},"rowHeightMode":{"default":"standard","enum":["short","standard","tall","custom"],"type":"string"}},"required":["columnWidthMode","rowHeightMode","items"],"type":"object"},"AutoGridRepeatOptions":{"additionalProperties":false,"properties":{"mode":{"$ref":"#/components/schemas/RepeatMode"},"value":{"type":"string"}},"required":["mode","value"],"type":"object"},"ConditionalRenderingDataKind":{"additionalProperties":false,"properties":{"kind":{"const":"ConditionalRenderingData","type":"string"},"spec":{"$ref":"#/components/schemas/ConditionalRenderingDataSpec"}},"required":["kind","spec"],"type":"object"},"ConditionalRenderingDataSpec":{"additionalProperties":false,"properties":{"value":{"type":"boolean"}},"required":["value"],"type":"object"},"ConditionalRenderingGroupKind":{"additionalProperties":false,"properties":{"kind":{"const":"ConditionalRenderingGroup","type":"string"},"spec":{"$ref":"#/components/schemas/ConditionalRenderingGroupSpec"}},"required":["kind","spec"],"type":"object"},"ConditionalRenderingGroupSpec":{"additionalProperties":false,"properties":{"condition":{"enum":["and","or"],"type":"string"},"items":{"items":{"oneOf":[{"$ref":"#/components/schemas/ConditionalRenderingVariableKind"},{"$ref":"#/components/schemas/ConditionalRenderingDataKind"},{"$ref":"#/components/schemas/ConditionalRenderingTimeRangeSizeKind"}]},"type":"array"},"visibility":{"enum":["show","hide"],"type":"string"}},"required":["visibility","condition","items"],"type":"object"},"ConditionalRenderingTimeRangeSizeKind":{"additionalProperties":false,"properties":{"kind":{"const":"ConditionalRenderingTimeRangeSize","type":"string"},"spec":{"$ref":"#/components/schemas/ConditionalRenderingTimeRangeSizeSpec"}},"required":["kind","spec"],"type":"object"},"ConditionalRenderingTimeRangeSizeSpec":{"additionalProperties":false,"properties":{"value":{"type":"string"}},"required":["value"],"type":"object"},"ConditionalRenderingVariableKind":{"additionalProperties":false,"properties":{"kind":{"const":"ConditionalRenderingVariable","type":"string"},"spec":{"$ref":"#/components/schemas/ConditionalRenderingVariableSpec"}},"required":["kind","spec"],"type":"object"},"ConditionalRenderingVariableSpec":{"additionalProperties":false,"properties":{"operator":{"enum":["equals","notEquals","matches","notMatches"],"type":"string"},"value":{"type":"string"},"variable":{"type":"string"}},"required":["variable","operator","value"],"type":"object"},"ConstantVariableKind":{"additionalProperties":false,"description":"Constant variable kind","properties":{"kind":{"const":"ConstantVariable","type":"string"},"spec":{"$ref":"#/components/schemas/ConstantVariableSpec"}},"required":["kind","spec"],"type":"object"},"ConstantVariableSpec":{"additionalProperties":false,"description":"Constant variable specification","properties":{"current":{"$ref":"#/components/schemas/VariableOption","default":{"text":"","value":""}},"description":{"type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"label":{"type":"string"},"name":{"default":"","type":"string"},"query":{"default":"","type":"string"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","query","current","hide","skipUrlSync"],"type":"object"},"ConversionStatus":{"additionalProperties":false,"description":"ConversionStatus is the status of the conversion of the dashboard.","properties":{"error":{"description":"The error message from the conversion.\nEmpty if the conversion has not failed.","type":"string"},"failed":{"description":"Whether from another version has failed.\nIf true, means that the dashboard is not valid,\nand the caller should instead fetch the stored version.","type":"boolean"},"source":{"additionalProperties":{},"description":"The original value map[string]any","type":"object"},"storedVersion":{"description":"The version which was stored when the dashboard was created / updated.\nFetching this version should always succeed.","type":"string"}},"required":["failed"],"type":"object"},"CustomVariableKind":{"additionalProperties":false,"description":"Custom variable kind","properties":{"kind":{"const":"CustomVariable","type":"string"},"spec":{"$ref":"#/components/schemas/CustomVariableSpec"}},"required":["kind","spec"],"type":"object"},"CustomVariableSpec":{"additionalProperties":false,"description":"Custom variable specification","properties":{"allValue":{"type":"string"},"allowCustomValue":{"default":true,"type":"boolean"},"current":{"$ref":"#/components/schemas/VariableOption"},"description":{"type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"includeAll":{"default":false,"type":"boolean"},"label":{"type":"string"},"multi":{"default":false,"type":"boolean"},"name":{"default":"","type":"string"},"options":{"items":{"$ref":"#/components/schemas/VariableOption"},"type":"array"},"query":{"default":"","type":"string"},"skipUrlSync":{"default":false,"type":"boolean"},"valuesFormat":{"enum":["csv","json"],"type":"string"}},"required":["name","query","current","options","multi","includeAll","hide","skipUrlSync","allowCustomValue"],"type":"object"},"Dashboard":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"DashboardCursorSync":{"description":"\"Off\" for no shared crosshair or tooltip (default).\n\"Crosshair\" for shared crosshair.\n\"Tooltip\" for shared crosshair AND shared tooltip.","enum":["Crosshair","Tooltip","Off"],"type":"string"},"DashboardLink":{"additionalProperties":false,"description":"Links with references to other dashboards or external resources","properties":{"asDropdown":{"default":false,"description":"If true, all dashboards links will be displayed in a dropdown. If false, all dashboards links will be displayed side by side. Only valid if the type is dashboards","type":"boolean"},"icon":{"description":"Icon name to be displayed with the link","type":"string"},"includeVars":{"default":false,"description":"If true, includes current template variables values in the link as query params","type":"boolean"},"keepTime":{"default":false,"description":"If true, includes current time range in the link as query params","type":"boolean"},"placement":{"$ref":"#/components/schemas/DashboardLinkPlacement","description":"Placement can be used to display the link somewhere else on the dashboard other than above the visualisations."},"tags":{"description":"List of tags to limit the linked dashboards. If empty, all dashboards will be displayed. Only valid if the type is dashboards","items":{"type":"string"},"type":"array"},"targetBlank":{"default":false,"description":"If true, the link will be opened in a new tab","type":"boolean"},"title":{"description":"Title to display with the link","type":"string"},"tooltip":{"description":"Tooltip to display when the user hovers their mouse over it","type":"string"},"type":{"$ref":"#/components/schemas/DashboardLinkType","description":"Link type. Accepted values are dashboards (to refer to another dashboard) and link (to refer to an external resource)\nFIXME: The type is generated as ` + "`" + `type: DashboardLinkType | dashboardLinkType.Link;` + "`" + ` but it should be ` + "`" + `type: DashboardLinkType` + "`" + `"},"url":{"description":"Link URL. Only required/valid if the type is link","type":"string"}},"required":["title","type","icon","tooltip","tags","asDropdown","targetBlank","includeVars","keepTime"],"type":"object"},"DashboardLinkPlacement":{"const":"inControlsMenu","description":"Dashboard Link placement. Defines where the link should be displayed.\n- \"inControlsMenu\" renders the link in bottom part of the dashboard controls dropdown menu","type":"string"},"DashboardLinkType":{"description":"Dashboard Link type. Accepted values are dashboards (to refer to another dashboard) and link (to refer to an external resource)","enum":["link","dashboards"],"type":"string"},"DataLink":{"additionalProperties":false,"properties":{"targetBlank":{"type":"boolean"},"title":{"type":"string"},"url":{"type":"string"}},"required":["title","url"],"type":"object"},"DataQueryKind":{"additionalProperties":false,"properties":{"kind":{"description":"The kind of a DataQueryKind is the datasource type","type":"string"},"spec":{"additionalProperties":{"additionalProperties":{},"type":"object"},"type":"object"}},"required":["kind","spec"],"type":"object"},"DataSourceRef":{"additionalProperties":false,"properties":{"type":{"description":"The plugin type-id","type":"string"},"uid":{"description":"Specific datasource instance","type":"string"}},"type":"object"},"DataTopic":{"description":"A topic is attached to DataFrame metadata in query results.\nThis specifies where the data should be used.","enum":["series","annotations","alertStates"],"type":"string"},"DataTransformerConfig":{"additionalProperties":false,"description":"Transformations allow to manipulate data returned by a query before the system applies a visualization.\nUsing transformations you can: rename fields, join time series data, perform mathematical operations across queries,\nuse the output of one transformation as the input to another transformation, etc.","properties":{"disabled":{"description":"Disabled transformations are skipped","type":"boolean"},"filter":{"$ref":"#/components/schemas/MatcherConfig","description":"Optional frame matcher. When missing it will be applied to all results"},"id":{"description":"Unique identifier of transformer","type":"string"},"options":{"additionalProperties":{},"description":"Options to be passed to the transformer\nValid options depend on the transformer id","type":"object"},"topic":{"$ref":"#/components/schemas/DataTopic","description":"Where to pull DataFrames from as input to transformation"}},"required":["id","options"],"type":"object"},"DatasourceVariableKind":{"additionalProperties":false,"description":"Datasource variable kind","properties":{"kind":{"const":"DatasourceVariable","type":"string"},"spec":{"$ref":"#/components/schemas/DatasourceVariableSpec"}},"required":["kind","spec"],"type":"object"},"DatasourceVariableSpec":{"additionalProperties":false,"description":"Datasource variable specification","properties":{"allValue":{"type":"string"},"allowCustomValue":{"default":true,"type":"boolean"},"current":{"$ref":"#/components/schemas/VariableOption","default":{"text":"","value":""}},"description":{"type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"includeAll":{"default":false,"type":"boolean"},"label":{"type":"string"},"multi":{"default":false,"type":"boolean"},"name":{"default":"","type":"string"},"options":{"items":{"$ref":"#/components/schemas/VariableOption"},"type":"array"},"pluginId":{"default":"","type":"string"},"refresh":{"$ref":"#/components/schemas/VariableRefresh","default":"never"},"regex":{"default":"","type":"string"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","pluginId","refresh","regex","current","options","multi","includeAll","hide","skipUrlSync","allowCustomValue"],"type":"object"},"DynamicConfigValue":{"additionalProperties":false,"properties":{"id":{"default":"","type":"string"},"value":{"additionalProperties":{},"type":"object"}},"required":["id"],"type":"object"},"Element":{"description":"Supported dashboard elements\n|* more element types in the future","oneOf":[{"$ref":"#/components/schemas/PanelKind"},{"$ref":"#/components/schemas/LibraryPanelKind"}]},"ElementReference":{"additionalProperties":false,"properties":{"kind":{"const":"ElementReference","type":"string"},"name":{"type":"string"}},"required":["kind","name"],"type":"object"},"FetchOptions":{"additionalProperties":false,"properties":{"body":{"type":"string"},"headers":{"items":{"items":{"type":"string"},"type":"array"},"type":"array"},"method":{"$ref":"#/components/schemas/HttpRequestMethod"},"queryParams":{"description":"These are 2D arrays of strings, each representing a key-value pair\nWe are defining them this way because we can't generate a go struct that\nthat would have exactly two strings in each sub-array","items":{"items":{"type":"string"},"type":"array"},"type":"array"},"url":{"type":"string"}},"required":["method","url"],"type":"object"},"FieldColor":{"additionalProperties":false,"description":"Map a field to a color.","properties":{"fixedColor":{"description":"The fixed color value for fixed or shades color modes.","type":"string"},"mode":{"$ref":"#/components/schemas/FieldColorModeId","description":"The main color scheme mode."},"seriesBy":{"$ref":"#/components/schemas/FieldColorSeriesByMode","description":"Some visualizations need to know how to assign a series color from by value color schemes."}},"required":["mode"],"type":"object"},"FieldColorModeId":{"description":"Color mode for a field. You can specify a single color, or select a continuous (gradient) color schemes, based on a value.\nContinuous color interpolates a color using the percentage of a value relative to min and max.\nAccepted values are:\n` + "`" + `thresholds` + "`" + `: From thresholds. Informs Grafana to take the color from the matching threshold\n` + "`" + `palette-classic` + "`" + `: Classic palette. Grafana will assign color by looking up a color in a palette by series index. Useful for Graphs and pie charts and other categorical data visualizations\n` + "`" + `palette-classic-by-name` + "`" + `: Classic palette (by name). Grafana will assign color by looking up a color in a palette by series name. Useful for Graphs and pie charts and other categorical data visualizations\n` + "`" + `continuous-viridis` + "`" + `: Continuous Viridis palette mode\n` + "`" + `continuous-magma` + "`" + `: Continuous Magma palette mode\n` + "`" + `continuous-plasma` + "`" + `: Continuous Plasma palette mode\n` + "`" + `continuous-inferno` + "`" + `: Continuous Inferno palette mode\n` + "`" + `continuous-cividis` + "`" + `: Continuous Cividis palette mode\n` + "`" + `continuous-GrYlRd` + "`" + `: Continuous Green-Yellow-Red palette mode\n` + "`" + `continuous-RdYlGr` + "`" + `: Continuous Red-Yellow-Green palette mode\n` + "`" + `continuous-BlYlRd` + "`" + `: Continuous Blue-Yellow-Red palette mode\n` + "`" + `continuous-YlRd` + "`" + `: Continuous Yellow-Red palette mode\n` + "`" + `continuous-BlPu` + "`" + `: Continuous Blue-Purple palette mode\n` + "`" + `continuous-YlBl` + "`" + `: Continuous Yellow-Blue palette mode\n` + "`" + `continuous-blues` + "`" + `: Continuous Blue palette mode\n` + "`" + `continuous-reds` + "`" + `: Continuous Red palette mode\n` + "`" + `continuous-greens` + "`" + `: Continuous Green palette mode\n` + "`" + `continuous-purples` + "`" + `: Continuous Purple palette mode\n` + "`" + `shades` + "`" + `: Shades of a single color. Specify a single color, useful in an override rule.\n` + "`" + `fixed` + "`" + `: Fixed color mode. Specify a single color, useful in an override rule.","enum":["thresholds","palette-classic","palette-classic-by-name","continuous-viridis","continuous-magma","continuous-plasma","continuous-inferno","continuous-cividis","continuous-GrYlRd","continuous-RdYlGr","continuous-BlYlRd","continuous-YlRd","continuous-BlPu","continuous-YlBl","continuous-blues","continuous-reds","continuous-greens","continuous-purples","fixed","shades"],"type":"string"},"FieldColorSeriesByMode":{"description":"Defines how to assign a series color from \"by value\" color schemes. For example for an aggregated data points like a timeseries, the color can be assigned by the min, max or last value.","enum":["min","max","last"],"type":"string"},"FieldConfig":{"additionalProperties":false,"description":"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.\nEach column within this structure is called a field. A field can represent a single time series or table column.\nField options allow you to change how the data is displayed in your visualizations.","properties":{"actions":{"description":"Define interactive HTTP requests that can be triggered from data visualizations.","items":{"$ref":"#/components/schemas/Action"},"type":"array"},"color":{"$ref":"#/components/schemas/FieldColor","description":"Panel color configuration"},"custom":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"custom is specified by the FieldConfig field\nin panel plugin schemas.","type":"object"},"decimals":{"description":"Specify the number of decimals Grafana includes in the rendered value.\nIf you leave this field blank, Grafana automatically truncates the number of decimals based on the value.\nFor example 1.1234 will display as 1.12 and 100.456 will display as 100.\nTo display all decimals, set the unit to ` + "`" + `String` + "`" + `.","type":"number"},"description":{"description":"Human readable field metadata","type":"string"},"displayName":{"description":"The display value for this field. This supports template variables blank is auto","type":"string"},"displayNameFromDS":{"description":"This can be used by data sources that return and explicit naming structure for values and labels\nWhen this property is configured, this value is used rather than the default naming strategy.","type":"string"},"fieldMinMax":{"description":"Calculate min max per field","type":"boolean"},"filterable":{"description":"True if data source field supports ad-hoc filters","type":"boolean"},"links":{"description":"The behavior when clicking on a result","items":{"additionalProperties":{},"type":"object"},"type":"array"},"mappings":{"description":"Convert input values into a display string","items":{"$ref":"#/components/schemas/ValueMapping"},"type":"array"},"max":{"description":"The maximum value used in percentage threshold calculations. Leave blank for auto calculation based on all series and fields.","type":"number"},"min":{"description":"The minimum value used in percentage threshold calculations. Leave blank for auto calculation based on all series and fields.","type":"number"},"noValue":{"description":"Alternative to empty string","type":"string"},"nullValueMode":{"$ref":"#/components/schemas/NullValueMode","description":"How null values should be handled when calculating field stats\n\"null\" - Include null values, \"connected\" - Ignore nulls, \"null as zero\" - Treat nulls as zero"},"path":{"description":"An explicit path to the field in the datasource. When the frame meta includes a path,\nThis will default to ` + "`" + `${frame.meta.path}/${field.name}\n\nWhen defined, this value can be used as an identifier within the datasource scope, and\nmay be used to update the results","type":"string"},"thresholds":{"$ref":"#/components/schemas/ThresholdsConfig","description":"Map numeric values to states"},"unit":{"description":"Unit a field should use. The unit you select is applied to all fields except time.\nYou can use the units ID availables in Grafana or a custom unit.\nAvailable units in Grafana: https://github.com/grafana/grafana/blob/main/packages/grafana-data/src/valueFormats/categories.ts\nAs custom unit, you can use the following formats:\n` + "`" + `suffix:\u003csuffix\u003e` + "`" + ` for custom unit that should go after value.\n` + "`" + `prefix:\u003cprefix\u003e` + "`" + ` for custom unit that should go before value.\n` + "`" + `time:\u003cformat\u003e` + "`" + ` For custom date time formats type for example ` + "`" + `time:YYYY-MM-DD` + "`" + `.\n` + "`" + `si:\u003cbase scale\u003e\u003cunit characters\u003e` + "`" + ` for custom SI units. For example: ` + "`" + `si: mF` + "`" + `. This one is a bit more advanced as you can specify both a unit and the source data scale. So if your source data is represented as milli (thousands of) something prefix the unit with that SI scale character.\n` + "`" + `count:\u003cunit\u003e` + "`" + ` for a custom count unit.\n` + "`" + `currency:\u003cunit\u003e` + "`" + ` for custom a currency unit.","type":"string"},"writeable":{"description":"True if data source can write a value to the path. Auth/authz are supported separately","type":"boolean"}},"type":"object"},"FieldConfigSource":{"additionalProperties":false,"description":"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.\nEach column within this structure is called a field. A field can represent a single time series or table column.\nField options allow you to change how the data is displayed in your visualizations.","properties":{"defaults":{"$ref":"#/components/schemas/FieldConfig","description":"Defaults are the options applied to all fields."},"overrides":{"description":"Overrides are the options applied to specific fields overriding the defaults.","items":{"additionalProperties":false,"properties":{"__systemRef":{"description":"Describes config override rules created when interacting with Grafana.","type":"string"},"matcher":{"$ref":"#/components/schemas/MatcherConfig"},"properties":{"items":{"$ref":"#/components/schemas/DynamicConfigValue"},"type":"array"}},"required":["matcher","properties"],"type":"object"},"type":"array"}},"required":["defaults","overrides"],"type":"object"},"FilterOrigin":{"const":"dashboard","description":"Determine the origin of the adhoc variable filter","type":"string"},"GridLayoutItemKind":{"additionalProperties":false,"properties":{"kind":{"const":"GridLayoutItem","type":"string"},"spec":{"$ref":"#/components/schemas/GridLayoutItemSpec"}},"required":["kind","spec"],"type":"object"},"GridLayoutItemSpec":{"additionalProperties":false,"properties":{"element":{"$ref":"#/components/schemas/ElementReference","description":"reference to a PanelKind from dashboard.spec.elements Expressed as JSON Schema reference"},"height":{"type":"integer"},"repeat":{"$ref":"#/components/schemas/RepeatOptions"},"width":{"type":"integer"},"x":{"type":"integer"},"y":{"type":"integer"}},"required":["x","y","width","height","element"],"type":"object"},"GridLayoutKind":{"additionalProperties":false,"properties":{"kind":{"const":"GridLayout","type":"string"},"spec":{"$ref":"#/components/schemas/GridLayoutSpec"}},"required":["kind","spec"],"type":"object"},"GridLayoutSpec":{"additionalProperties":false,"properties":{"items":{"items":{"$ref":"#/components/schemas/GridLayoutItemKind"},"type":"array"}},"required":["items"],"type":"object"},"GroupByVariableKind":{"additionalProperties":false,"description":"Group variable kind","properties":{"kind":{"const":"GroupByVariable","type":"string"},"spec":{"$ref":"#/components/schemas/GroupByVariableSpec"}},"required":["kind","spec"],"type":"object"},"GroupByVariableSpec":{"additionalProperties":false,"description":"GroupBy variable specification","properties":{"current":{"$ref":"#/components/schemas/VariableOption","default":{"text":"","value":""}},"datasource":{"$ref":"#/components/schemas/DataSourceRef"},"defaultValue":{"$ref":"#/components/schemas/VariableOption"},"description":{"type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"label":{"type":"string"},"multi":{"default":false,"type":"boolean"},"name":{"default":"","type":"string"},"options":{"items":{"$ref":"#/components/schemas/VariableOption"},"type":"array"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","current","options","multi","hide","skipUrlSync"],"type":"object"},"HttpRequestMethod":{"enum":["GET","PUT","POST","DELETE","PATCH"],"type":"string"},"InfinityOptions":{"additionalProperties":false,"properties":{"body":{"type":"string"},"datasourceUid":{"type":"string"},"headers":{"items":{"items":{"type":"string"},"type":"array"},"type":"array"},"method":{"$ref":"#/components/schemas/HttpRequestMethod"},"queryParams":{"description":"These are 2D arrays of strings, each representing a key-value pair\nWe are defining them this way because we can't generate a go struct that\nthat would have exactly two strings in each sub-array","items":{"items":{"type":"string"},"type":"array"},"type":"array"},"url":{"type":"string"}},"required":["method","url","datasourceUid"],"type":"object"},"IntervalVariableKind":{"additionalProperties":false,"description":"Interval variable kind","properties":{"kind":{"const":"IntervalVariable","type":"string"},"spec":{"$ref":"#/components/schemas/IntervalVariableSpec"}},"required":["kind","spec"],"type":"object"},"IntervalVariableSpec":{"additionalProperties":false,"description":"Interval variable specification","properties":{"auto":{"default":false,"type":"boolean"},"auto_count":{"default":0,"type":"integer"},"auto_min":{"default":"","type":"string"},"current":{"$ref":"#/components/schemas/VariableOption","default":{"text":"","value":""}},"description":{"type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"label":{"type":"string"},"name":{"default":"","type":"string"},"options":{"items":{"$ref":"#/components/schemas/VariableOption"},"type":"array"},"query":{"default":"","type":"string"},"refresh":{"$ref":"#/components/schemas/VariableRefresh","default":"never"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","query","current","options","auto","auto_min","auto_count","refresh","hide","skipUrlSync"],"type":"object"},"LibraryPanelKind":{"additionalProperties":false,"properties":{"kind":{"const":"LibraryPanel","type":"string"},"spec":{"$ref":"#/components/schemas/LibraryPanelKindSpec"}},"required":["kind","spec"],"type":"object"},"LibraryPanelKindSpec":{"additionalProperties":false,"properties":{"id":{"description":"Panel ID for the library panel in the dashboard","type":"number"},"libraryPanel":{"$ref":"#/components/schemas/LibraryPanelRef"},"title":{"description":"Title for the library panel in the dashboard","type":"string"}},"required":["id","title","libraryPanel"],"type":"object"},"LibraryPanelRef":{"additionalProperties":false,"description":"A library panel is a reusable panel that you can use in any dashboard.\nWhen you make a change to a library panel, that change propagates to all instances of where the panel is used.\nLibrary panels streamline reuse of panels across multiple dashboards.","properties":{"name":{"description":"Library panel name","type":"string"},"uid":{"description":"Library panel uid","type":"string"}},"required":["name","uid"],"type":"object"},"MappingType":{"description":"Supported value mapping types\n` + "`" + `value` + "`" + `: Maps text values to a color or different display text and color. For example, you can configure a value mapping so that all instances of the value 10 appear as Perfection! rather than the number.\n` + "`" + `range` + "`" + `: Maps numerical ranges to a display text and color. For example, if a value is within a certain range, you can configure a range value mapping to display Low or High rather than the number.\n` + "`" + `regex` + "`" + `: Maps regular expressions to replacement text and a color. For example, if a value is www.example.com, you can configure a regex value mapping so that Grafana displays www and truncates the domain.\n` + "`" + `special` + "`" + `: Maps special values like Null, NaN (not a number), and boolean values like true and false to a display text and color. See SpecialValueMatch to see the list of special values. For example, you can configure a special value mapping so that null values appear as N/A.","enum":["value","range","regex","special"],"type":"string"},"MatcherConfig":{"additionalProperties":false,"description":"Matcher is a predicate configuration. Based on the config a set of field(s) or values is filtered in order to apply override / transformation.\nIt comes with in id ( to resolve implementation from registry) and a configuration that’s specific to a particular matcher type.","properties":{"id":{"default":"","description":"The matcher id. This is used to find the matcher implementation from registry.","type":"string"},"options":{"additionalProperties":{},"description":"The matcher options. This is specific to the matcher implementation.","type":"object"}},"required":["id"],"type":"object"},"MetricFindValue":{"additionalProperties":false,"description":"Define the MetricFindValue type","properties":{"expandable":{"type":"boolean"},"group":{"type":"string"},"text":{"type":"string"},"value":{"oneOf":[{"type":"string"},{"type":"number"}]}},"required":["text"],"type":"object"},"NullValueMode":{"description":"How null values should be handled","enum":["null","connected","null as zero"],"type":"string"},"PanelKind":{"additionalProperties":false,"properties":{"kind":{"const":"Panel","type":"string"},"spec":{"$ref":"#/components/schemas/PanelSpec"}},"required":["kind","spec"],"type":"object"},"PanelQueryKind":{"additionalProperties":false,"properties":{"kind":{"const":"PanelQuery","type":"string"},"spec":{"$ref":"#/components/schemas/PanelQuerySpec"}},"required":["kind","spec"],"type":"object"},"PanelQuerySpec":{"additionalProperties":false,"properties":{"datasource":{"$ref":"#/components/schemas/DataSourceRef"},"hidden":{"type":"boolean"},"query":{"$ref":"#/components/schemas/DataQueryKind"},"refId":{"type":"string"}},"required":["query","refId","hidden"],"type":"object"},"PanelSpec":{"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/QueryGroupKind"},"description":{"type":"string"},"id":{"type":"number"},"links":{"items":{"$ref":"#/components/schemas/DataLink"},"type":"array"},"title":{"type":"string"},"transparent":{"type":"boolean"},"vizConfig":{"$ref":"#/components/schemas/VizConfigKind"}},"required":["id","title","description","links","data","vizConfig"],"type":"object"},"QueryGroupKind":{"additionalProperties":false,"properties":{"kind":{"const":"QueryGroup","type":"string"},"spec":{"$ref":"#/components/schemas/QueryGroupSpec"}},"required":["kind","spec"],"type":"object"},"QueryGroupSpec":{"additionalProperties":false,"properties":{"queries":{"items":{"$ref":"#/components/schemas/PanelQueryKind"},"type":"array"},"queryOptions":{"$ref":"#/components/schemas/QueryOptionsSpec"},"transformations":{"items":{"$ref":"#/components/schemas/TransformationKind"},"type":"array"}},"required":["queries","transformations","queryOptions"],"type":"object"},"QueryOptionsSpec":{"additionalProperties":false,"properties":{"cacheTimeout":{"type":"string"},"hideTimeOverride":{"type":"boolean"},"interval":{"type":"string"},"maxDataPoints":{"type":"integer"},"queryCachingTTL":{"type":"integer"},"timeFrom":{"type":"string"},"timeShift":{"type":"string"}},"type":"object"},"QueryVariableKind":{"additionalProperties":false,"description":"Query variable kind","properties":{"kind":{"const":"QueryVariable","type":"string"},"spec":{"$ref":"#/components/schemas/QueryVariableSpec"}},"required":["kind","spec"],"type":"object"},"QueryVariableSpec":{"additionalProperties":false,"description":"Query variable specification","properties":{"allValue":{"type":"string"},"allowCustomValue":{"default":true,"type":"boolean"},"current":{"$ref":"#/components/schemas/VariableOption","default":{"text":"","value":""}},"datasource":{"$ref":"#/components/schemas/DataSourceRef"},"definition":{"type":"string"},"description":{"type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"includeAll":{"default":false,"type":"boolean"},"label":{"type":"string"},"multi":{"default":false,"type":"boolean"},"name":{"default":"","type":"string"},"options":{"items":{"$ref":"#/components/schemas/VariableOption"},"type":"array"},"placeholder":{"type":"string"},"query":{"$ref":"#/components/schemas/DataQueryKind"},"refresh":{"$ref":"#/components/schemas/VariableRefresh","default":"never"},"regex":{"default":"","type":"string"},"regexApplyTo":{"$ref":"#/components/schemas/VariableRegexApplyTo","default":"value"},"skipUrlSync":{"default":false,"type":"boolean"},"sort":{"$ref":"#/components/schemas/VariableSort"},"staticOptions":{"items":{"$ref":"#/components/schemas/VariableOption"},"type":"array"},"staticOptionsOrder":{"enum":["before","after","sorted"],"type":"string"}},"required":["name","current","hide","refresh","skipUrlSync","query","regex","sort","options","multi","includeAll","allowCustomValue"],"type":"object"},"RangeMap":{"additionalProperties":false,"description":"Maps numerical ranges to a display text and color.\nFor example, if a value is within a certain range, you can configure a range value mapping to display Low or High rather than the number.","properties":{"options":{"additionalProperties":false,"description":"Range to match against and the result to apply when the value is within the range","properties":{"from":{"description":"Min value of the range. It can be null which means -Infinity","type":"number"},"result":{"$ref":"#/components/schemas/ValueMappingResult","description":"Config to apply when the value is within the range"},"to":{"description":"Max value of the range. It can be null which means +Infinity","type":"number"}},"required":["from","to","result"],"type":"object"},"type":{"$ref":"#/components/schemas/MappingType"}},"required":["type","options"],"type":"object"},"RegexMap":{"additionalProperties":false,"description":"Maps regular expressions to replacement text and a color.\nFor example, if a value is www.example.com, you can configure a regex value mapping so that Grafana displays www and truncates the domain.","properties":{"options":{"additionalProperties":false,"description":"Regular expression to match against and the result to apply when the value matches the regex","properties":{"pattern":{"description":"Regular expression to match against","type":"string"},"result":{"$ref":"#/components/schemas/ValueMappingResult","description":"Config to apply when the value matches the regex"}},"required":["pattern","result"],"type":"object"},"type":{"$ref":"#/components/schemas/MappingType"}},"required":["type","options"],"type":"object"},"RepeatMode":{"const":"variable","description":"other repeat modes will be added in the future: label, frame","type":"string"},"RepeatOptions":{"additionalProperties":false,"properties":{"direction":{"enum":["h","v"],"type":"string"},"maxPerRow":{"type":"integer"},"mode":{"$ref":"#/components/schemas/RepeatMode"},"value":{"type":"string"}},"required":["mode","value"],"type":"object"},"RowRepeatOptions":{"additionalProperties":false,"properties":{"mode":{"$ref":"#/components/schemas/RepeatMode"},"value":{"type":"string"}},"required":["mode","value"],"type":"object"},"RowsLayoutKind":{"additionalProperties":false,"properties":{"kind":{"const":"RowsLayout","type":"string"},"spec":{"$ref":"#/components/schemas/RowsLayoutSpec"}},"required":["kind","spec"],"type":"object"},"RowsLayoutRowKind":{"additionalProperties":false,"properties":{"kind":{"const":"RowsLayoutRow","type":"string"},"spec":{"$ref":"#/components/schemas/RowsLayoutRowSpec"}},"required":["kind","spec"],"type":"object"},"RowsLayoutRowSpec":{"additionalProperties":false,"properties":{"collapse":{"type":"boolean"},"conditionalRendering":{"$ref":"#/components/schemas/ConditionalRenderingGroupKind"},"fillScreen":{"type":"boolean"},"hideHeader":{"type":"boolean"},"layout":{"oneOf":[{"$ref":"#/components/schemas/GridLayoutKind"},{"$ref":"#/components/schemas/AutoGridLayoutKind"},{"$ref":"#/components/schemas/TabsLayoutKind"},{"$ref":"#/components/schemas/RowsLayoutKind"}]},"repeat":{"$ref":"#/components/schemas/RowRepeatOptions"},"title":{"type":"string"}},"required":["layout"],"type":"object"},"RowsLayoutSpec":{"additionalProperties":false,"properties":{"rows":{"items":{"$ref":"#/components/schemas/RowsLayoutRowKind"},"type":"array"}},"required":["rows"],"type":"object"},"SpecialValueMap":{"additionalProperties":false,"description":"Maps special values like Null, NaN (not a number), and boolean values like true and false to a display text and color.\nSee SpecialValueMatch to see the list of special values.\nFor example, you can configure a special value mapping so that null values appear as N/A.","properties":{"options":{"additionalProperties":false,"properties":{"match":{"$ref":"#/components/schemas/SpecialValueMatch","description":"Special value to match against"},"result":{"$ref":"#/components/schemas/ValueMappingResult","description":"Config to apply when the value matches the special value"}},"required":["match","result"],"type":"object"},"type":{"$ref":"#/components/schemas/MappingType"}},"required":["type","options"],"type":"object"},"SpecialValueMatch":{"description":"Special value types supported by the ` + "`" + `SpecialValueMap` + "`" + `","enum":["true","false","null","nan","null+nan","empty"],"type":"string"},"SwitchVariableKind":{"additionalProperties":false,"properties":{"kind":{"const":"SwitchVariable","type":"string"},"spec":{"$ref":"#/components/schemas/SwitchVariableSpec"}},"required":["kind","spec"],"type":"object"},"SwitchVariableSpec":{"additionalProperties":false,"description":"Switch variable specification","properties":{"current":{"default":"false","type":"string"},"description":{"type":"string"},"disabledValue":{"default":"false","type":"string"},"enabledValue":{"default":"true","type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"label":{"type":"string"},"name":{"default":"","type":"string"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","current","enabledValue","disabledValue","hide","skipUrlSync"],"type":"object"},"TabRepeatOptions":{"additionalProperties":false,"properties":{"mode":{"$ref":"#/components/schemas/RepeatMode"},"value":{"type":"string"}},"required":["mode","value"],"type":"object"},"TabsLayoutKind":{"additionalProperties":false,"properties":{"kind":{"const":"TabsLayout","type":"string"},"spec":{"$ref":"#/components/schemas/TabsLayoutSpec"}},"required":["kind","spec"],"type":"object"},"TabsLayoutSpec":{"additionalProperties":false,"properties":{"tabs":{"items":{"$ref":"#/components/schemas/TabsLayoutTabKind"},"type":"array"}},"required":["tabs"],"type":"object"},"TabsLayoutTabKind":{"additionalProperties":false,"properties":{"kind":{"const":"TabsLayoutTab","type":"string"},"spec":{"$ref":"#/components/schemas/TabsLayoutTabSpec"}},"required":["kind","spec"],"type":"object"},"TabsLayoutTabSpec":{"additionalProperties":false,"properties":{"conditionalRendering":{"$ref":"#/components/schemas/ConditionalRenderingGroupKind"},"layout":{"oneOf":[{"$ref":"#/components/schemas/GridLayoutKind"},{"$ref":"#/components/schemas/RowsLayoutKind"},{"$ref":"#/components/schemas/AutoGridLayoutKind"},{"$ref":"#/components/schemas/TabsLayoutKind"}]},"repeat":{"$ref":"#/components/schemas/TabRepeatOptions"},"title":{"type":"string"}},"required":["layout"],"type":"object"},"TextVariableKind":{"additionalProperties":false,"description":"Text variable kind","properties":{"kind":{"const":"TextVariable","type":"string"},"spec":{"$ref":"#/components/schemas/TextVariableSpec"}},"required":["kind","spec"],"type":"object"},"TextVariableSpec":{"additionalProperties":false,"description":"Text variable specification","properties":{"current":{"$ref":"#/components/schemas/VariableOption","default":{"text":"","value":""}},"description":{"type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"label":{"type":"string"},"name":{"default":"","type":"string"},"query":{"default":"","type":"string"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","current","query","hide","skipUrlSync"],"type":"object"},"Threshold":{"additionalProperties":false,"properties":{"color":{"type":"string"},"value":{"description":"Value null means -Infinity","type":"number"}},"required":["value","color"],"type":"object"},"ThresholdsConfig":{"additionalProperties":false,"properties":{"mode":{"$ref":"#/components/schemas/ThresholdsMode"},"steps":{"items":{"$ref":"#/components/schemas/Threshold"},"type":"array"}},"required":["mode","steps"],"type":"object"},"ThresholdsMode":{"enum":["absolute","percentage"],"type":"string"},"TimeRangeOption":{"additionalProperties":false,"properties":{"display":{"default":"Last 6 hours","type":"string"},"from":{"default":"now-6h","type":"string"},"to":{"default":"now","type":"string"}},"required":["display","from","to"],"type":"object"},"TimeSettingsSpec":{"additionalProperties":false,"description":"Time configuration\nIt defines the default time config for the time picker, the refresh picker for the specific dashboard.","properties":{"autoRefresh":{"default":"","description":"Refresh rate of dashboard. Represented via interval string, e.g. \"5s\", \"1m\", \"1h\", \"1d\".\nv1: refresh","type":"string"},"autoRefreshIntervals":{"default":["5s","10s","30s","1m","5m","15m","30m","1h","2h","1d"],"description":"Interval options available in the refresh picker dropdown.\nv1: timepicker.refresh_intervals","items":{"type":"string"},"type":"array"},"fiscalYearStartMonth":{"default":0,"description":"The month that the fiscal year starts on. 0 = January, 11 = December","type":"integer"},"from":{"default":"now-6h","description":"Start time range for dashboard.\nAccepted values are relative time strings like \"now-6h\" or absolute time strings like \"2020-07-10T08:00:00.000Z\".","type":"string"},"hideTimepicker":{"default":false,"description":"Whether timepicker is visible or not.\nv1: timepicker.hidden","type":"boolean"},"nowDelay":{"description":"Override the now time by entering a time delay. Use this option to accommodate known delays in data aggregation to avoid null values.\nv1: timepicker.nowDelay","type":"string"},"quickRanges":{"description":"Selectable options available in the time picker dropdown. Has no effect on provisioned dashboard.\nv1: timepicker.quick_ranges , not exposed in the UI","items":{"$ref":"#/components/schemas/TimeRangeOption"},"type":"array"},"timezone":{"default":"browser","description":"Timezone of dashboard. Accepted values are IANA TZDB zone ID or \"browser\" or \"utc\".","type":"string"},"to":{"default":"now","description":"End time range for dashboard.\nAccepted values are relative time strings like \"now-6h\" or absolute time strings like \"2020-07-10T08:00:00.000Z\".","type":"string"},"weekStart":{"description":"Day when the week starts. Expressed by the name of the day in lowercase, e.g. \"monday\".","enum":["saturday","monday","sunday"],"type":"string"}},"required":["from","to","autoRefresh","autoRefreshIntervals","hideTimepicker","fiscalYearStartMonth"],"type":"object"},"TransformationKind":{"additionalProperties":false,"properties":{"kind":{"description":"The kind of a TransformationKind is the transformation ID","type":"string"},"spec":{"$ref":"#/components/schemas/DataTransformerConfig"}},"required":["kind","spec"],"type":"object"},"ValueMap":{"additionalProperties":false,"description":"Maps text values to a color or different display text and color.\nFor example, you can configure a value mapping so that all instances of the value 10 appear as Perfection! rather than the number.","properties":{"options":{"additionalProperties":{"$ref":"#/components/schemas/ValueMappingResult"},"description":"Map with \u003cvalue_to_match\u003e: ValueMappingResult. For example: { \"10\": { text: \"Perfection!\", color: \"green\" } }","type":"object"},"type":{"$ref":"#/components/schemas/MappingType"}},"required":["type","options"],"type":"object"},"ValueMapping":{"oneOf":[{"$ref":"#/components/schemas/ValueMap"},{"$ref":"#/components/schemas/RangeMap"},{"$ref":"#/components/schemas/RegexMap"},{"$ref":"#/components/schemas/SpecialValueMap"}]},"ValueMappingResult":{"additionalProperties":false,"description":"Result used as replacement with text and color when the value matches","properties":{"color":{"description":"Text to use when the value matches","type":"string"},"icon":{"description":"Icon to display when the value matches. Only specific visualizations.","type":"string"},"index":{"description":"Position in the mapping array. Only used internally.","type":"integer"},"text":{"description":"Text to display when the value matches","type":"string"}},"type":"object"},"VariableHide":{"description":"Determine if the variable shows on dashboard\nAccepted values are ` + "`" + `dontHide` + "`" + ` (show label and value), ` + "`" + `hideLabel` + "`" + ` (show value only), ` + "`" + `hideVariable` + "`" + ` (show nothing).","enum":["dontHide","hideLabel","hideVariable"],"type":"string"},"VariableKind":{"oneOf":[{"$ref":"#/components/schemas/QueryVariableKind"},{"$ref":"#/components/schemas/TextVariableKind"},{"$ref":"#/components/schemas/ConstantVariableKind"},{"$ref":"#/components/schemas/DatasourceVariableKind"},{"$ref":"#/components/schemas/IntervalVariableKind"},{"$ref":"#/components/schemas/CustomVariableKind"},{"$ref":"#/components/schemas/GroupByVariableKind"},{"$ref":"#/components/schemas/AdhocVariableKind"},{"$ref":"#/components/schemas/SwitchVariableKind"}]},"VariableOption":{"additionalProperties":false,"description":"Variable option specification","properties":{"selected":{"description":"Whether the option is selected or not","type":"boolean"},"text":{"description":"Text to be displayed for the option","oneOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"}]},"value":{"description":"Value of the option","oneOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"}]}},"required":["text","value"],"type":"object"},"VariableRefresh":{"description":"Options to config when to refresh a variable\n` + "`" + `never` + "`" + `: Never refresh the variable\n` + "`" + `onDashboardLoad` + "`" + `: Queries the data source every time the dashboard loads.\n` + "`" + `onTimeRangeChanged` + "`" + `: Queries the data source when the dashboard time range changes.","enum":["never","onDashboardLoad","onTimeRangeChanged"],"type":"string"},"VariableRegexApplyTo":{"description":"Determine whether regex applies to variable value or display text\nAccepted values are ` + "`" + `value` + "`" + ` (apply to value used in queries) or ` + "`" + `text` + "`" + ` (apply to display text shown to users)","enum":["value","text"],"type":"string"},"VariableSort":{"description":"Sort variable options\nAccepted values are:\n` + "`" + `disabled` + "`" + `: No sorting\n` + "`" + `alphabeticalAsc` + "`" + `: Alphabetical ASC\n` + "`" + `alphabeticalDesc` + "`" + `: Alphabetical DESC\n` + "`" + `numericalAsc` + "`" + `: Numerical ASC\n` + "`" + `numericalDesc` + "`" + `: Numerical DESC\n` + "`" + `alphabeticalCaseInsensitiveAsc` + "`" + `: Alphabetical Case Insensitive ASC\n` + "`" + `alphabeticalCaseInsensitiveDesc` + "`" + `: Alphabetical Case Insensitive DESC\n` + "`" + `naturalAsc` + "`" + `: Natural ASC\n` + "`" + `naturalDesc` + "`" + `: Natural DESC\nVariableSort enum with default value","enum":["disabled","alphabeticalAsc","alphabeticalDesc","numericalAsc","numericalDesc","alphabeticalCaseInsensitiveAsc","alphabeticalCaseInsensitiveDesc","naturalAsc","naturalDesc"],"type":"string"},"VizConfigKind":{"additionalProperties":false,"properties":{"kind":{"description":"The kind of a VizConfigKind is the plugin ID","type":"string"},"spec":{"$ref":"#/components/schemas/VizConfigSpec"}},"required":["kind","spec"],"type":"object"},"VizConfigSpec":{"additionalProperties":false,"description":"--- Kinds ---","properties":{"fieldConfig":{"$ref":"#/components/schemas/FieldConfigSource"},"options":{"additionalProperties":{"additionalProperties":{},"type":"object"},"type":"object"},"pluginVersion":{"type":"string"}},"required":["pluginVersion","options","fieldConfig"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"annotations":{"items":{"$ref":"#/components/schemas/AnnotationQueryKind"},"type":"array"},"cursorSync":{"$ref":"#/components/schemas/DashboardCursorSync","default":"Off","description":"Configuration of dashboard cursor sync behavior.\n\"Off\" for no shared crosshair or tooltip (default).\n\"Crosshair\" for shared crosshair.\n\"Tooltip\" for shared crosshair AND shared tooltip."},"description":{"description":"Description of dashboard.","type":"string"},"editable":{"default":true,"description":"Whether a dashboard is editable or not.","type":"boolean"},"elements":{"additionalProperties":{"$ref":"#/components/schemas/Element"},"type":"object"},"layout":{"oneOf":[{"$ref":"#/components/schemas/GridLayoutKind"},{"$ref":"#/components/schemas/RowsLayoutKind"},{"$ref":"#/components/schemas/AutoGridLayoutKind"},{"$ref":"#/components/schemas/TabsLayoutKind"}]},"links":{"description":"Links with references to other dashboards or external websites.","items":{"$ref":"#/components/schemas/DashboardLink"},"type":"array"},"liveNow":{"description":"When set to true, the dashboard will redraw panels at an interval matching the pixel width.\nThis will keep data \"moving left\" regardless of the query refresh rate. This setting helps\navoid dashboards presenting stale live data.","type":"boolean"},"preload":{"default":false,"description":"When set to true, the dashboard will load all panels in the dashboard when it's loaded.","type":"boolean"},"revision":{"description":"Plugins only. The version of the dashboard installed together with the plugin.\nThis is used to determine if the dashboard should be updated when the plugin is updated.","type":"integer"},"tags":{"description":"Tags associated with dashboard.","items":{"type":"string"},"type":"array"},"timeSettings":{"$ref":"#/components/schemas/TimeSettingsSpec"},"title":{"description":"Title of dashboard.","type":"string"},"variables":{"description":"Configured template variables.","items":{"$ref":"#/components/schemas/VariableKind"},"type":"array"}},"required":["annotations","cursorSync","elements","layout","links","preload","tags","timeSettings","title","variables"],"type":"object"},"status":{"additionalProperties":false,"properties":{"conversion":{"$ref":"#/components/schemas/ConversionStatus","description":"Optional conversion status."}},"type":"object"}}`) versionSchemaDashboardv2alpha1 app.VersionSchema _ = json.Unmarshal(rawSchemaDashboardv2alpha1, &versionSchemaDashboardv2alpha1) - rawSchemaDashboardv2beta1 = []byte(`{"Action":{"additionalProperties":false,"properties":{"confirmation":{"type":"string"},"fetch":{"$ref":"#/components/schemas/FetchOptions"},"infinity":{"$ref":"#/components/schemas/InfinityOptions"},"oneClick":{"type":"boolean"},"style":{"additionalProperties":false,"properties":{"backgroundColor":{"type":"string"}},"type":"object"},"title":{"type":"string"},"type":{"$ref":"#/components/schemas/ActionType"},"variables":{"items":{"$ref":"#/components/schemas/ActionVariable"},"type":"array"}},"required":["type","title"],"type":"object"},"ActionType":{"enum":["fetch","infinity"],"type":"string"},"ActionVariable":{"additionalProperties":false,"properties":{"key":{"type":"string"},"name":{"type":"string"},"type":{"$ref":"#/components/schemas/ActionVariableType"}},"required":["key","name","type"],"type":"object"},"ActionVariableType":{"const":"string","description":"Action variable type","type":"string"},"AdHocFilterWithLabels":{"additionalProperties":false,"description":"Define the AdHocFilterWithLabels type","properties":{"condition":{"description":"@deprecated","type":"string"},"forceEdit":{"type":"boolean"},"key":{"type":"string"},"keyLabel":{"type":"string"},"operator":{"type":"string"},"origin":{"$ref":"#/components/schemas/FilterOrigin"},"value":{"type":"string"},"valueLabels":{"items":{"type":"string"},"type":"array"},"values":{"items":{"type":"string"},"type":"array"}},"required":["key","operator","value"],"type":"object"},"AdhocVariableKind":{"additionalProperties":false,"description":"Adhoc variable kind","properties":{"datasource":{"additionalProperties":false,"properties":{"name":{"type":"string"}},"type":"object"},"group":{"type":"string"},"kind":{"const":"AdhocVariable","type":"string"},"spec":{"$ref":"#/components/schemas/AdhocVariableSpec"}},"required":["kind","group","spec"],"type":"object"},"AdhocVariableSpec":{"additionalProperties":false,"description":"Adhoc variable specification","properties":{"allowCustomValue":{"default":true,"type":"boolean"},"baseFilters":{"items":{"$ref":"#/components/schemas/AdHocFilterWithLabels"},"type":"array"},"defaultKeys":{"items":{"$ref":"#/components/schemas/MetricFindValue"},"type":"array"},"description":{"type":"string"},"filters":{"items":{"$ref":"#/components/schemas/AdHocFilterWithLabels"},"type":"array"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"label":{"type":"string"},"name":{"default":"","type":"string"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","baseFilters","filters","defaultKeys","hide","skipUrlSync","allowCustomValue"],"type":"object"},"AnnotationEventFieldMapping":{"additionalProperties":false,"description":"Annotation event field mapping. Defines how to map a data frame field to an annotation event field.","properties":{"regex":{"description":"Regular expression to apply to the field value","type":"string"},"source":{"default":"field","description":"Source type for the field value","type":"string"},"value":{"description":"Constant value to use when source is \"text\"","type":"string"}},"type":"object"},"AnnotationPanelFilter":{"additionalProperties":false,"properties":{"exclude":{"default":false,"description":"Should the specified panels be included or excluded","type":"boolean"},"ids":{"description":"Panel IDs that should be included or excluded","items":{"type":"integer"},"type":"array"}},"required":["ids"],"type":"object"},"AnnotationQueryKind":{"additionalProperties":false,"properties":{"kind":{"const":"AnnotationQuery","type":"string"},"spec":{"$ref":"#/components/schemas/AnnotationQuerySpec"}},"required":["kind","spec"],"type":"object"},"AnnotationQueryPlacement":{"const":"inControlsMenu","description":"Annotation Query placement. Defines where the annotation query should be displayed.\n- \"inControlsMenu\" renders the annotation query in the dashboard controls dropdown menu","type":"string"},"AnnotationQuerySpec":{"additionalProperties":false,"properties":{"builtIn":{"default":false,"type":"boolean"},"enable":{"type":"boolean"},"filter":{"$ref":"#/components/schemas/AnnotationPanelFilter"},"hide":{"type":"boolean"},"iconColor":{"type":"string"},"legacyOptions":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"Catch-all field for datasource-specific properties. Should not be available in as code tooling.","type":"object"},"mappings":{"additionalProperties":{"$ref":"#/components/schemas/AnnotationEventFieldMapping"},"description":"Mappings define how to convert data frame fields to annotation event fields.","type":"object"},"name":{"type":"string"},"placement":{"$ref":"#/components/schemas/AnnotationQueryPlacement","description":"Placement can be used to display the annotation query somewhere else on the dashboard other than the default location."},"query":{"$ref":"#/components/schemas/DataQueryKind"}},"required":["query","enable","hide","iconColor","name"],"type":"object"},"AutoGridLayoutItemKind":{"additionalProperties":false,"properties":{"kind":{"const":"AutoGridLayoutItem","type":"string"},"spec":{"$ref":"#/components/schemas/AutoGridLayoutItemSpec"}},"required":["kind","spec"],"type":"object"},"AutoGridLayoutItemSpec":{"additionalProperties":false,"properties":{"conditionalRendering":{"$ref":"#/components/schemas/ConditionalRenderingGroupKind"},"element":{"$ref":"#/components/schemas/ElementReference"},"repeat":{"$ref":"#/components/schemas/AutoGridRepeatOptions"}},"required":["element"],"type":"object"},"AutoGridLayoutKind":{"additionalProperties":false,"properties":{"kind":{"const":"AutoGridLayout","type":"string"},"spec":{"$ref":"#/components/schemas/AutoGridLayoutSpec"}},"required":["kind","spec"],"type":"object"},"AutoGridLayoutSpec":{"additionalProperties":false,"properties":{"columnWidth":{"type":"number"},"columnWidthMode":{"default":"standard","enum":["narrow","standard","wide","custom"],"type":"string"},"fillScreen":{"default":false,"type":"boolean"},"items":{"items":{"$ref":"#/components/schemas/AutoGridLayoutItemKind"},"type":"array"},"maxColumnCount":{"default":3,"type":"number"},"rowHeight":{"type":"number"},"rowHeightMode":{"default":"standard","enum":["short","standard","tall","custom"],"type":"string"}},"required":["columnWidthMode","rowHeightMode","items"],"type":"object"},"AutoGridRepeatOptions":{"additionalProperties":false,"properties":{"mode":{"$ref":"#/components/schemas/RepeatMode"},"value":{"type":"string"}},"required":["mode","value"],"type":"object"},"ConditionalRenderingDataKind":{"additionalProperties":false,"properties":{"kind":{"const":"ConditionalRenderingData","type":"string"},"spec":{"$ref":"#/components/schemas/ConditionalRenderingDataSpec"}},"required":["kind","spec"],"type":"object"},"ConditionalRenderingDataSpec":{"additionalProperties":false,"properties":{"value":{"type":"boolean"}},"required":["value"],"type":"object"},"ConditionalRenderingGroupKind":{"additionalProperties":false,"properties":{"kind":{"const":"ConditionalRenderingGroup","type":"string"},"spec":{"$ref":"#/components/schemas/ConditionalRenderingGroupSpec"}},"required":["kind","spec"],"type":"object"},"ConditionalRenderingGroupSpec":{"additionalProperties":false,"properties":{"condition":{"enum":["and","or"],"type":"string"},"items":{"items":{"oneOf":[{"$ref":"#/components/schemas/ConditionalRenderingVariableKind"},{"$ref":"#/components/schemas/ConditionalRenderingDataKind"},{"$ref":"#/components/schemas/ConditionalRenderingTimeRangeSizeKind"}]},"type":"array"},"visibility":{"enum":["show","hide"],"type":"string"}},"required":["visibility","condition","items"],"type":"object"},"ConditionalRenderingTimeRangeSizeKind":{"additionalProperties":false,"properties":{"kind":{"const":"ConditionalRenderingTimeRangeSize","type":"string"},"spec":{"$ref":"#/components/schemas/ConditionalRenderingTimeRangeSizeSpec"}},"required":["kind","spec"],"type":"object"},"ConditionalRenderingTimeRangeSizeSpec":{"additionalProperties":false,"properties":{"value":{"type":"string"}},"required":["value"],"type":"object"},"ConditionalRenderingVariableKind":{"additionalProperties":false,"properties":{"kind":{"const":"ConditionalRenderingVariable","type":"string"},"spec":{"$ref":"#/components/schemas/ConditionalRenderingVariableSpec"}},"required":["kind","spec"],"type":"object"},"ConditionalRenderingVariableSpec":{"additionalProperties":false,"properties":{"operator":{"enum":["equals","notEquals","matches","notMatches"],"type":"string"},"value":{"type":"string"},"variable":{"type":"string"}},"required":["variable","operator","value"],"type":"object"},"ConstantVariableKind":{"additionalProperties":false,"description":"Constant variable kind","properties":{"kind":{"const":"ConstantVariable","type":"string"},"spec":{"$ref":"#/components/schemas/ConstantVariableSpec"}},"required":["kind","spec"],"type":"object"},"ConstantVariableSpec":{"additionalProperties":false,"description":"Constant variable specification","properties":{"current":{"$ref":"#/components/schemas/VariableOption","default":{"text":"","value":""}},"description":{"type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"label":{"type":"string"},"name":{"default":"","type":"string"},"query":{"default":"","type":"string"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","query","current","hide","skipUrlSync"],"type":"object"},"ConversionStatus":{"additionalProperties":false,"description":"ConversionStatus is the status of the conversion of the dashboard.","properties":{"error":{"description":"The error message from the conversion.\nEmpty if the conversion has not failed.","type":"string"},"failed":{"description":"Whether from another version has failed.\nIf true, means that the dashboard is not valid,\nand the caller should instead fetch the stored version.","type":"boolean"},"source":{"additionalProperties":{},"description":"The original value map[string]any","type":"object"},"storedVersion":{"description":"The version which was stored when the dashboard was created / updated.\nFetching this version should always succeed.","type":"string"}},"required":["failed"],"type":"object"},"CustomVariableKind":{"additionalProperties":false,"description":"Custom variable kind","properties":{"kind":{"const":"CustomVariable","type":"string"},"spec":{"$ref":"#/components/schemas/CustomVariableSpec"}},"required":["kind","spec"],"type":"object"},"CustomVariableSpec":{"additionalProperties":false,"description":"Custom variable specification","properties":{"allValue":{"type":"string"},"allowCustomValue":{"default":true,"type":"boolean"},"current":{"$ref":"#/components/schemas/VariableOption"},"description":{"type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"includeAll":{"default":false,"type":"boolean"},"label":{"type":"string"},"multi":{"default":false,"type":"boolean"},"name":{"default":"","type":"string"},"options":{"items":{"$ref":"#/components/schemas/VariableOption"},"type":"array"},"query":{"default":"","type":"string"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","query","current","options","multi","includeAll","hide","skipUrlSync","allowCustomValue"],"type":"object"},"Dashboard":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"DashboardCursorSync":{"description":"\"Off\" for no shared crosshair or tooltip (default).\n\"Crosshair\" for shared crosshair.\n\"Tooltip\" for shared crosshair AND shared tooltip.","enum":["Crosshair","Tooltip","Off"],"type":"string"},"DashboardLink":{"additionalProperties":false,"description":"Links with references to other dashboards or external resources","properties":{"asDropdown":{"default":false,"description":"If true, all dashboards links will be displayed in a dropdown. If false, all dashboards links will be displayed side by side. Only valid if the type is dashboards","type":"boolean"},"icon":{"description":"Icon name to be displayed with the link","type":"string"},"includeVars":{"default":false,"description":"If true, includes current template variables values in the link as query params","type":"boolean"},"keepTime":{"default":false,"description":"If true, includes current time range in the link as query params","type":"boolean"},"placement":{"$ref":"#/components/schemas/DashboardLinkPlacement","description":"Placement can be used to display the link somewhere else on the dashboard other than above the visualisations."},"tags":{"description":"List of tags to limit the linked dashboards. If empty, all dashboards will be displayed. Only valid if the type is dashboards","items":{"type":"string"},"type":"array"},"targetBlank":{"default":false,"description":"If true, the link will be opened in a new tab","type":"boolean"},"title":{"description":"Title to display with the link","type":"string"},"tooltip":{"description":"Tooltip to display when the user hovers their mouse over it","type":"string"},"type":{"$ref":"#/components/schemas/DashboardLinkType","description":"Link type. Accepted values are dashboards (to refer to another dashboard) and link (to refer to an external resource)\nFIXME: The type is generated as ` + "`" + `type: DashboardLinkType | dashboardLinkType.Link;` + "`" + ` but it should be ` + "`" + `type: DashboardLinkType` + "`" + `"},"url":{"description":"Link URL. Only required/valid if the type is link","type":"string"}},"required":["title","type","icon","tooltip","tags","asDropdown","targetBlank","includeVars","keepTime"],"type":"object"},"DashboardLinkPlacement":{"const":"inControlsMenu","description":"Dashboard Link placement. Defines where the link should be displayed.\n- \"inControlsMenu\" renders the link in bottom part of the dashboard controls dropdown menu","type":"string"},"DashboardLinkType":{"description":"Dashboard Link type. Accepted values are dashboards (to refer to another dashboard) and link (to refer to an external resource)","enum":["link","dashboards"],"type":"string"},"DataLink":{"additionalProperties":false,"properties":{"targetBlank":{"type":"boolean"},"title":{"type":"string"},"url":{"type":"string"}},"required":["title","url"],"type":"object"},"DataQueryKind":{"additionalProperties":false,"properties":{"datasource":{"additionalProperties":false,"description":"New type for datasource reference\nNot creating a new type until we figure out how to handle DS refs for group by, adhoc, and every place that uses DataSourceRef in TS.","properties":{"name":{"type":"string"}},"type":"object"},"group":{"type":"string"},"kind":{"const":"DataQuery","type":"string"},"spec":{"additionalProperties":{"additionalProperties":{},"type":"object"},"type":"object"},"version":{"default":"v0","type":"string"}},"required":["kind","group","version","spec"],"type":"object"},"DataTopic":{"description":"A topic is attached to DataFrame metadata in query results.\nThis specifies where the data should be used.","enum":["series","annotations","alertStates"],"type":"string"},"DataTransformerConfig":{"additionalProperties":false,"description":"Transformations allow to manipulate data returned by a query before the system applies a visualization.\nUsing transformations you can: rename fields, join time series data, perform mathematical operations across queries,\nuse the output of one transformation as the input to another transformation, etc.","properties":{"disabled":{"description":"Disabled transformations are skipped","type":"boolean"},"filter":{"$ref":"#/components/schemas/MatcherConfig","description":"Optional frame matcher. When missing it will be applied to all results"},"id":{"description":"Unique identifier of transformer","type":"string"},"options":{"additionalProperties":{},"description":"Options to be passed to the transformer\nValid options depend on the transformer id","type":"object"},"topic":{"$ref":"#/components/schemas/DataTopic","description":"Where to pull DataFrames from as input to transformation"}},"required":["id","options"],"type":"object"},"DatasourceVariableKind":{"additionalProperties":false,"description":"Datasource variable kind","properties":{"kind":{"const":"DatasourceVariable","type":"string"},"spec":{"$ref":"#/components/schemas/DatasourceVariableSpec"}},"required":["kind","spec"],"type":"object"},"DatasourceVariableSpec":{"additionalProperties":false,"description":"Datasource variable specification","properties":{"allValue":{"type":"string"},"allowCustomValue":{"default":true,"type":"boolean"},"current":{"$ref":"#/components/schemas/VariableOption","default":{"text":"","value":""}},"description":{"type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"includeAll":{"default":false,"type":"boolean"},"label":{"type":"string"},"multi":{"default":false,"type":"boolean"},"name":{"default":"","type":"string"},"options":{"items":{"$ref":"#/components/schemas/VariableOption"},"type":"array"},"pluginId":{"default":"","type":"string"},"refresh":{"$ref":"#/components/schemas/VariableRefresh","default":"never"},"regex":{"default":"","type":"string"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","pluginId","refresh","regex","current","options","multi","includeAll","hide","skipUrlSync","allowCustomValue"],"type":"object"},"DynamicConfigValue":{"additionalProperties":false,"properties":{"id":{"default":"","type":"string"},"value":{"additionalProperties":{},"type":"object"}},"required":["id"],"type":"object"},"Element":{"description":"Supported dashboard elements\n|* more element types in the future","oneOf":[{"$ref":"#/components/schemas/PanelKind"},{"$ref":"#/components/schemas/LibraryPanelKind"}]},"ElementReference":{"additionalProperties":false,"properties":{"kind":{"const":"ElementReference","type":"string"},"name":{"type":"string"}},"required":["kind","name"],"type":"object"},"FetchOptions":{"additionalProperties":false,"properties":{"body":{"type":"string"},"headers":{"items":{"items":{"type":"string"},"type":"array"},"type":"array"},"method":{"$ref":"#/components/schemas/HttpRequestMethod"},"queryParams":{"description":"These are 2D arrays of strings, each representing a key-value pair\nWe are defining them this way because we can't generate a go struct that\nthat would have exactly two strings in each sub-array","items":{"items":{"type":"string"},"type":"array"},"type":"array"},"url":{"type":"string"}},"required":["method","url"],"type":"object"},"FieldColor":{"additionalProperties":false,"description":"Map a field to a color.","properties":{"fixedColor":{"description":"The fixed color value for fixed or shades color modes.","type":"string"},"mode":{"$ref":"#/components/schemas/FieldColorModeId","description":"The main color scheme mode."},"seriesBy":{"$ref":"#/components/schemas/FieldColorSeriesByMode","description":"Some visualizations need to know how to assign a series color from by value color schemes."}},"required":["mode"],"type":"object"},"FieldColorModeId":{"description":"Color mode for a field. You can specify a single color, or select a continuous (gradient) color schemes, based on a value.\nContinuous color interpolates a color using the percentage of a value relative to min and max.\nAccepted values are:\n` + "`" + `thresholds` + "`" + `: From thresholds. Informs Grafana to take the color from the matching threshold\n` + "`" + `palette-classic` + "`" + `: Classic palette. Grafana will assign color by looking up a color in a palette by series index. Useful for Graphs and pie charts and other categorical data visualizations\n` + "`" + `palette-classic-by-name` + "`" + `: Classic palette (by name). Grafana will assign color by looking up a color in a palette by series name. Useful for Graphs and pie charts and other categorical data visualizations\n` + "`" + `continuous-viridis` + "`" + `: Continuous Viridis palette mode\n` + "`" + `continuous-magma` + "`" + `: Continuous Magma palette mode\n` + "`" + `continuous-plasma` + "`" + `: Continuous Plasma palette mode\n` + "`" + `continuous-inferno` + "`" + `: Continuous Inferno palette mode\n` + "`" + `continuous-cividis` + "`" + `: Continuous Cividis palette mode\n` + "`" + `continuous-GrYlRd` + "`" + `: Continuous Green-Yellow-Red palette mode\n` + "`" + `continuous-RdYlGr` + "`" + `: Continuous Red-Yellow-Green palette mode\n` + "`" + `continuous-BlYlRd` + "`" + `: Continuous Blue-Yellow-Red palette mode\n` + "`" + `continuous-YlRd` + "`" + `: Continuous Yellow-Red palette mode\n` + "`" + `continuous-BlPu` + "`" + `: Continuous Blue-Purple palette mode\n` + "`" + `continuous-YlBl` + "`" + `: Continuous Yellow-Blue palette mode\n` + "`" + `continuous-blues` + "`" + `: Continuous Blue palette mode\n` + "`" + `continuous-reds` + "`" + `: Continuous Red palette mode\n` + "`" + `continuous-greens` + "`" + `: Continuous Green palette mode\n` + "`" + `continuous-purples` + "`" + `: Continuous Purple palette mode\n` + "`" + `shades` + "`" + `: Shades of a single color. Specify a single color, useful in an override rule.\n` + "`" + `fixed` + "`" + `: Fixed color mode. Specify a single color, useful in an override rule.","enum":["thresholds","palette-classic","palette-classic-by-name","continuous-viridis","continuous-magma","continuous-plasma","continuous-inferno","continuous-cividis","continuous-GrYlRd","continuous-RdYlGr","continuous-BlYlRd","continuous-YlRd","continuous-BlPu","continuous-YlBl","continuous-blues","continuous-reds","continuous-greens","continuous-purples","fixed","shades"],"type":"string"},"FieldColorSeriesByMode":{"description":"Defines how to assign a series color from \"by value\" color schemes. For example for an aggregated data points like a timeseries, the color can be assigned by the min, max or last value.","enum":["min","max","last"],"type":"string"},"FieldConfig":{"additionalProperties":false,"description":"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.\nEach column within this structure is called a field. A field can represent a single time series or table column.\nField options allow you to change how the data is displayed in your visualizations.","properties":{"actions":{"description":"Define interactive HTTP requests that can be triggered from data visualizations.","items":{"$ref":"#/components/schemas/Action"},"type":"array"},"color":{"$ref":"#/components/schemas/FieldColor","description":"Panel color configuration"},"custom":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"custom is specified by the FieldConfig field\nin panel plugin schemas.","type":"object"},"decimals":{"description":"Specify the number of decimals Grafana includes in the rendered value.\nIf you leave this field blank, Grafana automatically truncates the number of decimals based on the value.\nFor example 1.1234 will display as 1.12 and 100.456 will display as 100.\nTo display all decimals, set the unit to ` + "`" + `String` + "`" + `.","type":"number"},"description":{"description":"Human readable field metadata","type":"string"},"displayName":{"description":"The display value for this field. This supports template variables blank is auto","type":"string"},"displayNameFromDS":{"description":"This can be used by data sources that return and explicit naming structure for values and labels\nWhen this property is configured, this value is used rather than the default naming strategy.","type":"string"},"filterable":{"description":"True if data source field supports ad-hoc filters","type":"boolean"},"links":{"description":"The behavior when clicking on a result","items":{"additionalProperties":{},"type":"object"},"type":"array"},"mappings":{"description":"Convert input values into a display string","items":{"$ref":"#/components/schemas/ValueMapping"},"type":"array"},"max":{"description":"The maximum value used in percentage threshold calculations. Leave blank for auto calculation based on all series and fields.","type":"number"},"min":{"description":"The minimum value used in percentage threshold calculations. Leave blank for auto calculation based on all series and fields.","type":"number"},"noValue":{"description":"Alternative to empty string","type":"string"},"path":{"description":"An explicit path to the field in the datasource. When the frame meta includes a path,\nThis will default to ` + "`" + `${frame.meta.path}/${field.name}\n\nWhen defined, this value can be used as an identifier within the datasource scope, and\nmay be used to update the results","type":"string"},"thresholds":{"$ref":"#/components/schemas/ThresholdsConfig","description":"Map numeric values to states"},"unit":{"description":"Unit a field should use. The unit you select is applied to all fields except time.\nYou can use the units ID availables in Grafana or a custom unit.\nAvailable units in Grafana: https://github.com/grafana/grafana/blob/main/packages/grafana-data/src/valueFormats/categories.ts\nAs custom unit, you can use the following formats:\n` + "`" + `suffix:\u003csuffix\u003e` + "`" + ` for custom unit that should go after value.\n` + "`" + `prefix:\u003cprefix\u003e` + "`" + ` for custom unit that should go before value.\n` + "`" + `time:\u003cformat\u003e` + "`" + ` For custom date time formats type for example ` + "`" + `time:YYYY-MM-DD` + "`" + `.\n` + "`" + `si:\u003cbase scale\u003e\u003cunit characters\u003e` + "`" + ` for custom SI units. For example: ` + "`" + `si: mF` + "`" + `. This one is a bit more advanced as you can specify both a unit and the source data scale. So if your source data is represented as milli (thousands of) something prefix the unit with that SI scale character.\n` + "`" + `count:\u003cunit\u003e` + "`" + ` for a custom count unit.\n` + "`" + `currency:\u003cunit\u003e` + "`" + ` for custom a currency unit.","type":"string"},"writeable":{"description":"True if data source can write a value to the path. Auth/authz are supported separately","type":"boolean"}},"type":"object"},"FieldConfigSource":{"additionalProperties":false,"description":"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.\nEach column within this structure is called a field. A field can represent a single time series or table column.\nField options allow you to change how the data is displayed in your visualizations.","properties":{"defaults":{"$ref":"#/components/schemas/FieldConfig","description":"Defaults are the options applied to all fields."},"overrides":{"description":"Overrides are the options applied to specific fields overriding the defaults.","items":{"additionalProperties":false,"properties":{"__systemRef":{"description":"Describes config override rules created when interacting with Grafana.","type":"string"},"matcher":{"$ref":"#/components/schemas/MatcherConfig"},"properties":{"items":{"$ref":"#/components/schemas/DynamicConfigValue"},"type":"array"}},"required":["matcher","properties"],"type":"object"},"type":"array"}},"required":["defaults","overrides"],"type":"object"},"FilterOrigin":{"const":"dashboard","description":"Determine the origin of the adhoc variable filter","type":"string"},"GridLayoutItemKind":{"additionalProperties":false,"properties":{"kind":{"const":"GridLayoutItem","type":"string"},"spec":{"$ref":"#/components/schemas/GridLayoutItemSpec"}},"required":["kind","spec"],"type":"object"},"GridLayoutItemSpec":{"additionalProperties":false,"properties":{"element":{"$ref":"#/components/schemas/ElementReference","description":"reference to a PanelKind from dashboard.spec.elements Expressed as JSON Schema reference"},"height":{"type":"integer"},"repeat":{"$ref":"#/components/schemas/RepeatOptions"},"width":{"type":"integer"},"x":{"type":"integer"},"y":{"type":"integer"}},"required":["x","y","width","height","element"],"type":"object"},"GridLayoutKind":{"additionalProperties":false,"properties":{"kind":{"const":"GridLayout","type":"string"},"spec":{"$ref":"#/components/schemas/GridLayoutSpec"}},"required":["kind","spec"],"type":"object"},"GridLayoutSpec":{"additionalProperties":false,"properties":{"items":{"items":{"$ref":"#/components/schemas/GridLayoutItemKind"},"type":"array"}},"required":["items"],"type":"object"},"GroupByVariableKind":{"additionalProperties":false,"description":"Group variable kind","properties":{"datasource":{"additionalProperties":false,"properties":{"name":{"type":"string"}},"type":"object"},"group":{"type":"string"},"kind":{"const":"GroupByVariable","type":"string"},"spec":{"$ref":"#/components/schemas/GroupByVariableSpec"}},"required":["kind","group","spec"],"type":"object"},"GroupByVariableSpec":{"additionalProperties":false,"description":"GroupBy variable specification","properties":{"current":{"$ref":"#/components/schemas/VariableOption","default":{"text":"","value":""}},"defaultValue":{"$ref":"#/components/schemas/VariableOption"},"description":{"type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"label":{"type":"string"},"multi":{"default":false,"type":"boolean"},"name":{"default":"","type":"string"},"options":{"items":{"$ref":"#/components/schemas/VariableOption"},"type":"array"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","current","options","multi","hide","skipUrlSync"],"type":"object"},"HttpRequestMethod":{"enum":["GET","PUT","POST","DELETE","PATCH"],"type":"string"},"InfinityOptions":{"additionalProperties":false,"properties":{"body":{"type":"string"},"datasourceUid":{"type":"string"},"headers":{"items":{"items":{"type":"string"},"type":"array"},"type":"array"},"method":{"$ref":"#/components/schemas/HttpRequestMethod"},"queryParams":{"description":"These are 2D arrays of strings, each representing a key-value pair\nWe are defining them this way because we can't generate a go struct that\nthat would have exactly two strings in each sub-array","items":{"items":{"type":"string"},"type":"array"},"type":"array"},"url":{"type":"string"}},"required":["method","url","datasourceUid"],"type":"object"},"IntervalVariableKind":{"additionalProperties":false,"description":"Interval variable kind","properties":{"kind":{"const":"IntervalVariable","type":"string"},"spec":{"$ref":"#/components/schemas/IntervalVariableSpec"}},"required":["kind","spec"],"type":"object"},"IntervalVariableSpec":{"additionalProperties":false,"description":"Interval variable specification","properties":{"auto":{"default":false,"type":"boolean"},"auto_count":{"default":0,"type":"integer"},"auto_min":{"default":"","type":"string"},"current":{"$ref":"#/components/schemas/VariableOption","default":{"text":"","value":""}},"description":{"type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"label":{"type":"string"},"name":{"default":"","type":"string"},"options":{"items":{"$ref":"#/components/schemas/VariableOption"},"type":"array"},"query":{"default":"","type":"string"},"refresh":{"const":"onTimeRangeChanged","type":"string"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","query","current","options","auto","auto_min","auto_count","refresh","hide","skipUrlSync"],"type":"object"},"LibraryPanelKind":{"additionalProperties":false,"properties":{"kind":{"const":"LibraryPanel","type":"string"},"spec":{"$ref":"#/components/schemas/LibraryPanelKindSpec"}},"required":["kind","spec"],"type":"object"},"LibraryPanelKindSpec":{"additionalProperties":false,"properties":{"id":{"description":"Panel ID for the library panel in the dashboard","type":"number"},"libraryPanel":{"$ref":"#/components/schemas/LibraryPanelRef"},"title":{"description":"Title for the library panel in the dashboard","type":"string"}},"required":["id","title","libraryPanel"],"type":"object"},"LibraryPanelRef":{"additionalProperties":false,"description":"A library panel is a reusable panel that you can use in any dashboard.\nWhen you make a change to a library panel, that change propagates to all instances of where the panel is used.\nLibrary panels streamline reuse of panels across multiple dashboards.","properties":{"name":{"description":"Library panel name","type":"string"},"uid":{"description":"Library panel uid","type":"string"}},"required":["name","uid"],"type":"object"},"MappingType":{"description":"Supported value mapping types\n` + "`" + `value` + "`" + `: Maps text values to a color or different display text and color. For example, you can configure a value mapping so that all instances of the value 10 appear as Perfection! rather than the number.\n` + "`" + `range` + "`" + `: Maps numerical ranges to a display text and color. For example, if a value is within a certain range, you can configure a range value mapping to display Low or High rather than the number.\n` + "`" + `regex` + "`" + `: Maps regular expressions to replacement text and a color. For example, if a value is www.example.com, you can configure a regex value mapping so that Grafana displays www and truncates the domain.\n` + "`" + `special` + "`" + `: Maps special values like Null, NaN (not a number), and boolean values like true and false to a display text and color. See SpecialValueMatch to see the list of special values. For example, you can configure a special value mapping so that null values appear as N/A.","enum":["value","range","regex","special"],"type":"string"},"MatcherConfig":{"additionalProperties":false,"description":"Matcher is a predicate configuration. Based on the config a set of field(s) or values is filtered in order to apply override / transformation.\nIt comes with in id ( to resolve implementation from registry) and a configuration that’s specific to a particular matcher type.","properties":{"id":{"default":"","description":"The matcher id. This is used to find the matcher implementation from registry.","type":"string"},"options":{"additionalProperties":{},"description":"The matcher options. This is specific to the matcher implementation.","type":"object"}},"required":["id"],"type":"object"},"MetricFindValue":{"additionalProperties":false,"description":"Define the MetricFindValue type","properties":{"expandable":{"type":"boolean"},"group":{"type":"string"},"text":{"type":"string"},"value":{"oneOf":[{"type":"string"},{"type":"number"}]}},"required":["text"],"type":"object"},"PanelKind":{"additionalProperties":false,"properties":{"kind":{"const":"Panel","type":"string"},"spec":{"$ref":"#/components/schemas/PanelSpec"}},"required":["kind","spec"],"type":"object"},"PanelQueryKind":{"additionalProperties":false,"properties":{"kind":{"const":"PanelQuery","type":"string"},"spec":{"$ref":"#/components/schemas/PanelQuerySpec"}},"required":["kind","spec"],"type":"object"},"PanelQuerySpec":{"additionalProperties":false,"properties":{"hidden":{"type":"boolean"},"query":{"$ref":"#/components/schemas/DataQueryKind"},"refId":{"default":"A","type":"string"}},"required":["query","refId","hidden"],"type":"object"},"PanelSpec":{"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/QueryGroupKind"},"description":{"type":"string"},"id":{"type":"number"},"links":{"items":{"$ref":"#/components/schemas/DataLink"},"type":"array"},"title":{"type":"string"},"transparent":{"type":"boolean"},"vizConfig":{"$ref":"#/components/schemas/VizConfigKind"}},"required":["id","title","description","links","data","vizConfig"],"type":"object"},"QueryGroupKind":{"additionalProperties":false,"properties":{"kind":{"const":"QueryGroup","type":"string"},"spec":{"$ref":"#/components/schemas/QueryGroupSpec"}},"required":["kind","spec"],"type":"object"},"QueryGroupSpec":{"additionalProperties":false,"properties":{"queries":{"items":{"$ref":"#/components/schemas/PanelQueryKind"},"type":"array"},"queryOptions":{"$ref":"#/components/schemas/QueryOptionsSpec"},"transformations":{"items":{"$ref":"#/components/schemas/TransformationKind"},"type":"array"}},"required":["queries","transformations","queryOptions"],"type":"object"},"QueryOptionsSpec":{"additionalProperties":false,"properties":{"cacheTimeout":{"type":"string"},"hideTimeOverride":{"type":"boolean"},"interval":{"type":"string"},"maxDataPoints":{"type":"integer"},"queryCachingTTL":{"type":"integer"},"timeCompare":{"type":"string"},"timeFrom":{"type":"string"},"timeShift":{"type":"string"}},"type":"object"},"QueryVariableKind":{"additionalProperties":false,"description":"Query variable kind","properties":{"kind":{"const":"QueryVariable","type":"string"},"spec":{"$ref":"#/components/schemas/QueryVariableSpec"}},"required":["kind","spec"],"type":"object"},"QueryVariableSpec":{"additionalProperties":false,"description":"Query variable specification","properties":{"allValue":{"type":"string"},"allowCustomValue":{"default":true,"type":"boolean"},"current":{"$ref":"#/components/schemas/VariableOption","default":{"text":"","value":""}},"definition":{"type":"string"},"description":{"type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"includeAll":{"default":false,"type":"boolean"},"label":{"type":"string"},"multi":{"default":false,"type":"boolean"},"name":{"default":"","type":"string"},"options":{"items":{"$ref":"#/components/schemas/VariableOption"},"type":"array"},"placeholder":{"type":"string"},"query":{"$ref":"#/components/schemas/DataQueryKind"},"refresh":{"$ref":"#/components/schemas/VariableRefresh","default":"never"},"regex":{"default":"","type":"string"},"regexApplyTo":{"$ref":"#/components/schemas/VariableRegexApplyTo","default":"value"},"skipUrlSync":{"default":false,"type":"boolean"},"sort":{"$ref":"#/components/schemas/VariableSort"},"staticOptions":{"items":{"$ref":"#/components/schemas/VariableOption"},"type":"array"},"staticOptionsOrder":{"enum":["before","after","sorted"],"type":"string"}},"required":["name","current","hide","refresh","skipUrlSync","query","regex","sort","options","multi","includeAll","allowCustomValue"],"type":"object"},"RangeMap":{"additionalProperties":false,"description":"Maps numerical ranges to a display text and color.\nFor example, if a value is within a certain range, you can configure a range value mapping to display Low or High rather than the number.","properties":{"options":{"additionalProperties":false,"description":"Range to match against and the result to apply when the value is within the range","properties":{"from":{"description":"Min value of the range. It can be null which means -Infinity","type":"number"},"result":{"$ref":"#/components/schemas/ValueMappingResult","description":"Config to apply when the value is within the range"},"to":{"description":"Max value of the range. It can be null which means +Infinity","type":"number"}},"required":["from","to","result"],"type":"object"},"type":{"$ref":"#/components/schemas/MappingType"}},"required":["type","options"],"type":"object"},"RegexMap":{"additionalProperties":false,"description":"Maps regular expressions to replacement text and a color.\nFor example, if a value is www.example.com, you can configure a regex value mapping so that Grafana displays www and truncates the domain.","properties":{"options":{"additionalProperties":false,"description":"Regular expression to match against and the result to apply when the value matches the regex","properties":{"pattern":{"description":"Regular expression to match against","type":"string"},"result":{"$ref":"#/components/schemas/ValueMappingResult","description":"Config to apply when the value matches the regex"}},"required":["pattern","result"],"type":"object"},"type":{"$ref":"#/components/schemas/MappingType"}},"required":["type","options"],"type":"object"},"RepeatMode":{"const":"variable","description":"other repeat modes will be added in the future: label, frame","type":"string"},"RepeatOptions":{"additionalProperties":false,"properties":{"direction":{"enum":["h","v"],"type":"string"},"maxPerRow":{"type":"integer"},"mode":{"$ref":"#/components/schemas/RepeatMode"},"value":{"type":"string"}},"required":["mode","value"],"type":"object"},"RowRepeatOptions":{"additionalProperties":false,"properties":{"mode":{"$ref":"#/components/schemas/RepeatMode"},"value":{"type":"string"}},"required":["mode","value"],"type":"object"},"RowsLayoutKind":{"additionalProperties":false,"properties":{"kind":{"const":"RowsLayout","type":"string"},"spec":{"$ref":"#/components/schemas/RowsLayoutSpec"}},"required":["kind","spec"],"type":"object"},"RowsLayoutRowKind":{"additionalProperties":false,"properties":{"kind":{"const":"RowsLayoutRow","type":"string"},"spec":{"$ref":"#/components/schemas/RowsLayoutRowSpec"}},"required":["kind","spec"],"type":"object"},"RowsLayoutRowSpec":{"additionalProperties":false,"properties":{"collapse":{"type":"boolean"},"conditionalRendering":{"$ref":"#/components/schemas/ConditionalRenderingGroupKind"},"fillScreen":{"type":"boolean"},"hideHeader":{"type":"boolean"},"layout":{"oneOf":[{"$ref":"#/components/schemas/GridLayoutKind"},{"$ref":"#/components/schemas/AutoGridLayoutKind"},{"$ref":"#/components/schemas/TabsLayoutKind"},{"$ref":"#/components/schemas/RowsLayoutKind"}]},"repeat":{"$ref":"#/components/schemas/RowRepeatOptions"},"title":{"type":"string"}},"required":["layout"],"type":"object"},"RowsLayoutSpec":{"additionalProperties":false,"properties":{"rows":{"items":{"$ref":"#/components/schemas/RowsLayoutRowKind"},"type":"array"}},"required":["rows"],"type":"object"},"SpecialValueMap":{"additionalProperties":false,"description":"Maps special values like Null, NaN (not a number), and boolean values like true and false to a display text and color.\nSee SpecialValueMatch to see the list of special values.\nFor example, you can configure a special value mapping so that null values appear as N/A.","properties":{"options":{"additionalProperties":false,"properties":{"match":{"$ref":"#/components/schemas/SpecialValueMatch","description":"Special value to match against"},"result":{"$ref":"#/components/schemas/ValueMappingResult","description":"Config to apply when the value matches the special value"}},"required":["match","result"],"type":"object"},"type":{"$ref":"#/components/schemas/MappingType"}},"required":["type","options"],"type":"object"},"SpecialValueMatch":{"description":"Special value types supported by the ` + "`" + `SpecialValueMap` + "`" + `","enum":["true","false","null","nan","null+nan","empty"],"type":"string"},"SwitchVariableKind":{"additionalProperties":false,"properties":{"kind":{"const":"SwitchVariable","type":"string"},"spec":{"$ref":"#/components/schemas/SwitchVariableSpec"}},"required":["kind","spec"],"type":"object"},"SwitchVariableSpec":{"additionalProperties":false,"properties":{"current":{"default":"false","type":"string"},"description":{"type":"string"},"disabledValue":{"default":"false","type":"string"},"enabledValue":{"default":"true","type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"label":{"type":"string"},"name":{"default":"","type":"string"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","current","enabledValue","disabledValue","hide","skipUrlSync"],"type":"object"},"TabRepeatOptions":{"additionalProperties":false,"properties":{"mode":{"$ref":"#/components/schemas/RepeatMode"},"value":{"type":"string"}},"required":["mode","value"],"type":"object"},"TabsLayoutKind":{"additionalProperties":false,"properties":{"kind":{"const":"TabsLayout","type":"string"},"spec":{"$ref":"#/components/schemas/TabsLayoutSpec"}},"required":["kind","spec"],"type":"object"},"TabsLayoutSpec":{"additionalProperties":false,"properties":{"tabs":{"items":{"$ref":"#/components/schemas/TabsLayoutTabKind"},"type":"array"}},"required":["tabs"],"type":"object"},"TabsLayoutTabKind":{"additionalProperties":false,"properties":{"kind":{"const":"TabsLayoutTab","type":"string"},"spec":{"$ref":"#/components/schemas/TabsLayoutTabSpec"}},"required":["kind","spec"],"type":"object"},"TabsLayoutTabSpec":{"additionalProperties":false,"properties":{"conditionalRendering":{"$ref":"#/components/schemas/ConditionalRenderingGroupKind"},"layout":{"oneOf":[{"$ref":"#/components/schemas/GridLayoutKind"},{"$ref":"#/components/schemas/RowsLayoutKind"},{"$ref":"#/components/schemas/AutoGridLayoutKind"},{"$ref":"#/components/schemas/TabsLayoutKind"}]},"repeat":{"$ref":"#/components/schemas/TabRepeatOptions"},"title":{"type":"string"}},"required":["layout"],"type":"object"},"TextVariableKind":{"additionalProperties":false,"description":"Text variable kind","properties":{"kind":{"const":"TextVariable","type":"string"},"spec":{"$ref":"#/components/schemas/TextVariableSpec"}},"required":["kind","spec"],"type":"object"},"TextVariableSpec":{"additionalProperties":false,"description":"Text variable specification","properties":{"current":{"$ref":"#/components/schemas/VariableOption","default":{"text":"","value":""}},"description":{"type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"label":{"type":"string"},"name":{"default":"","type":"string"},"query":{"default":"","type":"string"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","current","query","hide","skipUrlSync"],"type":"object"},"Threshold":{"additionalProperties":false,"properties":{"color":{"type":"string"},"value":{"description":"Value null means -Infinity","type":"number"}},"required":["value","color"],"type":"object"},"ThresholdsConfig":{"additionalProperties":false,"properties":{"mode":{"$ref":"#/components/schemas/ThresholdsMode"},"steps":{"items":{"$ref":"#/components/schemas/Threshold"},"type":"array"}},"required":["mode","steps"],"type":"object"},"ThresholdsMode":{"enum":["absolute","percentage"],"type":"string"},"TimeRangeOption":{"additionalProperties":false,"properties":{"display":{"default":"Last 6 hours","type":"string"},"from":{"default":"now-6h","type":"string"},"to":{"default":"now","type":"string"}},"required":["display","from","to"],"type":"object"},"TimeSettingsSpec":{"additionalProperties":false,"description":"Time configuration\nIt defines the default time config for the time picker, the refresh picker for the specific dashboard.","properties":{"autoRefresh":{"default":"","description":"Refresh rate of dashboard. Represented via interval string, e.g. \"5s\", \"1m\", \"1h\", \"1d\".\nv1: refresh","type":"string"},"autoRefreshIntervals":{"default":["5s","10s","30s","1m","5m","15m","30m","1h","2h","1d"],"description":"Interval options available in the refresh picker dropdown.\nv1: timepicker.refresh_intervals","items":{"type":"string"},"type":"array"},"fiscalYearStartMonth":{"default":0,"description":"The month that the fiscal year starts on. 0 = January, 11 = December","type":"integer"},"from":{"default":"now-6h","description":"Start time range for dashboard.\nAccepted values are relative time strings like \"now-6h\" or absolute time strings like \"2020-07-10T08:00:00.000Z\".","type":"string"},"hideTimepicker":{"default":false,"description":"Whether timepicker is visible or not.\nv1: timepicker.hidden","type":"boolean"},"nowDelay":{"description":"Override the now time by entering a time delay. Use this option to accommodate known delays in data aggregation to avoid null values.\nv1: timepicker.nowDelay","type":"string"},"quickRanges":{"description":"Selectable options available in the time picker dropdown. Has no effect on provisioned dashboard.\nv1: timepicker.quick_ranges , not exposed in the UI","items":{"$ref":"#/components/schemas/TimeRangeOption"},"type":"array"},"timezone":{"default":"browser","description":"Timezone of dashboard. Accepted values are IANA TZDB zone ID or \"browser\" or \"utc\".","type":"string"},"to":{"default":"now","description":"End time range for dashboard.\nAccepted values are relative time strings like \"now-6h\" or absolute time strings like \"2020-07-10T08:00:00.000Z\".","type":"string"},"weekStart":{"description":"Day when the week starts. Expressed by the name of the day in lowercase, e.g. \"monday\".","enum":["saturday","monday","sunday"],"type":"string"}},"required":["from","to","autoRefresh","autoRefreshIntervals","hideTimepicker","fiscalYearStartMonth"],"type":"object"},"TransformationKind":{"additionalProperties":false,"properties":{"kind":{"description":"The kind of a TransformationKind is the transformation ID","type":"string"},"spec":{"$ref":"#/components/schemas/DataTransformerConfig"}},"required":["kind","spec"],"type":"object"},"ValueMap":{"additionalProperties":false,"description":"Maps text values to a color or different display text and color.\nFor example, you can configure a value mapping so that all instances of the value 10 appear as Perfection! rather than the number.","properties":{"options":{"additionalProperties":{"$ref":"#/components/schemas/ValueMappingResult"},"description":"Map with \u003cvalue_to_match\u003e: ValueMappingResult. For example: { \"10\": { text: \"Perfection!\", color: \"green\" } }","type":"object"},"type":{"$ref":"#/components/schemas/MappingType"}},"required":["type","options"],"type":"object"},"ValueMapping":{"oneOf":[{"$ref":"#/components/schemas/ValueMap"},{"$ref":"#/components/schemas/RangeMap"},{"$ref":"#/components/schemas/RegexMap"},{"$ref":"#/components/schemas/SpecialValueMap"}]},"ValueMappingResult":{"additionalProperties":false,"description":"Result used as replacement with text and color when the value matches","properties":{"color":{"description":"Text to use when the value matches","type":"string"},"icon":{"description":"Icon to display when the value matches. Only specific visualizations.","type":"string"},"index":{"description":"Position in the mapping array. Only used internally.","type":"integer"},"text":{"description":"Text to display when the value matches","type":"string"}},"type":"object"},"VariableHide":{"description":"Determine if the variable shows on dashboard\nAccepted values are ` + "`" + `dontHide` + "`" + ` (show label and value), ` + "`" + `hideLabel` + "`" + ` (show value only), ` + "`" + `hideVariable` + "`" + ` (show nothing), ` + "`" + `inControlsMenu` + "`" + ` (show in a drop-down menu).","enum":["dontHide","hideLabel","hideVariable","inControlsMenu"],"type":"string"},"VariableKind":{"oneOf":[{"$ref":"#/components/schemas/QueryVariableKind"},{"$ref":"#/components/schemas/TextVariableKind"},{"$ref":"#/components/schemas/ConstantVariableKind"},{"$ref":"#/components/schemas/DatasourceVariableKind"},{"$ref":"#/components/schemas/IntervalVariableKind"},{"$ref":"#/components/schemas/CustomVariableKind"},{"$ref":"#/components/schemas/GroupByVariableKind"},{"$ref":"#/components/schemas/AdhocVariableKind"},{"$ref":"#/components/schemas/SwitchVariableKind"}]},"VariableOption":{"additionalProperties":false,"description":"Variable option specification","properties":{"selected":{"description":"Whether the option is selected or not","type":"boolean"},"text":{"description":"Text to be displayed for the option","oneOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"}]},"value":{"description":"Value of the option","oneOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"}]}},"required":["text","value"],"type":"object"},"VariableRefresh":{"description":"Options to config when to refresh a variable\n` + "`" + `never` + "`" + `: Never refresh the variable\n` + "`" + `onDashboardLoad` + "`" + `: Queries the data source every time the dashboard loads.\n` + "`" + `onTimeRangeChanged` + "`" + `: Queries the data source when the dashboard time range changes.","enum":["never","onDashboardLoad","onTimeRangeChanged"],"type":"string"},"VariableRegexApplyTo":{"description":"Determine whether regex applies to variable value or display text\nAccepted values are ` + "`" + `value` + "`" + ` (apply to value used in queries) or ` + "`" + `text` + "`" + ` (apply to display text shown to users)","enum":["value","text"],"type":"string"},"VariableSort":{"description":"Sort variable options\nAccepted values are:\n` + "`" + `disabled` + "`" + `: No sorting\n` + "`" + `alphabeticalAsc` + "`" + `: Alphabetical ASC\n` + "`" + `alphabeticalDesc` + "`" + `: Alphabetical DESC\n` + "`" + `numericalAsc` + "`" + `: Numerical ASC\n` + "`" + `numericalDesc` + "`" + `: Numerical DESC\n` + "`" + `alphabeticalCaseInsensitiveAsc` + "`" + `: Alphabetical Case Insensitive ASC\n` + "`" + `alphabeticalCaseInsensitiveDesc` + "`" + `: Alphabetical Case Insensitive DESC\n` + "`" + `naturalAsc` + "`" + `: Natural ASC\n` + "`" + `naturalDesc` + "`" + `: Natural DESC\nVariableSort enum with default value","enum":["disabled","alphabeticalAsc","alphabeticalDesc","numericalAsc","numericalDesc","alphabeticalCaseInsensitiveAsc","alphabeticalCaseInsensitiveDesc","naturalAsc","naturalDesc"],"type":"string"},"VizConfigKind":{"additionalProperties":false,"properties":{"group":{"description":"The group is the plugin ID","type":"string"},"kind":{"const":"VizConfig","type":"string"},"spec":{"$ref":"#/components/schemas/VizConfigSpec"},"version":{"type":"string"}},"required":["kind","group","version","spec"],"type":"object"},"VizConfigSpec":{"additionalProperties":false,"description":"--- Kinds ---","properties":{"fieldConfig":{"$ref":"#/components/schemas/FieldConfigSource"},"options":{"additionalProperties":{"additionalProperties":{},"type":"object"},"type":"object"}},"required":["options","fieldConfig"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"annotations":{"items":{"$ref":"#/components/schemas/AnnotationQueryKind"},"type":"array"},"cursorSync":{"$ref":"#/components/schemas/DashboardCursorSync","default":"Off","description":"Configuration of dashboard cursor sync behavior.\n\"Off\" for no shared crosshair or tooltip (default).\n\"Crosshair\" for shared crosshair.\n\"Tooltip\" for shared crosshair AND shared tooltip."},"description":{"description":"Description of dashboard.","type":"string"},"editable":{"default":true,"description":"Whether a dashboard is editable or not.","type":"boolean"},"elements":{"additionalProperties":{"$ref":"#/components/schemas/Element"},"type":"object"},"layout":{"oneOf":[{"$ref":"#/components/schemas/GridLayoutKind"},{"$ref":"#/components/schemas/RowsLayoutKind"},{"$ref":"#/components/schemas/AutoGridLayoutKind"},{"$ref":"#/components/schemas/TabsLayoutKind"}]},"links":{"description":"Links with references to other dashboards or external websites.","items":{"$ref":"#/components/schemas/DashboardLink"},"type":"array"},"liveNow":{"description":"When set to true, the dashboard will redraw panels at an interval matching the pixel width.\nThis will keep data \"moving left\" regardless of the query refresh rate. This setting helps\navoid dashboards presenting stale live data.","type":"boolean"},"preload":{"default":false,"description":"When set to true, the dashboard will load all panels in the dashboard when it's loaded.","type":"boolean"},"revision":{"description":"Plugins only. The version of the dashboard installed together with the plugin.\nThis is used to determine if the dashboard should be updated when the plugin is updated.","type":"integer"},"tags":{"description":"Tags associated with dashboard.","items":{"type":"string"},"type":"array"},"timeSettings":{"$ref":"#/components/schemas/TimeSettingsSpec"},"title":{"description":"Title of dashboard.","type":"string"},"variables":{"description":"Configured template variables.","items":{"$ref":"#/components/schemas/VariableKind"},"type":"array"}},"required":["annotations","cursorSync","elements","layout","links","preload","tags","timeSettings","title","variables"],"type":"object"},"status":{"additionalProperties":false,"properties":{"conversion":{"$ref":"#/components/schemas/ConversionStatus","description":"Optional conversion status."}},"type":"object"}}`) + rawSchemaDashboardv2beta1 = []byte(`{"Action":{"additionalProperties":false,"properties":{"confirmation":{"type":"string"},"fetch":{"$ref":"#/components/schemas/FetchOptions"},"infinity":{"$ref":"#/components/schemas/InfinityOptions"},"oneClick":{"type":"boolean"},"style":{"additionalProperties":false,"properties":{"backgroundColor":{"type":"string"}},"type":"object"},"title":{"type":"string"},"type":{"$ref":"#/components/schemas/ActionType"},"variables":{"items":{"$ref":"#/components/schemas/ActionVariable"},"type":"array"}},"required":["type","title"],"type":"object"},"ActionType":{"enum":["fetch","infinity"],"type":"string"},"ActionVariable":{"additionalProperties":false,"properties":{"key":{"type":"string"},"name":{"type":"string"},"type":{"$ref":"#/components/schemas/ActionVariableType"}},"required":["key","name","type"],"type":"object"},"ActionVariableType":{"const":"string","description":"Action variable type","type":"string"},"AdHocFilterWithLabels":{"additionalProperties":false,"description":"Define the AdHocFilterWithLabels type","properties":{"condition":{"description":"@deprecated","type":"string"},"forceEdit":{"type":"boolean"},"key":{"type":"string"},"keyLabel":{"type":"string"},"operator":{"type":"string"},"origin":{"$ref":"#/components/schemas/FilterOrigin"},"value":{"type":"string"},"valueLabels":{"items":{"type":"string"},"type":"array"},"values":{"items":{"type":"string"},"type":"array"}},"required":["key","operator","value"],"type":"object"},"AdhocVariableKind":{"additionalProperties":false,"description":"Adhoc variable kind","properties":{"datasource":{"additionalProperties":false,"properties":{"name":{"type":"string"}},"type":"object"},"group":{"type":"string"},"kind":{"const":"AdhocVariable","type":"string"},"spec":{"$ref":"#/components/schemas/AdhocVariableSpec"}},"required":["kind","group","spec"],"type":"object"},"AdhocVariableSpec":{"additionalProperties":false,"description":"Adhoc variable specification","properties":{"allowCustomValue":{"default":true,"type":"boolean"},"baseFilters":{"items":{"$ref":"#/components/schemas/AdHocFilterWithLabels"},"type":"array"},"defaultKeys":{"items":{"$ref":"#/components/schemas/MetricFindValue"},"type":"array"},"description":{"type":"string"},"filters":{"items":{"$ref":"#/components/schemas/AdHocFilterWithLabels"},"type":"array"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"label":{"type":"string"},"name":{"default":"","type":"string"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","baseFilters","filters","defaultKeys","hide","skipUrlSync","allowCustomValue"],"type":"object"},"AnnotationEventFieldMapping":{"additionalProperties":false,"description":"Annotation event field mapping. Defines how to map a data frame field to an annotation event field.","properties":{"regex":{"description":"Regular expression to apply to the field value","type":"string"},"source":{"default":"field","description":"Source type for the field value","type":"string"},"value":{"description":"Constant value to use when source is \"text\"","type":"string"}},"type":"object"},"AnnotationPanelFilter":{"additionalProperties":false,"properties":{"exclude":{"default":false,"description":"Should the specified panels be included or excluded","type":"boolean"},"ids":{"description":"Panel IDs that should be included or excluded","items":{"type":"integer"},"type":"array"}},"required":["ids"],"type":"object"},"AnnotationQueryKind":{"additionalProperties":false,"properties":{"kind":{"const":"AnnotationQuery","type":"string"},"spec":{"$ref":"#/components/schemas/AnnotationQuerySpec"}},"required":["kind","spec"],"type":"object"},"AnnotationQueryPlacement":{"const":"inControlsMenu","description":"Annotation Query placement. Defines where the annotation query should be displayed.\n- \"inControlsMenu\" renders the annotation query in the dashboard controls dropdown menu","type":"string"},"AnnotationQuerySpec":{"additionalProperties":false,"properties":{"builtIn":{"default":false,"type":"boolean"},"enable":{"type":"boolean"},"filter":{"$ref":"#/components/schemas/AnnotationPanelFilter"},"hide":{"type":"boolean"},"iconColor":{"type":"string"},"legacyOptions":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"Catch-all field for datasource-specific properties. Should not be available in as code tooling.","type":"object"},"mappings":{"additionalProperties":{"$ref":"#/components/schemas/AnnotationEventFieldMapping"},"description":"Mappings define how to convert data frame fields to annotation event fields.","type":"object"},"name":{"type":"string"},"placement":{"$ref":"#/components/schemas/AnnotationQueryPlacement","description":"Placement can be used to display the annotation query somewhere else on the dashboard other than the default location."},"query":{"$ref":"#/components/schemas/DataQueryKind"}},"required":["query","enable","hide","iconColor","name"],"type":"object"},"AutoGridLayoutItemKind":{"additionalProperties":false,"properties":{"kind":{"const":"AutoGridLayoutItem","type":"string"},"spec":{"$ref":"#/components/schemas/AutoGridLayoutItemSpec"}},"required":["kind","spec"],"type":"object"},"AutoGridLayoutItemSpec":{"additionalProperties":false,"properties":{"conditionalRendering":{"$ref":"#/components/schemas/ConditionalRenderingGroupKind"},"element":{"$ref":"#/components/schemas/ElementReference"},"repeat":{"$ref":"#/components/schemas/AutoGridRepeatOptions"}},"required":["element"],"type":"object"},"AutoGridLayoutKind":{"additionalProperties":false,"properties":{"kind":{"const":"AutoGridLayout","type":"string"},"spec":{"$ref":"#/components/schemas/AutoGridLayoutSpec"}},"required":["kind","spec"],"type":"object"},"AutoGridLayoutSpec":{"additionalProperties":false,"properties":{"columnWidth":{"type":"number"},"columnWidthMode":{"default":"standard","enum":["narrow","standard","wide","custom"],"type":"string"},"fillScreen":{"default":false,"type":"boolean"},"items":{"items":{"$ref":"#/components/schemas/AutoGridLayoutItemKind"},"type":"array"},"maxColumnCount":{"default":3,"type":"number"},"rowHeight":{"type":"number"},"rowHeightMode":{"default":"standard","enum":["short","standard","tall","custom"],"type":"string"}},"required":["columnWidthMode","rowHeightMode","items"],"type":"object"},"AutoGridRepeatOptions":{"additionalProperties":false,"properties":{"mode":{"$ref":"#/components/schemas/RepeatMode"},"value":{"type":"string"}},"required":["mode","value"],"type":"object"},"ConditionalRenderingDataKind":{"additionalProperties":false,"properties":{"kind":{"const":"ConditionalRenderingData","type":"string"},"spec":{"$ref":"#/components/schemas/ConditionalRenderingDataSpec"}},"required":["kind","spec"],"type":"object"},"ConditionalRenderingDataSpec":{"additionalProperties":false,"properties":{"value":{"type":"boolean"}},"required":["value"],"type":"object"},"ConditionalRenderingGroupKind":{"additionalProperties":false,"properties":{"kind":{"const":"ConditionalRenderingGroup","type":"string"},"spec":{"$ref":"#/components/schemas/ConditionalRenderingGroupSpec"}},"required":["kind","spec"],"type":"object"},"ConditionalRenderingGroupSpec":{"additionalProperties":false,"properties":{"condition":{"enum":["and","or"],"type":"string"},"items":{"items":{"oneOf":[{"$ref":"#/components/schemas/ConditionalRenderingVariableKind"},{"$ref":"#/components/schemas/ConditionalRenderingDataKind"},{"$ref":"#/components/schemas/ConditionalRenderingTimeRangeSizeKind"}]},"type":"array"},"visibility":{"enum":["show","hide"],"type":"string"}},"required":["visibility","condition","items"],"type":"object"},"ConditionalRenderingTimeRangeSizeKind":{"additionalProperties":false,"properties":{"kind":{"const":"ConditionalRenderingTimeRangeSize","type":"string"},"spec":{"$ref":"#/components/schemas/ConditionalRenderingTimeRangeSizeSpec"}},"required":["kind","spec"],"type":"object"},"ConditionalRenderingTimeRangeSizeSpec":{"additionalProperties":false,"properties":{"value":{"type":"string"}},"required":["value"],"type":"object"},"ConditionalRenderingVariableKind":{"additionalProperties":false,"properties":{"kind":{"const":"ConditionalRenderingVariable","type":"string"},"spec":{"$ref":"#/components/schemas/ConditionalRenderingVariableSpec"}},"required":["kind","spec"],"type":"object"},"ConditionalRenderingVariableSpec":{"additionalProperties":false,"properties":{"operator":{"enum":["equals","notEquals","matches","notMatches"],"type":"string"},"value":{"type":"string"},"variable":{"type":"string"}},"required":["variable","operator","value"],"type":"object"},"ConstantVariableKind":{"additionalProperties":false,"description":"Constant variable kind","properties":{"kind":{"const":"ConstantVariable","type":"string"},"spec":{"$ref":"#/components/schemas/ConstantVariableSpec"}},"required":["kind","spec"],"type":"object"},"ConstantVariableSpec":{"additionalProperties":false,"description":"Constant variable specification","properties":{"current":{"$ref":"#/components/schemas/VariableOption","default":{"text":"","value":""}},"description":{"type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"label":{"type":"string"},"name":{"default":"","type":"string"},"query":{"default":"","type":"string"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","query","current","hide","skipUrlSync"],"type":"object"},"ConversionStatus":{"additionalProperties":false,"description":"ConversionStatus is the status of the conversion of the dashboard.","properties":{"error":{"description":"The error message from the conversion.\nEmpty if the conversion has not failed.","type":"string"},"failed":{"description":"Whether from another version has failed.\nIf true, means that the dashboard is not valid,\nand the caller should instead fetch the stored version.","type":"boolean"},"source":{"additionalProperties":{},"description":"The original value map[string]any","type":"object"},"storedVersion":{"description":"The version which was stored when the dashboard was created / updated.\nFetching this version should always succeed.","type":"string"}},"required":["failed"],"type":"object"},"CustomVariableKind":{"additionalProperties":false,"description":"Custom variable kind","properties":{"kind":{"const":"CustomVariable","type":"string"},"spec":{"$ref":"#/components/schemas/CustomVariableSpec"}},"required":["kind","spec"],"type":"object"},"CustomVariableSpec":{"additionalProperties":false,"description":"Custom variable specification","properties":{"allValue":{"type":"string"},"allowCustomValue":{"default":true,"type":"boolean"},"current":{"$ref":"#/components/schemas/VariableOption"},"description":{"type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"includeAll":{"default":false,"type":"boolean"},"label":{"type":"string"},"multi":{"default":false,"type":"boolean"},"name":{"default":"","type":"string"},"options":{"items":{"$ref":"#/components/schemas/VariableOption"},"type":"array"},"query":{"default":"","type":"string"},"skipUrlSync":{"default":false,"type":"boolean"},"valuesFormat":{"enum":["csv","json"],"type":"string"}},"required":["name","query","current","options","multi","includeAll","hide","skipUrlSync","allowCustomValue"],"type":"object"},"Dashboard":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"DashboardCursorSync":{"description":"\"Off\" for no shared crosshair or tooltip (default).\n\"Crosshair\" for shared crosshair.\n\"Tooltip\" for shared crosshair AND shared tooltip.","enum":["Crosshair","Tooltip","Off"],"type":"string"},"DashboardLink":{"additionalProperties":false,"description":"Links with references to other dashboards or external resources","properties":{"asDropdown":{"default":false,"description":"If true, all dashboards links will be displayed in a dropdown. If false, all dashboards links will be displayed side by side. Only valid if the type is dashboards","type":"boolean"},"icon":{"description":"Icon name to be displayed with the link","type":"string"},"includeVars":{"default":false,"description":"If true, includes current template variables values in the link as query params","type":"boolean"},"keepTime":{"default":false,"description":"If true, includes current time range in the link as query params","type":"boolean"},"placement":{"$ref":"#/components/schemas/DashboardLinkPlacement","description":"Placement can be used to display the link somewhere else on the dashboard other than above the visualisations."},"tags":{"description":"List of tags to limit the linked dashboards. If empty, all dashboards will be displayed. Only valid if the type is dashboards","items":{"type":"string"},"type":"array"},"targetBlank":{"default":false,"description":"If true, the link will be opened in a new tab","type":"boolean"},"title":{"description":"Title to display with the link","type":"string"},"tooltip":{"description":"Tooltip to display when the user hovers their mouse over it","type":"string"},"type":{"$ref":"#/components/schemas/DashboardLinkType","description":"Link type. Accepted values are dashboards (to refer to another dashboard) and link (to refer to an external resource)\nFIXME: The type is generated as ` + "`" + `type: DashboardLinkType | dashboardLinkType.Link;` + "`" + ` but it should be ` + "`" + `type: DashboardLinkType` + "`" + `"},"url":{"description":"Link URL. Only required/valid if the type is link","type":"string"}},"required":["title","type","icon","tooltip","tags","asDropdown","targetBlank","includeVars","keepTime"],"type":"object"},"DashboardLinkPlacement":{"const":"inControlsMenu","description":"Dashboard Link placement. Defines where the link should be displayed.\n- \"inControlsMenu\" renders the link in bottom part of the dashboard controls dropdown menu","type":"string"},"DashboardLinkType":{"description":"Dashboard Link type. Accepted values are dashboards (to refer to another dashboard) and link (to refer to an external resource)","enum":["link","dashboards"],"type":"string"},"DataLink":{"additionalProperties":false,"properties":{"targetBlank":{"type":"boolean"},"title":{"type":"string"},"url":{"type":"string"}},"required":["title","url"],"type":"object"},"DataQueryKind":{"additionalProperties":false,"properties":{"datasource":{"additionalProperties":false,"description":"New type for datasource reference\nNot creating a new type until we figure out how to handle DS refs for group by, adhoc, and every place that uses DataSourceRef in TS.","properties":{"name":{"type":"string"}},"type":"object"},"group":{"type":"string"},"kind":{"const":"DataQuery","type":"string"},"spec":{"additionalProperties":{"additionalProperties":{},"type":"object"},"type":"object"},"version":{"default":"v0","type":"string"}},"required":["kind","group","version","spec"],"type":"object"},"DataTopic":{"description":"A topic is attached to DataFrame metadata in query results.\nThis specifies where the data should be used.","enum":["series","annotations","alertStates"],"type":"string"},"DataTransformerConfig":{"additionalProperties":false,"description":"Transformations allow to manipulate data returned by a query before the system applies a visualization.\nUsing transformations you can: rename fields, join time series data, perform mathematical operations across queries,\nuse the output of one transformation as the input to another transformation, etc.","properties":{"disabled":{"description":"Disabled transformations are skipped","type":"boolean"},"filter":{"$ref":"#/components/schemas/MatcherConfig","description":"Optional frame matcher. When missing it will be applied to all results"},"id":{"description":"Unique identifier of transformer","type":"string"},"options":{"additionalProperties":{},"description":"Options to be passed to the transformer\nValid options depend on the transformer id","type":"object"},"topic":{"$ref":"#/components/schemas/DataTopic","description":"Where to pull DataFrames from as input to transformation"}},"required":["id","options"],"type":"object"},"DatasourceVariableKind":{"additionalProperties":false,"description":"Datasource variable kind","properties":{"kind":{"const":"DatasourceVariable","type":"string"},"spec":{"$ref":"#/components/schemas/DatasourceVariableSpec"}},"required":["kind","spec"],"type":"object"},"DatasourceVariableSpec":{"additionalProperties":false,"description":"Datasource variable specification","properties":{"allValue":{"type":"string"},"allowCustomValue":{"default":true,"type":"boolean"},"current":{"$ref":"#/components/schemas/VariableOption","default":{"text":"","value":""}},"description":{"type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"includeAll":{"default":false,"type":"boolean"},"label":{"type":"string"},"multi":{"default":false,"type":"boolean"},"name":{"default":"","type":"string"},"options":{"items":{"$ref":"#/components/schemas/VariableOption"},"type":"array"},"pluginId":{"default":"","type":"string"},"refresh":{"$ref":"#/components/schemas/VariableRefresh","default":"never"},"regex":{"default":"","type":"string"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","pluginId","refresh","regex","current","options","multi","includeAll","hide","skipUrlSync","allowCustomValue"],"type":"object"},"DynamicConfigValue":{"additionalProperties":false,"properties":{"id":{"default":"","type":"string"},"value":{"additionalProperties":{},"type":"object"}},"required":["id"],"type":"object"},"Element":{"description":"Supported dashboard elements\n|* more element types in the future","oneOf":[{"$ref":"#/components/schemas/PanelKind"},{"$ref":"#/components/schemas/LibraryPanelKind"}]},"ElementReference":{"additionalProperties":false,"properties":{"kind":{"const":"ElementReference","type":"string"},"name":{"type":"string"}},"required":["kind","name"],"type":"object"},"FetchOptions":{"additionalProperties":false,"properties":{"body":{"type":"string"},"headers":{"items":{"items":{"type":"string"},"type":"array"},"type":"array"},"method":{"$ref":"#/components/schemas/HttpRequestMethod"},"queryParams":{"description":"These are 2D arrays of strings, each representing a key-value pair\nWe are defining them this way because we can't generate a go struct that\nthat would have exactly two strings in each sub-array","items":{"items":{"type":"string"},"type":"array"},"type":"array"},"url":{"type":"string"}},"required":["method","url"],"type":"object"},"FieldColor":{"additionalProperties":false,"description":"Map a field to a color.","properties":{"fixedColor":{"description":"The fixed color value for fixed or shades color modes.","type":"string"},"mode":{"$ref":"#/components/schemas/FieldColorModeId","description":"The main color scheme mode."},"seriesBy":{"$ref":"#/components/schemas/FieldColorSeriesByMode","description":"Some visualizations need to know how to assign a series color from by value color schemes."}},"required":["mode"],"type":"object"},"FieldColorModeId":{"description":"Color mode for a field. You can specify a single color, or select a continuous (gradient) color schemes, based on a value.\nContinuous color interpolates a color using the percentage of a value relative to min and max.\nAccepted values are:\n` + "`" + `thresholds` + "`" + `: From thresholds. Informs Grafana to take the color from the matching threshold\n` + "`" + `palette-classic` + "`" + `: Classic palette. Grafana will assign color by looking up a color in a palette by series index. Useful for Graphs and pie charts and other categorical data visualizations\n` + "`" + `palette-classic-by-name` + "`" + `: Classic palette (by name). Grafana will assign color by looking up a color in a palette by series name. Useful for Graphs and pie charts and other categorical data visualizations\n` + "`" + `continuous-viridis` + "`" + `: Continuous Viridis palette mode\n` + "`" + `continuous-magma` + "`" + `: Continuous Magma palette mode\n` + "`" + `continuous-plasma` + "`" + `: Continuous Plasma palette mode\n` + "`" + `continuous-inferno` + "`" + `: Continuous Inferno palette mode\n` + "`" + `continuous-cividis` + "`" + `: Continuous Cividis palette mode\n` + "`" + `continuous-GrYlRd` + "`" + `: Continuous Green-Yellow-Red palette mode\n` + "`" + `continuous-RdYlGr` + "`" + `: Continuous Red-Yellow-Green palette mode\n` + "`" + `continuous-BlYlRd` + "`" + `: Continuous Blue-Yellow-Red palette mode\n` + "`" + `continuous-YlRd` + "`" + `: Continuous Yellow-Red palette mode\n` + "`" + `continuous-BlPu` + "`" + `: Continuous Blue-Purple palette mode\n` + "`" + `continuous-YlBl` + "`" + `: Continuous Yellow-Blue palette mode\n` + "`" + `continuous-blues` + "`" + `: Continuous Blue palette mode\n` + "`" + `continuous-reds` + "`" + `: Continuous Red palette mode\n` + "`" + `continuous-greens` + "`" + `: Continuous Green palette mode\n` + "`" + `continuous-purples` + "`" + `: Continuous Purple palette mode\n` + "`" + `shades` + "`" + `: Shades of a single color. Specify a single color, useful in an override rule.\n` + "`" + `fixed` + "`" + `: Fixed color mode. Specify a single color, useful in an override rule.","enum":["thresholds","palette-classic","palette-classic-by-name","continuous-viridis","continuous-magma","continuous-plasma","continuous-inferno","continuous-cividis","continuous-GrYlRd","continuous-RdYlGr","continuous-BlYlRd","continuous-YlRd","continuous-BlPu","continuous-YlBl","continuous-blues","continuous-reds","continuous-greens","continuous-purples","fixed","shades"],"type":"string"},"FieldColorSeriesByMode":{"description":"Defines how to assign a series color from \"by value\" color schemes. For example for an aggregated data points like a timeseries, the color can be assigned by the min, max or last value.","enum":["min","max","last"],"type":"string"},"FieldConfig":{"additionalProperties":false,"description":"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.\nEach column within this structure is called a field. A field can represent a single time series or table column.\nField options allow you to change how the data is displayed in your visualizations.","properties":{"actions":{"description":"Define interactive HTTP requests that can be triggered from data visualizations.","items":{"$ref":"#/components/schemas/Action"},"type":"array"},"color":{"$ref":"#/components/schemas/FieldColor","description":"Panel color configuration"},"custom":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"custom is specified by the FieldConfig field\nin panel plugin schemas.","type":"object"},"decimals":{"description":"Specify the number of decimals Grafana includes in the rendered value.\nIf you leave this field blank, Grafana automatically truncates the number of decimals based on the value.\nFor example 1.1234 will display as 1.12 and 100.456 will display as 100.\nTo display all decimals, set the unit to ` + "`" + `String` + "`" + `.","type":"number"},"description":{"description":"Human readable field metadata","type":"string"},"displayName":{"description":"The display value for this field. This supports template variables blank is auto","type":"string"},"displayNameFromDS":{"description":"This can be used by data sources that return and explicit naming structure for values and labels\nWhen this property is configured, this value is used rather than the default naming strategy.","type":"string"},"fieldMinMax":{"description":"Calculate min max per field","type":"boolean"},"filterable":{"description":"True if data source field supports ad-hoc filters","type":"boolean"},"links":{"description":"The behavior when clicking on a result","items":{"additionalProperties":{},"type":"object"},"type":"array"},"mappings":{"description":"Convert input values into a display string","items":{"$ref":"#/components/schemas/ValueMapping"},"type":"array"},"max":{"description":"The maximum value used in percentage threshold calculations. Leave blank for auto calculation based on all series and fields.","type":"number"},"min":{"description":"The minimum value used in percentage threshold calculations. Leave blank for auto calculation based on all series and fields.","type":"number"},"noValue":{"description":"Alternative to empty string","type":"string"},"nullValueMode":{"$ref":"#/components/schemas/NullValueMode","description":"How null values should be handled when calculating field stats\n\"null\" - Include null values, \"connected\" - Ignore nulls, \"null as zero\" - Treat nulls as zero"},"path":{"description":"An explicit path to the field in the datasource. When the frame meta includes a path,\nThis will default to ` + "`" + `${frame.meta.path}/${field.name}\n\nWhen defined, this value can be used as an identifier within the datasource scope, and\nmay be used to update the results","type":"string"},"thresholds":{"$ref":"#/components/schemas/ThresholdsConfig","description":"Map numeric values to states"},"unit":{"description":"Unit a field should use. The unit you select is applied to all fields except time.\nYou can use the units ID availables in Grafana or a custom unit.\nAvailable units in Grafana: https://github.com/grafana/grafana/blob/main/packages/grafana-data/src/valueFormats/categories.ts\nAs custom unit, you can use the following formats:\n` + "`" + `suffix:\u003csuffix\u003e` + "`" + ` for custom unit that should go after value.\n` + "`" + `prefix:\u003cprefix\u003e` + "`" + ` for custom unit that should go before value.\n` + "`" + `time:\u003cformat\u003e` + "`" + ` For custom date time formats type for example ` + "`" + `time:YYYY-MM-DD` + "`" + `.\n` + "`" + `si:\u003cbase scale\u003e\u003cunit characters\u003e` + "`" + ` for custom SI units. For example: ` + "`" + `si: mF` + "`" + `. This one is a bit more advanced as you can specify both a unit and the source data scale. So if your source data is represented as milli (thousands of) something prefix the unit with that SI scale character.\n` + "`" + `count:\u003cunit\u003e` + "`" + ` for a custom count unit.\n` + "`" + `currency:\u003cunit\u003e` + "`" + ` for custom a currency unit.","type":"string"},"writeable":{"description":"True if data source can write a value to the path. Auth/authz are supported separately","type":"boolean"}},"type":"object"},"FieldConfigSource":{"additionalProperties":false,"description":"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.\nEach column within this structure is called a field. A field can represent a single time series or table column.\nField options allow you to change how the data is displayed in your visualizations.","properties":{"defaults":{"$ref":"#/components/schemas/FieldConfig","description":"Defaults are the options applied to all fields."},"overrides":{"description":"Overrides are the options applied to specific fields overriding the defaults.","items":{"additionalProperties":false,"properties":{"__systemRef":{"description":"Describes config override rules created when interacting with Grafana.","type":"string"},"matcher":{"$ref":"#/components/schemas/MatcherConfig"},"properties":{"items":{"$ref":"#/components/schemas/DynamicConfigValue"},"type":"array"}},"required":["matcher","properties"],"type":"object"},"type":"array"}},"required":["defaults","overrides"],"type":"object"},"FilterOrigin":{"const":"dashboard","description":"Determine the origin of the adhoc variable filter","type":"string"},"GridLayoutItemKind":{"additionalProperties":false,"properties":{"kind":{"const":"GridLayoutItem","type":"string"},"spec":{"$ref":"#/components/schemas/GridLayoutItemSpec"}},"required":["kind","spec"],"type":"object"},"GridLayoutItemSpec":{"additionalProperties":false,"properties":{"element":{"$ref":"#/components/schemas/ElementReference","description":"reference to a PanelKind from dashboard.spec.elements Expressed as JSON Schema reference"},"height":{"type":"integer"},"repeat":{"$ref":"#/components/schemas/RepeatOptions"},"width":{"type":"integer"},"x":{"type":"integer"},"y":{"type":"integer"}},"required":["x","y","width","height","element"],"type":"object"},"GridLayoutKind":{"additionalProperties":false,"properties":{"kind":{"const":"GridLayout","type":"string"},"spec":{"$ref":"#/components/schemas/GridLayoutSpec"}},"required":["kind","spec"],"type":"object"},"GridLayoutSpec":{"additionalProperties":false,"properties":{"items":{"items":{"$ref":"#/components/schemas/GridLayoutItemKind"},"type":"array"}},"required":["items"],"type":"object"},"GroupByVariableKind":{"additionalProperties":false,"description":"Group variable kind","properties":{"datasource":{"additionalProperties":false,"properties":{"name":{"type":"string"}},"type":"object"},"group":{"type":"string"},"kind":{"const":"GroupByVariable","type":"string"},"spec":{"$ref":"#/components/schemas/GroupByVariableSpec"}},"required":["kind","group","spec"],"type":"object"},"GroupByVariableSpec":{"additionalProperties":false,"description":"GroupBy variable specification","properties":{"current":{"$ref":"#/components/schemas/VariableOption","default":{"text":"","value":""}},"defaultValue":{"$ref":"#/components/schemas/VariableOption"},"description":{"type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"label":{"type":"string"},"multi":{"default":false,"type":"boolean"},"name":{"default":"","type":"string"},"options":{"items":{"$ref":"#/components/schemas/VariableOption"},"type":"array"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","current","options","multi","hide","skipUrlSync"],"type":"object"},"HttpRequestMethod":{"enum":["GET","PUT","POST","DELETE","PATCH"],"type":"string"},"InfinityOptions":{"additionalProperties":false,"properties":{"body":{"type":"string"},"datasourceUid":{"type":"string"},"headers":{"items":{"items":{"type":"string"},"type":"array"},"type":"array"},"method":{"$ref":"#/components/schemas/HttpRequestMethod"},"queryParams":{"description":"These are 2D arrays of strings, each representing a key-value pair\nWe are defining them this way because we can't generate a go struct that\nthat would have exactly two strings in each sub-array","items":{"items":{"type":"string"},"type":"array"},"type":"array"},"url":{"type":"string"}},"required":["method","url","datasourceUid"],"type":"object"},"IntervalVariableKind":{"additionalProperties":false,"description":"Interval variable kind","properties":{"kind":{"const":"IntervalVariable","type":"string"},"spec":{"$ref":"#/components/schemas/IntervalVariableSpec"}},"required":["kind","spec"],"type":"object"},"IntervalVariableSpec":{"additionalProperties":false,"description":"Interval variable specification","properties":{"auto":{"default":false,"type":"boolean"},"auto_count":{"default":0,"type":"integer"},"auto_min":{"default":"","type":"string"},"current":{"$ref":"#/components/schemas/VariableOption","default":{"text":"","value":""}},"description":{"type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"label":{"type":"string"},"name":{"default":"","type":"string"},"options":{"items":{"$ref":"#/components/schemas/VariableOption"},"type":"array"},"query":{"default":"","type":"string"},"refresh":{"const":"onTimeRangeChanged","type":"string"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","query","current","options","auto","auto_min","auto_count","refresh","hide","skipUrlSync"],"type":"object"},"LibraryPanelKind":{"additionalProperties":false,"properties":{"kind":{"const":"LibraryPanel","type":"string"},"spec":{"$ref":"#/components/schemas/LibraryPanelKindSpec"}},"required":["kind","spec"],"type":"object"},"LibraryPanelKindSpec":{"additionalProperties":false,"properties":{"id":{"description":"Panel ID for the library panel in the dashboard","type":"number"},"libraryPanel":{"$ref":"#/components/schemas/LibraryPanelRef"},"title":{"description":"Title for the library panel in the dashboard","type":"string"}},"required":["id","title","libraryPanel"],"type":"object"},"LibraryPanelRef":{"additionalProperties":false,"description":"A library panel is a reusable panel that you can use in any dashboard.\nWhen you make a change to a library panel, that change propagates to all instances of where the panel is used.\nLibrary panels streamline reuse of panels across multiple dashboards.","properties":{"name":{"description":"Library panel name","type":"string"},"uid":{"description":"Library panel uid","type":"string"}},"required":["name","uid"],"type":"object"},"MappingType":{"description":"Supported value mapping types\n` + "`" + `value` + "`" + `: Maps text values to a color or different display text and color. For example, you can configure a value mapping so that all instances of the value 10 appear as Perfection! rather than the number.\n` + "`" + `range` + "`" + `: Maps numerical ranges to a display text and color. For example, if a value is within a certain range, you can configure a range value mapping to display Low or High rather than the number.\n` + "`" + `regex` + "`" + `: Maps regular expressions to replacement text and a color. For example, if a value is www.example.com, you can configure a regex value mapping so that Grafana displays www and truncates the domain.\n` + "`" + `special` + "`" + `: Maps special values like Null, NaN (not a number), and boolean values like true and false to a display text and color. See SpecialValueMatch to see the list of special values. For example, you can configure a special value mapping so that null values appear as N/A.","enum":["value","range","regex","special"],"type":"string"},"MatcherConfig":{"additionalProperties":false,"description":"Matcher is a predicate configuration. Based on the config a set of field(s) or values is filtered in order to apply override / transformation.\nIt comes with in id ( to resolve implementation from registry) and a configuration that’s specific to a particular matcher type.","properties":{"id":{"default":"","description":"The matcher id. This is used to find the matcher implementation from registry.","type":"string"},"options":{"additionalProperties":{},"description":"The matcher options. This is specific to the matcher implementation.","type":"object"}},"required":["id"],"type":"object"},"MetricFindValue":{"additionalProperties":false,"description":"Define the MetricFindValue type","properties":{"expandable":{"type":"boolean"},"group":{"type":"string"},"text":{"type":"string"},"value":{"oneOf":[{"type":"string"},{"type":"number"}]}},"required":["text"],"type":"object"},"NullValueMode":{"description":"How null values should be handled","enum":["null","connected","null as zero"],"type":"string"},"PanelKind":{"additionalProperties":false,"properties":{"kind":{"const":"Panel","type":"string"},"spec":{"$ref":"#/components/schemas/PanelSpec"}},"required":["kind","spec"],"type":"object"},"PanelQueryKind":{"additionalProperties":false,"properties":{"kind":{"const":"PanelQuery","type":"string"},"spec":{"$ref":"#/components/schemas/PanelQuerySpec"}},"required":["kind","spec"],"type":"object"},"PanelQuerySpec":{"additionalProperties":false,"properties":{"hidden":{"type":"boolean"},"query":{"$ref":"#/components/schemas/DataQueryKind"},"refId":{"default":"A","type":"string"}},"required":["query","refId","hidden"],"type":"object"},"PanelSpec":{"additionalProperties":false,"properties":{"data":{"$ref":"#/components/schemas/QueryGroupKind"},"description":{"type":"string"},"id":{"type":"number"},"links":{"items":{"$ref":"#/components/schemas/DataLink"},"type":"array"},"title":{"type":"string"},"transparent":{"type":"boolean"},"vizConfig":{"$ref":"#/components/schemas/VizConfigKind"}},"required":["id","title","description","links","data","vizConfig"],"type":"object"},"QueryGroupKind":{"additionalProperties":false,"properties":{"kind":{"const":"QueryGroup","type":"string"},"spec":{"$ref":"#/components/schemas/QueryGroupSpec"}},"required":["kind","spec"],"type":"object"},"QueryGroupSpec":{"additionalProperties":false,"properties":{"queries":{"items":{"$ref":"#/components/schemas/PanelQueryKind"},"type":"array"},"queryOptions":{"$ref":"#/components/schemas/QueryOptionsSpec"},"transformations":{"items":{"$ref":"#/components/schemas/TransformationKind"},"type":"array"}},"required":["queries","transformations","queryOptions"],"type":"object"},"QueryOptionsSpec":{"additionalProperties":false,"properties":{"cacheTimeout":{"type":"string"},"hideTimeOverride":{"type":"boolean"},"interval":{"type":"string"},"maxDataPoints":{"type":"integer"},"queryCachingTTL":{"type":"integer"},"timeCompare":{"type":"string"},"timeFrom":{"type":"string"},"timeShift":{"type":"string"}},"type":"object"},"QueryVariableKind":{"additionalProperties":false,"description":"Query variable kind","properties":{"kind":{"const":"QueryVariable","type":"string"},"spec":{"$ref":"#/components/schemas/QueryVariableSpec"}},"required":["kind","spec"],"type":"object"},"QueryVariableSpec":{"additionalProperties":false,"description":"Query variable specification","properties":{"allValue":{"type":"string"},"allowCustomValue":{"default":true,"type":"boolean"},"current":{"$ref":"#/components/schemas/VariableOption","default":{"text":"","value":""}},"definition":{"type":"string"},"description":{"type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"includeAll":{"default":false,"type":"boolean"},"label":{"type":"string"},"multi":{"default":false,"type":"boolean"},"name":{"default":"","type":"string"},"options":{"items":{"$ref":"#/components/schemas/VariableOption"},"type":"array"},"placeholder":{"type":"string"},"query":{"$ref":"#/components/schemas/DataQueryKind"},"refresh":{"$ref":"#/components/schemas/VariableRefresh","default":"never"},"regex":{"default":"","type":"string"},"regexApplyTo":{"$ref":"#/components/schemas/VariableRegexApplyTo","default":"value"},"skipUrlSync":{"default":false,"type":"boolean"},"sort":{"$ref":"#/components/schemas/VariableSort"},"staticOptions":{"items":{"$ref":"#/components/schemas/VariableOption"},"type":"array"},"staticOptionsOrder":{"enum":["before","after","sorted"],"type":"string"}},"required":["name","current","hide","refresh","skipUrlSync","query","regex","sort","options","multi","includeAll","allowCustomValue"],"type":"object"},"RangeMap":{"additionalProperties":false,"description":"Maps numerical ranges to a display text and color.\nFor example, if a value is within a certain range, you can configure a range value mapping to display Low or High rather than the number.","properties":{"options":{"additionalProperties":false,"description":"Range to match against and the result to apply when the value is within the range","properties":{"from":{"description":"Min value of the range. It can be null which means -Infinity","type":"number"},"result":{"$ref":"#/components/schemas/ValueMappingResult","description":"Config to apply when the value is within the range"},"to":{"description":"Max value of the range. It can be null which means +Infinity","type":"number"}},"required":["from","to","result"],"type":"object"},"type":{"$ref":"#/components/schemas/MappingType"}},"required":["type","options"],"type":"object"},"RegexMap":{"additionalProperties":false,"description":"Maps regular expressions to replacement text and a color.\nFor example, if a value is www.example.com, you can configure a regex value mapping so that Grafana displays www and truncates the domain.","properties":{"options":{"additionalProperties":false,"description":"Regular expression to match against and the result to apply when the value matches the regex","properties":{"pattern":{"description":"Regular expression to match against","type":"string"},"result":{"$ref":"#/components/schemas/ValueMappingResult","description":"Config to apply when the value matches the regex"}},"required":["pattern","result"],"type":"object"},"type":{"$ref":"#/components/schemas/MappingType"}},"required":["type","options"],"type":"object"},"RepeatMode":{"const":"variable","description":"other repeat modes will be added in the future: label, frame","type":"string"},"RepeatOptions":{"additionalProperties":false,"properties":{"direction":{"enum":["h","v"],"type":"string"},"maxPerRow":{"type":"integer"},"mode":{"$ref":"#/components/schemas/RepeatMode"},"value":{"type":"string"}},"required":["mode","value"],"type":"object"},"RowRepeatOptions":{"additionalProperties":false,"properties":{"mode":{"$ref":"#/components/schemas/RepeatMode"},"value":{"type":"string"}},"required":["mode","value"],"type":"object"},"RowsLayoutKind":{"additionalProperties":false,"properties":{"kind":{"const":"RowsLayout","type":"string"},"spec":{"$ref":"#/components/schemas/RowsLayoutSpec"}},"required":["kind","spec"],"type":"object"},"RowsLayoutRowKind":{"additionalProperties":false,"properties":{"kind":{"const":"RowsLayoutRow","type":"string"},"spec":{"$ref":"#/components/schemas/RowsLayoutRowSpec"}},"required":["kind","spec"],"type":"object"},"RowsLayoutRowSpec":{"additionalProperties":false,"properties":{"collapse":{"type":"boolean"},"conditionalRendering":{"$ref":"#/components/schemas/ConditionalRenderingGroupKind"},"fillScreen":{"type":"boolean"},"hideHeader":{"type":"boolean"},"layout":{"oneOf":[{"$ref":"#/components/schemas/GridLayoutKind"},{"$ref":"#/components/schemas/AutoGridLayoutKind"},{"$ref":"#/components/schemas/TabsLayoutKind"},{"$ref":"#/components/schemas/RowsLayoutKind"}]},"repeat":{"$ref":"#/components/schemas/RowRepeatOptions"},"title":{"type":"string"}},"required":["layout"],"type":"object"},"RowsLayoutSpec":{"additionalProperties":false,"properties":{"rows":{"items":{"$ref":"#/components/schemas/RowsLayoutRowKind"},"type":"array"}},"required":["rows"],"type":"object"},"SpecialValueMap":{"additionalProperties":false,"description":"Maps special values like Null, NaN (not a number), and boolean values like true and false to a display text and color.\nSee SpecialValueMatch to see the list of special values.\nFor example, you can configure a special value mapping so that null values appear as N/A.","properties":{"options":{"additionalProperties":false,"properties":{"match":{"$ref":"#/components/schemas/SpecialValueMatch","description":"Special value to match against"},"result":{"$ref":"#/components/schemas/ValueMappingResult","description":"Config to apply when the value matches the special value"}},"required":["match","result"],"type":"object"},"type":{"$ref":"#/components/schemas/MappingType"}},"required":["type","options"],"type":"object"},"SpecialValueMatch":{"description":"Special value types supported by the ` + "`" + `SpecialValueMap` + "`" + `","enum":["true","false","null","nan","null+nan","empty"],"type":"string"},"SwitchVariableKind":{"additionalProperties":false,"properties":{"kind":{"const":"SwitchVariable","type":"string"},"spec":{"$ref":"#/components/schemas/SwitchVariableSpec"}},"required":["kind","spec"],"type":"object"},"SwitchVariableSpec":{"additionalProperties":false,"properties":{"current":{"default":"false","type":"string"},"description":{"type":"string"},"disabledValue":{"default":"false","type":"string"},"enabledValue":{"default":"true","type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"label":{"type":"string"},"name":{"default":"","type":"string"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","current","enabledValue","disabledValue","hide","skipUrlSync"],"type":"object"},"TabRepeatOptions":{"additionalProperties":false,"properties":{"mode":{"$ref":"#/components/schemas/RepeatMode"},"value":{"type":"string"}},"required":["mode","value"],"type":"object"},"TabsLayoutKind":{"additionalProperties":false,"properties":{"kind":{"const":"TabsLayout","type":"string"},"spec":{"$ref":"#/components/schemas/TabsLayoutSpec"}},"required":["kind","spec"],"type":"object"},"TabsLayoutSpec":{"additionalProperties":false,"properties":{"tabs":{"items":{"$ref":"#/components/schemas/TabsLayoutTabKind"},"type":"array"}},"required":["tabs"],"type":"object"},"TabsLayoutTabKind":{"additionalProperties":false,"properties":{"kind":{"const":"TabsLayoutTab","type":"string"},"spec":{"$ref":"#/components/schemas/TabsLayoutTabSpec"}},"required":["kind","spec"],"type":"object"},"TabsLayoutTabSpec":{"additionalProperties":false,"properties":{"conditionalRendering":{"$ref":"#/components/schemas/ConditionalRenderingGroupKind"},"layout":{"oneOf":[{"$ref":"#/components/schemas/GridLayoutKind"},{"$ref":"#/components/schemas/RowsLayoutKind"},{"$ref":"#/components/schemas/AutoGridLayoutKind"},{"$ref":"#/components/schemas/TabsLayoutKind"}]},"repeat":{"$ref":"#/components/schemas/TabRepeatOptions"},"title":{"type":"string"}},"required":["layout"],"type":"object"},"TextVariableKind":{"additionalProperties":false,"description":"Text variable kind","properties":{"kind":{"const":"TextVariable","type":"string"},"spec":{"$ref":"#/components/schemas/TextVariableSpec"}},"required":["kind","spec"],"type":"object"},"TextVariableSpec":{"additionalProperties":false,"description":"Text variable specification","properties":{"current":{"$ref":"#/components/schemas/VariableOption","default":{"text":"","value":""}},"description":{"type":"string"},"hide":{"$ref":"#/components/schemas/VariableHide","default":"dontHide"},"label":{"type":"string"},"name":{"default":"","type":"string"},"query":{"default":"","type":"string"},"skipUrlSync":{"default":false,"type":"boolean"}},"required":["name","current","query","hide","skipUrlSync"],"type":"object"},"Threshold":{"additionalProperties":false,"properties":{"color":{"type":"string"},"value":{"description":"Value null means -Infinity","type":"number"}},"required":["value","color"],"type":"object"},"ThresholdsConfig":{"additionalProperties":false,"properties":{"mode":{"$ref":"#/components/schemas/ThresholdsMode"},"steps":{"items":{"$ref":"#/components/schemas/Threshold"},"type":"array"}},"required":["mode","steps"],"type":"object"},"ThresholdsMode":{"enum":["absolute","percentage"],"type":"string"},"TimeRangeOption":{"additionalProperties":false,"properties":{"display":{"default":"Last 6 hours","type":"string"},"from":{"default":"now-6h","type":"string"},"to":{"default":"now","type":"string"}},"required":["display","from","to"],"type":"object"},"TimeSettingsSpec":{"additionalProperties":false,"description":"Time configuration\nIt defines the default time config for the time picker, the refresh picker for the specific dashboard.","properties":{"autoRefresh":{"default":"","description":"Refresh rate of dashboard. Represented via interval string, e.g. \"5s\", \"1m\", \"1h\", \"1d\".\nv1: refresh","type":"string"},"autoRefreshIntervals":{"default":["5s","10s","30s","1m","5m","15m","30m","1h","2h","1d"],"description":"Interval options available in the refresh picker dropdown.\nv1: timepicker.refresh_intervals","items":{"type":"string"},"type":"array"},"fiscalYearStartMonth":{"default":0,"description":"The month that the fiscal year starts on. 0 = January, 11 = December","type":"integer"},"from":{"default":"now-6h","description":"Start time range for dashboard.\nAccepted values are relative time strings like \"now-6h\" or absolute time strings like \"2020-07-10T08:00:00.000Z\".","type":"string"},"hideTimepicker":{"default":false,"description":"Whether timepicker is visible or not.\nv1: timepicker.hidden","type":"boolean"},"nowDelay":{"description":"Override the now time by entering a time delay. Use this option to accommodate known delays in data aggregation to avoid null values.\nv1: timepicker.nowDelay","type":"string"},"quickRanges":{"description":"Selectable options available in the time picker dropdown. Has no effect on provisioned dashboard.\nv1: timepicker.quick_ranges , not exposed in the UI","items":{"$ref":"#/components/schemas/TimeRangeOption"},"type":"array"},"timezone":{"default":"browser","description":"Timezone of dashboard. Accepted values are IANA TZDB zone ID or \"browser\" or \"utc\".","type":"string"},"to":{"default":"now","description":"End time range for dashboard.\nAccepted values are relative time strings like \"now-6h\" or absolute time strings like \"2020-07-10T08:00:00.000Z\".","type":"string"},"weekStart":{"description":"Day when the week starts. Expressed by the name of the day in lowercase, e.g. \"monday\".","enum":["saturday","monday","sunday"],"type":"string"}},"required":["from","to","autoRefresh","autoRefreshIntervals","hideTimepicker","fiscalYearStartMonth"],"type":"object"},"TransformationKind":{"additionalProperties":false,"properties":{"kind":{"description":"The kind of a TransformationKind is the transformation ID","type":"string"},"spec":{"$ref":"#/components/schemas/DataTransformerConfig"}},"required":["kind","spec"],"type":"object"},"ValueMap":{"additionalProperties":false,"description":"Maps text values to a color or different display text and color.\nFor example, you can configure a value mapping so that all instances of the value 10 appear as Perfection! rather than the number.","properties":{"options":{"additionalProperties":{"$ref":"#/components/schemas/ValueMappingResult"},"description":"Map with \u003cvalue_to_match\u003e: ValueMappingResult. For example: { \"10\": { text: \"Perfection!\", color: \"green\" } }","type":"object"},"type":{"$ref":"#/components/schemas/MappingType"}},"required":["type","options"],"type":"object"},"ValueMapping":{"oneOf":[{"$ref":"#/components/schemas/ValueMap"},{"$ref":"#/components/schemas/RangeMap"},{"$ref":"#/components/schemas/RegexMap"},{"$ref":"#/components/schemas/SpecialValueMap"}]},"ValueMappingResult":{"additionalProperties":false,"description":"Result used as replacement with text and color when the value matches","properties":{"color":{"description":"Text to use when the value matches","type":"string"},"icon":{"description":"Icon to display when the value matches. Only specific visualizations.","type":"string"},"index":{"description":"Position in the mapping array. Only used internally.","type":"integer"},"text":{"description":"Text to display when the value matches","type":"string"}},"type":"object"},"VariableHide":{"description":"Determine if the variable shows on dashboard\nAccepted values are ` + "`" + `dontHide` + "`" + ` (show label and value), ` + "`" + `hideLabel` + "`" + ` (show value only), ` + "`" + `hideVariable` + "`" + ` (show nothing), ` + "`" + `inControlsMenu` + "`" + ` (show in a drop-down menu).","enum":["dontHide","hideLabel","hideVariable","inControlsMenu"],"type":"string"},"VariableKind":{"oneOf":[{"$ref":"#/components/schemas/QueryVariableKind"},{"$ref":"#/components/schemas/TextVariableKind"},{"$ref":"#/components/schemas/ConstantVariableKind"},{"$ref":"#/components/schemas/DatasourceVariableKind"},{"$ref":"#/components/schemas/IntervalVariableKind"},{"$ref":"#/components/schemas/CustomVariableKind"},{"$ref":"#/components/schemas/GroupByVariableKind"},{"$ref":"#/components/schemas/AdhocVariableKind"},{"$ref":"#/components/schemas/SwitchVariableKind"}]},"VariableOption":{"additionalProperties":false,"description":"Variable option specification","properties":{"selected":{"description":"Whether the option is selected or not","type":"boolean"},"text":{"description":"Text to be displayed for the option","oneOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"}]},"value":{"description":"Value of the option","oneOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"}]}},"required":["text","value"],"type":"object"},"VariableRefresh":{"description":"Options to config when to refresh a variable\n` + "`" + `never` + "`" + `: Never refresh the variable\n` + "`" + `onDashboardLoad` + "`" + `: Queries the data source every time the dashboard loads.\n` + "`" + `onTimeRangeChanged` + "`" + `: Queries the data source when the dashboard time range changes.","enum":["never","onDashboardLoad","onTimeRangeChanged"],"type":"string"},"VariableRegexApplyTo":{"description":"Determine whether regex applies to variable value or display text\nAccepted values are ` + "`" + `value` + "`" + ` (apply to value used in queries) or ` + "`" + `text` + "`" + ` (apply to display text shown to users)","enum":["value","text"],"type":"string"},"VariableSort":{"description":"Sort variable options\nAccepted values are:\n` + "`" + `disabled` + "`" + `: No sorting\n` + "`" + `alphabeticalAsc` + "`" + `: Alphabetical ASC\n` + "`" + `alphabeticalDesc` + "`" + `: Alphabetical DESC\n` + "`" + `numericalAsc` + "`" + `: Numerical ASC\n` + "`" + `numericalDesc` + "`" + `: Numerical DESC\n` + "`" + `alphabeticalCaseInsensitiveAsc` + "`" + `: Alphabetical Case Insensitive ASC\n` + "`" + `alphabeticalCaseInsensitiveDesc` + "`" + `: Alphabetical Case Insensitive DESC\n` + "`" + `naturalAsc` + "`" + `: Natural ASC\n` + "`" + `naturalDesc` + "`" + `: Natural DESC\nVariableSort enum with default value","enum":["disabled","alphabeticalAsc","alphabeticalDesc","numericalAsc","numericalDesc","alphabeticalCaseInsensitiveAsc","alphabeticalCaseInsensitiveDesc","naturalAsc","naturalDesc"],"type":"string"},"VizConfigKind":{"additionalProperties":false,"properties":{"group":{"description":"The group is the plugin ID","type":"string"},"kind":{"const":"VizConfig","type":"string"},"spec":{"$ref":"#/components/schemas/VizConfigSpec"},"version":{"type":"string"}},"required":["kind","group","version","spec"],"type":"object"},"VizConfigSpec":{"additionalProperties":false,"description":"--- Kinds ---","properties":{"fieldConfig":{"$ref":"#/components/schemas/FieldConfigSource"},"options":{"additionalProperties":{"additionalProperties":{},"type":"object"},"type":"object"}},"required":["options","fieldConfig"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"annotations":{"items":{"$ref":"#/components/schemas/AnnotationQueryKind"},"type":"array"},"cursorSync":{"$ref":"#/components/schemas/DashboardCursorSync","default":"Off","description":"Configuration of dashboard cursor sync behavior.\n\"Off\" for no shared crosshair or tooltip (default).\n\"Crosshair\" for shared crosshair.\n\"Tooltip\" for shared crosshair AND shared tooltip."},"description":{"description":"Description of dashboard.","type":"string"},"editable":{"default":true,"description":"Whether a dashboard is editable or not.","type":"boolean"},"elements":{"additionalProperties":{"$ref":"#/components/schemas/Element"},"type":"object"},"layout":{"oneOf":[{"$ref":"#/components/schemas/GridLayoutKind"},{"$ref":"#/components/schemas/RowsLayoutKind"},{"$ref":"#/components/schemas/AutoGridLayoutKind"},{"$ref":"#/components/schemas/TabsLayoutKind"}]},"links":{"description":"Links with references to other dashboards or external websites.","items":{"$ref":"#/components/schemas/DashboardLink"},"type":"array"},"liveNow":{"description":"When set to true, the dashboard will redraw panels at an interval matching the pixel width.\nThis will keep data \"moving left\" regardless of the query refresh rate. This setting helps\navoid dashboards presenting stale live data.","type":"boolean"},"preload":{"default":false,"description":"When set to true, the dashboard will load all panels in the dashboard when it's loaded.","type":"boolean"},"revision":{"description":"Plugins only. The version of the dashboard installed together with the plugin.\nThis is used to determine if the dashboard should be updated when the plugin is updated.","type":"integer"},"tags":{"description":"Tags associated with dashboard.","items":{"type":"string"},"type":"array"},"timeSettings":{"$ref":"#/components/schemas/TimeSettingsSpec"},"title":{"description":"Title of dashboard.","type":"string"},"variables":{"description":"Configured template variables.","items":{"$ref":"#/components/schemas/VariableKind"},"type":"array"}},"required":["annotations","cursorSync","elements","layout","links","preload","tags","timeSettings","title","variables"],"type":"object"},"status":{"additionalProperties":false,"properties":{"conversion":{"$ref":"#/components/schemas/ConversionStatus","description":"Optional conversion status."}},"type":"object"}}`) versionSchemaDashboardv2beta1 app.VersionSchema _ = json.Unmarshal(rawSchemaDashboardv2beta1, &versionSchemaDashboardv2beta1) ) diff --git a/apps/dashboard/pkg/migration/conversion/conversion_data_loss_detection.go b/apps/dashboard/pkg/migration/conversion/conversion_data_loss_detection.go index db3353b66a1..269fb51bd70 100644 --- a/apps/dashboard/pkg/migration/conversion/conversion_data_loss_detection.go +++ b/apps/dashboard/pkg/migration/conversion/conversion_data_loss_detection.go @@ -180,12 +180,15 @@ func countAnnotationsV0V1(spec map[string]interface{}) int { return 0 } - annotationList, ok := annotations["list"].([]interface{}) - if !ok { - return 0 + // Handle both []interface{} (from JSON unmarshaling) and []map[string]interface{} (from programmatic creation) + if annotationList, ok := annotations["list"].([]interface{}); ok { + return len(annotationList) + } + if annotationList, ok := annotations["list"].([]map[string]interface{}); ok { + return len(annotationList) } - return len(annotationList) + return 0 } // countLinksV0V1 counts dashboard links in v0alpha1 or v1beta1 dashboard spec @@ -194,12 +197,15 @@ func countLinksV0V1(spec map[string]interface{}) int { return 0 } - links, ok := spec["links"].([]interface{}) - if !ok { - return 0 + // Handle both []interface{} (from JSON unmarshaling) and []map[string]interface{} (from programmatic creation) + if links, ok := spec["links"].([]interface{}); ok { + return len(links) + } + if links, ok := spec["links"].([]map[string]interface{}); ok { + return len(links) } - return len(links) + return 0 } // countVariablesV0V1 counts template variables in v0alpha1 or v1beta1 dashboard spec @@ -213,12 +219,15 @@ func countVariablesV0V1(spec map[string]interface{}) int { return 0 } - variableList, ok := templating["list"].([]interface{}) - if !ok { - return 0 + // Handle both []interface{} (from JSON unmarshaling) and []map[string]interface{} (from programmatic creation) + if variableList, ok := templating["list"].([]interface{}); ok { + return len(variableList) + } + if variableList, ok := templating["list"].([]map[string]interface{}); ok { + return len(variableList) } - return len(variableList) + return 0 } // collectStatsV0V1 collects statistics from v0alpha1 or v1beta1 dashboard diff --git a/apps/dashboard/pkg/migration/conversion/metrics.go b/apps/dashboard/pkg/migration/conversion/metrics.go index 5a60aa848de..9cbdec193e8 100644 --- a/apps/dashboard/pkg/migration/conversion/metrics.go +++ b/apps/dashboard/pkg/migration/conversion/metrics.go @@ -85,20 +85,20 @@ func withConversionMetrics(sourceVersionAPI, targetVersionAPI string, conversion // Only track schema versions for v0/v1 dashboards (v2+ info is redundant with API version) switch source := a.(type) { case *dashv0.Dashboard: - dashboardUID = string(source.UID) + dashboardUID = source.Name if source.Spec.Object != nil { sourceSchemaVersion = schemaversion.GetSchemaVersion(source.Spec.Object) } case *dashv1.Dashboard: - dashboardUID = string(source.UID) + dashboardUID = source.Name if source.Spec.Object != nil { sourceSchemaVersion = schemaversion.GetSchemaVersion(source.Spec.Object) } case *dashv2alpha1.Dashboard: - dashboardUID = string(source.UID) + dashboardUID = source.Name // Don't track schema version for v2+ (redundant with API version) case *dashv2beta1.Dashboard: - dashboardUID = string(source.UID) + dashboardUID = source.Name // Don't track schema version for v2+ (redundant with API version) } diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/annotations/v1beta1.annotation-filtering.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/annotations/v1beta1.annotation-filtering.v42.json new file mode 100644 index 00000000000..5e3d12546e1 --- /dev/null +++ b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/annotations/v1beta1.annotation-filtering.v42.json @@ -0,0 +1,427 @@ +{ + "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" + }, + { + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations \u0026 Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + }, + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "enable": true, + "filter": { + "exclude": false, + "ids": [ + 1 + ] + }, + "iconColor": "red", + "name": "Red, only panel 1", + "target": { + "lines": 4, + "refId": "Anno", + "scenarioId": "annotations" + } + }, + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "enable": true, + "filter": { + "exclude": true, + "ids": [ + 1 + ] + }, + "iconColor": "yellow", + "name": "Yellow - all except 1", + "target": { + "lines": 5, + "refId": "Anno", + "scenarioId": "annotations" + } + }, + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "enable": true, + "filter": { + "exclude": false, + "ids": [ + 3, + 4 + ] + }, + "iconColor": "dark-purple", + "name": "Purple only panel 3+4", + "target": { + "lines": 6, + "refId": "Anno", + "scenarioId": "annotations" + } + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 119, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "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": { + "mode": "single", + "sort": "none" + } + }, + "title": "Panel one", + "type": "timeseries" + }, + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "title": "Panel two", + "type": "timeseries" + }, + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "title": "Panel three", + "type": "timeseries" + }, + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "title": "Panel four", + "type": "timeseries" + } + ], + "refresh": "", + "schemaVersion": 42, + "tags": [ + "gdev", + "annotations" + ], + "templating": { + "list": [] + }, + "time": { + "from": "now-30m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Annotation filtering", + "uid": "ed155665", + "weekStart": "" +} \ No newline at end of file diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/annotations/v0alpha1.multi-lane-annotations.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/annotations/v1beta1.multi-lane-annotations.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/annotations/v0alpha1.multi-lane-annotations.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/annotations/v1beta1.multi-lane-annotations.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-elasticsearch/v0alpha1.elasticsearch_complex.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-elasticsearch/v1beta1.elasticsearch_complex.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-elasticsearch/v0alpha1.elasticsearch_complex.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-elasticsearch/v1beta1.elasticsearch_complex.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-elasticsearch/v0alpha1.elasticsearch_migration.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-elasticsearch/v1beta1.elasticsearch_migration.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-elasticsearch/v0alpha1.elasticsearch_migration.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-elasticsearch/v1beta1.elasticsearch_migration.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-elasticsearch/v0alpha1.elasticsearch_simple.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-elasticsearch/v1beta1.elasticsearch_simple.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-elasticsearch/v0alpha1.elasticsearch_simple.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-elasticsearch/v1beta1.elasticsearch_simple.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-influxdb/v0alpha1.influxdb-logs.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-influxdb/v1beta1.influxdb-logs.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-influxdb/v0alpha1.influxdb-logs.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-influxdb/v1beta1.influxdb-logs.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-influxdb/v0alpha1.influxdb-templated.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-influxdb/v1beta1.influxdb-templated.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-influxdb/v0alpha1.influxdb-templated.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-influxdb/v1beta1.influxdb-templated.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-loki/v0alpha1.loki_fakedata.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-loki/v1beta1.loki_fakedata.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-loki/v0alpha1.loki_fakedata.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-loki/v1beta1.loki_fakedata.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-loki/v0alpha1.loki_query_splitting.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-loki/v1beta1.loki_query_splitting.v42.json similarity index 98% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-loki/v0alpha1.loki_query_splitting.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-loki/v1beta1.loki_query_splitting.v42.json index a7beffa4cdc..8af239195cb 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-loki/v0alpha1.loki_query_splitting.v42.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-loki/v1beta1.loki_query_splitting.v42.json @@ -219,8 +219,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -312,8 +311,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -492,8 +490,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -584,8 +581,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -676,8 +672,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -791,8 +786,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -906,8 +900,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -1022,8 +1015,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-mssql/v0alpha1.mssql_fakedata.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-mssql/v1beta1.mssql_fakedata.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-mssql/v0alpha1.mssql_fakedata.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-mssql/v1beta1.mssql_fakedata.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-mssql/v0alpha1.mssql_unittest.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-mssql/v1beta1.mssql_unittest.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-mssql/v0alpha1.mssql_unittest.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-mssql/v1beta1.mssql_unittest.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-mysql/v0alpha1.mysql_fakedata.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-mysql/v1beta1.mysql_fakedata.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-mysql/v0alpha1.mysql_fakedata.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-mysql/v1beta1.mysql_fakedata.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-mysql/v0alpha1.mysql_unittest.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-mysql/v1beta1.mysql_unittest.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-mysql/v0alpha1.mysql_unittest.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-mysql/v1beta1.mysql_unittest.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-opentsdb/v0alpha1.opentsdb.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-opentsdb/v1beta1.opentsdb.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-opentsdb/v0alpha1.opentsdb.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-opentsdb/v1beta1.opentsdb.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-opentsdb/v0alpha1.opentsdb_v23.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-opentsdb/v1beta1.opentsdb_v23.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-opentsdb/v0alpha1.opentsdb_v23.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-opentsdb/v1beta1.opentsdb_v23.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-postgres/v0alpha1.postgres_fakedata.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-postgres/v1beta1.postgres_fakedata.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-postgres/v0alpha1.postgres_fakedata.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-postgres/v1beta1.postgres_fakedata.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-postgres/v0alpha1.postgres_unittest.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-postgres/v1beta1.postgres_unittest.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-postgres/v0alpha1.postgres_unittest.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-postgres/v1beta1.postgres_unittest.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-testdata/v0alpha1.bar-gauge-demo2.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-testdata/v1beta1.bar-gauge-demo2.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-testdata/v0alpha1.bar-gauge-demo2.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-testdata/v1beta1.bar-gauge-demo2.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-testdata/v0alpha1.demo1.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-testdata/v1beta1.demo1.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-testdata/v0alpha1.demo1.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-testdata/v1beta1.demo1.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-testdata/v0alpha1.new_features_in_v74.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-testdata/v1beta1.new_features_in_v74.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-testdata/v0alpha1.new_features_in_v74.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-testdata/v1beta1.new_features_in_v74.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-testdata/v0alpha1.new_features_in_v8.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-testdata/v1beta1.new_features_in_v8.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-testdata/v0alpha1.new_features_in_v8.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/datasource-testdata/v1beta1.new_features_in_v8.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/e2e-repeats/v0alpha1.Repeating-Kitchen-Sink.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/e2e-repeats/v1beta1.Repeating-Kitchen-Sink.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/e2e-repeats/v0alpha1.Repeating-Kitchen-Sink.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/e2e-repeats/v1beta1.Repeating-Kitchen-Sink.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/e2e-repeats/v0alpha1.Repeating-a-panel-horizontally.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/e2e-repeats/v1beta1.Repeating-a-panel-horizontally.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/e2e-repeats/v0alpha1.Repeating-a-panel-horizontally.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/e2e-repeats/v1beta1.Repeating-a-panel-horizontally.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/e2e-repeats/v0alpha1.Repeating-a-panel-vertically.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/e2e-repeats/v1beta1.Repeating-a-panel-vertically.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/e2e-repeats/v0alpha1.Repeating-a-panel-vertically.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/e2e-repeats/v1beta1.Repeating-a-panel-vertically.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/e2e-repeats/v0alpha1.Repeating-a-row-with-a-repeating-horizontal-panel.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/e2e-repeats/v1beta1.Repeating-a-row-with-a-repeating-horizontal-panel.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/e2e-repeats/v0alpha1.Repeating-a-row-with-a-repeating-horizontal-panel.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/e2e-repeats/v1beta1.Repeating-a-row-with-a-repeating-horizontal-panel.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/e2e-repeats/v0alpha1.Repeating-a-row-with-a-repeating-vertical-panel.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/e2e-repeats/v1beta1.Repeating-a-row-with-a-repeating-vertical-panel.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/e2e-repeats/v0alpha1.Repeating-a-row-with-a-repeating-vertical-panel.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/e2e-repeats/v1beta1.Repeating-a-row-with-a-repeating-vertical-panel.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/e2e-repeats/v0alpha1.Repeating-an-empty-row.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/e2e-repeats/v1beta1.Repeating-an-empty-row.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/e2e-repeats/v0alpha1.Repeating-an-empty-row.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/e2e-repeats/v1beta1.Repeating-an-empty-row.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/extensions/v0alpha1.link-onclick-extensions.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/extensions/v1beta1.link-onclick-extensions.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/extensions/v0alpha1.link-onclick-extensions.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/extensions/v1beta1.link-onclick-extensions.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/extensions/v0alpha1.link-path-extensions.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/extensions/v1beta1.link-path-extensions.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/extensions/v0alpha1.link-path-extensions.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/extensions/v1beta1.link-path-extensions.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v0alpha1.datadata-macros.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v1beta1.datadata-macros.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v0alpha1.datadata-macros.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v1beta1.datadata-macros.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v0alpha1.global-variables-and-interpolation.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v1beta1.global-variables-and-interpolation.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v0alpha1.global-variables-and-interpolation.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v1beta1.global-variables-and-interpolation.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v0alpha1.templating-dashboard-links-and-variables.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v1beta1.templating-dashboard-links-and-variables.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v0alpha1.templating-dashboard-links-and-variables.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v1beta1.templating-dashboard-links-and-variables.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v0alpha1.templating-repeating-panels.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v1beta1.templating-repeating-panels.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v0alpha1.templating-repeating-panels.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v1beta1.templating-repeating-panels.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v0alpha1.templating-repeating-rows.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v1beta1.templating-repeating-rows.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v0alpha1.templating-repeating-rows.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v1beta1.templating-repeating-rows.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v0alpha1.templating-textbox-e2e-scenarios.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v1beta1.templating-textbox-e2e-scenarios.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v0alpha1.templating-textbox-e2e-scenarios.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v1beta1.templating-textbox-e2e-scenarios.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-datalinks.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v1beta1.testdata-datalinks.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-datalinks.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v1beta1.testdata-datalinks.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-nested-variables-drilldown.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v1beta1.testdata-nested-variables-drilldown.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-nested-variables-drilldown.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v1beta1.testdata-nested-variables-drilldown.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-nested-variables.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v1beta1.testdata-nested-variables.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-nested-variables.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v1beta1.testdata-nested-variables.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-test-variable-output.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v1beta1.testdata-test-variable-output.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-test-variable-output.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v1beta1.testdata-test-variable-output.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-variables-textbox.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v1beta1.testdata-variables-textbox.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-variables-textbox.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v1beta1.testdata-variables-textbox.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-variables-that-update-on-time-change.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v1beta1.testdata-variables-that-update-on-time-change.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-variables-that-update-on-time-change.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/feature-templating/v1beta1.testdata-variables-that-update-on-time-change.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/live/v0alpha1.live-flakey-refresh.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/live/v1beta1.live-flakey-refresh.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/live/v0alpha1.live-flakey-refresh.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/live/v1beta1.live-flakey-refresh.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/live/v0alpha1.live-flakey.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/live/v1beta1.live-flakey.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/live/v0alpha1.live-flakey.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/live/v1beta1.live-flakey.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/live/v0alpha1.live-publish.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/live/v1beta1.live-publish.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/live/v0alpha1.live-publish.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/live/v1beta1.live-publish.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/live/v0alpha1.live-streams.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/live/v1beta1.live-streams.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/live/v0alpha1.live-streams.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/live/v1beta1.live-streams.v42.json 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/v1beta1.migrations.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/migrations/v0alpha1.migrations.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/migrations/v1beta1.migrations.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-barchart/v0alpha1.barchart-autosizing.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-barchart/v1beta1.barchart-autosizing.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-barchart/v0alpha1.barchart-autosizing.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-barchart/v1beta1.barchart-autosizing.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-barchart/v0alpha1.barchart-label-rotation-skipping.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-barchart/v1beta1.barchart-label-rotation-skipping.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-barchart/v0alpha1.barchart-label-rotation-skipping.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-barchart/v1beta1.barchart-label-rotation-skipping.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-barchart/v0alpha1.barchart-series-toggle.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-barchart/v1beta1.barchart-series-toggle.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-barchart/v0alpha1.barchart-series-toggle.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-barchart/v1beta1.barchart-series-toggle.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-barchart/v0alpha1.barchart-thresholds-mappings.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-barchart/v1beta1.barchart-thresholds-mappings.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-barchart/v0alpha1.barchart-thresholds-mappings.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-barchart/v1beta1.barchart-thresholds-mappings.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-barchart/v0alpha1.barchart-tooltips-legends.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-barchart/v1beta1.barchart-tooltips-legends.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-barchart/v0alpha1.barchart-tooltips-legends.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-barchart/v1beta1.barchart-tooltips-legends.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-bargauge/v0alpha1.bar_gauge_demo.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-bargauge/v1beta1.bar_gauge_demo.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-bargauge/v0alpha1.bar_gauge_demo.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-bargauge/v1beta1.bar_gauge_demo.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-bargauge/v0alpha1.panel_tests_bar_gauge.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-bargauge/v1beta1.panel_tests_bar_gauge.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-bargauge/v0alpha1.panel_tests_bar_gauge.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-bargauge/v1beta1.panel_tests_bar_gauge.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-bargauge/v0alpha1.panel_tests_bar_gauge2.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-bargauge/v1beta1.panel_tests_bar_gauge2.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-bargauge/v0alpha1.panel_tests_bar_gauge2.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-bargauge/v1beta1.panel_tests_bar_gauge2.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-candlestick/v0alpha1.candlestick.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-candlestick/v1beta1.candlestick.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-candlestick/v0alpha1.candlestick.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-candlestick/v1beta1.candlestick.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-canvas/v0alpha1.canvas-connection-examples.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-canvas/v1beta1.canvas-connection-examples.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-canvas/v0alpha1.canvas-connection-examples.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-canvas/v1beta1.canvas-connection-examples.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-canvas/v0alpha1.canvas-datalinks.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-canvas/v1beta1.canvas-datalinks.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-canvas/v0alpha1.canvas-datalinks.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-canvas/v1beta1.canvas-datalinks.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-canvas/v0alpha1.canvas-examples.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-canvas/v1beta1.canvas-examples.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-canvas/v0alpha1.canvas-examples.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-canvas/v1beta1.canvas-examples.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-common/v0alpha1.auto_decimals.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-common/v1beta1.auto_decimals.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-common/v0alpha1.auto_decimals.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-common/v1beta1.auto_decimals.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-common/v0alpha1.color_modes.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-common/v1beta1.color_modes.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-common/v0alpha1.color_modes.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-common/v1beta1.color_modes.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-common/v0alpha1.lazy_loading.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-common/v1beta1.lazy_loading.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-common/v0alpha1.lazy_loading.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-common/v1beta1.lazy_loading.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-common/v0alpha1.linked-viz.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-common/v1beta1.linked-viz.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-common/v0alpha1.linked-viz.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-common/v1beta1.linked-viz.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-common/v0alpha1.panels_without_title.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-common/v1beta1.panels_without_title.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-common/v0alpha1.panels_without_title.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-common/v1beta1.panels_without_title.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-common/v0alpha1.shared_queries.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-common/v1beta1.shared_queries.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-common/v0alpha1.shared_queries.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-common/v1beta1.shared_queries.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-dashlist/v0alpha1.dashlist.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-dashlist/v1beta1.dashlist.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-dashlist/v0alpha1.dashlist.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-dashlist/v1beta1.dashlist.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-datagrid/v0alpha1.datagrid_metric_values.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-datagrid/v1beta1.datagrid_metric_values.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-datagrid/v0alpha1.datagrid_metric_values.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-datagrid/v1beta1.datagrid_metric_values.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-flamegraph/v0alpha1.panel_tests_flame_graph.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-flamegraph/v1beta1.panel_tests_flame_graph.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-flamegraph/v0alpha1.panel_tests_flame_graph.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-flamegraph/v1beta1.panel_tests_flame_graph.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge-multi-series.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-gauge/v1beta1.gauge-multi-series.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge-multi-series.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-gauge/v1beta1.gauge-multi-series.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-gauge/v1beta1.gauge_tests.v42.json similarity index 93% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-gauge/v1beta1.gauge_tests.v42.json index 92a865b0b10..b00b08dd2ab 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests.v42.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-gauge/v1beta1.gauge_tests.v42.json @@ -65,17 +65,14 @@ "mode": "absolute", "steps": [ { - "color": "#7EB26D", - "index": 0 + "color": "#7EB26D" }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -136,17 +133,14 @@ "mode": "absolute", "steps": [ { - "color": "#7EB26D", - "index": 0 + "color": "#7EB26D" }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -207,17 +201,14 @@ "mode": "absolute", "steps": [ { - "color": "#7EB26D", - "index": 0 + "color": "#7EB26D" }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -271,7 +262,6 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "", "mappings": [], "max": 100, "min": 0, @@ -279,17 +269,14 @@ "mode": "absolute", "steps": [ { - "color": "#7EB26D", - "index": 0 + "color": "#7EB26D" }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -342,7 +329,6 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "", "mappings": [], "max": 100, "min": 0, @@ -350,17 +336,14 @@ "mode": "absolute", "steps": [ { - "color": "#7EB26D", - "index": 0 + "color": "#7EB26D" }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -414,7 +397,6 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "", "mappings": [], "max": 100, "min": 0, @@ -422,17 +404,14 @@ "mode": "absolute", "steps": [ { - "color": "#7EB26D", - "index": 0 + "color": "#7EB26D" }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -485,7 +464,6 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "", "mappings": [], "max": 100, "min": 0, @@ -493,17 +471,14 @@ "mode": "absolute", "steps": [ { - "color": "#7EB26D", - "index": 0 + "color": "#7EB26D" }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -668,7 +643,6 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "", "mappings": [ { "options": { @@ -685,17 +659,14 @@ "mode": "absolute", "steps": [ { - "color": "#7EB26D", - "index": 0 + "color": "#7EB26D" }, { "color": "#ef843c", - "index": 1, "value": 75 }, { - "color": "#e24d42", - "index": 2, + "color": "#e24d42", "value": 90 } ] @@ -750,7 +721,6 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "", "mappings": [ { "options": { @@ -768,17 +738,14 @@ "mode": "absolute", "steps": [ { - "color": "#7EB26D", - "index": 0 + "color": "#7EB26D" }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -833,7 +800,6 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "", "mappings": [ { "options": { @@ -852,17 +818,14 @@ "mode": "absolute", "steps": [ { - "color": "#7EB26D", - "index": 0 + "color": "#7EB26D" }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -917,7 +880,6 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "", "mappings": [ { "options": { @@ -946,17 +908,14 @@ "mode": "absolute", "steps": [ { - "color": "#7EB26D", - "index": 0 + "color": "#7EB26D" }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -1038,7 +997,7 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "2", + "decimals": 2, "mappings": [], "max": 100, "min": 0, @@ -1046,17 +1005,14 @@ "mode": "absolute", "steps": [ { - "color": "#7EB26D", - "index": 0 + "color": "#7EB26D" }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests_new.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-gauge/v1beta1.gauge_tests_new.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests_new.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-gauge/v1beta1.gauge_tests_new.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests_old_to_new.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-gauge/v1beta1.gauge_tests_old_to_new.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests_old_to_new.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-gauge/v1beta1.gauge_tests_old_to_new.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-geomap/v0alpha1.geomap-color-field.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-geomap/v1beta1.geomap-color-field.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-geomap/v0alpha1.geomap-color-field.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-geomap/v1beta1.geomap-color-field.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-geomap/v0alpha1.geomap-photo-layer.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-geomap/v1beta1.geomap-photo-layer.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-geomap/v0alpha1.geomap-photo-layer.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-geomap/v1beta1.geomap-photo-layer.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-geomap/v0alpha1.geomap-route-layer.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-geomap/v1beta1.geomap-route-layer.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-geomap/v0alpha1.geomap-route-layer.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-geomap/v1beta1.geomap-route-layer.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-geomap/v0alpha1.geomap-spatial-operations-transformer.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-geomap/v1beta1.geomap-spatial-operations-transformer.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-geomap/v0alpha1.geomap-spatial-operations-transformer.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-geomap/v1beta1.geomap-spatial-operations-transformer.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-geomap/v0alpha1.geomap-v91.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-geomap/v1beta1.geomap-v91.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-geomap/v0alpha1.geomap-v91.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-geomap/v1beta1.geomap-v91.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-geomap/v0alpha1.geomap_multi-layers.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-geomap/v1beta1.geomap_multi-layers.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-geomap/v0alpha1.geomap_multi-layers.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-geomap/v1beta1.geomap_multi-layers.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-geomap/v0alpha1.panel-geomap.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-geomap/v1beta1.panel-geomap.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-geomap/v0alpha1.panel-geomap.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-geomap/v1beta1.panel-geomap.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-graph/v0alpha1.graph-gradient-area-fills.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-graph/v1beta1.graph-gradient-area-fills.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-graph/v0alpha1.graph-gradient-area-fills.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-graph/v1beta1.graph-gradient-area-fills.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-graph/v0alpha1.graph-shared-tooltips.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-graph/v1beta1.graph-shared-tooltips.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-graph/v0alpha1.graph-shared-tooltips.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-graph/v1beta1.graph-shared-tooltips.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-graph/v0alpha1.graph-time-regions.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-graph/v1beta1.graph-time-regions.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-graph/v0alpha1.graph-time-regions.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-graph/v1beta1.graph-time-regions.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-graph/v0alpha1.graph_tests.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-graph/v1beta1.graph_tests.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-graph/v0alpha1.graph_tests.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-graph/v1beta1.graph_tests.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-graph/v0alpha1.graph_y_axis.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-graph/v1beta1.graph_y_axis.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-graph/v0alpha1.graph_y_axis.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-graph/v1beta1.graph_y_axis.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-heatmap/v0alpha1.heatmap-calculate-log.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-heatmap/v1beta1.heatmap-calculate-log.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-heatmap/v0alpha1.heatmap-calculate-log.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-heatmap/v1beta1.heatmap-calculate-log.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-heatmap/v0alpha1.heatmap-legacy.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-heatmap/v1beta1.heatmap-legacy.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-heatmap/v0alpha1.heatmap-legacy.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-heatmap/v1beta1.heatmap-legacy.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-heatmap/v0alpha1.heatmap-x.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-heatmap/v1beta1.heatmap-x.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-heatmap/v0alpha1.heatmap-x.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-heatmap/v1beta1.heatmap-x.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-histogram/v0alpha1.histogram_tests.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-histogram/v1beta1.histogram_tests.v42.json similarity index 99% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-histogram/v0alpha1.histogram_tests.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-histogram/v1beta1.histogram_tests.v42.json index 7e392bd55d0..5b3e0ed0b72 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-histogram/v0alpha1.histogram_tests.v42.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-histogram/v1beta1.histogram_tests.v42.json @@ -58,8 +58,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -127,8 +126,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -196,8 +194,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -277,8 +274,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -355,8 +351,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -448,8 +443,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -536,8 +530,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [ { @@ -619,8 +612,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [ { @@ -702,8 +694,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [ { @@ -785,8 +776,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -850,8 +840,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [ { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-library/v0alpha1.panel-library.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-library/v1beta1.panel-library.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-library/v0alpha1.panel-library.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-library/v1beta1.panel-library.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-piechart/v0alpha1.panel_test_piechart.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-piechart/v1beta1.panel_test_piechart.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-piechart/v0alpha1.panel_test_piechart.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-piechart/v1beta1.panel_test_piechart.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-polystat/v0alpha1.polystat_test.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-polystat/v1beta1.polystat_test.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-polystat/v0alpha1.polystat_test.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-polystat/v1beta1.polystat_test.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-stat/v0alpha1.panel-stat-tests.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-stat/v1beta1.panel-stat-tests.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-stat/v0alpha1.panel-stat-tests.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-stat/v1beta1.panel-stat-tests.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-status-history/v0alpha1.status-history-thresholds-mappings.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-status-history/v1beta1.status-history-thresholds-mappings.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-status-history/v0alpha1.status-history-thresholds-mappings.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-status-history/v1beta1.status-history-thresholds-mappings.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v0alpha1.table_footer.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v1beta1.table_footer.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v0alpha1.table_footer.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v1beta1.table_footer.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v0alpha1.table_kitchen_sink.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v1beta1.table_kitchen_sink.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v0alpha1.table_kitchen_sink.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v1beta1.table_kitchen_sink.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v0alpha1.table_markdown.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v1beta1.table_markdown.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v0alpha1.table_markdown.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v1beta1.table_markdown.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v0alpha1.table_pagination.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v1beta1.table_pagination.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v0alpha1.table_pagination.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v1beta1.table_pagination.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v0alpha1.table_sparkline_cell.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v1beta1.table_sparkline_cell.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v0alpha1.table_sparkline_cell.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v1beta1.table_sparkline_cell.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v0alpha1.table_tests.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v1beta1.table_tests.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v0alpha1.table_tests.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v1beta1.table_tests.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v0alpha1.table_tests_new.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v1beta1.table_tests_new.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v0alpha1.table_tests_new.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v1beta1.table_tests_new.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v0alpha1.table_v12_2_migrations.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v1beta1.table_v12_2_migrations.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v0alpha1.table_v12_2_migrations.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-table/v1beta1.table_v12_2_migrations.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-text/v0alpha1.text-options.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-text/v1beta1.text-options.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-text/v0alpha1.text-options.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-text/v1beta1.text-options.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeline/v0alpha1.timeline-align-endtime.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeline/v1beta1.timeline-align-endtime.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeline/v0alpha1.timeline-align-endtime.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeline/v1beta1.timeline-align-endtime.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeline/v0alpha1.timeline-align-nulls-retain.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeline/v1beta1.timeline-align-nulls-retain.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeline/v0alpha1.timeline-align-nulls-retain.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeline/v1beta1.timeline-align-nulls-retain.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeline/v0alpha1.timeline-demo.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeline/v1beta1.timeline-demo.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeline/v0alpha1.timeline-demo.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeline/v1beta1.timeline-demo.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeline/v0alpha1.timeline-modes.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeline/v1beta1.timeline-modes.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeline/v0alpha1.timeline-modes.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeline/v1beta1.timeline-modes.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeline/v0alpha1.timeline-thresholds-mappings.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeline/v1beta1.timeline-thresholds-mappings.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeline/v0alpha1.timeline-thresholds-mappings.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeline/v1beta1.timeline-thresholds-mappings.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-bars-high-density.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-bars-high-density.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-bars-high-density.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-bars-high-density.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-by-value-color-schemes.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-by-value-color-schemes.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-by-value-color-schemes.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-by-value-color-schemes.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-formats.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-formats.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-formats.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-formats.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-gradient-area.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-gradient-area.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-gradient-area.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-gradient-area.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-hue-gradients.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-hue-gradients.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-hue-gradients.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-hue-gradients.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-nulls.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-nulls.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-nulls.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-nulls.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-out-of-rage.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-out-of-rage.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-out-of-rage.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-out-of-rage.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-shared-tooltip-cursor-position.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-shared-tooltip-cursor-position.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-shared-tooltip-cursor-position.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-shared-tooltip-cursor-position.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-soft-limits.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-soft-limits.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-soft-limits.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-soft-limits.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-stacking.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-stacking.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-stacking.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-stacking.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-stacking2.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-stacking2.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-stacking2.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-stacking2.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-thresholds.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-thresholds.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-thresholds.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-thresholds.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-time.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-time.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-time.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-time.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-y-ticks-zero-decimals.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-y-ticks-zero-decimals.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-y-ticks-zero-decimals.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-y-ticks-zero-decimals.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-yaxis-ticks.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-yaxis-ticks.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-yaxis-ticks.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries-yaxis-ticks.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-timeseries/v1beta1.timeseries.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-trend/v0alpha1.trend_example.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-trend/v1beta1.trend_example.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-trend/v0alpha1.trend_example.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-trend/v1beta1.trend_example.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-xychart/v0alpha1.xychart-demo.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-xychart/v1beta1.xychart-demo.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-xychart/v0alpha1.xychart-demo.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-xychart/v1beta1.xychart-demo.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-xychart/v0alpha1.xychart-migrations.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-xychart/v1beta1.xychart-migrations.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-xychart/v0alpha1.xychart-migrations.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-xychart/v1beta1.xychart-migrations.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-xychart/v0alpha1.xychart-tooltip-color-test.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-xychart/v1beta1.xychart-tooltip-color-test.v42.json similarity index 98% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-xychart/v0alpha1.xychart-tooltip-color-test.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-xychart/v1beta1.xychart-tooltip-color-test.v42.json index 417ea1661e1..f28fee864e5 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-xychart/v0alpha1.xychart-tooltip-color-test.v42.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/panel-xychart/v1beta1.xychart-tooltip-color-test.v42.json @@ -61,8 +61,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -148,8 +147,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -235,8 +233,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -322,8 +319,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -416,8 +412,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -510,8 +505,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -604,8 +598,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/scenarios/v0alpha1.mostly-blank-dashboard.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/scenarios/v1beta1.mostly-blank-dashboard.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/scenarios/v0alpha1.mostly-blank-dashboard.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/scenarios/v1beta1.mostly-blank-dashboard.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/scenarios/v0alpha1.relative_time_zone_support.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/scenarios/v1beta1.relative_time_zone_support.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/scenarios/v0alpha1.relative_time_zone_support.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/scenarios/v1beta1.relative_time_zone_support.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/scenarios/v0alpha1.slow_queries_and_annotations.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/scenarios/v1beta1.slow_queries_and_annotations.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/scenarios/v0alpha1.slow_queries_and_annotations.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/scenarios/v1beta1.slow_queries_and_annotations.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/scenarios/v0alpha1.tall_dashboard.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/scenarios/v1beta1.tall_dashboard.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/scenarios/v0alpha1.tall_dashboard.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/scenarios/v1beta1.tall_dashboard.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/scenarios/v0alpha1.time_zone_support.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/scenarios/v1beta1.time_zone_support.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/scenarios/v0alpha1.time_zone_support.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/scenarios/v1beta1.time_zone_support.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v0alpha1.config-from-query.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v1beta1.config-from-query.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v0alpha1.config-from-query.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v1beta1.config-from-query.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v0alpha1.extract-json-paths.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v1beta1.extract-json-paths.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v0alpha1.extract-json-paths.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v1beta1.extract-json-paths.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v0alpha1.filter.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v1beta1.filter.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v0alpha1.filter.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v1beta1.filter.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v0alpha1.join-by-field.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v1beta1.join-by-field.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v0alpha1.join-by-field.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v1beta1.join-by-field.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v0alpha1.join-by-labels.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v1beta1.join-by-labels.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v0alpha1.join-by-labels.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v1beta1.join-by-labels.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v0alpha1.regression-analysis.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v1beta1.regression-analysis.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v0alpha1.regression-analysis.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v1beta1.regression-analysis.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v0alpha1.reuse.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v1beta1.reuse.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v0alpha1.reuse.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v1beta1.reuse.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v0alpha1.rows-to-fields.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v1beta1.rows-to-fields.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v0alpha1.rows-to-fields.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/transforms/v1beta1.rows-to-fields.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/v0alpha1.v1beta1.v1beta1.all-panels.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/v1beta1.v1beta1.v1beta1.all-panels.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/v0alpha1.v1beta1.v1beta1.all-panels.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/v1beta1.v1beta1.v1beta1.all-panels.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/v0alpha1.v1beta1.v1beta1.home.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/v1beta1.v1beta1.v1beta1.home.v42.json similarity index 100% rename from apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/v0alpha1.v1beta1.v1beta1.home.v42.json rename to apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/v1beta1.v1beta1.v1beta1.home.v42.json diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/v1beta1.bom-in-links.json b/apps/dashboard/pkg/migration/conversion/testdata/input/v1beta1.bom-in-links.json new file mode 100644 index 00000000000..86992c3380c --- /dev/null +++ b/apps/dashboard/pkg/migration/conversion/testdata/input/v1beta1.bom-in-links.json @@ -0,0 +1,142 @@ +{ + "kind": "Dashboard", + "apiVersion": "dashboard.grafana.app/v1beta1", + "metadata": { + "name": "bom-in-links-test", + "namespace": "org-1", + "labels": { + "test": "bom-stripping" + } + }, + "spec": { + "title": "BOM Stripping Test Dashboard", + "description": "Testing that BOM characters are stripped from URLs during conversion", + "schemaVersion": 42, + "tags": ["test", "bom"], + "editable": true, + "links": [ + { + "title": "Dashboard link with BOM", + "type": "link", + "url": "http://example.com?var=${datasource}&other=value", + "targetBlank": true, + "icon": "external link" + } + ], + "panels": [ + { + "id": 1, + "type": "table", + "title": "Panel with BOM in field config override links", + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + {"color": "green"}, + {"color": "red", "value": 80} + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "server" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "title": "Override link with BOM", + "url": "http://localhost:3000/d/test?var-datacenter=${__data.fields[datacenter]}&var-server=${__value.raw}" + } + ] + } + ] + } + ] + }, + "links": [ + { + "title": "Panel data link with BOM", + "url": "http://example.com/${__data.fields.cluster}&var=value", + "targetBlank": true + } + ], + "targets": [ + { + "refId": "A", + "datasource": { + "type": "prometheus", + "uid": "test-ds" + } + } + ] + }, + { + "id": 2, + "type": "timeseries", + "title": "Panel with BOM in options dataLinks", + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "options": { + "legend": { + "showLegend": true, + "displayMode": "list", + "placement": "bottom" + }, + "dataLinks": [ + { + "title": "Options data link with BOM", + "url": "http://example.com?series=${__series.name}&time=${__value.time}", + "targetBlank": true + } + ] + }, + "fieldConfig": { + "defaults": { + "links": [ + { + "title": "Field config default link with BOM", + "url": "http://example.com?field=${__field.name}&value=${__value.raw}", + "targetBlank": false + } + ] + }, + "overrides": [] + }, + "targets": [ + { + "refId": "A", + "datasource": { + "type": "prometheus", + "uid": "test-ds" + } + } + ] + } + ], + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m"] + } + } +} + diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/v1beta1.legacy-ds-ref.json b/apps/dashboard/pkg/migration/conversion/testdata/input/v1beta1.legacy-ds-ref.json new file mode 100644 index 00000000000..7bb2bc70f81 --- /dev/null +++ b/apps/dashboard/pkg/migration/conversion/testdata/input/v1beta1.legacy-ds-ref.json @@ -0,0 +1,287 @@ +{ + "kind": "Dashboard", + "apiVersion": "dashboard.grafana.app/v1beta1", + "metadata": { + "name": "legacy-ds-ref" + }, + "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, + "panels": [ + { + "datasource": "${datasource}", + "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": [ + { + "matcher": { + "id": "byName", + "options": "Minimum cluster size" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [10, 10], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 1 + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 8, + "x": 0, + "y": 0 + }, + "id": 16, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "timeCompare": false, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": "${datasource}", + "editorMode": "code", + "expr": "count by (version) (alloy_build_info{cluster=~\"$cluster\", namespace=~\"$namespace\", job=~\"$job\"})", + "instant": false, + "legendFormat": "{{version}}", + "range": true, + "refId": "B" + } + ], + "title": "Number of Alloy Instances", + "type": "timeseries" + }, + { + "datasource": "${datasource}", + "description": "CPU usage of the Alloy process relative to 1 CPU core.\n\nFor example, 100% means using one entire CPU core.\n", + "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 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "Total" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": true, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 8, + "x": 8, + "y": 0 + }, + "id": 17, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "timeCompare": false, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": "${datasource}", + "expr": "rate(alloy_resources_process_cpu_seconds_total{cluster=~\"$cluster\", namespace=~\"$namespace\", job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])\n", + "hide": true, + "instant": false, + "legendFormat": "{{instance}}", + "range": true, + "refId": "A" + }, + { + "datasource": "${datasource}", + "editorMode": "code", + "expr": "sum(rate(alloy_resources_process_cpu_seconds_total{cluster=~\"$cluster\", namespace=~\"$namespace\", job=~\"$job\", instance=~\"$instance\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "Total", + "range": true, + "refId": "B" + } + ], + "title": "CPU usage", + "type": "timeseries" + } + ], + "time": { + "from": "now-90m", + "to": "now" + }, + "timezone": "utc", + "title": "Legacy DS Panel Query Ref", + "weekStart": "" + } +} + + \ No newline at end of file diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/v2alpha1.ds-data-query.json b/apps/dashboard/pkg/migration/conversion/testdata/input/v2alpha1.ds-data-query.json index a27c33c3239..ac88b83370f 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/input/v2alpha1.ds-data-query.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/input/v2alpha1.ds-data-query.json @@ -852,6 +852,194 @@ } } } + }, + "panel-7": { + "kind": "Panel", + "spec": { + "id": 7, + "title": "Single Dashboard DS Query", + "description": "Panel with a single -- Dashboard -- datasource query", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "datasource", + "spec": { + "panelId": 1, + "withTransforms": true + } + }, + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "stat", + "spec": { + "pluginVersion": "12.1.0-pre", + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "fieldConfig": { + "defaults": { + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": 0, + "color": "green" + } + ] + }, + "color": { + "mode": "thresholds" + } + }, + "overrides": [] + } + } + } + } + }, + "panel-8": { + "kind": "Panel", + "spec": { + "id": 8, + "title": "Multiple Dashboard DS Queries", + "description": "Panel with multiple -- Dashboard -- datasource queries (should be mixed)", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "datasource", + "spec": { + "panelId": 1, + "withTransforms": true + } + }, + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "refId": "A", + "hidden": false + } + }, + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "datasource", + "spec": { + "panelId": 2, + "withTransforms": true + } + }, + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "refId": "B", + "hidden": false + } + }, + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "datasource", + "spec": { + "panelId": 3, + "withTransforms": true + } + }, + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "refId": "C", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "stat", + "spec": { + "pluginVersion": "12.1.0-pre", + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "fieldConfig": { + "defaults": { + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": 0, + "color": "green" + } + ] + }, + "color": { + "mode": "thresholds" + } + }, + "overrides": [] + } + } + } + } } }, "layout": { @@ -914,6 +1102,24 @@ "name": "panel-6" } } + }, + { + "kind": "AutoGridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-7" + } + } + }, + { + "kind": "AutoGridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-8" + } + } } ] } diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/v2beta1.ds-data-query.json b/apps/dashboard/pkg/migration/conversion/testdata/input/v2beta1.ds-data-query.json index 0c787609714..fad72787d19 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/input/v2beta1.ds-data-query.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/input/v2beta1.ds-data-query.json @@ -879,6 +879,200 @@ } } } + }, + "panel-7": { + "kind": "Panel", + "spec": { + "id": 7, + "title": "Single Dashboard DS Query", + "description": "Panel with a single -- Dashboard -- datasource query", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "datasource", + "version": "v0", + "datasource": { + "name": "-- Dashboard --" + }, + "spec": { + "panelId": 1, + "withTransforms": true + } + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "stat", + "version": "12.1.0-pre", + "spec": { + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "fieldConfig": { + "defaults": { + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": 0, + "color": "green" + } + ] + }, + "color": { + "mode": "thresholds" + } + }, + "overrides": [] + } + } + } + } + }, + "panel-8": { + "kind": "Panel", + "spec": { + "id": 8, + "title": "Multiple Dashboard DS Queries", + "description": "Panel with multiple -- Dashboard -- datasource queries (should be mixed)", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "datasource", + "version": "v0", + "datasource": { + "name": "-- Dashboard --" + }, + "spec": { + "panelId": 1, + "withTransforms": true + } + }, + "refId": "A", + "hidden": false + } + }, + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "datasource", + "version": "v0", + "datasource": { + "name": "-- Dashboard --" + }, + "spec": { + "panelId": 2, + "withTransforms": true + } + }, + "refId": "B", + "hidden": false + } + }, + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "datasource", + "version": "v0", + "datasource": { + "name": "-- Dashboard --" + }, + "spec": { + "panelId": 3, + "withTransforms": true + } + }, + "refId": "C", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "stat", + "version": "12.1.0-pre", + "spec": { + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "fieldConfig": { + "defaults": { + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": 0, + "color": "green" + } + ] + }, + "color": { + "mode": "thresholds" + } + }, + "overrides": [] + } + } + } + } } }, "layout": { @@ -973,6 +1167,32 @@ "name": "panel-6" } } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 6, + "width": 8, + "height": 3, + "element": { + "kind": "ElementReference", + "name": "panel-7" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 8, + "y": 6, + "width": 8, + "height": 3, + "element": { + "kind": "ElementReference", + "name": "panel-8" + } + } } ] } diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v10.table_thresholds.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v10.table_thresholds.v0alpha1.json index 5a6cebb8a91..e181c66eaf1 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v10.table_thresholds.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v10.table_thresholds.v0alpha1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -49,6 +53,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -71,6 +79,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v10.table_thresholds.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v10.table_thresholds.v1beta1.json index 122c6772dfe..6c7da8a3864 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v10.table_thresholds.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v10.table_thresholds.v1beta1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -49,6 +53,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -71,6 +79,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v11.no-op-migration.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v11.no-op-migration.v0alpha1.json index 0442d15c222..ed6e158988b 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v11.no-op-migration.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v11.no-op-migration.v0alpha1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -49,6 +53,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v11.no-op-migration.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v11.no-op-migration.v1beta1.json index e1548f77853..dab8e4d166c 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v11.no-op-migration.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v11.no-op-migration.v1beta1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -49,6 +53,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v13.graph_thresholds.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v13.graph_thresholds.v0alpha1.json index 7aadfcf8535..0d943be33e1 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v13.graph_thresholds.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v13.graph_thresholds.v0alpha1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -49,6 +53,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -71,6 +79,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -93,6 +105,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -115,6 +131,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v13.graph_thresholds.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v13.graph_thresholds.v1beta1.json index 7f7f61699e5..7d51fccb5f4 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v13.graph_thresholds.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v13.graph_thresholds.v1beta1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -49,6 +53,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -71,6 +79,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -93,6 +105,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -115,6 +131,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v13.minimal_graph_config.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v13.minimal_graph_config.v0alpha1.json index e768e617055..d26aeb546b0 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v13.minimal_graph_config.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v13.minimal_graph_config.v0alpha1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "gdev-prometheus" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v13.minimal_graph_config.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v13.minimal_graph_config.v1beta1.json index 2c88ea03447..1dc3f1743cd 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v13.minimal_graph_config.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v13.minimal_graph_config.v1beta1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "gdev-prometheus" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v14.shared_crosshair_to_graph_tooltip.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v14.shared_crosshair_to_graph_tooltip.v0alpha1.json index 6f6b04077da..cefd07bd3b0 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v14.shared_crosshair_to_graph_tooltip.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v14.shared_crosshair_to_graph_tooltip.v0alpha1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -50,6 +54,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v14.shared_crosshair_to_graph_tooltip.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v14.shared_crosshair_to_graph_tooltip.v1beta1.json index d83cb315419..765bf5993d3 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v14.shared_crosshair_to_graph_tooltip.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v14.shared_crosshair_to_graph_tooltip.v1beta1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -50,6 +54,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v15.mimir_rollout_debugging.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v15.mimir_rollout_debugging.v0alpha1.json index cc366a688e3..556e8ee5040 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v15.mimir_rollout_debugging.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v15.mimir_rollout_debugging.v0alpha1.json @@ -65,6 +65,9 @@ "type": "row" }, { + "datasource": { + "uid": "$datasource" + }, "description": "### Versions running\nShows the versions reported by each running pod.\n\nThe rollout will fail if any pod is not running the expected version.\n\nPods in green are running the expected version, while pods running other versions are shown in orange.\n\n", "fieldConfig": { "defaults": { @@ -185,6 +188,9 @@ "type": "barchart" }, { + "datasource": { + "uid": "$datasource" + }, "description": "### Deployment rollout progress\nShows the number of pods for each `Deployment` that match the desired configuration, as a proportion of the desired number of pods.\n\nThe rollout will fail if insufficient pods match the desired configuration for any `Deployment`.\n\nPods in green match the desired configuration, while pods that do not match the desired configuration are shown in orange.\n\n", "fieldConfig": { "defaults": { @@ -286,6 +292,9 @@ "type": "barchart" }, { + "datasource": { + "uid": "$datasource" + }, "description": "### StatefulSet rollout progress\nShows the number of pods for each `StatefulSet` that match the desired configuration, as a proportion of the desired number of pods.\n\nThe rollout will fail if insufficient pods match the desired configuration for any `StatefulSet`.\n\nPods in green match the desired configuration, while pods that do not match the desired configuration are shown in orange.\n\n", "fieldConfig": { "defaults": { @@ -399,6 +408,9 @@ "type": "row" }, { + "datasource": { + "uid": "$datasource" + }, "description": "### Aggregator lag\nShows the consumption lag of each aggregator pod.\n\nThis panel may show no data if aggregators are not deployed to this cell.\n\nThe rollout will fail if any pod's consumption lag is both:\n* greater than 30s (red area on graph), and\n* trending upwards compared to 1 minute earlier\n\n", "fieldConfig": { "defaults": { @@ -468,6 +480,9 @@ "type": "timeseries" }, { + "datasource": { + "uid": "$datasource" + }, "description": "### Unhealthy Deployment replicas\nShows the number of unavailable pods for each `Deployment`.\n\nThe rollout will fail if any `Deployment` has an unavailable pod.\n\nBoth this panel and the rollout check ignore any `Deployment`s that require spot nodes, as these are expected to be unavailable from time to time.\n\n`Deployment`s shown in green do not have any unavailable pods, while `Deployment`s shown in orange have one or more unavailable pods.\n\n", "fieldConfig": { "defaults": { @@ -569,6 +584,9 @@ "type": "barchart" }, { + "datasource": { + "uid": "$datasource" + }, "description": "### Unhealthy StatefulSet replicas\nShows the number of pods for each `StatefulSet` that are not ready.\n\nThe rollout will fail if any `StatefulSet` has fewer ready pods than requested.\n\nBoth this panel and the rollout check ignore any `StatefulSets`s that require spot nodes, as these are expected to be unavailable from time to time.\n\n`StatefulSets`s shown in green do not have any pods that are not ready, while `StatefulSet`s shown in orange have one or more pods that are not ready.\n\n", "fieldConfig": { "defaults": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v15.mimir_rollout_debugging.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v15.mimir_rollout_debugging.v1beta1.json index cbe61ee0ed7..0b50d42fbe7 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v15.mimir_rollout_debugging.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v15.mimir_rollout_debugging.v1beta1.json @@ -65,6 +65,9 @@ "type": "row" }, { + "datasource": { + "uid": "$datasource" + }, "description": "### Versions running\nShows the versions reported by each running pod.\n\nThe rollout will fail if any pod is not running the expected version.\n\nPods in green are running the expected version, while pods running other versions are shown in orange.\n\n", "fieldConfig": { "defaults": { @@ -185,6 +188,9 @@ "type": "barchart" }, { + "datasource": { + "uid": "$datasource" + }, "description": "### Deployment rollout progress\nShows the number of pods for each `Deployment` that match the desired configuration, as a proportion of the desired number of pods.\n\nThe rollout will fail if insufficient pods match the desired configuration for any `Deployment`.\n\nPods in green match the desired configuration, while pods that do not match the desired configuration are shown in orange.\n\n", "fieldConfig": { "defaults": { @@ -286,6 +292,9 @@ "type": "barchart" }, { + "datasource": { + "uid": "$datasource" + }, "description": "### StatefulSet rollout progress\nShows the number of pods for each `StatefulSet` that match the desired configuration, as a proportion of the desired number of pods.\n\nThe rollout will fail if insufficient pods match the desired configuration for any `StatefulSet`.\n\nPods in green match the desired configuration, while pods that do not match the desired configuration are shown in orange.\n\n", "fieldConfig": { "defaults": { @@ -399,6 +408,9 @@ "type": "row" }, { + "datasource": { + "uid": "$datasource" + }, "description": "### Aggregator lag\nShows the consumption lag of each aggregator pod.\n\nThis panel may show no data if aggregators are not deployed to this cell.\n\nThe rollout will fail if any pod's consumption lag is both:\n* greater than 30s (red area on graph), and\n* trending upwards compared to 1 minute earlier\n\n", "fieldConfig": { "defaults": { @@ -468,6 +480,9 @@ "type": "timeseries" }, { + "datasource": { + "uid": "$datasource" + }, "description": "### Unhealthy Deployment replicas\nShows the number of unavailable pods for each `Deployment`.\n\nThe rollout will fail if any `Deployment` has an unavailable pod.\n\nBoth this panel and the rollout check ignore any `Deployment`s that require spot nodes, as these are expected to be unavailable from time to time.\n\n`Deployment`s shown in green do not have any unavailable pods, while `Deployment`s shown in orange have one or more unavailable pods.\n\n", "fieldConfig": { "defaults": { @@ -569,6 +584,9 @@ "type": "barchart" }, { + "datasource": { + "uid": "$datasource" + }, "description": "### Unhealthy StatefulSet replicas\nShows the number of pods for each `StatefulSet` that are not ready.\n\nThe rollout will fail if any `StatefulSet` has fewer ready pods than requested.\n\nBoth this panel and the rollout check ignore any `StatefulSets`s that require spot nodes, as these are expected to be unavailable from time to time.\n\n`StatefulSets`s shown in green do not have any pods that are not ready, while `StatefulSet`s shown in orange have one or more pods that are not ready.\n\n", "fieldConfig": { "defaults": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v15.no-op-migration.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v15.no-op-migration.v0alpha1.json index dd68f978199..720fff258cc 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v15.no-op-migration.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v15.no-op-migration.v0alpha1.json @@ -37,6 +37,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -59,6 +63,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v15.no-op-migration.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v15.no-op-migration.v1beta1.json index 6efa2fd1853..370eafaad0c 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v15.no-op-migration.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v15.no-op-migration.v1beta1.json @@ -37,6 +37,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -59,6 +63,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v16.empty-rows-and-panels-array.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v16.empty-rows-and-panels-array.v0alpha1.json index 3d8d1b11ad3..99a2102204c 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v16.empty-rows-and-panels-array.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v16.empty-rows-and-panels-array.v0alpha1.json @@ -44,6 +44,9 @@ "liveNow": false, "panels": [ { + "datasource": { + "uid": "${example_datasource}" + }, "description": "Sample metric showing connection count.", "fieldConfig": { "defaults": { @@ -134,6 +137,9 @@ "type": "timeseries" }, { + "datasource": { + "uid": "${example_datasource}" + }, "description": "Sample counter metric.", "fieldConfig": { "defaults": { @@ -224,6 +230,9 @@ "type": "timeseries" }, { + "datasource": { + "uid": "${example_datasource}" + }, "description": "Sample error metric.", "fieldConfig": { "defaults": { @@ -314,6 +323,9 @@ "type": "timeseries" }, { + "datasource": { + "uid": "${example_datasource}" + }, "description": "Sample event rate metric.", "fieldConfig": { "defaults": { @@ -404,6 +416,9 @@ "type": "timeseries" }, { + "datasource": { + "uid": "${example_datasource}" + }, "description": "Sample resource utilization metric.", "fieldConfig": { "defaults": { @@ -493,6 +508,9 @@ "type": "timeseries" }, { + "datasource": { + "uid": "${example_datasource}" + }, "description": "Sample memory allocation metrics.", "fieldConfig": { "defaults": { @@ -593,6 +611,9 @@ "type": "timeseries" }, { + "datasource": { + "uid": "${example_datasource}" + }, "description": "Sample utilization percentage.", "fieldConfig": { "defaults": { @@ -662,6 +683,9 @@ "type": "row" }, { + "datasource": { + "uid": "${example_datasource}" + }, "description": "Sample latency metric for primary operations.", "fieldConfig": { "defaults": { @@ -748,6 +772,9 @@ "type": "timeseries" }, { + "datasource": { + "uid": "${example_datasource}" + }, "description": "Sample latency metric for secondary operations.", "fieldConfig": { "defaults": { @@ -834,6 +861,9 @@ "type": "timeseries" }, { + "datasource": { + "uid": "${example_datasource}" + }, "description": "Sample expansion events metric.", "fieldConfig": { "defaults": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v16.empty-rows-and-panels-array.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v16.empty-rows-and-panels-array.v1beta1.json index e93a8eb3132..58f46289f57 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v16.empty-rows-and-panels-array.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v16.empty-rows-and-panels-array.v1beta1.json @@ -44,6 +44,9 @@ "liveNow": false, "panels": [ { + "datasource": { + "uid": "${example_datasource}" + }, "description": "Sample metric showing connection count.", "fieldConfig": { "defaults": { @@ -134,6 +137,9 @@ "type": "timeseries" }, { + "datasource": { + "uid": "${example_datasource}" + }, "description": "Sample counter metric.", "fieldConfig": { "defaults": { @@ -224,6 +230,9 @@ "type": "timeseries" }, { + "datasource": { + "uid": "${example_datasource}" + }, "description": "Sample error metric.", "fieldConfig": { "defaults": { @@ -314,6 +323,9 @@ "type": "timeseries" }, { + "datasource": { + "uid": "${example_datasource}" + }, "description": "Sample event rate metric.", "fieldConfig": { "defaults": { @@ -404,6 +416,9 @@ "type": "timeseries" }, { + "datasource": { + "uid": "${example_datasource}" + }, "description": "Sample resource utilization metric.", "fieldConfig": { "defaults": { @@ -493,6 +508,9 @@ "type": "timeseries" }, { + "datasource": { + "uid": "${example_datasource}" + }, "description": "Sample memory allocation metrics.", "fieldConfig": { "defaults": { @@ -593,6 +611,9 @@ "type": "timeseries" }, { + "datasource": { + "uid": "${example_datasource}" + }, "description": "Sample utilization percentage.", "fieldConfig": { "defaults": { @@ -662,6 +683,9 @@ "type": "row" }, { + "datasource": { + "uid": "${example_datasource}" + }, "description": "Sample latency metric for primary operations.", "fieldConfig": { "defaults": { @@ -748,6 +772,9 @@ "type": "timeseries" }, { + "datasource": { + "uid": "${example_datasource}" + }, "description": "Sample latency metric for secondary operations.", "fieldConfig": { "defaults": { @@ -834,6 +861,9 @@ "type": "timeseries" }, { + "datasource": { + "uid": "${example_datasource}" + }, "description": "Sample expansion events metric.", "fieldConfig": { "defaults": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v16.grid_layout_upgrade.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v16.grid_layout_upgrade.v0alpha1.json index 286cc75e2c0..025ec384a0c 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v16.grid_layout_upgrade.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v16.grid_layout_upgrade.v0alpha1.json @@ -39,6 +39,10 @@ "type": "row" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 7, "w": 12, @@ -61,6 +65,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 7, "w": 12, @@ -151,6 +159,10 @@ "type": "row" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 6, "w": 8, @@ -173,6 +185,10 @@ "type": "gauge" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 6, "w": 8, @@ -195,6 +211,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 6, "w": 8, @@ -229,6 +249,10 @@ "type": "row" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 4, "w": 16, @@ -251,6 +275,10 @@ "type": "text" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 8, @@ -286,6 +314,10 @@ "type": "row" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 7, "w": 24, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v16.grid_layout_upgrade.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v16.grid_layout_upgrade.v1beta1.json index a4d76abe265..1334aad64b4 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v16.grid_layout_upgrade.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v16.grid_layout_upgrade.v1beta1.json @@ -39,6 +39,10 @@ "type": "row" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 7, "w": 12, @@ -61,6 +65,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 7, "w": 12, @@ -151,6 +159,10 @@ "type": "row" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 6, "w": 8, @@ -173,6 +185,10 @@ "type": "gauge" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 6, "w": 8, @@ -195,6 +211,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 6, "w": 8, @@ -229,6 +249,10 @@ "type": "row" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 4, "w": 16, @@ -251,6 +275,10 @@ "type": "text" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 8, @@ -286,6 +314,10 @@ "type": "row" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 7, "w": 24, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v16.span_zero_demo.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v16.span_zero_demo.v0alpha1.json index a57a713ba61..0279b19424c 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v16.span_zero_demo.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v16.span_zero_demo.v0alpha1.json @@ -41,6 +41,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 24, @@ -78,6 +82,10 @@ "type": "row" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 7, "w": 8, @@ -103,6 +111,10 @@ "type": "text" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 7, "w": 8, @@ -128,6 +140,10 @@ "type": "text" }, { + "datasource": { + "type": "prometheus", + "uid": "${prom}" + }, "fieldConfig": { "defaults": { "thresholds": { @@ -174,6 +190,10 @@ "type": "stat" }, { + "datasource": { + "type": "loki", + "uid": "${loki}" + }, "gridPos": { "h": 7, "w": 8, @@ -202,6 +222,10 @@ "type": "logs" }, { + "datasource": { + "type": "loki", + "uid": "${loki}" + }, "gridPos": { "h": 7, "w": 8, @@ -230,6 +254,10 @@ "type": "logs" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 7, "w": 8, @@ -255,6 +283,10 @@ "type": "text" }, { + "datasource": { + "type": "prometheus", + "uid": "${prom}" + }, "description": "Number of concurrent processing threads available for handling operations", "gridPos": { "h": 7, @@ -280,6 +312,10 @@ "type": "stat" }, { + "datasource": { + "type": "tempo", + "uid": "${tempo}" + }, "gridPos": { "h": 7, "w": 8, @@ -324,6 +360,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "${prom}" + }, "description": "Histogram showing p99, p95, p50, and p10 percentiles for job processing duration based on number of resources changed", "fieldConfig": { "defaults": { @@ -425,6 +465,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "${prom}" + }, "description": "Histogram showing p99, p95, p50, and p10 percentiles for job processing duration based on number of resources changed", "gridPos": { "h": 7, @@ -477,6 +521,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${prom}" + }, "description": "Total number of jobs waiting to be processed", "gridPos": { "h": 7, @@ -502,6 +550,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "${prom}" + }, "fieldConfig": { "defaults": { "unit": "s" @@ -532,6 +584,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "${prom}" + }, "description": "How long a job is in the queue before being picked up", "gridPos": { "h": 7, @@ -584,6 +640,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 7, "w": 8, @@ -609,6 +669,10 @@ "type": "text" }, { + "datasource": { + "type": "prometheus", + "uid": "${prom}" + }, "gridPos": { "h": 7, "w": 8, @@ -633,6 +697,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${prom}" + }, "gridPos": { "h": 7, "w": 8, @@ -675,6 +743,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${prom}" + }, "gridPos": { "h": 7, "w": 8, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v16.span_zero_demo.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v16.span_zero_demo.v1beta1.json index 61094ee5dbd..5597a468c53 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v16.span_zero_demo.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v16.span_zero_demo.v1beta1.json @@ -41,6 +41,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 24, @@ -78,6 +82,10 @@ "type": "row" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 7, "w": 8, @@ -103,6 +111,10 @@ "type": "text" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 7, "w": 8, @@ -128,6 +140,10 @@ "type": "text" }, { + "datasource": { + "type": "prometheus", + "uid": "${prom}" + }, "fieldConfig": { "defaults": { "thresholds": { @@ -174,6 +190,10 @@ "type": "stat" }, { + "datasource": { + "type": "loki", + "uid": "${loki}" + }, "gridPos": { "h": 7, "w": 8, @@ -202,6 +222,10 @@ "type": "logs" }, { + "datasource": { + "type": "loki", + "uid": "${loki}" + }, "gridPos": { "h": 7, "w": 8, @@ -230,6 +254,10 @@ "type": "logs" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 7, "w": 8, @@ -255,6 +283,10 @@ "type": "text" }, { + "datasource": { + "type": "prometheus", + "uid": "${prom}" + }, "description": "Number of concurrent processing threads available for handling operations", "gridPos": { "h": 7, @@ -280,6 +312,10 @@ "type": "stat" }, { + "datasource": { + "type": "tempo", + "uid": "${tempo}" + }, "gridPos": { "h": 7, "w": 8, @@ -324,6 +360,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "${prom}" + }, "description": "Histogram showing p99, p95, p50, and p10 percentiles for job processing duration based on number of resources changed", "fieldConfig": { "defaults": { @@ -425,6 +465,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "${prom}" + }, "description": "Histogram showing p99, p95, p50, and p10 percentiles for job processing duration based on number of resources changed", "gridPos": { "h": 7, @@ -477,6 +521,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${prom}" + }, "description": "Total number of jobs waiting to be processed", "gridPos": { "h": 7, @@ -502,6 +550,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "${prom}" + }, "fieldConfig": { "defaults": { "unit": "s" @@ -532,6 +584,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "${prom}" + }, "description": "How long a job is in the queue before being picked up", "gridPos": { "h": 7, @@ -584,6 +640,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 7, "w": 8, @@ -609,6 +669,10 @@ "type": "text" }, { + "datasource": { + "type": "prometheus", + "uid": "${prom}" + }, "gridPos": { "h": 7, "w": 8, @@ -633,6 +697,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${prom}" + }, "gridPos": { "h": 7, "w": 8, @@ -675,6 +743,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${prom}" + }, "gridPos": { "h": 7, "w": 8, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v17.minspan_to_maxperrow.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v17.minspan_to_maxperrow.v0alpha1.json index e169d2bfa64..ae598c96c0e 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v17.minspan_to_maxperrow.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v17.minspan_to_maxperrow.v0alpha1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 8, "w": 12, @@ -49,6 +53,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 8, "w": 12, @@ -71,6 +79,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 4, "w": 6, @@ -93,6 +105,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 4, @@ -115,6 +131,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 6, "w": 8, @@ -137,6 +157,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 4, "w": 6, @@ -159,6 +183,10 @@ "type": "text" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 6, "w": 24, @@ -181,6 +209,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 4, "w": 24, @@ -203,6 +235,10 @@ "type": "gauge" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 4, "w": 6, @@ -225,6 +261,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 4, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v17.minspan_to_maxperrow.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v17.minspan_to_maxperrow.v1beta1.json index b5a64a7634f..6b5a09f65ab 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v17.minspan_to_maxperrow.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v17.minspan_to_maxperrow.v1beta1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 8, "w": 12, @@ -49,6 +53,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 8, "w": 12, @@ -71,6 +79,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 4, "w": 6, @@ -93,6 +105,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 4, @@ -115,6 +131,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 6, "w": 8, @@ -137,6 +157,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 4, "w": 6, @@ -159,6 +183,10 @@ "type": "text" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 6, "w": 24, @@ -181,6 +209,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 4, "w": 24, @@ -203,6 +235,10 @@ "type": "gauge" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 4, "w": 6, @@ -225,6 +261,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 4, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v18.gauge_options.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v18.gauge_options.v0alpha1.json index cc57f1b1914..a34b41d8bb6 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v18.gauge_options.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v18.gauge_options.v0alpha1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -71,6 +75,10 @@ "type": "gauge" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -98,6 +106,10 @@ "type": "gauge" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -126,6 +138,10 @@ "type": "gauge" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -160,6 +176,10 @@ "type": "gauge" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v18.gauge_options.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v18.gauge_options.v1beta1.json index 1fcfe058203..269085d6048 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v18.gauge_options.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v18.gauge_options.v1beta1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -71,6 +75,10 @@ "type": "gauge" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -98,6 +106,10 @@ "type": "gauge" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -126,6 +138,10 @@ "type": "gauge" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -160,6 +176,10 @@ "type": "gauge" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v19.panel_links.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v19.panel_links.v0alpha1.json index 44bdfd7c1a0..d71f8e881d2 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v19.panel_links.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v19.panel_links.v0alpha1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -55,6 +59,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -83,6 +91,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -111,6 +123,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -140,6 +156,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -168,6 +188,10 @@ "type": "gauge" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v19.panel_links.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v19.panel_links.v1beta1.json index 432355ba671..288d4f1c8aa 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v19.panel_links.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v19.panel_links.v1beta1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -55,6 +59,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -83,6 +91,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -111,6 +123,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -140,6 +156,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -168,6 +188,10 @@ "type": "gauge" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v2.panels-and-services.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v2.panels-and-services.v0alpha1.json index ec7aab7bc7a..ea66d446c51 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v2.panels-and-services.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v2.panels-and-services.v0alpha1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -50,6 +54,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -73,6 +81,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -95,6 +107,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v2.panels-and-services.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v2.panels-and-services.v1beta1.json index 5aaa48878d6..bd99678a8ff 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v2.panels-and-services.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v2.panels-and-services.v1beta1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -50,6 +54,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -73,6 +81,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -95,6 +107,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v20.variable_syntax_links.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v20.variable_syntax_links.v0alpha1.json index 40a06e400a4..7e234377108 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v20.variable_syntax_links.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v20.variable_syntax_links.v0alpha1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 8, "w": 12, @@ -62,6 +66,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 8, "w": 12, @@ -102,6 +110,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 8, "w": 24, @@ -144,6 +156,10 @@ "type": "gauge" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 8, "w": 12, @@ -186,6 +202,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 8, "w": 12, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v20.variable_syntax_links.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v20.variable_syntax_links.v1beta1.json index a914c1f29b6..4f519fb3d9c 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v20.variable_syntax_links.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v20.variable_syntax_links.v1beta1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 8, "w": 12, @@ -62,6 +66,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 8, "w": 12, @@ -102,6 +110,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 8, "w": 24, @@ -144,6 +156,10 @@ "type": "gauge" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 8, "w": 12, @@ -186,6 +202,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 8, "w": 12, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v21.data_links_series_to_field.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v21.data_links_series_to_field.v0alpha1.json index 25823b0fd99..c4240b5dd20 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v21.data_links_series_to_field.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v21.data_links_series_to_field.v0alpha1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -60,6 +64,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -97,6 +105,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -136,6 +148,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -165,6 +181,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v21.data_links_series_to_field.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v21.data_links_series_to_field.v1beta1.json index 6f5594d57f0..90783f28c4d 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v21.data_links_series_to_field.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v21.data_links_series_to_field.v1beta1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -60,6 +64,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -97,6 +105,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -136,6 +148,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -165,6 +181,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v22.table_panel_align.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v22.table_panel_align.v0alpha1.json index ab9f271d900..a6e6e123cdb 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v22.table_panel_align.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v22.table_panel_align.v0alpha1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v22.table_panel_align.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v22.table_panel_align.v1beta1.json index b17a18593b8..19143fd0ac0 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v22.table_panel_align.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v22.table_panel_align.v1beta1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v23.multi_variable_alignment.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v23.multi_variable_alignment.v0alpha1.json index 6bf600c5014..f55f52af9cf 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v23.multi_variable_alignment.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v23.multi_variable_alignment.v0alpha1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v23.multi_variable_alignment.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v23.multi_variable_alignment.v1beta1.json index 4f174d6742a..dd7c60c0e90 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v23.multi_variable_alignment.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v23.multi_variable_alignment.v1beta1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v24.table-angular.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v24.table-angular.v0alpha1.json index 876be802767..aeec2f8300d 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v24.table-angular.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v24.table-angular.v0alpha1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests basic migration with default style pattern (/.*/) containing thresholds and colors. Should convert styles to fieldConfig.defaults with threshold steps.", "gridPos": { "h": 3, @@ -57,6 +61,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests comprehensive migration including: default style with thresholds/colors/unit/decimals/align/colorMode, column overrides with exact name and regex patterns, date formatting, hidden columns, and links with tooltips.", "gridPos": { "h": 3, @@ -80,6 +88,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests migration of timeseries_aggregations transform to reduce transformation with column mappings (avg-\u003emean, max-\u003emax, min-\u003emin, total-\u003esum, current-\u003elastNotNull, count-\u003ecount).", "gridPos": { "h": 3, @@ -103,6 +115,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests migration of timeseries_to_rows transform to seriesToRows transformation.", "gridPos": { "h": 3, @@ -126,6 +142,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests migration of timeseries_to_columns transform to seriesToColumns transformation.", "gridPos": { "h": 3, @@ -149,6 +169,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests migration of table transform to merge transformation. Also tests auto alignment conversion to empty string.", "gridPos": { "h": 3, @@ -172,6 +196,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests that existing transformations are preserved and new transformation from old format is appended to the list.", "gridPos": { "h": 3, @@ -208,6 +236,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests handling of mixed numeric and string threshold values (int, string, float) with proper type conversion.", "gridPos": { "h": 3, @@ -231,6 +263,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests all color mode mappings: cell-\u003ecolor-background, row-\u003ecolor-background, value-\u003ecolor-text.", "gridPos": { "h": 3, @@ -254,6 +290,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests all alignment options: left, center, right, and auto (should convert to empty string).", "gridPos": { "h": 3, @@ -277,6 +317,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests both field matcher types: byName for exact matches and byRegexp for regex patterns.", "gridPos": { "h": 3, @@ -300,6 +344,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests various link configurations: with and without tooltip, with and without target blank.", "gridPos": { "h": 3, @@ -323,6 +371,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests various date format patterns and aliases.", "gridPos": { "h": 3, @@ -346,6 +398,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "React table (table2) should not be migrated. Properties should remain unchanged.", "gridPos": { "h": 3, @@ -369,6 +425,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Angular table without styles property should not be migrated.", "gridPos": { "h": 3, @@ -392,6 +452,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Non-table panels should remain completely unchanged.", "gridPos": { "h": 3, @@ -415,6 +479,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Other panel types should not be affected by table migration.", "gridPos": { "h": 3, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v24.table-angular.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v24.table-angular.v1beta1.json index d79faf07932..f9a126e5f34 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v24.table-angular.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v24.table-angular.v1beta1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests basic migration with default style pattern (/.*/) containing thresholds and colors. Should convert styles to fieldConfig.defaults with threshold steps.", "gridPos": { "h": 3, @@ -57,6 +61,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests comprehensive migration including: default style with thresholds/colors/unit/decimals/align/colorMode, column overrides with exact name and regex patterns, date formatting, hidden columns, and links with tooltips.", "gridPos": { "h": 3, @@ -80,6 +88,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests migration of timeseries_aggregations transform to reduce transformation with column mappings (avg-\u003emean, max-\u003emax, min-\u003emin, total-\u003esum, current-\u003elastNotNull, count-\u003ecount).", "gridPos": { "h": 3, @@ -103,6 +115,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests migration of timeseries_to_rows transform to seriesToRows transformation.", "gridPos": { "h": 3, @@ -126,6 +142,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests migration of timeseries_to_columns transform to seriesToColumns transformation.", "gridPos": { "h": 3, @@ -149,6 +169,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests migration of table transform to merge transformation. Also tests auto alignment conversion to empty string.", "gridPos": { "h": 3, @@ -172,6 +196,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests that existing transformations are preserved and new transformation from old format is appended to the list.", "gridPos": { "h": 3, @@ -208,6 +236,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests handling of mixed numeric and string threshold values (int, string, float) with proper type conversion.", "gridPos": { "h": 3, @@ -231,6 +263,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests all color mode mappings: cell-\u003ecolor-background, row-\u003ecolor-background, value-\u003ecolor-text.", "gridPos": { "h": 3, @@ -254,6 +290,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests all alignment options: left, center, right, and auto (should convert to empty string).", "gridPos": { "h": 3, @@ -277,6 +317,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests both field matcher types: byName for exact matches and byRegexp for regex patterns.", "gridPos": { "h": 3, @@ -300,6 +344,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests various link configurations: with and without tooltip, with and without target blank.", "gridPos": { "h": 3, @@ -323,6 +371,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests various date format patterns and aliases.", "gridPos": { "h": 3, @@ -346,6 +398,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "React table (table2) should not be migrated. Properties should remain unchanged.", "gridPos": { "h": 3, @@ -369,6 +425,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Angular table without styles property should not be migrated.", "gridPos": { "h": 3, @@ -392,6 +452,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Non-table panels should remain completely unchanged.", "gridPos": { "h": 3, @@ -415,6 +479,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Other panel types should not be affected by table migration.", "gridPos": { "h": 3, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v25.no-op-migration.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v25.no-op-migration.v0alpha1.json index 704035dffdf..92c8eaf2b14 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v25.no-op-migration.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v25.no-op-migration.v0alpha1.json @@ -33,6 +33,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -55,6 +59,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v25.no-op-migration.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v25.no-op-migration.v1beta1.json index 7daaf9fa380..2e0d3dbe0ef 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v25.no-op-migration.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v25.no-op-migration.v1beta1.json @@ -33,6 +33,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -55,6 +59,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v26.text2_to_text.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v26.text2_to_text.v0alpha1.json index 4ddc375e3d0..c36b9aaa1b9 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v26.text2_to_text.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v26.text2_to_text.v0alpha1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -49,6 +53,10 @@ "type": "text" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -71,6 +79,10 @@ "type": "text" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v26.text2_to_text.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v26.text2_to_text.v1beta1.json index ed958f0fc45..028ecd9792b 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v26.text2_to_text.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v26.text2_to_text.v1beta1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -49,6 +53,10 @@ "type": "text" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -71,6 +79,10 @@ "type": "text" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v27.repeated_panels_and_constant_variable.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v27.repeated_panels_and_constant_variable.v0alpha1.json index 99bdb079082..883875f9227 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v27.repeated_panels_and_constant_variable.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v27.repeated_panels_and_constant_variable.v0alpha1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v27.repeated_panels_and_constant_variable.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v27.repeated_panels_and_constant_variable.v1beta1.json index e2a7c8d360f..2775106705e 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v27.repeated_panels_and_constant_variable.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v27.repeated_panels_and_constant_variable.v1beta1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v28.singlestat_and_variable_properties.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v28.singlestat_and_variable_properties.v0alpha1.json index 549d23f389c..baaa4bd3d9f 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v28.singlestat_and_variable_properties.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v28.singlestat_and_variable_properties.v0alpha1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -56,6 +60,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -78,6 +86,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -107,6 +119,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v28.singlestat_and_variable_properties.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v28.singlestat_and_variable_properties.v1beta1.json index 8fdfe74a0ca..da477bdc06d 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v28.singlestat_and_variable_properties.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v28.singlestat_and_variable_properties.v1beta1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -56,6 +60,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -78,6 +86,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -107,6 +119,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v28.singlestat_migration.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v28.singlestat_migration.v0alpha1.json index f47146292f4..103dc503a7c 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v28.singlestat_migration.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v28.singlestat_migration.v0alpha1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -56,6 +60,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -85,6 +93,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -107,6 +119,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -136,6 +152,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -159,6 +179,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "PD8C576611E62080A" + }, "gridPos": { "h": 8, "w": 8, @@ -182,6 +206,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "PD8C576611E62080A" + }, "fieldConfig": { "defaults": { "mappings": [ @@ -249,6 +277,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "PD8C576611E62080A" + }, "gridPos": { "h": 8, "w": 8, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v28.singlestat_migration.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v28.singlestat_migration.v1beta1.json index 9e27ce9b373..fc357d68563 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v28.singlestat_migration.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v28.singlestat_migration.v1beta1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -56,6 +60,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -85,6 +93,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -107,6 +119,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -136,6 +152,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -159,6 +179,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "PD8C576611E62080A" + }, "gridPos": { "h": 8, "w": 8, @@ -182,6 +206,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "PD8C576611E62080A" + }, "fieldConfig": { "defaults": { "mappings": [ @@ -249,6 +277,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "PD8C576611E62080A" + }, "gridPos": { "h": 8, "w": 8, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v29.query_variables_refresh_and_options.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v29.query_variables_refresh_and_options.v0alpha1.json index 46a5be539cf..846bb168d12 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v29.query_variables_refresh_and_options.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v29.query_variables_refresh_and_options.v0alpha1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v29.query_variables_refresh_and_options.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v29.query_variables_refresh_and_options.v1beta1.json index 797aa7aa93b..da06dcbea48 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v29.query_variables_refresh_and_options.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v29.query_variables_refresh_and_options.v1beta1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v3.no-op.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v3.no-op.v0alpha1.json index 811f9a00d89..f1b00a18973 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v3.no-op.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v3.no-op.v0alpha1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -49,6 +53,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -71,6 +79,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -93,6 +105,10 @@ "type": "barchart" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v3.no-op.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v3.no-op.v1beta1.json index 63203ed95de..4703aad237e 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v3.no-op.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v3.no-op.v1beta1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -49,6 +53,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -71,6 +79,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -93,6 +105,10 @@ "type": "barchart" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v30.value_mappings_and_tooltip_options.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v30.value_mappings_and_tooltip_options.v0alpha1.json index e6ec721a7f3..a7847652883 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v30.value_mappings_and_tooltip_options.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v30.value_mappings_and_tooltip_options.v0alpha1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "fieldConfig": { "defaults": { "mappings": [ @@ -125,6 +129,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -151,6 +159,10 @@ "type": "xychart" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -178,6 +190,10 @@ "type": "xychart2" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -204,6 +220,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "fieldConfig": { "defaults": { "mappings": [ @@ -305,6 +325,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "fieldConfig": { "defaults": { "unit": "bytes" @@ -337,6 +361,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "fieldConfig": { "overrides": [ { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v30.value_mappings_and_tooltip_options.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v30.value_mappings_and_tooltip_options.v1beta1.json index 240ee83acfe..21fb00e8845 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v30.value_mappings_and_tooltip_options.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v30.value_mappings_and_tooltip_options.v1beta1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "fieldConfig": { "defaults": { "mappings": [ @@ -125,6 +129,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -151,6 +159,10 @@ "type": "xychart" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -178,6 +190,10 @@ "type": "xychart2" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -204,6 +220,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "fieldConfig": { "defaults": { "mappings": [ @@ -305,6 +325,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "fieldConfig": { "defaults": { "unit": "bytes" @@ -337,6 +361,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "fieldConfig": { "overrides": [ { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v31.labels_to_fields_merge.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v31.labels_to_fields_merge.v0alpha1.json index b3261291c34..00817bd05b6 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v31.labels_to_fields_merge.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v31.labels_to_fields_merge.v0alpha1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -59,6 +63,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -99,6 +107,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -149,6 +161,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -171,6 +187,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -259,6 +279,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v31.labels_to_fields_merge.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v31.labels_to_fields_merge.v1beta1.json index 74ddec4f78c..6f3fb009a55 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v31.labels_to_fields_merge.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v31.labels_to_fields_merge.v1beta1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -59,6 +63,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -99,6 +107,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -149,6 +161,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -171,6 +187,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -259,6 +279,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v32.no_op_migration.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v32.no_op_migration.v0alpha1.json index bde81f8e5b9..3389666f1ef 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v32.no_op_migration.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v32.no_op_migration.v0alpha1.json @@ -33,6 +33,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -71,6 +75,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v32.no_op_migration.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v32.no_op_migration.v1beta1.json index 18aee40e8eb..ecf3f1bbd52 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v32.no_op_migration.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v32.no_op_migration.v1beta1.json @@ -33,6 +33,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -71,6 +75,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v33.panel_ds_name_to_ref.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v33.panel_ds_name_to_ref.v0alpha1.json index a860cf2dd06..142d01d9ffb 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v33.panel_ds_name_to_ref.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v33.panel_ds_name_to_ref.v0alpha1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "loki", + "uid": "non-default-test-ds-uid" + }, "description": "Tests v33 migration behavior when panel datasource is explicitly null. Should remain null after migration (returnDefaultAsNull: true).", "gridPos": { "h": 3, @@ -51,6 +55,10 @@ "type": "stat" }, { + "datasource": { + "type": "elasticsearch", + "uid": "existing-target-uid" + }, "description": "Tests v33 migration behavior when panel datasource is already a proper object reference. Should remain unchanged.", "gridPos": { "h": 3, @@ -75,6 +83,10 @@ "type": "stat" }, { + "datasource": { + "type": "loki", + "uid": "non-default-test-ds-uid" + }, "description": "Tests v33 migration when panel datasource is a string name. Should convert to proper object with uid, type, apiVersion.", "gridPos": { "h": 3, @@ -98,6 +110,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests v33 migration when panel has datasource string but empty targets array. Panel datasource should still migrate.", "gridPos": { "h": 3, @@ -283,6 +299,10 @@ "id": -1, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Nested panel with string datasource should migrate to proper object reference, proving row panel recursion works.", "gridPos": { "h": 3, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v33.panel_ds_name_to_ref.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v33.panel_ds_name_to_ref.v1beta1.json index 36b1c55fb41..d9af9bca3d7 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v33.panel_ds_name_to_ref.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v33.panel_ds_name_to_ref.v1beta1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "loki", + "uid": "non-default-test-ds-uid" + }, "description": "Tests v33 migration behavior when panel datasource is explicitly null. Should remain null after migration (returnDefaultAsNull: true).", "gridPos": { "h": 3, @@ -51,6 +55,10 @@ "type": "stat" }, { + "datasource": { + "type": "elasticsearch", + "uid": "existing-target-uid" + }, "description": "Tests v33 migration behavior when panel datasource is already a proper object reference. Should remain unchanged.", "gridPos": { "h": 3, @@ -75,6 +83,10 @@ "type": "stat" }, { + "datasource": { + "type": "loki", + "uid": "non-default-test-ds-uid" + }, "description": "Tests v33 migration when panel datasource is a string name. Should convert to proper object with uid, type, apiVersion.", "gridPos": { "h": 3, @@ -98,6 +110,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests v33 migration when panel has datasource string but empty targets array. Panel datasource should still migrate.", "gridPos": { "h": 3, @@ -283,6 +299,10 @@ "id": -1, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Nested panel with string datasource should migrate to proper object reference, proving row panel recursion works.", "gridPos": { "h": 3, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v34.multiple_stats_cloudwatch.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v34.multiple_stats_cloudwatch.v0alpha1.json index af5a9eb4fb2..7755aa29cf7 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v34.multiple_stats_cloudwatch.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v34.multiple_stats_cloudwatch.v0alpha1.json @@ -289,6 +289,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -355,6 +359,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -386,6 +394,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -492,6 +504,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -522,6 +538,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -626,6 +646,10 @@ "id": -1, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -689,6 +713,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -738,6 +766,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -769,6 +801,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -818,6 +854,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -849,6 +889,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -927,6 +971,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -1006,6 +1054,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v34.multiple_stats_cloudwatch.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v34.multiple_stats_cloudwatch.v1beta1.json index 8a6009228aa..1568231f000 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v34.multiple_stats_cloudwatch.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v34.multiple_stats_cloudwatch.v1beta1.json @@ -289,6 +289,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -355,6 +359,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -386,6 +394,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -492,6 +504,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -522,6 +538,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -626,6 +646,10 @@ "id": -1, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -689,6 +713,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -738,6 +766,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -769,6 +801,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -818,6 +854,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -849,6 +889,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -927,6 +971,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -1006,6 +1054,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v35.ensure_x_axis_visibility.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v35.ensure_x_axis_visibility.v0alpha1.json index 83e0d94fd78..9aef1000c89 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v35.ensure_x_axis_visibility.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v35.ensure_x_axis_visibility.v0alpha1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "fieldConfig": { "defaults": { "custom": { @@ -70,6 +74,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "fieldConfig": { "defaults": { "custom": { @@ -125,6 +133,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "fieldConfig": { "defaults": { "custom": { @@ -154,6 +166,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "fieldConfig": { "defaults": { "custom": { @@ -183,6 +199,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -205,6 +225,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -227,6 +251,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "fieldConfig": { "defaults": { "unit": "bytes" @@ -254,6 +282,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "fieldConfig": { "defaults": { "custom": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v35.ensure_x_axis_visibility.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v35.ensure_x_axis_visibility.v1beta1.json index 59a03171c59..5b383957bd3 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v35.ensure_x_axis_visibility.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v35.ensure_x_axis_visibility.v1beta1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "fieldConfig": { "defaults": { "custom": { @@ -70,6 +74,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "fieldConfig": { "defaults": { "custom": { @@ -125,6 +133,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "fieldConfig": { "defaults": { "custom": { @@ -154,6 +166,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "fieldConfig": { "defaults": { "custom": { @@ -183,6 +199,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -205,6 +225,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -227,6 +251,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "fieldConfig": { "defaults": { "unit": "bytes" @@ -254,6 +282,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "fieldConfig": { "defaults": { "custom": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v36.ds_name_to_ref.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v36.ds_name_to_ref.v0alpha1.json index 6cfba3afdaf..4678a84253d 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v36.ds_name_to_ref.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v36.ds_name_to_ref.v0alpha1.json @@ -77,6 +77,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests null panel datasource migration with targets - should fallback to default", "gridPos": { "h": 3, @@ -100,6 +104,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests null panel datasource with empty targets array - should create default target", "gridPos": { "h": 3, @@ -123,6 +131,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests null panel datasource with missing targets - should create default target array", "gridPos": { "h": 3, @@ -180,6 +192,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "elasticsearch", + "uid": "existing-target-uid" + }, "description": "Tests panel with already migrated datasource object - should preserve existing refs", "gridPos": { "h": 3, @@ -203,6 +219,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "unknown-target-datasource" + }, "description": "Tests panel with unknown datasource - should preserve as UID-only reference", "gridPos": { "h": 3, @@ -260,6 +280,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "elasticsearch", + "uid": "existing-target-uid" + }, "description": "Tests panel inheriting datasource from target when panel datasource was default", "gridPos": { "h": 3, @@ -283,6 +307,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "elasticsearch", + "uid": "existing-target-uid" + }, "description": "Tests panel with datasource referenced by name - should migrate to full object", "gridPos": { "h": 3, @@ -306,6 +334,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "elasticsearch", + "uid": "existing-target-uid" + }, "description": "Tests panel with datasource referenced by UID - should migrate to full object", "gridPos": { "h": 3, @@ -345,6 +377,10 @@ "id": -1, "panels": [ { + "datasource": { + "type": "elasticsearch", + "uid": "existing-target-uid" + }, "description": "Nested panel in collapsed row with default datasource", "gridPos": { "h": 3, @@ -368,6 +404,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "elasticsearch", + "uid": "existing-target-uid" + }, "description": "Nested panel in collapsed row with unknown datasource", "gridPos": { "h": 3, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v36.ds_name_to_ref.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v36.ds_name_to_ref.v1beta1.json index 535ea1447f0..a1b5270382b 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v36.ds_name_to_ref.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v36.ds_name_to_ref.v1beta1.json @@ -77,6 +77,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests null panel datasource migration with targets - should fallback to default", "gridPos": { "h": 3, @@ -100,6 +104,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests null panel datasource with empty targets array - should create default target", "gridPos": { "h": 3, @@ -123,6 +131,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "description": "Tests null panel datasource with missing targets - should create default target array", "gridPos": { "h": 3, @@ -180,6 +192,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "elasticsearch", + "uid": "existing-target-uid" + }, "description": "Tests panel with already migrated datasource object - should preserve existing refs", "gridPos": { "h": 3, @@ -203,6 +219,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "unknown-target-datasource" + }, "description": "Tests panel with unknown datasource - should preserve as UID-only reference", "gridPos": { "h": 3, @@ -260,6 +280,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "elasticsearch", + "uid": "existing-target-uid" + }, "description": "Tests panel inheriting datasource from target when panel datasource was default", "gridPos": { "h": 3, @@ -283,6 +307,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "elasticsearch", + "uid": "existing-target-uid" + }, "description": "Tests panel with datasource referenced by name - should migrate to full object", "gridPos": { "h": 3, @@ -306,6 +334,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "elasticsearch", + "uid": "existing-target-uid" + }, "description": "Tests panel with datasource referenced by UID - should migrate to full object", "gridPos": { "h": 3, @@ -345,6 +377,10 @@ "id": -1, "panels": [ { + "datasource": { + "type": "elasticsearch", + "uid": "existing-target-uid" + }, "description": "Nested panel in collapsed row with default datasource", "gridPos": { "h": 3, @@ -368,6 +404,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "elasticsearch", + "uid": "existing-target-uid" + }, "description": "Nested panel in collapsed row with unknown datasource", "gridPos": { "h": 3, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v4.no-op.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v4.no-op.v0alpha1.json index 5daafe44636..5be318447ec 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v4.no-op.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v4.no-op.v0alpha1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -49,6 +53,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -71,6 +79,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v4.no-op.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v4.no-op.v1beta1.json index e5b057639fb..8e1436e850a 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v4.no-op.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v4.no-op.v1beta1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -49,6 +53,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -71,6 +79,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v5.no-op.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v5.no-op.v0alpha1.json index 4872dd21894..07538e41a8f 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v5.no-op.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v5.no-op.v0alpha1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -49,6 +53,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -71,6 +79,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v5.no-op.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v5.no-op.v1beta1.json index aeb12a936e1..88148baa546 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v5.no-op.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v5.no-op.v1beta1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -49,6 +53,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -71,6 +79,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v6.pulldowns_and_templating.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v6.pulldowns_and_templating.v0alpha1.json index 7f61b3e7b90..5cdc2d5e424 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v6.pulldowns_and_templating.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v6.pulldowns_and_templating.v0alpha1.json @@ -49,6 +49,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 8, "w": 12, @@ -72,6 +76,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 8, "w": 12, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v6.pulldowns_and_templating.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v6.pulldowns_and_templating.v1beta1.json index cb826c382bd..558e765f719 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v6.pulldowns_and_templating.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v6.pulldowns_and_templating.v1beta1.json @@ -49,6 +49,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 8, "w": 12, @@ -72,6 +76,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 8, "w": 12, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v7.timepicker.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v7.timepicker.v0alpha1.json index 100c239dc08..db8c34264b4 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v7.timepicker.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v7.timepicker.v0alpha1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v7.timepicker.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v7.timepicker.v1beta1.json index 2a2541d7861..18283a762cb 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v7.timepicker.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v7.timepicker.v1beta1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v9.no-op.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v9.no-op.v0alpha1.json index 3f575f7f5fc..8ffe55cd0d9 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v9.no-op.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v9.no-op.v0alpha1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -49,6 +53,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -71,6 +79,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v9.no-op.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v9.no-op.v1beta1.json index fd2231c5509..d2ea95d4a03 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v9.no-op.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dashboards_from_v0_to_v2/v2beta1.v9.no-op.v1beta1.json @@ -27,6 +27,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -49,6 +53,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, @@ -71,6 +79,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "default-ds-uid" + }, "gridPos": { "h": 3, "w": 6, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/annotations/v0alpha1.multi-lane-annotations.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/annotations/v0alpha1.multi-lane-annotations.v42.v2alpha1.json index b6addcc81ed..d6f207c6fdd 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/annotations/v0alpha1.multi-lane-annotations.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/annotations/v0alpha1.multi-lane-annotations.v42.v2alpha1.json @@ -970,8 +970,7 @@ "le": 1e-9 }, "legend": { - "show": true, - "showLegend": true + "show": true }, "rowsFrame": { "layout": "auto" @@ -1064,8 +1063,7 @@ "le": 1e-9 }, "legend": { - "show": true, - "showLegend": true + "show": true }, "rowsFrame": { "layout": "auto" diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/annotations/v0alpha1.multi-lane-annotations.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/annotations/v0alpha1.multi-lane-annotations.v42.v2beta1.json index f806e27a98f..c7ef28fa2b8 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/annotations/v0alpha1.multi-lane-annotations.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/annotations/v0alpha1.multi-lane-annotations.v42.v2beta1.json @@ -991,8 +991,7 @@ "le": 1e-9 }, "legend": { - "show": true, - "showLegend": true + "show": true }, "rowsFrame": { "layout": "auto" @@ -1087,8 +1086,7 @@ "le": 1e-9 }, "legend": { - "show": true, - "showLegend": true + "show": true }, "rowsFrame": { "layout": "auto" diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-loki/v0alpha1.loki_query_splitting.v42.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-loki/v0alpha1.loki_query_splitting.v42.v1beta1.json index aed8292522f..3cb966ba891 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-loki/v0alpha1.loki_query_splitting.v42.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-loki/v0alpha1.loki_query_splitting.v42.v1beta1.json @@ -225,8 +225,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -318,8 +317,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -498,8 +496,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -590,8 +587,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -682,8 +678,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -797,8 +792,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -912,8 +906,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -1028,8 +1021,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "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 89857905689..4d208a1d8dc 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 @@ -120,7 +120,7 @@ "value": [ { "title": "filter", - "url": "http://localhost:3000/d/-Y-tnEDWk/templating-nested-template-variables?var-datacenter=${__data.fields[datacenter]}\u0026var-server=${__value.raw}" + "url": "http://localhost:3000/d/-Y-tnEDWk/templating-nested-template-variables?var-datacenter=${__data.fields[datacenter]}\u0026var-server=${__value.raw}" } ] } @@ -467,7 +467,8 @@ "title": "Go to drilldown", "url": "/d/O6GmNPvWk/dashboard-tests-nested-template-variables-drilldown?orgId=1\u0026${__all_variables}\u0026${__url_time_range}" } - ] + ], + "nullValueMode": "connected" }, "overrides": [] } @@ -550,7 +551,8 @@ "title": "Go to drilldown", "url": "/d/O6GmNPvWk/dashboard-tests-nested-template-variables-drilldown?orgId=1\u0026${__all_variables}\u0026${__url_time_range}" } - ] + ], + "nullValueMode": "connected" }, "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 13320b47904..5165f97554d 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 @@ -124,7 +124,7 @@ "value": [ { "title": "filter", - "url": "http://localhost:3000/d/-Y-tnEDWk/templating-nested-template-variables?var-datacenter=${__data.fields[datacenter]}\u0026var-server=${__value.raw}" + "url": "http://localhost:3000/d/-Y-tnEDWk/templating-nested-template-variables?var-datacenter=${__data.fields[datacenter]}\u0026var-server=${__value.raw}" } ] } @@ -481,7 +481,8 @@ "title": "Go to drilldown", "url": "/d/O6GmNPvWk/dashboard-tests-nested-template-variables-drilldown?orgId=1\u0026${__all_variables}\u0026${__url_time_range}" } - ] + ], + "nullValueMode": "connected" }, "overrides": [] } @@ -566,7 +567,8 @@ "title": "Go to drilldown", "url": "/d/O6GmNPvWk/dashboard-tests-nested-template-variables-drilldown?orgId=1\u0026${__all_variables}\u0026${__url_time_range}" } - ] + ], + "nullValueMode": "connected" }, "overrides": [] } diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests_new.v42.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests_new.v42.v1beta1.json index e04d448a5b8..66ce1cd0f3a 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests_new.v42.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests_new.v42.v1beta1.json @@ -2051,4 +2051,4 @@ "storedVersion": "v0alpha1" } } -} +} \ No newline at end of file diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests_new.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests_new.v42.v2alpha1.json index 0e6e3e13da5..95850646c59 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests_new.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests_new.v42.v2alpha1.json @@ -2691,4 +2691,4 @@ "storedVersion": "v0alpha1" } } -} +} \ No newline at end of file diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests_new.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests_new.v42.v2beta1.json index ad2b8ca0385..fda0d31e71b 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests_new.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests_new.v42.v2beta1.json @@ -2764,4 +2764,4 @@ "storedVersion": "v0alpha1" } } -} +} \ No newline at end of file diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests_old_to_new.v42.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests_old_to_new.v42.v1beta1.json index 1d9f7e56513..2dddd657c5f 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests_old_to_new.v42.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests_old_to_new.v42.v1beta1.json @@ -1173,4 +1173,4 @@ "storedVersion": "v0alpha1" } } -} +} \ No newline at end of file diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests_old_to_new.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests_old_to_new.v42.v2alpha1.json index 7b3f601b5cf..db19ac588c1 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests_old_to_new.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests_old_to_new.v42.v2alpha1.json @@ -1618,4 +1618,4 @@ "storedVersion": "v0alpha1" } } -} +} \ No newline at end of file diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests_old_to_new.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests_old_to_new.v42.v2beta1.json index 534e7a1600c..8ddc6feb297 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests_old_to_new.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests_old_to_new.v42.v2beta1.json @@ -1670,4 +1670,4 @@ "storedVersion": "v0alpha1" } } -} +} \ No newline at end of file diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-heatmap/v0alpha1.heatmap-x.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-heatmap/v0alpha1.heatmap-x.v42.v2alpha1.json index 2eb67e36f2f..a1b9c4b230a 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-heatmap/v0alpha1.heatmap-x.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-heatmap/v0alpha1.heatmap-x.v42.v2alpha1.json @@ -169,8 +169,7 @@ "le": 1e-9 }, "legend": { - "show": true, - "showLegend": true + "show": true }, "rowsFrame": { "layout": "auto" @@ -336,8 +335,7 @@ "le": 1e-9 }, "legend": { - "show": true, - "showLegend": true + "show": true }, "rowsFrame": { "layout": "auto" @@ -408,8 +406,7 @@ "le": 1e-9 }, "legend": { - "show": true, - "showLegend": true + "show": true }, "rowsFrame": { "layout": "auto" diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-heatmap/v0alpha1.heatmap-x.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-heatmap/v0alpha1.heatmap-x.v42.v2beta1.json index acba4cedbc2..2428d6fd107 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-heatmap/v0alpha1.heatmap-x.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-heatmap/v0alpha1.heatmap-x.v42.v2beta1.json @@ -175,8 +175,7 @@ "le": 1e-9 }, "legend": { - "show": true, - "showLegend": true + "show": true }, "rowsFrame": { "layout": "auto" @@ -347,8 +346,7 @@ "le": 1e-9 }, "legend": { - "show": true, - "showLegend": true + "show": true }, "rowsFrame": { "layout": "auto" @@ -420,8 +418,7 @@ "le": 1e-9 }, "legend": { - "show": true, - "showLegend": true + "show": true }, "rowsFrame": { "layout": "auto" diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-histogram/v0alpha1.histogram_tests.v42.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-histogram/v0alpha1.histogram_tests.v42.v1beta1.json index b65608bc758..c3435f0f17d 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-histogram/v0alpha1.histogram_tests.v42.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-histogram/v0alpha1.histogram_tests.v42.v1beta1.json @@ -64,8 +64,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -133,8 +132,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -202,8 +200,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -283,8 +280,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -361,8 +357,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -454,8 +449,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -542,8 +536,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [ { @@ -625,8 +618,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [ { @@ -708,8 +700,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [ { @@ -791,8 +782,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -856,8 +846,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [ { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-histogram/v0alpha1.histogram_tests.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-histogram/v0alpha1.histogram_tests.v42.v2alpha1.json index 57fbcad9d99..ec5c52a7119 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-histogram/v0alpha1.histogram_tests.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-histogram/v0alpha1.histogram_tests.v42.v2alpha1.json @@ -882,6 +882,7 @@ "kind": "filterFieldsByName", "spec": { "id": "filterFieldsByName", + "disabled": true, "options": { "include": { "names": [ @@ -895,6 +896,7 @@ "kind": "histogram", "spec": { "id": "histogram", + "disabled": true, "options": { "combine": true, "fields": {} diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-histogram/v0alpha1.histogram_tests.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-histogram/v0alpha1.histogram_tests.v42.v2beta1.json index 5b2ee8d8df2..3ff41469dbc 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-histogram/v0alpha1.histogram_tests.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-histogram/v0alpha1.histogram_tests.v42.v2beta1.json @@ -911,6 +911,7 @@ "kind": "filterFieldsByName", "spec": { "id": "filterFieldsByName", + "disabled": true, "options": { "include": { "names": [ @@ -924,6 +925,7 @@ "kind": "histogram", "spec": { "id": "histogram", + "disabled": true, "options": { "combine": true, "fields": {} diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-status-history/v0alpha1.status-history-thresholds-mappings.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-status-history/v0alpha1.status-history-thresholds-mappings.v42.v2alpha1.json index d90c8dc52cd..b9ba0b13da4 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-status-history/v0alpha1.status-history-thresholds-mappings.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-status-history/v0alpha1.status-history-thresholds-mappings.v42.v2alpha1.json @@ -222,7 +222,8 @@ "insertNulls": false, "lineWidth": 0, "spanNulls": false - } + }, + "fieldMinMax": false }, "overrides": [] } @@ -318,7 +319,8 @@ "insertNulls": false, "lineWidth": 0, "spanNulls": false - } + }, + "fieldMinMax": false }, "overrides": [] } @@ -424,7 +426,8 @@ "insertNulls": false, "lineWidth": 0, "spanNulls": false - } + }, + "fieldMinMax": false }, "overrides": [] } @@ -507,7 +510,8 @@ "insertNulls": false, "lineWidth": 0, "spanNulls": false - } + }, + "fieldMinMax": false }, "overrides": [] } diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-status-history/v0alpha1.status-history-thresholds-mappings.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-status-history/v0alpha1.status-history-thresholds-mappings.v42.v2beta1.json index 7aaa0fff33a..e130fc7e172 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-status-history/v0alpha1.status-history-thresholds-mappings.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-status-history/v0alpha1.status-history-thresholds-mappings.v42.v2beta1.json @@ -229,7 +229,8 @@ "insertNulls": false, "lineWidth": 0, "spanNulls": false - } + }, + "fieldMinMax": false }, "overrides": [] } @@ -328,7 +329,8 @@ "insertNulls": false, "lineWidth": 0, "spanNulls": false - } + }, + "fieldMinMax": false }, "overrides": [] } @@ -437,7 +439,8 @@ "insertNulls": false, "lineWidth": 0, "spanNulls": false - } + }, + "fieldMinMax": false }, "overrides": [] } @@ -523,7 +526,8 @@ "insertNulls": false, "lineWidth": 0, "spanNulls": false - } + }, + "fieldMinMax": false }, "overrides": [] } diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_footer.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_footer.v42.v2alpha1.json index 540f0d9e54d..9d15475c82d 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_footer.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_footer.v42.v2alpha1.json @@ -167,7 +167,8 @@ }, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -361,7 +362,8 @@ }, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -596,7 +598,8 @@ }, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -787,7 +790,8 @@ }, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -974,7 +978,8 @@ }, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -1181,7 +1186,8 @@ }, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -1384,7 +1390,8 @@ }, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -1573,7 +1580,8 @@ }, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_footer.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_footer.v42.v2beta1.json index 6c9aa023163..3965312c00a 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_footer.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_footer.v42.v2beta1.json @@ -173,7 +173,8 @@ }, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -372,7 +373,8 @@ }, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -612,7 +614,8 @@ }, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -808,7 +811,8 @@ }, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -1000,7 +1004,8 @@ }, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -1212,7 +1217,8 @@ }, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -1420,7 +1426,8 @@ }, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -1614,7 +1621,8 @@ }, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_kitchen_sink.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_kitchen_sink.v42.v2alpha1.json index bccce10d162..f342cab8373 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_kitchen_sink.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_kitchen_sink.v42.v2alpha1.json @@ -194,7 +194,8 @@ "filterable": true, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -1190,7 +1191,8 @@ "reducer": [] }, "inspect": true - } + }, + "fieldMinMax": true }, "overrides": [] } @@ -1262,7 +1264,8 @@ "type": "auto" }, "inspect": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -1418,7 +1421,8 @@ "type": "auto" }, "inspect": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -1575,7 +1579,8 @@ "type": "auto" }, "inspect": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -1737,7 +1742,8 @@ "type": "auto" }, "inspect": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -1888,7 +1894,8 @@ "type": "auto" }, "inspect": false - } + }, + "fieldMinMax": true }, "overrides": [ { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_kitchen_sink.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_kitchen_sink.v42.v2beta1.json index 5e186ef1443..59f9b3d7942 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_kitchen_sink.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_kitchen_sink.v42.v2beta1.json @@ -200,7 +200,8 @@ "filterable": true, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -1208,7 +1209,8 @@ "reducer": [] }, "inspect": true - } + }, + "fieldMinMax": true }, "overrides": [] } @@ -1283,7 +1285,8 @@ "type": "auto" }, "inspect": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -1442,7 +1445,8 @@ "type": "auto" }, "inspect": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -1602,7 +1606,8 @@ "type": "auto" }, "inspect": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -1767,7 +1772,8 @@ "type": "auto" }, "inspect": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -1921,7 +1927,8 @@ "type": "auto" }, "inspect": false - } + }, + "fieldMinMax": true }, "overrides": [ { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_sparkline_cell.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_sparkline_cell.v42.v2alpha1.json index e5e260fd150..92729fdddcb 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_sparkline_cell.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_sparkline_cell.v42.v2alpha1.json @@ -302,6 +302,23 @@ "url": "https://google.com/search?q=grafana" } ], + "actions": [ + { + "type": "fetch", + "title": "Get instance health", + "fetch": { + "method": "GET", + "url": "/api/health", + "body": "{}", + "headers": [ + [ + "Content-Type", + "application/json" + ] + ] + } + } + ], "custom": { "align": "auto", "cellOptions": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_sparkline_cell.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_sparkline_cell.v42.v2beta1.json index ac15a298939..5246af0a06b 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_sparkline_cell.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_sparkline_cell.v42.v2beta1.json @@ -312,6 +312,23 @@ "url": "https://google.com/search?q=grafana" } ], + "actions": [ + { + "type": "fetch", + "title": "Get instance health", + "fetch": { + "method": "GET", + "url": "/api/health", + "body": "{}", + "headers": [ + [ + "Content-Type", + "application/json" + ] + ] + } + } + ], "custom": { "align": "auto", "cellOptions": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_v12_2_migrations.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_v12_2_migrations.v42.v2alpha1.json index 1b6348c35d5..d6451b5d80f 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_v12_2_migrations.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_v12_2_migrations.v42.v2alpha1.json @@ -206,7 +206,8 @@ }, "filterable": true, "inspect": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -753,7 +754,8 @@ }, "filterable": true, "inspect": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -1303,7 +1305,8 @@ "filterable": true, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -1497,7 +1500,8 @@ "filterable": true, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -1692,7 +1696,8 @@ "filterable": true, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -1886,7 +1891,8 @@ "filterable": true, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -2081,7 +2087,8 @@ "filterable": true, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -2276,7 +2283,8 @@ "filterable": true, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_v12_2_migrations.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_v12_2_migrations.v42.v2beta1.json index a77140c5beb..75353a995ac 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_v12_2_migrations.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_v12_2_migrations.v42.v2beta1.json @@ -212,7 +212,8 @@ }, "filterable": true, "inspect": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -764,7 +765,8 @@ }, "filterable": true, "inspect": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -1319,7 +1321,8 @@ "filterable": true, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -1518,7 +1521,8 @@ "filterable": true, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -1718,7 +1722,8 @@ "filterable": true, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -1917,7 +1922,8 @@ "filterable": true, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -2117,7 +2123,8 @@ "filterable": true, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { @@ -2317,7 +2324,8 @@ "filterable": true, "inspect": false, "wrapText": false - } + }, + "fieldMinMax": true }, "overrides": [ { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeline/v0alpha1.timeline-thresholds-mappings.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeline/v0alpha1.timeline-thresholds-mappings.v42.v2alpha1.json index 8dff3c34ccf..3366490c00a 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeline/v0alpha1.timeline-thresholds-mappings.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeline/v0alpha1.timeline-thresholds-mappings.v42.v2alpha1.json @@ -222,7 +222,8 @@ "insertNulls": false, "lineWidth": 0, "spanNulls": false - } + }, + "fieldMinMax": false }, "overrides": [] } @@ -318,7 +319,8 @@ "insertNulls": false, "lineWidth": 0, "spanNulls": false - } + }, + "fieldMinMax": false }, "overrides": [] } @@ -424,7 +426,8 @@ "insertNulls": false, "lineWidth": 0, "spanNulls": false - } + }, + "fieldMinMax": false }, "overrides": [] } @@ -507,7 +510,8 @@ "insertNulls": false, "lineWidth": 0, "spanNulls": false - } + }, + "fieldMinMax": false }, "overrides": [] } diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeline/v0alpha1.timeline-thresholds-mappings.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeline/v0alpha1.timeline-thresholds-mappings.v42.v2beta1.json index 3baa3d21130..59d2e929972 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeline/v0alpha1.timeline-thresholds-mappings.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeline/v0alpha1.timeline-thresholds-mappings.v42.v2beta1.json @@ -229,7 +229,8 @@ "insertNulls": false, "lineWidth": 0, "spanNulls": false - } + }, + "fieldMinMax": false }, "overrides": [] } @@ -328,7 +329,8 @@ "insertNulls": false, "lineWidth": 0, "spanNulls": false - } + }, + "fieldMinMax": false }, "overrides": [] } @@ -437,7 +439,8 @@ "insertNulls": false, "lineWidth": 0, "spanNulls": false - } + }, + "fieldMinMax": false }, "overrides": [] } @@ -523,7 +526,8 @@ "insertNulls": false, "lineWidth": 0, "spanNulls": false - } + }, + "fieldMinMax": false }, "overrides": [] } diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-gradient-area.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-gradient-area.v42.v2alpha1.json index 5b43876c65f..bde73320d42 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-gradient-area.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-gradient-area.v42.v2alpha1.json @@ -110,7 +110,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { @@ -217,7 +218,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { @@ -324,7 +326,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { @@ -431,7 +434,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { @@ -537,7 +541,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { @@ -643,7 +648,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-gradient-area.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-gradient-area.v42.v2beta1.json index ca96f9d5720..06331f32233 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-gradient-area.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-gradient-area.v42.v2beta1.json @@ -114,7 +114,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { @@ -223,7 +224,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { @@ -332,7 +334,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { @@ -441,7 +444,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { @@ -549,7 +553,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { @@ -657,7 +662,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-hue-gradients.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-hue-gradients.v42.v2alpha1.json index 74cba148009..c4bb5720d36 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-hue-gradients.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-hue-gradients.v42.v2alpha1.json @@ -116,7 +116,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { @@ -229,7 +230,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { @@ -342,7 +344,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { @@ -455,7 +458,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { @@ -568,7 +572,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { @@ -681,7 +686,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { @@ -794,7 +800,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { @@ -907,7 +914,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { @@ -1020,7 +1028,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-hue-gradients.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-hue-gradients.v42.v2beta1.json index 7e64bc79ef3..7c18be27f07 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-hue-gradients.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-hue-gradients.v42.v2beta1.json @@ -120,7 +120,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { @@ -235,7 +236,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { @@ -350,7 +352,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { @@ -465,7 +468,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { @@ -580,7 +584,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { @@ -695,7 +700,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { @@ -810,7 +816,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { @@ -925,7 +932,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { @@ -1040,7 +1048,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries.v42.v2alpha1.json index e50b453076a..cb63e4f234d 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries.v42.v2alpha1.json @@ -3607,7 +3607,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { @@ -3740,7 +3741,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries.v42.v2beta1.json index 65105663c85..a57e430cc63 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries.v42.v2beta1.json @@ -3674,7 +3674,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { @@ -3809,7 +3810,8 @@ }, "showPoints": "never", "spanNulls": true - } + }, + "nullValueMode": "null" }, "overrides": [ { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-xychart/v0alpha1.xychart-tooltip-color-test.v42.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-xychart/v0alpha1.xychart-tooltip-color-test.v42.v1beta1.json index cdc93bf3cfa..1b7c9effbe8 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-xychart/v0alpha1.xychart-tooltip-color-test.v42.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-xychart/v0alpha1.xychart-tooltip-color-test.v42.v1beta1.json @@ -67,8 +67,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -154,8 +153,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -241,8 +239,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -328,8 +325,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -422,8 +418,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -516,8 +511,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -610,8 +604,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-xychart/v0alpha1.xychart-tooltip-color-test.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-xychart/v0alpha1.xychart-tooltip-color-test.v42.v2alpha1.json index 1d60f0ef9bf..861c4b41a6c 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-xychart/v0alpha1.xychart-tooltip-color-test.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-xychart/v0alpha1.xychart-tooltip-color-test.v42.v2alpha1.json @@ -124,7 +124,8 @@ "type": "linear" }, "show": "points" - } + }, + "fieldMinMax": false }, "overrides": [] } @@ -225,7 +226,8 @@ "type": "linear" }, "show": "points" - } + }, + "fieldMinMax": false }, "overrides": [] } @@ -326,7 +328,8 @@ "type": "linear" }, "show": "points" - } + }, + "fieldMinMax": false }, "overrides": [] } @@ -434,7 +437,8 @@ "type": "linear" }, "show": "points" - } + }, + "fieldMinMax": false }, "overrides": [] } @@ -542,7 +546,8 @@ "type": "linear" }, "show": "points" - } + }, + "fieldMinMax": false }, "overrides": [] } @@ -650,7 +655,8 @@ "type": "linear" }, "show": "points" - } + }, + "fieldMinMax": false }, "overrides": [] } diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-xychart/v0alpha1.xychart-tooltip-color-test.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-xychart/v0alpha1.xychart-tooltip-color-test.v42.v2beta1.json index 5a46646474d..0ae6dc172bd 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-xychart/v0alpha1.xychart-tooltip-color-test.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-xychart/v0alpha1.xychart-tooltip-color-test.v42.v2beta1.json @@ -128,7 +128,8 @@ "type": "linear" }, "show": "points" - } + }, + "fieldMinMax": false }, "overrides": [] } @@ -232,7 +233,8 @@ "type": "linear" }, "show": "points" - } + }, + "fieldMinMax": false }, "overrides": [] } @@ -336,7 +338,8 @@ "type": "linear" }, "show": "points" - } + }, + "fieldMinMax": false }, "overrides": [] } @@ -447,7 +450,8 @@ "type": "linear" }, "show": "points" - } + }, + "fieldMinMax": false }, "overrides": [] } @@ -558,7 +562,8 @@ "type": "linear" }, "show": "points" - } + }, + "fieldMinMax": false }, "overrides": [] } @@ -669,7 +674,8 @@ "type": "linear" }, "show": "points" - } + }, + "fieldMinMax": false }, "overrides": [] } diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/transforms/v0alpha1.filter.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/transforms/v0alpha1.filter.v42.v2alpha1.json index 056fdc62383..dd3ba7146e5 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/transforms/v0alpha1.filter.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/transforms/v0alpha1.filter.v42.v2alpha1.json @@ -81,6 +81,10 @@ "kind": "reduce", "spec": { "id": "reduce", + "filter": { + "id": "byRefId", + "options": "A" + }, "options": { "includeTimeField": false, "mode": "reduceFields", @@ -94,6 +98,10 @@ "kind": "reduce", "spec": { "id": "reduce", + "filter": { + "id": "byRefId", + "options": "B" + }, "options": { "includeTimeField": false, "mode": "reduceFields", diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/transforms/v0alpha1.filter.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/transforms/v0alpha1.filter.v42.v2beta1.json index 57c5559add1..0f4ab69c96a 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/transforms/v0alpha1.filter.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/transforms/v0alpha1.filter.v42.v2beta1.json @@ -86,6 +86,10 @@ "kind": "reduce", "spec": { "id": "reduce", + "filter": { + "id": "byRefId", + "options": "A" + }, "options": { "includeTimeField": false, "mode": "reduceFields", @@ -99,6 +103,10 @@ "kind": "reduce", "spec": { "id": "reduce", + "filter": { + "id": "byRefId", + "options": "B" + }, "options": { "includeTimeField": false, "mode": "reduceFields", diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.bom-in-links.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.bom-in-links.v0alpha1.json new file mode 100644 index 00000000000..449e76f1173 --- /dev/null +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.bom-in-links.v0alpha1.json @@ -0,0 +1,161 @@ +{ + "kind": "Dashboard", + "apiVersion": "dashboard.grafana.app/v0alpha1", + "metadata": { + "name": "bom-in-links-test", + "namespace": "org-1", + "labels": { + "test": "bom-stripping" + } + }, + "spec": { + "description": "Testing that BOM characters are stripped from URLs during conversion", + "editable": true, + "links": [ + { + "icon": "external link", + "targetBlank": true, + "title": "Dashboard link with BOM", + "type": "link", + "url": "http://example.com?var=${datasource}\u0026other=value" + } + ], + "panels": [ + { + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "server" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "title": "Override link with BOM", + "url": "http://localhost:3000/d/test?var-datacenter=${__data.fields[datacenter]}\u0026var-server=${__value.raw}" + } + ] + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 1, + "links": [ + { + "targetBlank": true, + "title": "Panel data link with BOM", + "url": "http://example.com/${__data.fields.cluster}\u0026var=value" + } + ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "test-ds" + }, + "refId": "A" + } + ], + "title": "Panel with BOM in field config override links", + "type": "table" + }, + { + "fieldConfig": { + "defaults": { + "links": [ + { + "targetBlank": false, + "title": "Field config default link with BOM", + "url": "http://example.com?field=${__field.name}\u0026value=${__value.raw}" + } + ] + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 2, + "options": { + "dataLinks": [ + { + "targetBlank": true, + "title": "Options data link with BOM", + "url": "http://example.com?series=${__series.name}\u0026time=${__value.time}" + } + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "test-ds" + }, + "refId": "A" + } + ], + "title": "Panel with BOM in options dataLinks", + "type": "timeseries" + } + ], + "schemaVersion": 42, + "tags": [ + "test", + "bom" + ], + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m" + ] + }, + "title": "BOM Stripping Test Dashboard" + }, + "status": { + "conversion": { + "failed": false, + "storedVersion": "v1beta1" + } + } +} \ No newline at end of file diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.bom-in-links.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.bom-in-links.v2alpha1.json new file mode 100644 index 00000000000..38547ea5b8e --- /dev/null +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.bom-in-links.v2alpha1.json @@ -0,0 +1,242 @@ +{ + "kind": "Dashboard", + "apiVersion": "dashboard.grafana.app/v2alpha1", + "metadata": { + "name": "bom-in-links-test", + "namespace": "org-1", + "labels": { + "test": "bom-stripping" + } + }, + "spec": { + "annotations": [], + "cursorSync": "Off", + "description": "Testing that BOM characters are stripped from URLs during conversion", + "editable": true, + "elements": { + "panel-1": { + "kind": "Panel", + "spec": { + "id": 1, + "title": "Panel with BOM in field config override links", + "description": "", + "links": [ + { + "title": "Panel data link with BOM", + "url": "http://example.com/${__data.fields.cluster}\u0026var=value", + "targetBlank": true + } + ], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "prometheus", + "spec": {} + }, + "datasource": { + "type": "prometheus", + "uid": "test-ds" + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "table", + "spec": { + "pluginVersion": "", + "options": {}, + "fieldConfig": { + "defaults": { + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + }, + { + "value": 80, + "color": "red" + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "server" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "title": "Override link with BOM", + "url": "http://localhost:3000/d/test?var-datacenter=${__data.fields[datacenter]}\u0026var-server=${__value.raw}" + } + ] + } + ] + } + ] + } + } + } + } + }, + "panel-2": { + "kind": "Panel", + "spec": { + "id": 2, + "title": "Panel with BOM in options dataLinks", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "prometheus", + "spec": {} + }, + "datasource": { + "type": "prometheus", + "uid": "test-ds" + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "timeseries", + "spec": { + "pluginVersion": "", + "options": { + "dataLinks": [ + { + "targetBlank": true, + "title": "Options data link with BOM", + "url": "http://example.com?series=${__series.name}\u0026time=${__value.time}" + } + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + } + }, + "fieldConfig": { + "defaults": { + "links": [ + { + "targetBlank": false, + "title": "Field config default link with BOM", + "url": "http://example.com?field=${__field.name}\u0026value=${__value.raw}" + } + ] + }, + "overrides": [] + } + } + } + } + } + }, + "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" + } + } + } + ] + } + }, + "links": [ + { + "title": "Dashboard link with BOM", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": "http://example.com?var=${datasource}\u0026other=value", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + } + ], + "liveNow": false, + "preload": false, + "tags": [ + "test", + "bom" + ], + "timeSettings": { + "timezone": "browser", + "from": "now-6h", + "to": "now", + "autoRefresh": "", + "autoRefreshIntervals": [ + "5s", + "10s", + "30s", + "1m", + "5m" + ], + "hideTimepicker": false, + "fiscalYearStartMonth": 0 + }, + "title": "BOM Stripping Test Dashboard", + "variables": [] + }, + "status": { + "conversion": { + "failed": false, + "storedVersion": "v1beta1" + } + } +} \ No newline at end of file diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.bom-in-links.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.bom-in-links.v2beta1.json new file mode 100644 index 00000000000..d85da89fe7a --- /dev/null +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.bom-in-links.v2beta1.json @@ -0,0 +1,246 @@ +{ + "kind": "Dashboard", + "apiVersion": "dashboard.grafana.app/v2beta1", + "metadata": { + "name": "bom-in-links-test", + "namespace": "org-1", + "labels": { + "test": "bom-stripping" + } + }, + "spec": { + "annotations": [], + "cursorSync": "Off", + "description": "Testing that BOM characters are stripped from URLs during conversion", + "editable": true, + "elements": { + "panel-1": { + "kind": "Panel", + "spec": { + "id": 1, + "title": "Panel with BOM in field config override links", + "description": "", + "links": [ + { + "title": "Panel data link with BOM", + "url": "http://example.com/${__data.fields.cluster}\u0026var=value", + "targetBlank": true + } + ], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "prometheus", + "version": "v0", + "datasource": { + "name": "test-ds" + }, + "spec": {} + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "table", + "version": "", + "spec": { + "options": {}, + "fieldConfig": { + "defaults": { + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + }, + { + "value": 80, + "color": "red" + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "server" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "title": "Override link with BOM", + "url": "http://localhost:3000/d/test?var-datacenter=${__data.fields[datacenter]}\u0026var-server=${__value.raw}" + } + ] + } + ] + } + ] + } + } + } + } + }, + "panel-2": { + "kind": "Panel", + "spec": { + "id": 2, + "title": "Panel with BOM in options dataLinks", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "prometheus", + "version": "v0", + "datasource": { + "name": "test-ds" + }, + "spec": {} + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "timeseries", + "version": "", + "spec": { + "options": { + "dataLinks": [ + { + "targetBlank": true, + "title": "Options data link with BOM", + "url": "http://example.com?series=${__series.name}\u0026time=${__value.time}" + } + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + } + }, + "fieldConfig": { + "defaults": { + "links": [ + { + "targetBlank": false, + "title": "Field config default link with BOM", + "url": "http://example.com?field=${__field.name}\u0026value=${__value.raw}" + } + ] + }, + "overrides": [] + } + } + } + } + } + }, + "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" + } + } + } + ] + } + }, + "links": [ + { + "title": "Dashboard link with BOM", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": "http://example.com?var=${datasource}\u0026other=value", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + } + ], + "liveNow": false, + "preload": false, + "tags": [ + "test", + "bom" + ], + "timeSettings": { + "timezone": "browser", + "from": "now-6h", + "to": "now", + "autoRefresh": "", + "autoRefreshIntervals": [ + "5s", + "10s", + "30s", + "1m", + "5m" + ], + "hideTimepicker": false, + "fiscalYearStartMonth": 0 + }, + "title": "BOM Stripping Test Dashboard", + "variables": [] + }, + "status": { + "conversion": { + "failed": false, + "storedVersion": "v1beta1" + } + } +} \ No newline at end of file diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.legacy-ds-ref.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.legacy-ds-ref.v0alpha1.json new file mode 100644 index 00000000000..9c6354b2319 --- /dev/null +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.legacy-ds-ref.v0alpha1.json @@ -0,0 +1,294 @@ +{ + "kind": "Dashboard", + "apiVersion": "dashboard.grafana.app/v0alpha1", + "metadata": { + "name": "legacy-ds-ref" + }, + "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, + "panels": [ + { + "datasource": "${datasource}", + "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": [ + { + "matcher": { + "id": "byName", + "options": "Minimum cluster size" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 1 + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 8, + "x": 0, + "y": 0 + }, + "id": 16, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "timeCompare": false, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": "${datasource}", + "editorMode": "code", + "expr": "count by (version) (alloy_build_info{cluster=~\"$cluster\", namespace=~\"$namespace\", job=~\"$job\"})", + "instant": false, + "legendFormat": "{{version}}", + "range": true, + "refId": "B" + } + ], + "title": "Number of Alloy Instances", + "type": "timeseries" + }, + { + "datasource": "${datasource}", + "description": "CPU usage of the Alloy process relative to 1 CPU core.\n\nFor example, 100% means using one entire CPU core.\n", + "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 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "Total" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": true, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 8, + "x": 8, + "y": 0 + }, + "id": 17, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "timeCompare": false, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": "${datasource}", + "expr": "rate(alloy_resources_process_cpu_seconds_total{cluster=~\"$cluster\", namespace=~\"$namespace\", job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])\n", + "hide": true, + "instant": false, + "legendFormat": "{{instance}}", + "range": true, + "refId": "A" + }, + { + "datasource": "${datasource}", + "editorMode": "code", + "expr": "sum(rate(alloy_resources_process_cpu_seconds_total{cluster=~\"$cluster\", namespace=~\"$namespace\", job=~\"$job\", instance=~\"$instance\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "Total", + "range": true, + "refId": "B" + } + ], + "title": "CPU usage", + "type": "timeseries" + } + ], + "time": { + "from": "now-90m", + "to": "now" + }, + "timezone": "utc", + "title": "Legacy DS Panel Query Ref", + "weekStart": "" + }, + "status": { + "conversion": { + "failed": false, + "storedVersion": "v1beta1" + } + } +} \ No newline at end of file diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.legacy-ds-ref.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.legacy-ds-ref.v2alpha1.json new file mode 100644 index 00000000000..23affbf4d4a --- /dev/null +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.legacy-ds-ref.v2alpha1.json @@ -0,0 +1,405 @@ +{ + "kind": "Dashboard", + "apiVersion": "dashboard.grafana.app/v2alpha1", + "metadata": { + "name": "legacy-ds-ref" + }, + "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-16": { + "kind": "Panel", + "spec": { + "id": 16, + "title": "Number of Alloy Instances", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "", + "spec": { + "editorMode": "code", + "expr": "count by (version) (alloy_build_info{cluster=~\"$cluster\", namespace=~\"$namespace\", job=~\"$job\"})", + "instant": false, + "legendFormat": "{{version}}", + "range": true + } + }, + "datasource": { + "type": "", + "uid": "${datasource}" + }, + "refId": "B", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "timeseries", + "spec": { + "pluginVersion": "", + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "timeCompare": false, + "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": [ + { + "matcher": { + "id": "byName", + "options": "Minimum cluster size" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 1 + } + ] + } + ] + } + } + } + } + }, + "panel-17": { + "kind": "Panel", + "spec": { + "id": 17, + "title": "CPU usage", + "description": "CPU usage of the Alloy process relative to 1 CPU core.\n\nFor example, 100% means using one entire CPU core.\n", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "", + "spec": { + "expr": "rate(alloy_resources_process_cpu_seconds_total{cluster=~\"$cluster\", namespace=~\"$namespace\", job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])\n", + "instant": false, + "legendFormat": "{{instance}}", + "range": true + } + }, + "datasource": { + "type": "", + "uid": "${datasource}" + }, + "refId": "A", + "hidden": true + } + }, + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "", + "spec": { + "editorMode": "code", + "expr": "sum(rate(alloy_resources_process_cpu_seconds_total{cluster=~\"$cluster\", namespace=~\"$namespace\", job=~\"$job\", instance=~\"$instance\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "Total", + "range": true + } + }, + "datasource": { + "type": "", + "uid": "${datasource}" + }, + "refId": "B", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "timeseries", + "spec": { + "pluginVersion": "", + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "timeCompare": false, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "fieldConfig": { + "defaults": { + "unit": "percentunit", + "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": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "Total" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": true, + "viz": true + } + } + ] + } + ] + } + } + } + } + } + }, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 0, + "width": 8, + "height": 9, + "element": { + "kind": "ElementReference", + "name": "panel-16" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 8, + "y": 0, + "width": 8, + "height": 9, + "element": { + "kind": "ElementReference", + "name": "panel-17" + } + } + } + ] + } + }, + "links": [], + "liveNow": false, + "preload": false, + "tags": [], + "timeSettings": { + "timezone": "utc", + "from": "now-90m", + "to": "now", + "autoRefresh": "", + "autoRefreshIntervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "hideTimepicker": false, + "fiscalYearStartMonth": 0 + }, + "title": "Legacy DS Panel Query Ref", + "variables": [] + }, + "status": { + "conversion": { + "failed": false, + "storedVersion": "v1beta1" + } + } +} \ No newline at end of file diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.legacy-ds-ref.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.legacy-ds-ref.v2beta1.json new file mode 100644 index 00000000000..758ffd9c348 --- /dev/null +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.legacy-ds-ref.v2beta1.json @@ -0,0 +1,411 @@ +{ + "kind": "Dashboard", + "apiVersion": "dashboard.grafana.app/v2beta1", + "metadata": { + "name": "legacy-ds-ref" + }, + "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-16": { + "kind": "Panel", + "spec": { + "id": 16, + "title": "Number of Alloy Instances", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "", + "version": "v0", + "datasource": { + "name": "${datasource}" + }, + "spec": { + "editorMode": "code", + "expr": "count by (version) (alloy_build_info{cluster=~\"$cluster\", namespace=~\"$namespace\", job=~\"$job\"})", + "instant": false, + "legendFormat": "{{version}}", + "range": true + } + }, + "refId": "B", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "timeseries", + "version": "", + "spec": { + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "timeCompare": false, + "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": [ + { + "matcher": { + "id": "byName", + "options": "Minimum cluster size" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "custom.lineStyle", + "value": { + "dash": [ + 10, + 10 + ], + "fill": "dash" + } + }, + { + "id": "custom.lineWidth", + "value": 1 + } + ] + } + ] + } + } + } + } + }, + "panel-17": { + "kind": "Panel", + "spec": { + "id": 17, + "title": "CPU usage", + "description": "CPU usage of the Alloy process relative to 1 CPU core.\n\nFor example, 100% means using one entire CPU core.\n", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "", + "version": "v0", + "datasource": { + "name": "${datasource}" + }, + "spec": { + "expr": "rate(alloy_resources_process_cpu_seconds_total{cluster=~\"$cluster\", namespace=~\"$namespace\", job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])\n", + "instant": false, + "legendFormat": "{{instance}}", + "range": true + } + }, + "refId": "A", + "hidden": true + } + }, + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "", + "version": "v0", + "datasource": { + "name": "${datasource}" + }, + "spec": { + "editorMode": "code", + "expr": "sum(rate(alloy_resources_process_cpu_seconds_total{cluster=~\"$cluster\", namespace=~\"$namespace\", job=~\"$job\", instance=~\"$instance\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "Total", + "range": true + } + }, + "refId": "B", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "timeseries", + "version": "", + "spec": { + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "timeCompare": false, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "fieldConfig": { + "defaults": { + "unit": "percentunit", + "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": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "Total" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": true, + "viz": true + } + } + ] + } + ] + } + } + } + } + } + }, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 0, + "width": 8, + "height": 9, + "element": { + "kind": "ElementReference", + "name": "panel-16" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 8, + "y": 0, + "width": 8, + "height": 9, + "element": { + "kind": "ElementReference", + "name": "panel-17" + } + } + } + ] + } + }, + "links": [], + "liveNow": false, + "preload": false, + "tags": [], + "timeSettings": { + "timezone": "utc", + "from": "now-90m", + "to": "now", + "autoRefresh": "", + "autoRefreshIntervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "hideTimepicker": false, + "fiscalYearStartMonth": 0 + }, + "title": "Legacy DS Panel Query Ref", + "variables": [] + }, + "status": { + "conversion": { + "failed": false, + "storedVersion": "v1beta1" + } + } +} \ No newline at end of file diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2alpha1.complete.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2alpha1.complete.v0alpha1.json index e3e0747bfc4..ecb9021b96c 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/v2alpha1.complete.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2alpha1.complete.v0alpha1.json @@ -66,6 +66,10 @@ "type": "row" }, { + "datasource": { + "type": "prometheus", + "uid": "gdev-prometheus" + }, "description": "This panel demonstrates conditional rendering features", "fieldConfig": { "defaults": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2alpha1.complete.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2alpha1.complete.v1beta1.json index 7c37ba8f8ab..35fc204793d 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/v2alpha1.complete.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2alpha1.complete.v1beta1.json @@ -66,6 +66,10 @@ "type": "row" }, { + "datasource": { + "type": "prometheus", + "uid": "gdev-prometheus" + }, "description": "This panel demonstrates conditional rendering features", "fieldConfig": { "defaults": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2alpha1.ds-data-query.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2alpha1.ds-data-query.v0alpha1.json index e648923e684..b38cf688949 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/v2alpha1.ds-data-query.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2alpha1.ds-data-query.v0alpha1.json @@ -150,6 +150,9 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus" + }, "fieldConfig": { "defaults": { "color": { @@ -245,6 +248,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "gdev-prometheus" + }, "fieldConfig": { "defaults": { "color": { @@ -341,6 +348,9 @@ "type": "timeseries" }, { + "datasource": { + "type": "grafana-testdata-datasource" + }, "fieldConfig": { "defaults": { "color": { @@ -400,6 +410,10 @@ "type": "stat" }, { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "gdev-testdata" + }, "fieldConfig": { "defaults": { "color": { @@ -697,6 +711,146 @@ ], "title": "Mixed DS WITHOUT REFS", "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "description": "Panel with a single -- Dashboard -- datasource query", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + } + }, + "gridPos": { + "h": 9, + "w": 8, + "x": 0, + "y": 18 + }, + "id": 7, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.1.0-pre", + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 1, + "refId": "A", + "withTransforms": true + } + ], + "title": "Single Dashboard DS Query", + "type": "stat" + }, + { + "datasource": { + "type": "mixed", + "uid": "-- Mixed --" + }, + "description": "Panel with multiple -- Dashboard -- datasource queries (should be mixed)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + } + }, + "gridPos": { + "h": 9, + "w": 8, + "x": 8, + "y": 18 + }, + "id": 8, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.1.0-pre", + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 1, + "refId": "A", + "withTransforms": true + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 2, + "refId": "B", + "withTransforms": true + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 3, + "refId": "C", + "withTransforms": true + } + ], + "title": "Multiple Dashboard DS Queries", + "type": "stat" } ], "preload": false, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2alpha1.ds-data-query.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2alpha1.ds-data-query.v1beta1.json index d2a4e93982e..0b7f512e6f1 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/v2alpha1.ds-data-query.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2alpha1.ds-data-query.v1beta1.json @@ -150,6 +150,9 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus" + }, "fieldConfig": { "defaults": { "color": { @@ -245,6 +248,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "gdev-prometheus" + }, "fieldConfig": { "defaults": { "color": { @@ -341,6 +348,9 @@ "type": "timeseries" }, { + "datasource": { + "type": "grafana-testdata-datasource" + }, "fieldConfig": { "defaults": { "color": { @@ -400,6 +410,10 @@ "type": "stat" }, { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "gdev-testdata" + }, "fieldConfig": { "defaults": { "color": { @@ -697,6 +711,146 @@ ], "title": "Mixed DS WITHOUT REFS", "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "description": "Panel with a single -- Dashboard -- datasource query", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + } + }, + "gridPos": { + "h": 9, + "w": 8, + "x": 0, + "y": 18 + }, + "id": 7, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.1.0-pre", + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 1, + "refId": "A", + "withTransforms": true + } + ], + "title": "Single Dashboard DS Query", + "type": "stat" + }, + { + "datasource": { + "type": "mixed", + "uid": "-- Mixed --" + }, + "description": "Panel with multiple -- Dashboard -- datasource queries (should be mixed)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + } + }, + "gridPos": { + "h": 9, + "w": 8, + "x": 8, + "y": 18 + }, + "id": 8, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.1.0-pre", + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 1, + "refId": "A", + "withTransforms": true + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 2, + "refId": "B", + "withTransforms": true + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 3, + "refId": "C", + "withTransforms": true + } + ], + "title": "Multiple Dashboard DS Queries", + "type": "stat" } ], "preload": false, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2alpha1.ds-data-query.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2alpha1.ds-data-query.v2beta1.json index 09e35c64258..aba5db6146d 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/v2alpha1.ds-data-query.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2alpha1.ds-data-query.v2beta1.json @@ -879,6 +879,200 @@ } } } + }, + "panel-7": { + "kind": "Panel", + "spec": { + "id": 7, + "title": "Single Dashboard DS Query", + "description": "Panel with a single -- Dashboard -- datasource query", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "datasource", + "version": "v0", + "datasource": { + "name": "-- Dashboard --" + }, + "spec": { + "panelId": 1, + "withTransforms": true + } + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "stat", + "version": "12.1.0-pre", + "spec": { + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "fieldConfig": { + "defaults": { + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": 0, + "color": "green" + } + ] + }, + "color": { + "mode": "thresholds" + } + }, + "overrides": [] + } + } + } + } + }, + "panel-8": { + "kind": "Panel", + "spec": { + "id": 8, + "title": "Multiple Dashboard DS Queries", + "description": "Panel with multiple -- Dashboard -- datasource queries (should be mixed)", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "datasource", + "version": "v0", + "datasource": { + "name": "-- Dashboard --" + }, + "spec": { + "panelId": 1, + "withTransforms": true + } + }, + "refId": "A", + "hidden": false + } + }, + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "datasource", + "version": "v0", + "datasource": { + "name": "-- Dashboard --" + }, + "spec": { + "panelId": 2, + "withTransforms": true + } + }, + "refId": "B", + "hidden": false + } + }, + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "datasource", + "version": "v0", + "datasource": { + "name": "-- Dashboard --" + }, + "spec": { + "panelId": 3, + "withTransforms": true + } + }, + "refId": "C", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "stat", + "version": "12.1.0-pre", + "spec": { + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "fieldConfig": { + "defaults": { + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": 0, + "color": "green" + } + ] + }, + "color": { + "mode": "thresholds" + } + }, + "overrides": [] + } + } + } + } } }, "layout": { @@ -941,6 +1135,24 @@ "name": "panel-6" } } + }, + { + "kind": "AutoGridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-7" + } + } + }, + { + "kind": "AutoGridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-8" + } + } } ] } diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2alpha1.viz-config.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2alpha1.viz-config.v0alpha1.json index 37bbba541cd..d57c8d086a9 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/v2alpha1.viz-config.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2alpha1.viz-config.v0alpha1.json @@ -14,6 +14,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "gdev-testdata" + }, "fieldConfig": { "defaults": { "color": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2alpha1.viz-config.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2alpha1.viz-config.v1beta1.json index 464c1d4c240..b2e7bd78dba 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/v2alpha1.viz-config.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2alpha1.viz-config.v1beta1.json @@ -14,6 +14,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "gdev-testdata" + }, "fieldConfig": { "defaults": { "color": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.complete.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.complete.v0alpha1.json index b942305c98d..f3b6ab864fb 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.complete.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.complete.v0alpha1.json @@ -66,6 +66,10 @@ "type": "row" }, { + "datasource": { + "type": "prometheus", + "uid": "gdev-prometheus" + }, "description": "This panel demonstrates conditional rendering features", "fieldConfig": { "defaults": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.complete.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.complete.v1beta1.json index 06f8c45bdad..e3236448c9d 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.complete.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.complete.v1beta1.json @@ -66,6 +66,10 @@ "type": "row" }, { + "datasource": { + "type": "prometheus", + "uid": "gdev-prometheus" + }, "description": "This panel demonstrates conditional rendering features", "fieldConfig": { "defaults": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.datasource-resolution.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.datasource-resolution.v0alpha1.json index c1066edc211..33fd022e0db 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.datasource-resolution.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.datasource-resolution.v0alpha1.json @@ -80,6 +80,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "gdev-testdata" + }, "description": "This should resolve to the grafana-testdata-datasource datasource", "fieldConfig": { "defaults": { @@ -170,6 +174,9 @@ "type": "timeseries" }, { + "datasource": { + "type": "elasticsearch" + }, "description": "This should resolve to the first elasticsearch datasource", "fieldConfig": { "defaults": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.datasource-resolution.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.datasource-resolution.v1beta1.json index 9bbd2f8f555..05d6df3537a 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.datasource-resolution.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.datasource-resolution.v1beta1.json @@ -80,6 +80,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "gdev-testdata" + }, "description": "This should resolve to the grafana-testdata-datasource datasource", "fieldConfig": { "defaults": { @@ -170,6 +174,9 @@ "type": "timeseries" }, { + "datasource": { + "type": "elasticsearch" + }, "description": "This should resolve to the first elasticsearch datasource", "fieldConfig": { "defaults": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.ds-data-query.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.ds-data-query.v0alpha1.json index 6a418f1e21d..99bcc3e9581 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.ds-data-query.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.ds-data-query.v0alpha1.json @@ -150,6 +150,9 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus" + }, "fieldConfig": { "defaults": { "color": { @@ -245,6 +248,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "gdev-prometheus" + }, "fieldConfig": { "defaults": { "color": { @@ -341,6 +348,9 @@ "type": "timeseries" }, { + "datasource": { + "type": "grafana-testdata-datasource" + }, "fieldConfig": { "defaults": { "color": { @@ -400,6 +410,10 @@ "type": "stat" }, { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "gdev-testdata" + }, "fieldConfig": { "defaults": { "color": { @@ -697,6 +711,146 @@ ], "title": "Mixed DS WITHOUT REFS", "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "description": "Panel with a single -- Dashboard -- datasource query", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + } + }, + "gridPos": { + "h": 3, + "w": 8, + "x": 0, + "y": 6 + }, + "id": 7, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.1.0-pre", + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 1, + "refId": "A", + "withTransforms": true + } + ], + "title": "Single Dashboard DS Query", + "type": "stat" + }, + { + "datasource": { + "type": "mixed", + "uid": "-- Mixed --" + }, + "description": "Panel with multiple -- Dashboard -- datasource queries (should be mixed)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + } + }, + "gridPos": { + "h": 3, + "w": 8, + "x": 8, + "y": 6 + }, + "id": 8, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.1.0-pre", + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 1, + "refId": "A", + "withTransforms": true + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 2, + "refId": "B", + "withTransforms": true + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 3, + "refId": "C", + "withTransforms": true + } + ], + "title": "Multiple Dashboard DS Queries", + "type": "stat" } ], "preload": false, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.ds-data-query.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.ds-data-query.v1beta1.json index 212dbdfd0f3..e2d54185ea5 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.ds-data-query.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.ds-data-query.v1beta1.json @@ -150,6 +150,9 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus" + }, "fieldConfig": { "defaults": { "color": { @@ -245,6 +248,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "gdev-prometheus" + }, "fieldConfig": { "defaults": { "color": { @@ -341,6 +348,9 @@ "type": "timeseries" }, { + "datasource": { + "type": "grafana-testdata-datasource" + }, "fieldConfig": { "defaults": { "color": { @@ -400,6 +410,10 @@ "type": "stat" }, { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "gdev-testdata" + }, "fieldConfig": { "defaults": { "color": { @@ -697,6 +711,146 @@ ], "title": "Mixed DS WITHOUT REFS", "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "description": "Panel with a single -- Dashboard -- datasource query", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + } + }, + "gridPos": { + "h": 3, + "w": 8, + "x": 0, + "y": 6 + }, + "id": 7, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.1.0-pre", + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 1, + "refId": "A", + "withTransforms": true + } + ], + "title": "Single Dashboard DS Query", + "type": "stat" + }, + { + "datasource": { + "type": "mixed", + "uid": "-- Mixed --" + }, + "description": "Panel with multiple -- Dashboard -- datasource queries (should be mixed)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + } + } + }, + "gridPos": { + "h": 3, + "w": 8, + "x": 8, + "y": 6 + }, + "id": 8, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.1.0-pre", + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 1, + "refId": "A", + "withTransforms": true + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 2, + "refId": "B", + "withTransforms": true + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 3, + "refId": "C", + "withTransforms": true + } + ], + "title": "Multiple Dashboard DS Queries", + "type": "stat" } ], "preload": false, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.ds-data-query.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.ds-data-query.v2alpha1.json index bb70e99ec48..d3ca201e380 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.ds-data-query.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.ds-data-query.v2alpha1.json @@ -852,6 +852,194 @@ } } } + }, + "panel-7": { + "kind": "Panel", + "spec": { + "id": 7, + "title": "Single Dashboard DS Query", + "description": "Panel with a single -- Dashboard -- datasource query", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "datasource", + "spec": { + "panelId": 1, + "withTransforms": true + } + }, + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "stat", + "spec": { + "pluginVersion": "12.1.0-pre", + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "fieldConfig": { + "defaults": { + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": 0, + "color": "green" + } + ] + }, + "color": { + "mode": "thresholds" + } + }, + "overrides": [] + } + } + } + } + }, + "panel-8": { + "kind": "Panel", + "spec": { + "id": 8, + "title": "Multiple Dashboard DS Queries", + "description": "Panel with multiple -- Dashboard -- datasource queries (should be mixed)", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "datasource", + "spec": { + "panelId": 1, + "withTransforms": true + } + }, + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "refId": "A", + "hidden": false + } + }, + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "datasource", + "spec": { + "panelId": 2, + "withTransforms": true + } + }, + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "refId": "B", + "hidden": false + } + }, + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "datasource", + "spec": { + "panelId": 3, + "withTransforms": true + } + }, + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "refId": "C", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "stat", + "spec": { + "pluginVersion": "12.1.0-pre", + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "fieldConfig": { + "defaults": { + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": 0, + "color": "green" + } + ] + }, + "color": { + "mode": "thresholds" + } + }, + "overrides": [] + } + } + } + } } }, "layout": { @@ -946,6 +1134,32 @@ "name": "panel-6" } } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 6, + "width": 8, + "height": 3, + "element": { + "kind": "ElementReference", + "name": "panel-7" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 8, + "y": 6, + "width": 8, + "height": 3, + "element": { + "kind": "ElementReference", + "name": "panel-8" + } + } } ] } diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.rows-with-nested-tabs.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.rows-with-nested-tabs.v0alpha1.json index f81abd723dc..bd7c8c392ee 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.rows-with-nested-tabs.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.rows-with-nested-tabs.v0alpha1.json @@ -67,6 +67,10 @@ "type": "row" }, { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "defin43am9o1sd" + }, "fieldConfig": { "defaults": { "color": { @@ -219,6 +223,10 @@ "type": "row" }, { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "defin43am9o1sd" + }, "fieldConfig": { "defaults": { "color": { @@ -309,6 +317,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "defin43am9o1sd" + }, "fieldConfig": { "defaults": { "color": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.rows-with-nested-tabs.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.rows-with-nested-tabs.v1beta1.json index 2ade48c620d..a81de0ed319 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.rows-with-nested-tabs.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.rows-with-nested-tabs.v1beta1.json @@ -67,6 +67,10 @@ "type": "row" }, { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "defin43am9o1sd" + }, "fieldConfig": { "defaults": { "color": { @@ -219,6 +223,10 @@ "type": "row" }, { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "defin43am9o1sd" + }, "fieldConfig": { "defaults": { "color": { @@ -309,6 +317,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "defin43am9o1sd" + }, "fieldConfig": { "defaults": { "color": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tab-with-multiple-panels.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tab-with-multiple-panels.v0alpha1.json index 0357c22536a..98791135a12 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tab-with-multiple-panels.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tab-with-multiple-panels.v0alpha1.json @@ -54,6 +54,10 @@ "type": "row" }, { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "PD8C576611E62080A" + }, "fieldConfig": { "defaults": { "color": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tab-with-multiple-panels.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tab-with-multiple-panels.v1beta1.json index 7a9ea77ba65..38c93eb1cc8 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tab-with-multiple-panels.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tab-with-multiple-panels.v1beta1.json @@ -54,6 +54,10 @@ "type": "row" }, { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "PD8C576611E62080A" + }, "fieldConfig": { "defaults": { "color": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tabs-and-rows-repeated.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tabs-and-rows-repeated.v0alpha1.json index ef513d48d97..716b476f825 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tabs-and-rows-repeated.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tabs-and-rows-repeated.v0alpha1.json @@ -54,6 +54,10 @@ "type": "row" }, { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "defin43am9o1sd" + }, "fieldConfig": { "defaults": { "color": { @@ -167,6 +171,10 @@ "id": -1, "panels": [ { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "defin43am9o1sd" + }, "fieldConfig": { "defaults": { "color": { @@ -271,6 +279,10 @@ "id": -1, "panels": [ { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "defin43am9o1sd" + }, "fieldConfig": { "defaults": { "color": { @@ -361,6 +373,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "defin43am9o1sd" + }, "fieldConfig": { "defaults": { "color": { @@ -467,6 +483,10 @@ "type": "row" }, { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "defin43am9o1sd" + }, "fieldConfig": { "defaults": { "color": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tabs-and-rows-repeated.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tabs-and-rows-repeated.v1beta1.json index f94a49fc420..f915142fd14 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tabs-and-rows-repeated.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tabs-and-rows-repeated.v1beta1.json @@ -54,6 +54,10 @@ "type": "row" }, { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "defin43am9o1sd" + }, "fieldConfig": { "defaults": { "color": { @@ -167,6 +171,10 @@ "id": -1, "panels": [ { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "defin43am9o1sd" + }, "fieldConfig": { "defaults": { "color": { @@ -271,6 +279,10 @@ "id": -1, "panels": [ { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "defin43am9o1sd" + }, "fieldConfig": { "defaults": { "color": { @@ -361,6 +373,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "defin43am9o1sd" + }, "fieldConfig": { "defaults": { "color": { @@ -467,6 +483,10 @@ "type": "row" }, { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "defin43am9o1sd" + }, "fieldConfig": { "defaults": { "color": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tabs-with-nested-rows.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tabs-with-nested-rows.v0alpha1.json index 6ed7076e121..ebc40675495 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tabs-with-nested-rows.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tabs-with-nested-rows.v0alpha1.json @@ -54,6 +54,10 @@ "type": "row" }, { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "defin43am9o1sd" + }, "fieldConfig": { "defaults": { "color": { @@ -167,6 +171,10 @@ "id": -1, "panels": [ { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "defin43am9o1sd" + }, "fieldConfig": { "defaults": { "color": { @@ -271,6 +279,10 @@ "id": -1, "panels": [ { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "defin43am9o1sd" + }, "fieldConfig": { "defaults": { "color": { @@ -361,6 +373,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "defin43am9o1sd" + }, "fieldConfig": { "defaults": { "color": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tabs-with-nested-rows.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tabs-with-nested-rows.v1beta1.json index 9444d6b8eef..b5c74ce6a26 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tabs-with-nested-rows.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.tabs-with-nested-rows.v1beta1.json @@ -54,6 +54,10 @@ "type": "row" }, { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "defin43am9o1sd" + }, "fieldConfig": { "defaults": { "color": { @@ -167,6 +171,10 @@ "id": -1, "panels": [ { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "defin43am9o1sd" + }, "fieldConfig": { "defaults": { "color": { @@ -271,6 +279,10 @@ "id": -1, "panels": [ { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "defin43am9o1sd" + }, "fieldConfig": { "defaults": { "color": { @@ -361,6 +373,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "defin43am9o1sd" + }, "fieldConfig": { "defaults": { "color": { 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 index bd8e440efb2..916f2442b71 100644 --- 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 @@ -36,6 +36,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, "description": "Panel with ValueMap mapping type - maps specific text values to colors and display text", "fieldConfig": { "defaults": { @@ -104,6 +108,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, "description": "Panel with RangeMap mapping type - maps numerical ranges to colors and display text", "fieldConfig": { "defaults": { @@ -188,6 +196,10 @@ "type": "gauge" }, { + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, "description": "Panel with RegexMap mapping type - maps values matching regex patterns to colors", "fieldConfig": { "defaults": { @@ -267,6 +279,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, "description": "Panel with SpecialValueMap mapping type - maps special values like null, NaN, true, false to display text", "fieldConfig": { "defaults": { @@ -380,6 +396,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, "description": "Panel with all mapping types combined - demonstrates mixing different mapping types and multiple override matchers", "fieldConfig": { "defaults": { @@ -567,6 +587,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, "description": "Panel with override that has empty properties array - tests conversion of overrides without any property modifications", "fieldConfig": { "overrides": [ 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 index 07d899db46c..9c96e15fbc3 100644 --- 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 @@ -36,6 +36,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, "description": "Panel with ValueMap mapping type - maps specific text values to colors and display text", "fieldConfig": { "defaults": { @@ -104,6 +108,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, "description": "Panel with RangeMap mapping type - maps numerical ranges to colors and display text", "fieldConfig": { "defaults": { @@ -188,6 +196,10 @@ "type": "gauge" }, { + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, "description": "Panel with RegexMap mapping type - maps values matching regex patterns to colors", "fieldConfig": { "defaults": { @@ -267,6 +279,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, "description": "Panel with SpecialValueMap mapping type - maps special values like null, NaN, true, false to display text", "fieldConfig": { "defaults": { @@ -380,6 +396,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, "description": "Panel with all mapping types combined - demonstrates mixing different mapping types and multiple override matchers", "fieldConfig": { "defaults": { @@ -567,6 +587,10 @@ "type": "table" }, { + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, "description": "Panel with override that has empty properties array - tests conversion of overrides without any property modifications", "fieldConfig": { "overrides": [ diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.viz-config.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.viz-config.v0alpha1.json index 0502ebf6b4c..083dfb5347c 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.viz-config.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.viz-config.v0alpha1.json @@ -14,6 +14,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "gdev-testdata" + }, "fieldConfig": { "defaults": { "color": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.viz-config.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.viz-config.v1beta1.json index 2187a3406e7..69cec2d4e7b 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.viz-config.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.viz-config.v1beta1.json @@ -14,6 +14,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "gdev-testdata" + }, "fieldConfig": { "defaults": { "color": { diff --git a/apps/dashboard/pkg/migration/conversion/v0alpha1_to_v1beta1.go b/apps/dashboard/pkg/migration/conversion/v0alpha1_to_v1beta1.go index d0679c76e63..df2db1ac5a1 100644 --- a/apps/dashboard/pkg/migration/conversion/v0alpha1_to_v1beta1.go +++ b/apps/dashboard/pkg/migration/conversion/v0alpha1_to_v1beta1.go @@ -88,6 +88,11 @@ func ConvertDashboard_V0_to_V1beta1(in *dashv0.Dashboard, out *dashv1.Dashboard, // Which means that we have schemaVersion: 42 dashboards where datasource variable references are still strings normalizeTemplateVariableDatasources(out.Spec.Object) + // Normalize panel and target datasources from string to object format + // This handles legacy dashboards where panels/targets have datasource: "$datasource" (string) + // instead of datasource: { uid: "$datasource" } (object) + normalizePanelDatasources(out.Spec.Object) + return nil } @@ -134,3 +139,62 @@ func isTemplateVariableRef(s string) bool { } return strings.HasPrefix(s, "$") || strings.HasPrefix(s, "${") } + +// normalizePanelDatasources converts panel and target string datasources to object format. +// Legacy dashboards may have panels/targets with datasource: "$datasource" (string). +// This normalizes them to datasource: { uid: "$datasource" } for consistent V1→V2 conversion. +func normalizePanelDatasources(dashboard map[string]interface{}) { + panels, ok := dashboard["panels"].([]interface{}) + if !ok { + return + } + + normalizePanelsDatasources(panels) +} + +// normalizePanelsDatasources normalizes datasources in a list of panels (including nested row panels) +func normalizePanelsDatasources(panels []interface{}) { + for _, panel := range panels { + panelMap, ok := panel.(map[string]interface{}) + if !ok { + continue + } + + // Handle row panels with nested panels + if panelType, _ := panelMap["type"].(string); panelType == "row" { + if nestedPanels, ok := panelMap["panels"].([]interface{}); ok { + normalizePanelsDatasources(nestedPanels) + } + } + + // Normalize panel-level datasource + if ds := panelMap["datasource"]; ds != nil { + if dsStr, ok := ds.(string); ok && isTemplateVariableRef(dsStr) { + panelMap["datasource"] = map[string]interface{}{ + "uid": dsStr, + } + } + } + + // Normalize target-level datasources + targets, ok := panelMap["targets"].([]interface{}) + if !ok { + continue + } + + for _, target := range targets { + targetMap, ok := target.(map[string]interface{}) + if !ok { + continue + } + + if ds := targetMap["datasource"]; ds != nil { + if dsStr, ok := ds.(string); ok && isTemplateVariableRef(dsStr) { + targetMap["datasource"] = map[string]interface{}{ + "uid": dsStr, + } + } + } + } + } +} diff --git a/apps/dashboard/pkg/migration/conversion/v1beta1_to_v2alpha1.go b/apps/dashboard/pkg/migration/conversion/v1beta1_to_v2alpha1.go index 224f222ae33..bfff3c49797 100644 --- a/apps/dashboard/pkg/migration/conversion/v1beta1_to_v2alpha1.go +++ b/apps/dashboard/pkg/migration/conversion/v1beta1_to_v2alpha1.go @@ -229,6 +229,36 @@ func getBoolField(m map[string]interface{}, key string, defaultValue bool) bool return defaultValue } +// stripBOM removes Byte Order Mark (BOM) characters from a string. +// BOMs (U+FEFF) can be introduced through copy/paste from certain editors +// and cause CUE validation errors ("illegal byte order mark"). +func stripBOM(s string) string { + return strings.ReplaceAll(s, "\ufeff", "") +} + +// stripBOMFromInterface recursively strips BOM characters from all strings +// in an interface{} value (map, slice, or string). +func stripBOMFromInterface(v interface{}) interface{} { + switch val := v.(type) { + case string: + return stripBOM(val) + case map[string]interface{}: + result := make(map[string]interface{}, len(val)) + for k, v := range val { + result[k] = stripBOMFromInterface(v) + } + return result + case []interface{}: + result := make([]interface{}, len(val)) + for i, item := range val { + result[i] = stripBOMFromInterface(item) + } + return result + default: + return v + } +} + func getUnionField[T ~string](m map[string]interface{}, key string) *T { if val, ok := m[key]; ok { if str, ok := val.(string); ok && str != "" { @@ -393,7 +423,8 @@ func transformLinks(dashboard map[string]interface{}) []dashv2alpha1.DashboardDa // Optional field - only set if present if url, exists := linkMap["url"]; exists { if urlStr, ok := url.(string); ok { - dashLink.Url = &urlStr + cleanUrl := stripBOM(urlStr) + dashLink.Url = &cleanUrl } } @@ -1305,6 +1336,17 @@ func buildCustomVariable(varMap map[string]interface{}, commonProps CommonVariab customVar.Spec.AllValue = &allValue } + if valuesFormat := schemaversion.GetStringValue(varMap, "valuesFormat"); valuesFormat != "" { + switch valuesFormat { + case string(dashv2alpha1.DashboardCustomVariableSpecValuesFormatJson): + format := dashv2alpha1.DashboardCustomVariableSpecValuesFormatJson + customVar.Spec.ValuesFormat = &format + case string(dashv2alpha1.DashboardCustomVariableSpecValuesFormatCsv): + format := dashv2alpha1.DashboardCustomVariableSpecValuesFormatCsv + customVar.Spec.ValuesFormat = &format + } + } + return dashv2alpha1.DashboardVariableKind{ CustomVariableKind: customVar, }, nil @@ -2017,6 +2059,12 @@ func transformPanelQueries(ctx context.Context, panelMap map[string]interface{}, Uid: &dsUID, } } + } else if dsStr, ok := ds.(string); ok && isTemplateVariable(dsStr) { + // Handle legacy panel datasource as string (template variable reference e.g., "$datasource") + // Only process template variables - other string values are not supported in V2 format + panelDatasource = &dashv2alpha1.DashboardDataSourceRef{ + Uid: &dsStr, + } } } @@ -2103,6 +2151,10 @@ func transformSingleQuery(ctx context.Context, targetMap map[string]interface{}, // Resolve Grafana datasource UID when type is "datasource" and UID is empty queryDatasourceUID = resolveGrafanaDatasourceUID(queryDatasourceType, queryDatasourceUID) } + } else if dsStr, ok := targetMap["datasource"].(string); ok && isTemplateVariable(dsStr) { + // Handle legacy target datasource as string (template variable reference e.g., "$datasource") + // Only process template variables - other string values are not supported in V2 format + queryDatasourceUID = dsStr } // Use panel datasource if target datasource is missing or empty @@ -2178,6 +2230,20 @@ func transformPanelTransformations(panelMap map[string]interface{}) []dashv2alph Options: options, }, } + + // Extract disabled if present (optional, transformations are enabled by default) + if disabled, ok := tMap["disabled"].(bool); ok && disabled { + transformationKind.Spec.Disabled = &disabled + } + + // Extract filter if present (optional frame matcher for transformations) + if filterMap, ok := tMap["filter"].(map[string]interface{}); ok { + transformationKind.Spec.Filter = &dashv2alpha1.DashboardMatcherConfig{ + Id: schemaversion.GetStringValue(filterMap, "id"), + Options: filterMap["options"], + } + } + result = append(result, transformationKind) } } @@ -2239,7 +2305,7 @@ func transformDataLinks(panelMap map[string]interface{}) []dashv2alpha1.Dashboar if linkMap, ok := link.(map[string]interface{}); ok { dataLink := dashv2alpha1.DashboardDataLink{ Title: schemaversion.GetStringValue(linkMap, "title"), - Url: schemaversion.GetStringValue(linkMap, "url"), + Url: stripBOM(schemaversion.GetStringValue(linkMap, "url")), } if _, exists := linkMap["targetBlank"]; exists { targetBlank := getBoolField(linkMap, "targetBlank", false) @@ -2297,14 +2363,6 @@ func buildVizConfig(panelMap map[string]interface{}) dashv2alpha1.DashboardVizCo } } - // Add frontend-style default options to match frontend behavior - if legend, ok := options["legend"].(map[string]interface{}); ok { - // Add showLegend: true to match frontend behavior - showLegend := getBoolField(legend, "showLegend", true) - legend["showLegend"] = showLegend - 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: @@ -2331,6 +2389,12 @@ func buildVizConfig(panelMap map[string]interface{}) dashv2alpha1.DashboardVizCo } } + // Strip BOMs from options (may contain dataLinks with URLs that have BOMs) + cleanedOptions := stripBOMFromInterface(options) + if cleanedMap, ok := cleanedOptions.(map[string]interface{}); ok { + options = cleanedMap + } + // Build field config by mapping each field individually fieldConfigSource := extractFieldConfigSource(fieldConfig) @@ -2473,10 +2537,30 @@ func extractFieldConfigDefaults(defaults map[string]interface{}) dashv2alpha1.Da fieldConfigDefaults.Writeable = val hasDefaults = true } + if val, ok := extractBoolField(defaults, "fieldMinMax"); ok { + fieldConfigDefaults.FieldMinMax = val + hasDefaults = true + } + if val, ok := defaults["nullValueMode"].(string); ok { + nullValueMode := dashv2alpha1.DashboardNullValueMode(val) + fieldConfigDefaults.NullValueMode = &nullValueMode + hasDefaults = true + } - // Extract array field + // Extract array field - strip BOMs from link URLs if linksArray, ok := extractArrayField(defaults, "links"); ok { - fieldConfigDefaults.Links = linksArray + cleanedLinks := stripBOMFromInterface(linksArray) + if cleanedArray, ok := cleanedLinks.([]interface{}); ok { + fieldConfigDefaults.Links = cleanedArray + } else { + fieldConfigDefaults.Links = linksArray + } + hasDefaults = true + } + + // Extract actions array + if actionsArray, ok := extractArrayField(defaults, "actions"); ok { + fieldConfigDefaults.Actions = convertActionsToV2(actionsArray) hasDefaults = true } @@ -2762,9 +2846,11 @@ func extractFieldConfigOverrides(fieldConfig map[string]interface{}) []dashv2alp fieldOverride.Properties = make([]dashv2alpha1.DashboardDynamicConfigValue, 0, len(propertiesArray)) for _, property := range propertiesArray { if propertyMap, ok := property.(map[string]interface{}); ok { + // Strip BOMs from property values (may contain links with URLs) + cleanedValue := stripBOMFromInterface(propertyMap["value"]) fieldOverride.Properties = append(fieldOverride.Properties, dashv2alpha1.DashboardDynamicConfigValue{ Id: schemaversion.GetStringValue(propertyMap, "id"), - Value: propertyMap["value"], + Value: cleanedValue, }) } } @@ -2777,6 +2863,157 @@ func extractFieldConfigOverrides(fieldConfig map[string]interface{}) []dashv2alp return result } +// convertActionsToV2 converts an array of V1 action objects to V2 DashboardAction structs. +func convertActionsToV2(actionsArray []interface{}) []dashv2alpha1.DashboardAction { + if len(actionsArray) == 0 { + return nil + } + + result := make([]dashv2alpha1.DashboardAction, 0, len(actionsArray)) + for _, action := range actionsArray { + actionMap, ok := action.(map[string]interface{}) + if !ok { + continue + } + + dashAction := dashv2alpha1.DashboardAction{ + Type: dashv2alpha1.DashboardActionType(schemaversion.GetStringValue(actionMap, "type")), + Title: schemaversion.GetStringValue(actionMap, "title"), + } + + // Convert confirmation + if confirmation, ok := actionMap["confirmation"].(string); ok && confirmation != "" { + dashAction.Confirmation = &confirmation + } + + // Convert oneClick + if oneClick, ok := actionMap["oneClick"].(bool); ok { + dashAction.OneClick = &oneClick + } + + // Convert fetch options + if fetchMap, ok := actionMap["fetch"].(map[string]interface{}); ok { + dashAction.Fetch = convertFetchOptionsToV2(fetchMap) + } + + // Convert infinity options + if infinityMap, ok := actionMap["infinity"].(map[string]interface{}); ok { + dashAction.Infinity = convertInfinityOptionsToV2(infinityMap) + } + + // Convert variables + if variablesArray, ok := actionMap["variables"].([]interface{}); ok { + dashAction.Variables = convertActionVariablesToV2(variablesArray) + } + + // Convert style + if styleMap, ok := actionMap["style"].(map[string]interface{}); ok { + dashAction.Style = convertActionStyleToV2(styleMap) + } + + result = append(result, dashAction) + } + + return result +} + +func convertFetchOptionsToV2(fetchMap map[string]interface{}) *dashv2alpha1.DashboardFetchOptions { + fetchOptions := &dashv2alpha1.DashboardFetchOptions{ + Method: dashv2alpha1.DashboardHttpRequestMethod(schemaversion.GetStringValue(fetchMap, "method")), + Url: schemaversion.GetStringValue(fetchMap, "url"), + } + + if body, ok := fetchMap["body"].(string); ok { + fetchOptions.Body = &body + } + + // Convert queryParams (2D array of strings) - preserve empty arrays + if queryParams, ok := fetchMap["queryParams"].([]interface{}); ok { + fetchOptions.QueryParams = convert2DStringArrayPreserveEmpty(queryParams) + } + + // Convert headers (2D array of strings) - preserve empty arrays + if headers, ok := fetchMap["headers"].([]interface{}); ok { + fetchOptions.Headers = convert2DStringArrayPreserveEmpty(headers) + } + + return fetchOptions +} + +func convertInfinityOptionsToV2(infinityMap map[string]interface{}) *dashv2alpha1.DashboardInfinityOptions { + infinityOptions := &dashv2alpha1.DashboardInfinityOptions{ + Method: dashv2alpha1.DashboardHttpRequestMethod(schemaversion.GetStringValue(infinityMap, "method")), + Url: schemaversion.GetStringValue(infinityMap, "url"), + DatasourceUid: schemaversion.GetStringValue(infinityMap, "datasourceUid"), + } + + if body, ok := infinityMap["body"].(string); ok { + infinityOptions.Body = &body + } + + if queryParams, ok := infinityMap["queryParams"].([]interface{}); ok { + infinityOptions.QueryParams = convert2DStringArrayPreserveEmpty(queryParams) + } + + if headers, ok := infinityMap["headers"].([]interface{}); ok { + infinityOptions.Headers = convert2DStringArrayPreserveEmpty(headers) + } + + return infinityOptions +} + +func convertActionVariablesToV2(variablesArray []interface{}) []dashv2alpha1.DashboardActionVariable { + if len(variablesArray) == 0 { + return nil + } + + result := make([]dashv2alpha1.DashboardActionVariable, 0, len(variablesArray)) + for _, variable := range variablesArray { + variableMap, ok := variable.(map[string]interface{}) + if !ok { + continue + } + + result = append(result, dashv2alpha1.DashboardActionVariable{ + Key: schemaversion.GetStringValue(variableMap, "key"), + Name: schemaversion.GetStringValue(variableMap, "name"), + Type: schemaversion.GetStringValue(variableMap, "type"), + }) + } + + return result +} + +func convertActionStyleToV2(styleMap map[string]interface{}) *dashv2alpha1.DashboardV2alpha1ActionStyle { + style := &dashv2alpha1.DashboardV2alpha1ActionStyle{} + + if backgroundColor, ok := styleMap["backgroundColor"].(string); ok { + style.BackgroundColor = &backgroundColor + } + + return style +} + +// convert2DStringArrayPreserveEmpty is like convert2DStringArray but returns +// an empty slice (not nil) when input is empty, to ensure JSON marshals as [] +func convert2DStringArrayPreserveEmpty(arr []interface{}) [][]string { + // Return empty slice (not nil) to preserve [] in JSON output + result := make([][]string, 0, len(arr)) + for _, item := range arr { + if innerArr, ok := item.([]interface{}); ok { + stringArr := make([]string, 0, len(innerArr)) + for _, s := range innerArr { + if str, ok := s.(string); ok { + stringArr = append(stringArr, str) + } + } + result = append(result, stringArr) + } + } + + 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. diff --git a/apps/dashboard/pkg/migration/conversion/v2alpha1_to_v1beta1.go b/apps/dashboard/pkg/migration/conversion/v2alpha1_to_v1beta1.go index e2a3e17843c..18d9ae90814 100644 --- a/apps/dashboard/pkg/migration/conversion/v2alpha1_to_v1beta1.go +++ b/apps/dashboard/pkg/migration/conversion/v2alpha1_to_v1beta1.go @@ -1072,10 +1072,14 @@ func convertPanelKindToV1(panelKind *dashv2alpha1.DashboardPanelKind, panel map[ } panel["targets"] = targets - // Detect mixed datasource - set panel.datasource to "mixed" if queries use different datasources - // This matches the frontend behavior in getPanelDataSource (layoutSerializers/utils.ts) - if mixedDS := detectMixedDatasource(spec.Data.Spec.Queries); mixedDS != nil { - panel["datasource"] = mixedDS + // Set panel-level datasource from queries. + // - If queries use different datasources, set to "mixed" + // - If all queries use the same datasource, set to that datasource + // This is required because the frontend's legacy PanelModel.PanelQueryRunner.run uses panel.datasource + // and some components like CSVExportPage rely on it to resolve the datasource. If undefined, it falls back to the default datasource + // which would overwrite the query's datasource. + if panelDS := getPanelDatasource(spec.Data.Spec.Queries); panelDS != nil { + panel["datasource"] = panelDS } // Convert transformations @@ -1086,6 +1090,17 @@ func convertPanelKindToV1(panelKind *dashv2alpha1.DashboardPanelKind, panel map[ "id": t.Spec.Id, "options": t.Spec.Options, } + // Add disabled if set + if t.Spec.Disabled != nil { + transformation["disabled"] = *t.Spec.Disabled + } + // Add filter if set + if t.Spec.Filter != nil { + transformation["filter"] = map[string]interface{}{ + "id": t.Spec.Filter.Id, + "options": t.Spec.Filter.Options, + } + } transformations = append(transformations, transformation) } panel["transformations"] = transformations @@ -1188,16 +1203,39 @@ func getDataSourceForQuery(explicitDS *dashv2alpha1.DashboardDataSourceRef, quer return nil } -// detectMixedDatasource checks if panel queries use different datasources. -// Returns a mixed datasource reference if queries use different datasources, nil otherwise. +// getPanelDatasource determines the panel-level datasource for V1. +// Returns: +// - Mixed datasource reference if queries use different datasources +// - Mixed datasource reference if multiple queries use Dashboard datasource (they fetch from different panels) +// - Dashboard datasource reference if a single query uses Dashboard datasource +// - First query's datasource if all queries use the same datasource +// - nil if no queries exist // Compares based on V2 input without runtime resolution: // - If query has explicit datasource.uid → use that UID and type // - Else → use query.Kind as type (empty UID) -func detectMixedDatasource(queries []dashv2alpha1.DashboardPanelQueryKind) map[string]interface{} { +func getPanelDatasource(queries []dashv2alpha1.DashboardPanelQueryKind) map[string]interface{} { + const sharedDashboardQuery = "-- Dashboard --" + if len(queries) == 0 { return nil } + // Count how many queries use Dashboard datasource + // Multiple dashboard queries need mixed mode because they fetch from different panels + // which may have different underlying datasources + dashboardDsQueryCount := 0 + for _, query := range queries { + if query.Spec.Datasource != nil && query.Spec.Datasource.Uid != nil && *query.Spec.Datasource.Uid == sharedDashboardQuery { + dashboardDsQueryCount++ + } + } + if dashboardDsQueryCount > 1 { + return map[string]interface{}{ + "type": "mixed", + "uid": "-- Mixed --", + } + } + var firstUID, firstType string var hasFirst bool @@ -1232,8 +1270,31 @@ func detectMixedDatasource(queries []dashv2alpha1.DashboardPanelQueryKind) map[s } } - // Not mixed - don't set panel-level datasource - return nil + // Handle case when a single query uses Dashboard datasource. + // This is needed for the frontend to properly activate and fetch data from source panels. + // See DashboardDatasourceBehaviour.tsx for more details. + if firstUID == sharedDashboardQuery { + return map[string]interface{}{ + "type": "datasource", + "uid": sharedDashboardQuery, + } + } + + // Not mixed - return the first query's datasource so the panel has a datasource set. + // This is required because the frontend's legacy PanelModel.PanelQueryRunner.run uses panel.datasource + // to resolve the datasource, and if undefined, it falls back to the default datasource + // which then overwrites the query's datasource. + if firstType == "" && firstUID == "" { + return nil + } + result := make(map[string]interface{}) + if firstType != "" { + result["type"] = firstType + } + if firstUID != "" { + result["uid"] = firstUID + } + return result } func convertLibraryPanelKindToV1(libPanelKind *dashv2alpha1.DashboardLibraryPanelKind, panel map[string]interface{}) (map[string]interface{}, error) { @@ -1935,9 +1996,18 @@ func convertFieldConfigDefaultsToV1(defaults *dashv2alpha1.DashboardFieldConfig) if defaults.Writeable != nil { result["writeable"] = *defaults.Writeable } + if defaults.FieldMinMax != nil { + result["fieldMinMax"] = *defaults.FieldMinMax + } + if defaults.NullValueMode != nil { + result["nullValueMode"] = string(*defaults.NullValueMode) + } if defaults.Links != nil { result["links"] = defaults.Links } + if len(defaults.Actions) > 0 { + result["actions"] = convertActionsToV1(defaults.Actions) + } if defaults.Color != nil { result["color"] = convertFieldColorToV1(defaults.Color) } @@ -2143,3 +2213,115 @@ func convertThresholdsToV1(thresholds *dashv2alpha1.DashboardThresholdsConfig) m return thresholdsMap } + +func convertActionsToV1(actions []dashv2alpha1.DashboardAction) []map[string]interface{} { + result := make([]map[string]interface{}, 0, len(actions)) + + for _, action := range actions { + actionMap := map[string]interface{}{ + "type": string(action.Type), + "title": action.Title, + } + + if action.Confirmation != nil { + actionMap["confirmation"] = *action.Confirmation + } + + if action.OneClick != nil { + actionMap["oneClick"] = *action.OneClick + } + + if action.Fetch != nil { + actionMap["fetch"] = convertFetchOptionsToV1(action.Fetch) + } + + if action.Infinity != nil { + actionMap["infinity"] = convertInfinityOptionsToV1(action.Infinity) + } + + if len(action.Variables) > 0 { + actionMap["variables"] = convertActionVariablesToV1(action.Variables) + } + + if action.Style != nil { + styleMap := map[string]interface{}{} + if action.Style.BackgroundColor != nil { + styleMap["backgroundColor"] = *action.Style.BackgroundColor + } + if len(styleMap) > 0 { + actionMap["style"] = styleMap + } + } + + result = append(result, actionMap) + } + + return result +} + +func convertFetchOptionsToV1(fetch *dashv2alpha1.DashboardFetchOptions) map[string]interface{} { + result := map[string]interface{}{ + "method": string(fetch.Method), + "url": fetch.Url, + } + + if fetch.Body != nil { + result["body"] = *fetch.Body + } + + if len(fetch.QueryParams) > 0 { + result["queryParams"] = convert2DStringArrayToInterface(fetch.QueryParams) + } + + if len(fetch.Headers) > 0 { + result["headers"] = convert2DStringArrayToInterface(fetch.Headers) + } + + return result +} + +func convertInfinityOptionsToV1(infinity *dashv2alpha1.DashboardInfinityOptions) map[string]interface{} { + result := map[string]interface{}{ + "method": string(infinity.Method), + "url": infinity.Url, + "datasourceUid": infinity.DatasourceUid, + } + + if infinity.Body != nil { + result["body"] = *infinity.Body + } + + if len(infinity.QueryParams) > 0 { + result["queryParams"] = convert2DStringArrayToInterface(infinity.QueryParams) + } + + if len(infinity.Headers) > 0 { + result["headers"] = convert2DStringArrayToInterface(infinity.Headers) + } + + return result +} + +func convertActionVariablesToV1(variables []dashv2alpha1.DashboardActionVariable) []map[string]interface{} { + result := make([]map[string]interface{}, 0, len(variables)) + for _, v := range variables { + result = append(result, map[string]interface{}{ + "key": v.Key, + "name": v.Name, + "type": v.Type, + }) + } + return result +} + +func convert2DStringArrayToInterface(arr [][]string) []interface{} { + result := make([]interface{}, 0, len(arr)) + for _, innerArr := range arr { + interfaceArr := make([]interface{}, 0, len(innerArr)) + for _, s := range innerArr { + interfaceArr = append(interfaceArr, s) + } + result = append(result, interfaceArr) + } + return result +} diff --git a/apps/dashboard/pkg/migration/conversion/v2alpha1_to_v2beta1.go b/apps/dashboard/pkg/migration/conversion/v2alpha1_to_v2beta1.go index 5b3a0d115b8..8435c56d83f 100644 --- a/apps/dashboard/pkg/migration/conversion/v2alpha1_to_v2beta1.go +++ b/apps/dashboard/pkg/migration/conversion/v2alpha1_to_v2beta1.go @@ -310,6 +310,9 @@ func convertFieldConfig_V2alpha1_to_V2beta1(in *dashv2alpha1.DashboardFieldConfi Links: in.Links, NoValue: in.NoValue, Custom: in.Custom, + FieldMinMax: in.FieldMinMax, + NullValueMode: (*dashv2beta1.DashboardNullValueMode)(in.NullValueMode), + Actions: convertActions_V2alpha1_to_V2beta1(in.Actions), } // Convert thresholds @@ -685,6 +688,7 @@ func convertVariable_V2alpha1_to_V2beta1(in *dashv2alpha1.DashboardVariableKind, SkipUrlSync: in.CustomVariableKind.Spec.SkipUrlSync, Description: in.CustomVariableKind.Spec.Description, AllowCustomValue: in.CustomVariableKind.Spec.AllowCustomValue, + ValuesFormat: convertCustomValuesFormat_V2alpha1_to_V2beta1(in.CustomVariableKind.Spec.ValuesFormat), }, } } @@ -758,6 +762,23 @@ func convertVariable_V2alpha1_to_V2beta1(in *dashv2alpha1.DashboardVariableKind, return nil } +func convertCustomValuesFormat_V2alpha1_to_V2beta1(in *dashv2alpha1.DashboardCustomVariableSpecValuesFormat) *dashv2beta1.DashboardCustomVariableSpecValuesFormat { + if in == nil { + return nil + } + + switch *in { + case dashv2alpha1.DashboardCustomVariableSpecValuesFormatJson: + v := dashv2beta1.DashboardCustomVariableSpecValuesFormatJson + return &v + case dashv2alpha1.DashboardCustomVariableSpecValuesFormatCsv: + v := dashv2beta1.DashboardCustomVariableSpecValuesFormatCsv + return &v + default: + return nil + } +} + func convertQueryVariableSpec_V2alpha1_to_V2beta1(in *dashv2alpha1.DashboardQueryVariableSpec, out *dashv2beta1.DashboardQueryVariableSpec, scope conversion.Scope) error { out.Name = in.Name out.Current = convertVariableOption_V2alpha1_to_V2beta1(in.Current) @@ -1003,3 +1024,59 @@ func convertAnnotationMappings_V2alpha1_to_V2beta1(in map[string]dashv2alpha1.Da } return out } + +func convertActions_V2alpha1_to_V2beta1(in []dashv2alpha1.DashboardAction) []dashv2beta1.DashboardAction { + if len(in) == 0 { + return nil + } + + out := make([]dashv2beta1.DashboardAction, len(in)) + for i, action := range in { + out[i] = dashv2beta1.DashboardAction{ + Type: dashv2beta1.DashboardActionType(action.Type), + Title: action.Title, + Confirmation: action.Confirmation, + OneClick: action.OneClick, + } + + if action.Fetch != nil { + out[i].Fetch = &dashv2beta1.DashboardFetchOptions{ + Method: dashv2beta1.DashboardHttpRequestMethod(action.Fetch.Method), + Url: action.Fetch.Url, + Body: action.Fetch.Body, + QueryParams: action.Fetch.QueryParams, + Headers: action.Fetch.Headers, + } + } + + if action.Infinity != nil { + out[i].Infinity = &dashv2beta1.DashboardInfinityOptions{ + Method: dashv2beta1.DashboardHttpRequestMethod(action.Infinity.Method), + Url: action.Infinity.Url, + Body: action.Infinity.Body, + QueryParams: action.Infinity.QueryParams, + Headers: action.Infinity.Headers, + DatasourceUid: action.Infinity.DatasourceUid, + } + } + + if len(action.Variables) > 0 { + out[i].Variables = make([]dashv2beta1.DashboardActionVariable, len(action.Variables)) + for j, v := range action.Variables { + out[i].Variables[j] = dashv2beta1.DashboardActionVariable{ + Key: v.Key, + Name: v.Name, + Type: v.Type, + } + } + } + + if action.Style != nil { + out[i].Style = &dashv2beta1.DashboardV2beta1ActionStyle{ + BackgroundColor: action.Style.BackgroundColor, + } + } + } + + return out +} diff --git a/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/datasource-loki/loki_query_splitting.v42.json b/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/datasource-loki/loki_query_splitting.v42.json index a7beffa4cdc..8af239195cb 100644 --- a/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/datasource-loki/loki_query_splitting.v42.json +++ b/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/datasource-loki/loki_query_splitting.v42.json @@ -219,8 +219,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -312,8 +311,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -492,8 +490,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -584,8 +581,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -676,8 +672,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -791,8 +786,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -906,8 +900,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -1022,8 +1015,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, diff --git a/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-canvas/canvas_kitchen_sink.v42.json b/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-canvas/canvas_kitchen_sink.v42.json new file mode 100644 index 00000000000..cf4db2fb1b6 --- /dev/null +++ b/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-canvas/canvas_kitchen_sink.v42.json @@ -0,0 +1,598 @@ +{ + "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": [], + "panels": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "1": { + "color": "green", + "icon": "img/icons/unicons/check-circle.svg", + "index": 0, + "text": "Success" + }, + "2": { + "color": "orange", + "icon": "img/icons/unicons/exclamation-triangle.svg", + "index": 1, + "text": "Warning" + }, + "3": { + "color": "red", + "icon": "img/icons/unicons/times-circle.svg", + "index": 2, + "text": "Error" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text" + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "mappings", + "value": [ + { + "options": { + "1": { + "color": "green", + "icon": "img/icons/unicons/check-circle.svg", + "index": 0, + "text": "Success" + } + }, + "type": "value" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "warning" + }, + "properties": [ + { + "id": "mappings", + "value": [ + { + "options": { + "2": { + "color": "orange", + "icon": "img/icons/unicons/exclamation-triangle.svg", + "index": 1, + "text": "Warning" + } + }, + "type": "value" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "error" + }, + "properties": [ + { + "id": "mappings", + "value": [ + { + "options": { + "3": { + "color": "red", + "icon": "img/icons/unicons/times-circle.svg", + "index": 2, + "text": "Error" + } + }, + "type": "value" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "unmapped" + }, + "properties": [ + { + "id": "mappings", + "value": [ + { + "options": { + "1": { + "color": "green", + "icon": "img/icons/unicons/check-circle.svg", + "index": 0, + "text": "Success" + }, + "2": { + "color": "orange", + "icon": "img/icons/unicons/exclamation-triangle.svg", + "index": 1, + "text": "Warning" + }, + "3": { + "color": "red", + "icon": "img/icons/unicons/times-circle.svg", + "index": 2, + "text": "Error" + } + }, + "type": "value" + } + ] + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 1, + "options": { + "inlineEditing": true, + "root": { + "background": { + "color": { + "fixed": "transparent" + } + }, + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "elements": [ + { + "config": { + "align": "center", + "color": { + "fixed": "text" + }, + "size": 16, + "text": { + "fixed": "Field-based Icons (from value mappings):", + "mode": "fixed" + }, + "valign": "middle" + }, + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "name": "Header", + "placement": { + "height": 40, + "left": 20, + "top": 10, + "width": 400 + }, + "type": "text" + }, + { + "config": { + "fill": { + "field": "success", + "fixed": "green" + }, + "path": { + "field": "success", + "mode": "field" + } + }, + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "name": "Success Icon", + "placement": { + "height": 50, + "left": 50, + "top": 60, + "width": 50 + }, + "type": "icon" + }, + { + "config": { + "align": "center", + "color": { + "field": "success", + "fixed": "text" + }, + "size": 12, + "text": { + "field": "success", + "mode": "field" + }, + "valign": "middle" + }, + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "name": "Success Text", + "placement": { + "height": 25, + "left": 30, + "top": 115, + "width": 90 + }, + "type": "text" + }, + { + "config": { + "fill": { + "field": "warning", + "fixed": "orange" + }, + "path": { + "field": "warning", + "mode": "field" + } + }, + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "name": "Warning Icon", + "placement": { + "height": 50, + "left": 180, + "top": 60, + "width": 50 + }, + "type": "icon" + }, + { + "config": { + "align": "center", + "color": { + "field": "warning", + "fixed": "text" + }, + "size": 12, + "text": { + "field": "warning", + "mode": "field" + }, + "valign": "middle" + }, + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "name": "Warning Text", + "placement": { + "height": 25, + "left": 160, + "top": 115, + "width": 90 + }, + "type": "text" + }, + { + "config": { + "fill": { + "field": "error", + "fixed": "red" + }, + "path": { + "field": "error", + "mode": "field" + } + }, + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "name": "Error Icon", + "placement": { + "height": 50, + "left": 310, + "top": 60, + "width": 50 + }, + "type": "icon" + }, + { + "config": { + "align": "center", + "color": { + "field": "error", + "fixed": "text" + }, + "size": 12, + "text": { + "field": "error", + "mode": "field" + }, + "valign": "middle" + }, + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "name": "Error Text", + "placement": { + "height": 25, + "left": 290, + "top": 115, + "width": 90 + }, + "type": "text" + }, + { + "config": { + "fill": { + "field": "unmapped", + "fixed": "#808080" + }, + "path": { + "field": "unmapped", + "fixed": "img/icons/unicons/question-circle.svg", + "mode": "field" + } + }, + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "name": "Unmapped Icon", + "placement": { + "height": 50, + "left": 440, + "top": 60, + "width": 50 + }, + "type": "icon" + }, + { + "config": { + "align": "center", + "color": { + "field": "unmapped", + "fixed": "text" + }, + "size": 12, + "text": { + "fixed": "No mapping (14)", + "mode": "fixed" + }, + "valign": "middle" + }, + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "name": "Unmapped Text", + "placement": { + "height": 25, + "left": 410, + "top": 115, + "width": 110 + }, + "type": "text" + }, + { + "config": { + "align": "center", + "color": { + "fixed": "text" + }, + "size": 14, + "text": { + "fixed": "Fixed Relative Path:", + "mode": "fixed" + }, + "valign": "middle" + }, + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "name": "Relative Label", + "placement": { + "height": 30, + "left": 50, + "top": 170, + "width": 200 + }, + "type": "text" + }, + { + "config": { + "fill": { + "fixed": "blue" + }, + "path": { + "fixed": "img/icons/unicons/cloud.svg", + "mode": "fixed" + } + }, + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "name": "Relative Icon", + "placement": { + "height": 50, + "left": 260, + "top": 165, + "width": 50 + }, + "type": "icon" + }, + { + "config": { + "align": "center", + "color": { + "fixed": "text" + }, + "size": 14, + "text": { + "fixed": "Fixed Absolute URL:", + "mode": "fixed" + }, + "valign": "middle" + }, + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "name": "Absolute Label", + "placement": { + "height": 30, + "left": 50, + "top": 240, + "width": 200 + }, + "type": "text" + }, + { + "config": { + "fill": { + "fixed": "purple" + }, + "path": { + "fixed": "https://grafana.com/static/assets/img/grafana_icon.svg", + "mode": "fixed" + } + }, + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "name": "Absolute Icon", + "placement": { + "height": 50, + "left": 260, + "top": 235, + "width": 50 + }, + "type": "icon" + } + ], + "name": "Canvas Root", + "placement": { + "height": 100, + "left": 0, + "top": 0, + "width": 100 + }, + "type": "frame" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "csvContent": "success\n1", + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_content" + }, + { + "csvContent": "warning\n2", + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "PD8C576611E62080A" + }, + "refId": "B", + "scenarioId": "csv_content" + }, + { + "csvContent": "error\n3", + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "PD8C576611E62080A" + }, + "refId": "C", + "scenarioId": "csv_content" + }, + { + "csvContent": "unmapped\n14", + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "PD8C576611E62080A" + }, + "refId": "D", + "scenarioId": "csv_content" + } + ], + "title": "Various SVG icons", + "type": "canvas" + } + ], + "refresh": "", + "schemaVersion": 42, + "tags": [ + "canvas", + "icons", + "test", + "v2" + ], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Panel tests - Canvas - Kitchen sink", + "uid": "canvas-icon-fix-test-v2", + "weekStart": "" +} \ No newline at end of file diff --git a/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-gauge/gauge_tests.v42.json b/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-gauge/gauge_tests.v42.json index 92a865b0b10..87b63411976 100644 --- a/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-gauge/gauge_tests.v42.json +++ b/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-gauge/gauge_tests.v42.json @@ -65,17 +65,14 @@ "mode": "absolute", "steps": [ { - "color": "#7EB26D", - "index": 0 + "color": "#7EB26D" }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -136,17 +133,14 @@ "mode": "absolute", "steps": [ { - "color": "#7EB26D", - "index": 0 + "color": "#7EB26D" }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -207,17 +201,14 @@ "mode": "absolute", "steps": [ { - "color": "#7EB26D", - "index": 0 + "color": "#7EB26D" }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -271,7 +262,6 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "", "mappings": [], "max": 100, "min": 0, @@ -279,17 +269,14 @@ "mode": "absolute", "steps": [ { - "color": "#7EB26D", - "index": 0 + "color": "#7EB26D" }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -342,7 +329,6 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "", "mappings": [], "max": 100, "min": 0, @@ -350,17 +336,14 @@ "mode": "absolute", "steps": [ { - "color": "#7EB26D", - "index": 0 + "color": "#7EB26D" }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -414,7 +397,6 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "", "mappings": [], "max": 100, "min": 0, @@ -422,17 +404,14 @@ "mode": "absolute", "steps": [ { - "color": "#7EB26D", - "index": 0 + "color": "#7EB26D" }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -485,7 +464,6 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "", "mappings": [], "max": 100, "min": 0, @@ -493,17 +471,14 @@ "mode": "absolute", "steps": [ { - "color": "#7EB26D", - "index": 0 + "color": "#7EB26D" }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -628,6 +603,20 @@ } ], "title": "Only nulls and no user set min \u0026 max", + "transformations": [ + { + "id": "convertFieldType", + "options": { + "conversions": [ + { + "destinationType": "number", + "targetField": "A-series" + } + ], + "fields": {} + } + } + ], "type": "gauge" }, { @@ -668,7 +657,6 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "", "mappings": [ { "options": { @@ -685,17 +673,14 @@ "mode": "absolute", "steps": [ { - "color": "#7EB26D", - "index": 0 + "color": "#7EB26D" }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -750,7 +735,6 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "", "mappings": [ { "options": { @@ -768,17 +752,14 @@ "mode": "absolute", "steps": [ { - "color": "#7EB26D", - "index": 0 + "color": "#7EB26D" }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -833,7 +814,6 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "", "mappings": [ { "options": { @@ -852,17 +832,14 @@ "mode": "absolute", "steps": [ { - "color": "#7EB26D", - "index": 0 + "color": "#7EB26D" }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -917,7 +894,6 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "", "mappings": [ { "options": { @@ -946,17 +922,14 @@ "mode": "absolute", "steps": [ { - "color": "#7EB26D", - "index": 0 + "color": "#7EB26D" }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -1038,7 +1011,7 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "2", + "decimals": 2, "mappings": [], "max": 100, "min": 0, @@ -1046,17 +1019,14 @@ "mode": "absolute", "steps": [ { - "color": "#7EB26D", - "index": 0 + "color": "#7EB26D" }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] diff --git a/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-gauge/gauge_tests_new.v42.json b/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-gauge/gauge_tests_new.v42.json index cb130445efc..61f092d491e 100644 --- a/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-gauge/gauge_tests_new.v42.json +++ b/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-gauge/gauge_tests_new.v42.json @@ -71,13 +71,13 @@ "id": 1, "maxDataPoints": 20, "options": { + "barShape": "rounded", "barWidthFactor": 0.4, "effects": { "barGlow": false, "centerGlow": false, "gradient": false }, - "barShape": "rounded", "orientation": "auto", "reduceOptions": { "calcs": [ @@ -149,13 +149,13 @@ "id": 4, "maxDataPoints": 20, "options": { + "barShape": "rounded", "barWidthFactor": 0.4, "effects": { "barGlow": false, "centerGlow": true, "gradient": false }, - "barShape": "rounded", "orientation": "auto", "reduceOptions": { "calcs": [ @@ -227,13 +227,13 @@ "id": 3, "maxDataPoints": 20, "options": { + "barShape": "rounded", "barWidthFactor": 0.4, "effects": { "barGlow": true, "centerGlow": true, "gradient": false }, - "barShape": "rounded", "orientation": "auto", "reduceOptions": { "calcs": [ @@ -305,13 +305,13 @@ "id": 8, "maxDataPoints": 20, "options": { + "barShape": "rounded", "barWidthFactor": 0.4, "effects": { "barGlow": true, "centerGlow": true, "gradient": false }, - "barShape": "rounded", "orientation": "auto", "reduceOptions": { "calcs": [ @@ -383,13 +383,13 @@ "id": 22, "maxDataPoints": 20, "options": { + "barShape": "flat", "barWidthFactor": 0.72, "effects": { "barGlow": true, "centerGlow": true, "gradient": false }, - "barShape": "flat", "orientation": "auto", "reduceOptions": { "calcs": [ @@ -461,13 +461,13 @@ "id": 23, "maxDataPoints": 20, "options": { + "barShape": "flat", "barWidthFactor": 0.72, "effects": { "barGlow": true, "centerGlow": true, "gradient": false }, - "barShape": "flat", "orientation": "auto", "reduceOptions": { "calcs": [ @@ -552,13 +552,13 @@ "id": 18, "maxDataPoints": 20, "options": { + "barShape": "rounded", "barWidthFactor": 0.1, "effects": { "barGlow": true, "centerGlow": true, "gradient": false }, - "barShape": "rounded", "orientation": "auto", "reduceOptions": { "calcs": [ @@ -630,13 +630,13 @@ "id": 19, "maxDataPoints": 20, "options": { + "barShape": "rounded", "barWidthFactor": 0.32, "effects": { "barGlow": true, "centerGlow": true, "gradient": false }, - "barShape": "rounded", "orientation": "auto", "reduceOptions": { "calcs": [ @@ -708,13 +708,13 @@ "id": 20, "maxDataPoints": 20, "options": { + "barShape": "rounded", "barWidthFactor": 0.57, "effects": { "barGlow": true, "centerGlow": true, "gradient": false }, - "barShape": "rounded", "orientation": "auto", "reduceOptions": { "calcs": [ @@ -786,13 +786,13 @@ "id": 21, "maxDataPoints": 20, "options": { + "barShape": "rounded", "barWidthFactor": 0.8, "effects": { "barGlow": true, "centerGlow": true, "gradient": false }, - "barShape": "rounded", "orientation": "auto", "reduceOptions": { "calcs": [ @@ -881,13 +881,13 @@ "id": 25, "maxDataPoints": 20, "options": { + "barShape": "flat", "barWidthFactor": 0.9, "effects": { "barGlow": false, "centerGlow": false, "gradient": false }, - "barShape": "flat", "orientation": "auto", "reduceOptions": { "calcs": [ @@ -959,13 +959,13 @@ "id": 26, "maxDataPoints": 20, "options": { + "barShape": "flat", "barWidthFactor": 0.72, "effects": { "barGlow": false, "centerGlow": false, "gradient": false }, - "barShape": "flat", "orientation": "auto", "reduceOptions": { "calcs": [ @@ -1037,13 +1037,13 @@ "id": 29, "maxDataPoints": 20, "options": { + "barShape": "flat", "barWidthFactor": 0.72, "effects": { "barGlow": false, "centerGlow": false, "gradient": true }, - "barShape": "flat", "orientation": "auto", "reduceOptions": { "calcs": [ @@ -1115,13 +1115,13 @@ "id": 30, "maxDataPoints": 20, "options": { + "barShape": "flat", "barWidthFactor": 0.9, "effects": { "barGlow": false, "centerGlow": false, "gradient": false }, - "barShape": "flat", "orientation": "auto", "reduceOptions": { "calcs": [ @@ -1193,13 +1193,13 @@ "id": 28, "maxDataPoints": 20, "options": { + "barShape": "flat", "barWidthFactor": 0.72, "effects": { "barGlow": false, "centerGlow": false, "gradient": false }, - "barShape": "flat", "orientation": "auto", "reduceOptions": { "calcs": [ @@ -1288,13 +1288,13 @@ "id": 32, "maxDataPoints": 20, "options": { + "barShape": "flat", "barWidthFactor": 0.9, "effects": { "barGlow": false, "centerGlow": false, "gradient": true }, - "barShape": "flat", "orientation": "auto", "reduceOptions": { "calcs": [ @@ -1370,13 +1370,13 @@ "id": 34, "maxDataPoints": 20, "options": { + "barShape": "flat", "barWidthFactor": 0.9, "effects": { "barGlow": false, "centerGlow": false, "gradient": true }, - "barShape": "flat", "orientation": "auto", "reduceOptions": { "calcs": [ @@ -1452,13 +1452,13 @@ "id": 33, "maxDataPoints": 20, "options": { + "barShape": "flat", "barWidthFactor": 0.9, "effects": { "barGlow": false, "centerGlow": false, "gradient": true }, - "barShape": "flat", "orientation": "auto", "reduceOptions": { "calcs": [ @@ -1541,9 +1541,9 @@ "id": 9, "maxDataPoints": 20, "options": { + "barShape": "rounded", "barWidth": 12, "barWidthFactor": 0.4, - "barShape": "rounded", "effects": { "barGlow": true, "centerGlow": true, @@ -1624,6 +1624,7 @@ "id": 11, "maxDataPoints": 20, "options": { + "barShape": "rounded", "barWidth": 12, "barWidthFactor": 0.4, "effects": { @@ -1631,7 +1632,6 @@ "centerGlow": true, "gradient": true }, - "barShape": "rounded", "glow": "both", "orientation": "auto", "reduceOptions": { @@ -1720,6 +1720,7 @@ "id": 13, "maxDataPoints": 20, "options": { + "barShape": "rounded", "barWidth": 12, "barWidthFactor": 0.49, "effects": { @@ -1727,7 +1728,6 @@ "centerGlow": true, "gradient": true }, - "barShape": "rounded", "glow": "both", "orientation": "auto", "reduceOptions": { @@ -1761,6 +1761,22 @@ } ], "title": "Active gateways", + "transformations": [ + { + "id": "calculateField", + "options": { + "mode": "unary", + "reduce": { + "reducer": "sum" + }, + "replaceFields": true, + "unary": { + "fieldName": "A-series", + "operator": "round" + } + } + } + ], "type": "radialbar" }, { @@ -1803,6 +1819,7 @@ "id": 14, "maxDataPoints": 20, "options": { + "barShape": "rounded", "barWidth": 12, "barWidthFactor": 0.49, "effects": { @@ -1810,7 +1827,6 @@ "centerGlow": true, "gradient": true }, - "barShape": "rounded", "glow": "both", "orientation": "auto", "reduceOptions": { @@ -1844,6 +1860,22 @@ } ], "title": "Active pods", + "transformations": [ + { + "id": "calculateField", + "options": { + "mode": "unary", + "reduce": { + "reducer": "sum" + }, + "replaceFields": true, + "unary": { + "fieldName": "A-series", + "operator": "round" + } + } + } + ], "type": "radialbar" }, { @@ -1885,6 +1917,7 @@ "id": 15, "maxDataPoints": 20, "options": { + "barShape": "rounded", "barWidth": 12, "barWidthFactor": 0.84, "effects": { @@ -1892,7 +1925,6 @@ "centerGlow": true, "gradient": true }, - "barShape": "rounded", "glow": "both", "orientation": "auto", "reduceOptions": { @@ -1967,6 +1999,7 @@ "id": 16, "maxDataPoints": 20, "options": { + "barShape": "rounded", "barWidth": 12, "barWidthFactor": 0.66, "effects": { @@ -1974,7 +2007,6 @@ "centerGlow": true, "gradient": true }, - "barShape": "rounded", "glow": "both", "orientation": "auto", "reduceOptions": { @@ -2054,13 +2086,13 @@ }, "id": 36, "options": { + "barShape": "flat", "barWidthFactor": 0.5, "effects": { "barGlow": false, "centerGlow": false, "gradient": true }, - "barShape": "flat", "orientation": "auto", "reduceOptions": { "calcs": [ @@ -2121,13 +2153,13 @@ }, "id": 37, "options": { + "barShape": "flat", "barWidthFactor": 0.5, "effects": { "barGlow": false, "centerGlow": false, "gradient": true }, - "barShape": "flat", "orientation": "auto", "reduceOptions": { "calcs": [ @@ -2169,4 +2201,4 @@ "title": "Panel tests - Gauge (new)", "uid": "panel-tests-gauge-new", "weekStart": "" -} +} \ No newline at end of file diff --git a/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-gauge/gauge_tests_old_to_new.v42.json b/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-gauge/gauge_tests_old_to_new.v42.json index dda0fbcd432..449955a9cc8 100644 --- a/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-gauge/gauge_tests_old_to_new.v42.json +++ b/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-gauge/gauge_tests_old_to_new.v42.json @@ -485,6 +485,7 @@ }, "id": 12, "options": { + "displayName": "My gauge", "minVizHeight": 75, "minVizWidth": 75, "orientation": "auto", @@ -1160,4 +1161,4 @@ "title": "Panel tests - Old gauge to new", "uid": "panel-tests-old-gauge-to-new", "weekStart": "" -} +} \ No newline at end of file diff --git a/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-histogram/histogram_tests.v42.json b/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-histogram/histogram_tests.v42.json index 7e392bd55d0..6c521eaec9b 100644 --- a/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-histogram/histogram_tests.v42.json +++ b/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-histogram/histogram_tests.v42.json @@ -58,8 +58,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -127,8 +126,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -196,8 +194,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -277,8 +274,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -355,8 +351,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -448,8 +443,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -536,8 +530,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [ { @@ -619,8 +612,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [ { @@ -702,8 +694,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [ { @@ -785,8 +776,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -850,8 +840,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [ { diff --git a/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-piechart/panel_test_piechart.v42.json b/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-piechart/panel_test_piechart.v42.json index f705124be5b..5b07f246ae3 100644 --- a/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-piechart/panel_test_piechart.v42.json +++ b/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-piechart/panel_test_piechart.v42.json @@ -290,7 +290,7 @@ ], "legend": { "displayMode": "table", - "placement": "bottom", + "placement": "right", "showLegend": true, "values": [ "percent" @@ -304,7 +304,7 @@ "fields": "", "values": false }, - "showLegend": false, + "showLegend": true, "strokeWidth": 1, "text": {} }, @@ -323,6 +323,15 @@ } ], "title": "Percent", + "transformations": [ + { + "id": "renameByRegex", + "options": { + "regex": "^Backend-(.*)$", + "renamePattern": "b-$1" + } + } + ], "type": "piechart" }, { @@ -366,7 +375,7 @@ ], "legend": { "displayMode": "table", - "placement": "bottom", + "placement": "right", "showLegend": true, "values": [ "value" @@ -380,7 +389,7 @@ "fields": "", "values": false }, - "showLegend": false, + "showLegend": true, "strokeWidth": 1, "text": {} }, @@ -399,6 +408,15 @@ } ], "title": "Value", + "transformations": [ + { + "id": "renameByRegex", + "options": { + "regex": "(.*)", + "renamePattern": "$1-how-much-wood-could-a-woodchuck-chuck-if-a-woodchuck-could-chuck-wood" + } + } + ], "type": "piechart" }, { diff --git a/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-xychart/xychart-tooltip-color-test.v42.json b/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-xychart/xychart-tooltip-color-test.v42.json index 417ea1661e1..f28fee864e5 100644 --- a/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-xychart/xychart-tooltip-color-test.v42.json +++ b/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-xychart/xychart-tooltip-color-test.v42.json @@ -61,8 +61,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -148,8 +147,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -235,8 +233,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -322,8 +319,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -416,8 +412,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -510,8 +505,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -604,8 +598,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, diff --git a/apps/iam/go.mod b/apps/iam/go.mod index 24769ca825f..e35a733d350 100644 --- a/apps/iam/go.mod +++ b/apps/iam/go.mod @@ -24,8 +24,6 @@ replace github.com/grafana/grafana/apps/alerting/historian => ../alerting/histor replace github.com/grafana/grafana/apps/correlations => ../correlations -replace github.com/grafana/grafana/apps/investigations => ../investigations - replace github.com/grafana/grafana/apps/logsdrilldown => ../logsdrilldown replace github.com/grafana/grafana/apps/playlist => ../playlist @@ -89,6 +87,7 @@ require ( github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 // indirect github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect github.com/IBM/pgxpoolprometheus v1.1.2 // indirect + github.com/Machiel/slugify v1.0.1 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver v1.5.0 // indirect github.com/Masterminds/semver/v3 v3.4.0 // indirect @@ -105,25 +104,25 @@ require ( github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/at-wat/mqtt-go v0.19.6 // indirect github.com/aws/aws-sdk-go v1.55.7 // indirect - github.com/aws/aws-sdk-go-v2 v1.39.1 // indirect + github.com/aws/aws-sdk-go-v2 v1.40.0 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.11 // indirect - github.com/aws/aws-sdk-go-v2/config v1.31.10 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.18.14 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.8 // indirect + github.com/aws/aws-sdk-go-v2/config v1.31.17 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.18.21 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13 // indirect github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.84 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.8 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.8 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.36 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.8 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.17 // indirect github.com/aws/aws-sdk-go-v2/service/s3 v1.84.0 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.29.4 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.0 // 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/aws/aws-sdk-go-v2/service/sso v1.30.1 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.5 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.39.1 // indirect + github.com/aws/smithy-go v1.23.2 // indirect github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df // indirect github.com/benbjohnson/clock v1.3.5 // indirect @@ -223,12 +222,12 @@ require ( github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect github.com/googleapis/gax-go/v2 v2.15.0 // indirect github.com/gorilla/mux v1.8.1 // indirect - github.com/grafana/alerting v0.0.0-20251212143239-491433b332b7 // indirect + github.com/grafana/alerting v0.0.0-20251231150637-b7821017d69f // indirect github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f // indirect github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4 // indirect github.com/grafana/dataplane/sdata v0.0.9 // indirect github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 // indirect - github.com/grafana/grafana-aws-sdk v1.3.0 // indirect + github.com/grafana/grafana-aws-sdk v1.4.2 // indirect github.com/grafana/grafana-azure-sdk-go/v2 v2.3.1 // indirect github.com/grafana/grafana-plugin-sdk-go v0.284.0 // indirect github.com/grafana/grafana/apps/dashboard v0.0.0 // indirect @@ -241,7 +240,7 @@ require ( github.com/grafana/otel-profiling-go v0.5.1 // indirect github.com/grafana/pyroscope-go/godeltaprof v0.1.9 // indirect github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect - github.com/grafana/sqlds/v4 v4.2.7 // indirect + github.com/grafana/sqlds/v5 v5.0.3 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 // indirect diff --git a/apps/iam/go.sum b/apps/iam/go.sum index 4584bbd9cc1..063696e3d5a 100644 --- a/apps/iam/go.sum +++ b/apps/iam/go.sum @@ -82,8 +82,8 @@ cloud.google.com/go/storage v1.55.0 h1:NESjdAToN9u1tmhVqhXCaCwYBuvEhZLLv0gBr+2zn cloud.google.com/go/storage v1.55.0/go.mod h1:ztSmTTwzsdXe5syLVS0YsbFxXuvEmEyZj7v7zChEmuY= 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= +connectrpc.com/connect v1.19.1 h1:R5M57z05+90EfEvCY1b7hBxDVOUl45PrtXtAV2fOC14= +connectrpc.com/connect v1.19.1/go.mod h1:tN20fjdGlewnSFeZxLKb0xwIZ6ozc3OQs2hTXy4du9w= 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= @@ -167,6 +167,8 @@ github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/IBM/pgxpoolprometheus v1.1.2 h1:sHJwxoL5Lw4R79Zt+H4Uj1zZ4iqXJLdk7XDE7TPs97U= github.com/IBM/pgxpoolprometheus v1.1.2/go.mod h1:+vWzISN6S9ssgurhUNmm6AlXL9XLah3TdWJktquKTR8= +github.com/Machiel/slugify v1.0.1 h1:EfWSlRWstMadsgzmiV7d0yVd2IFlagWH68Q+DcYCm4E= +github.com/Machiel/slugify v1.0.1/go.mod h1:fTFGn5uWEynW4CUMG7sWkYXOf1UgDxyTM3DbR6Qfg3k= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= @@ -236,24 +238,24 @@ github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/aws/aws-sdk-go v1.55.7 h1:UJrkFq7es5CShfBwlWAC8DA077vp8PyVbQd3lqLiztE= github.com/aws/aws-sdk-go v1.55.7/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= -github.com/aws/aws-sdk-go-v2 v1.39.1 h1:fWZhGAwVRK/fAN2tmt7ilH4PPAE11rDj7HytrmbZ2FE= -github.com/aws/aws-sdk-go-v2 v1.39.1/go.mod h1:sDioUELIUO9Znk23YVmIk86/9DOpkbyyVb1i/gUNFXY= +github.com/aws/aws-sdk-go-v2 v1.40.0 h1:/WMUA0kjhZExjOQN2z3oLALDREea1A7TobfuiBrKlwc= +github.com/aws/aws-sdk-go-v2 v1.40.0/go.mod h1:c9pm7VwuW0UPxAEYGyTmyurVcNrbF6Rt/wixFqDhcjE= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.11 h1:12SpdwU8Djs+YGklkinSSlcrPyj3H4VifVsKf78KbwA= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.11/go.mod h1:dd+Lkp6YmMryke+qxW/VnKyhMBDTYP41Q2Bb+6gNZgY= -github.com/aws/aws-sdk-go-v2/config v1.31.10 h1:7LllDZAegXU3yk41mwM6KcPu0wmjKGQB1bg99bNdQm4= -github.com/aws/aws-sdk-go-v2/config v1.31.10/go.mod h1:Ge6gzXPjqu4v0oHvgAwvGzYcK921GU0hQM25WF/Kl+8= -github.com/aws/aws-sdk-go-v2/credentials v1.18.14 h1:TxkI7QI+sFkTItN/6cJuMZEIVMFXeu2dI1ZffkXngKI= -github.com/aws/aws-sdk-go-v2/credentials v1.18.14/go.mod h1:12x4Uw/vijC11XkctTjy92TNCQ+UnNJkT7fzX0Yd93E= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.8 h1:gLD09eaJUdiszm7vd1btiQUYE0Hj+0I2b8AS+75z9AY= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.8/go.mod h1:4RW3oMPt1POR74qVOC4SbubxAwdP4pCT0nSw3jycOU4= +github.com/aws/aws-sdk-go-v2/config v1.31.17 h1:QFl8lL6RgakNK86vusim14P2k8BFSxjvUkcWLDjgz9Y= +github.com/aws/aws-sdk-go-v2/config v1.31.17/go.mod h1:V8P7ILjp/Uef/aX8TjGk6OHZN6IKPM5YW6S78QnRD5c= +github.com/aws/aws-sdk-go-v2/credentials v1.18.21 h1:56HGpsgnmD+2/KpG0ikvvR8+3v3COCwaF4r+oWwOeNA= +github.com/aws/aws-sdk-go-v2/credentials v1.18.21/go.mod h1:3YELwedmQbw7cXNaII2Wywd+YY58AmLPwX4LzARgmmA= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13 h1:T1brd5dR3/fzNFAQch/iBKeX07/ffu/cLu+q+RuzEWk= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13/go.mod h1:Peg/GBAQ6JDt+RoBf4meB1wylmAipb7Kg2ZFakZTlwk= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.84 h1:cTXRdLkpBanlDwISl+5chq5ui1d1YWg4PWMR9c3kXyw= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.84/go.mod h1:kwSy5X7tfIHN39uucmjQVs2LvDdXEjQucgQQEqCggEo= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.8 h1:6bgAZgRyT4RoFWhxS+aoGMFyE0cD1bSzFnEEi4bFPGI= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.8/go.mod h1:KcGkXFVU8U28qS4KvLEcPxytPZPBcRawaH2Pf/0jptE= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.8 h1:HhJYoES3zOz34yWEpGENqJvRVPqpmJyR3+AFg9ybhdY= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.8/go.mod h1:JnA+hPWeYAVbDssp83tv+ysAG8lTfLVXvSsyKg/7xNA= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14 h1:PZHqQACxYb8mYgms4RZbhZG0a7dPW06xOjmaH0EJC/I= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14/go.mod h1:VymhrMJUWs69D8u0/lZ7jSB6WgaG/NqHi3gX0aYf6U0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14 h1:bOS19y6zlJwagBfHxs0ESzr1XCOU2KXJCWcq3E2vfjY= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14/go.mod h1:1ipeGBMAxZ0xcTm6y6paC2C/J6f6OO7LBODV9afuAyM= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.36 h1:GMYy2EOWfzdP3wfVAGXBNKY5vK4K8vMET4sYOYltmqs= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.36/go.mod h1:gDhdAV6wL3PmPqBhiPbnlS447GoWs8HTTOYef9/9Inw= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.45.3 h1:Nn3qce+OHZuMj/edx4its32uxedAmquCDxtZkrdeiD4= @@ -262,12 +264,12 @@ github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.51.0 h1:e5cbPZYTIY2nUEFie github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.51.0/go.mod h1:UseIHRfrm7PqeZo6fcTb6FUCXzCnh1KJbQbmOfxArGM= github.com/aws/aws-sdk-go-v2/service/ec2 v1.225.2 h1:IfMb3Ar8xEaWjgH/zeVHYD8izwJdQgRP5mKCTDt4GNk= github.com/aws/aws-sdk-go-v2/service/ec2 v1.225.2/go.mod h1:35jGWx7ECvCwTsApqicFYzZ7JFEnBc6oHUuOQ3xIS54= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1 h1:oegbebPEMA/1Jny7kvwejowCaHz1FWZAQ94WXFNCyTM= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1/go.mod h1:kemo5Myr9ac0U9JfSjMo9yHLtw+pECEHsFtJ9tqCEI8= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 h1:x2Ibm/Af8Fi+BH+Hsn9TXGdT+hKbDd5XOTZxTMxDk7o= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3/go.mod h1:IW1jwyrQgMdhisceG8fQLmQIydcT/jWY21rFhzgaKwo= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.4 h1:nAP2GYbfh8dd2zGZqFRSMlq+/F6cMPBUuCsGAMkN074= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.4/go.mod h1:LT10DsiGjLWh4GbjInf9LQejkYEhBgBCjLG5+lvk4EE= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.8 h1:M6JI2aGFEzYxsF6CXIuRBnkge9Wf9a2xU39rNeXgu10= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.8/go.mod h1:Fw+MyTwlwjFsSTE31mH211Np+CUslml8mzc0AFEG09s= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13 h1:kDqdFvMY4AtKoACfzIGD8A0+hbT41KTKF//gq7jITfM= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13/go.mod h1:lmKuogqSU3HzQCwZ9ZtcqOc5XGMqtDK7OIc2+DxiUEg= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.17 h1:qcLWgdhq45sDM9na4cvXax9dyLitn8EYBRl8Ak4XtG4= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.17/go.mod h1:M+jkjBFZ2J6DJrjMv2+vkBbuht6kxJYtJiwoVgX4p4U= github.com/aws/aws-sdk-go-v2/service/kms v1.41.2 h1:zJeUxFP7+XP52u23vrp4zMcVhShTWbNO8dHV6xCSvFo= @@ -278,14 +280,16 @@ github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.26.6 h1:Pwbxovp github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.26.6/go.mod h1:Z4xLt5mXspLKjBV92i165wAJ/3T6TIv4n7RtIS8pWV0= github.com/aws/aws-sdk-go-v2/service/s3 v1.84.0 h1:0reDqfEN+tB+sozj2r92Bep8MEwBZgtAXTND1Kk9OXg= github.com/aws/aws-sdk-go-v2/service/s3 v1.84.0/go.mod h1:kUklwasNoCn5YpyAqC/97r6dzTA1SRKJfKq16SXeoDU= -github.com/aws/aws-sdk-go-v2/service/sso v1.29.4 h1:FTdEN9dtWPB0EOURNtDPmwGp6GGvMqRJCAihkSl/1No= -github.com/aws/aws-sdk-go-v2/service/sso v1.29.4/go.mod h1:mYubxV9Ff42fZH4kexj43gFPhgc/LyC7KqvUKt1watc= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.0 h1:I7ghctfGXrscr7r1Ga/mDqSJKm7Fkpl5Mwq79Z+rZqU= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.0/go.mod h1:Zo9id81XP6jbayIFWNuDpA6lMBWhsVy+3ou2jLa4JnA= -github.com/aws/aws-sdk-go-v2/service/sts v1.38.5 h1:+LVB0xBqEgjQoqr9bGZbRzvg212B0f17JdflleJRNR4= -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/aws/aws-sdk-go-v2/service/secretsmanager v1.40.1 h1:w6a0H79HrHf3lr+zrw+pSzR5B+caiQFAKiNHlrUcnoc= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.40.1/go.mod h1:c6Vg0BRiU7v0MVhHupw90RyL120QBwAMLbDCzptGeMk= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.1 h1:0JPwLz1J+5lEOfy/g0SURC9cxhbQ1lIMHMa+AHZSzz0= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.1/go.mod h1:fKvyjJcz63iL/ftA6RaM8sRCtN4r4zl4tjL3qw5ec7k= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.5 h1:OWs0/j2UYR5LOGi88sD5/lhN6TDLG6SfA7CqsQO9zF0= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.5/go.mod h1:klO+ejMvYsB4QATfEOIXk8WAEwN4N0aBfJpvC+5SZBo= +github.com/aws/aws-sdk-go-v2/service/sts v1.39.1 h1:mLlUgHn02ue8whiR4BmxxGJLR2gwU6s6ZzJ5wDamBUs= +github.com/aws/aws-sdk-go-v2/service/sts v1.39.1/go.mod h1:E19xDjpzPZC7LS2knI9E6BaRFDK43Eul7vd6rSq2HWk= +github.com/aws/smithy-go v1.23.2 h1:Crv0eatJUQhaManss33hS5r40CG3ZFH+21XSkqMrIUM= +github.com/aws/smithy-go v1.23.2/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= github.com/axiomhq/hyperloglog v0.0.0-20240507144631-af9851f82b27 h1:60m4tnanN1ctzIu4V3bfCNJ39BiOPSm1gHFlFjTkRE0= github.com/axiomhq/hyperloglog v0.0.0-20240507144631-af9851f82b27/go.mod h1:k08r+Yj1PRAmuayFiRK6MYuR5Ve4IuZtTfxErMIh0+c= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= @@ -745,6 +749,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 v0.7.1 h1:t5Kc7j/8kYr8t2u11rykRrPPovlEMG4+xdc/SpekATs= +github.com/google/gnostic v0.7.1/go.mod h1:KSw6sxnxEBFM8jLPfJd46xZP+yQcfE8XkiqfZx5zR28= 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= @@ -827,8 +833,8 @@ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v1.5.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/alerting v0.0.0-20251212143239-491433b332b7 h1:ZzG/gCclEit9w0QUfQt9GURcOycAIGcsQAhY1u0AEX0= -github.com/grafana/alerting v0.0.0-20251212143239-491433b332b7/go.mod h1:l7v67cgP7x72ajB9UPZlumdrHqNztpKoqQ52cU8T3LU= +github.com/grafana/alerting v0.0.0-20251231150637-b7821017d69f h1:Br4SaUL3dnVopKKNhDavCLgehw60jdtl/sIxdfzmVts= +github.com/grafana/alerting v0.0.0-20251231150637-b7821017d69f/go.mod h1:l7v67cgP7x72ajB9UPZlumdrHqNztpKoqQ52cU8T3LU= github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f h1:Cbm6OKkOcJ+7CSZsGsEJzktC/SIa5bxVeYKQLuYK86o= github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f/go.mod h1:axY0cdOg3q0TZHwpHnIz5x16xZ8ZBxJHShsSHHXcHQg= github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4 h1:Muoy+FMGrHj3GdFbvsMzUT7eusgii9PKf9L1ZaXDDbY= @@ -849,8 +855,8 @@ github.com/grafana/grafana-app-sdk v0.48.7 h1:9mF7nqkqP0QUYYDlznoOt+GIyjzj45wGfU 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-aws-sdk v1.4.2 h1:GrUEoLbs46r8rG/GZL4L2b63Bo+rkIYKdtCT7kT5KkM= +github.com/grafana/grafana-aws-sdk v1.4.2/go.mod h1:1qnZdYs6gQzxxF0dDodaE7Rn9fiMzuhwvtaAZ7ySnhY= 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-cloud-migration-snapshot v1.9.0 h1:JOzchPgptwJdruYoed7x28lFDwhzs7kssResYsnC0iI= @@ -883,12 +889,12 @@ github.com/grafana/prometheus-alertmanager v0.25.1-0.20250911094103-5456b6e45604 github.com/grafana/prometheus-alertmanager v0.25.1-0.20250911094103-5456b6e45604/go.mod h1:O/QP1BCm0HHIzbKvgMzqb5sSyH88rzkFk84F4TfJjBU= github.com/grafana/pyroscope-go/godeltaprof v0.1.9 h1:c1Us8i6eSmkW+Ez05d3co8kasnuOY813tbMN8i/a3Og= github.com/grafana/pyroscope-go/godeltaprof v0.1.9/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU= -github.com/grafana/pyroscope/api v1.2.1-0.20250415190842-3ff7247547ae h1:35W3Wjp9KWnSoV/DuymmyIj5aHE0CYlDQ5m2KeXUPAc= -github.com/grafana/pyroscope/api v1.2.1-0.20250415190842-3ff7247547ae/go.mod h1:6CJ1uXmLZ13ufpO9xE4pST+DyaBt0uszzrV0YnoaVLQ= +github.com/grafana/pyroscope/api v1.2.1-0.20251118081820-ace37f973a0f h1:fTlIj5n4x5dU63XHItug7GLjtnaeJdPqBlqg4zlABq0= +github.com/grafana/pyroscope/api v1.2.1-0.20251118081820-ace37f973a0f/go.mod h1:VBNcIhunCZsJ3/mcYx+j7uFf0P/108eiWa+8+Z9ll3o= github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248= github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk= -github.com/grafana/sqlds/v4 v4.2.7 h1:sFQhsS7DBakNMdxa++yOfJ9BVvkZwFJ0B95o57K0/XA= -github.com/grafana/sqlds/v4 v4.2.7/go.mod h1:BQRjUG8rOqrBI4NAaeoWrIMuoNgfi8bdhCJ+5cgEfLU= +github.com/grafana/sqlds/v5 v5.0.3 h1:+yUMUxfa0WANQsmS9xtTFSRX1Q55Iv1B9EjlrW4VlBU= +github.com/grafana/sqlds/v5 v5.0.3/go.mod h1:GKeTTiC+GeR1X0z3f0Iee+hZnNgN62uQpj5XVMx5Uew= github.com/grafana/tempo v1.5.1-0.20250529124718-87c2dc380cec h1:wnzJov9RhSHGaTYGzTygL4qq986fLen8xSqnQgaMd28= github.com/grafana/tempo v1.5.1-0.20250529124718-87c2dc380cec/go.mod h1:j1IY7J2rUz7TcTjFVVx6HCpyTlYOJPtXuGRZ7sI+vSo= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= @@ -2319,6 +2325,8 @@ modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk= +pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= 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= diff --git a/apps/iam/pkg/apis/iam/v0alpha1/extensions.go b/apps/iam/pkg/apis/iam/v0alpha1/extensions.go deleted file mode 100644 index c0c5a11f7e3..00000000000 --- a/apps/iam/pkg/apis/iam/v0alpha1/extensions.go +++ /dev/null @@ -1,43 +0,0 @@ -package v0alpha1 - -import ( - "fmt" - - "github.com/grafana/grafana/pkg/apimachinery/utils" -) - -func (u User) AuthID() string { - meta, err := utils.MetaAccessor(&u) - if err != nil { - return "" - } - // TODO: Workaround until we move all definitions - // After having all resource definitions here in the app, we can remove this - // and we need to change the List authorization to use the MetaAccessor and the GetDeprecatedInternalID method - //nolint:staticcheck - return fmt.Sprintf("%d", meta.GetDeprecatedInternalID()) -} - -func (s ServiceAccount) AuthID() string { - meta, err := utils.MetaAccessor(&s) - if err != nil { - return "" - } - // TODO: Workaround until we move all definitions - // After having all resource definitions here in the app, we can remove this - // and we need to change the List authorization to use the MetaAccessor and the GetDeprecatedInternalID method - //nolint:staticcheck - return fmt.Sprintf("%d", meta.GetDeprecatedInternalID()) -} - -func (t Team) AuthID() string { - meta, err := utils.MetaAccessor(&t) - if err != nil { - return "" - } - // TODO: Workaround until we move all definitions - // After having all resource definitions here in the app, we can remove this - // and we need to change the List authorization to use the MetaAccessor and the GetDeprecatedInternalID method - //nolint:staticcheck - return fmt.Sprintf("%d", meta.GetDeprecatedInternalID()) -} diff --git a/apps/investigations/Makefile b/apps/investigations/Makefile deleted file mode 100644 index bc8d6d30cb5..00000000000 --- a/apps/investigations/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -include ../sdk.mk - -.PHONY: generate # Run Grafana App SDK code generation -generate: install-app-sdk update-app-sdk - @$(APP_SDK_BIN) generate \ - --source=./kinds/ \ - --gogenpath=./pkg/apis \ - --grouping=group \ - --genoperatorstate=false \ - --defencoding=none \ No newline at end of file diff --git a/apps/investigations/example.json b/apps/investigations/example.json deleted file mode 100644 index 0a390fb074f..00000000000 --- a/apps/investigations/example.json +++ /dev/null @@ -1,152 +0,0 @@ -[ - { - "id": "896312ce-65b0-4b50-ade1-e7f04fa22c66", - "title": "Thursday morning investigation", - "hasCustomName": false, - "isFavorite": false, - "collectables": [ - { - "origin": "Explore Logs", - "type": "timeseries", - "queries": [ - { - "refId": "LABEL_BREAKDOWN_VALUES", - "queryType": "range", - "editorMode": "code", - "supportingQueryType": "grafana-lokiexplore-app", - "legendFormat": "{{detected_level}}", - "expr": "sum(count_over_time({service_name=\"web_app_1\"} | detected_level != \"\"[$__auto])) by (detected_level)" - } - ], - "timeRange": { - "to": "2025-02-13T11:31:20.536Z", - "from": "2025-02-13T11:16:20.536Z", - "raw": { - "from": "now-15m", - "to": "now" - } - }, - "datasource": { - "uid": "fe9k7u07b1a0wc" - }, - "url": "http://localhost:3000/a/grafana-lokiexplore-app/explore/service/web_app_1/labels?patterns=%5B%5D&from=now-15m&to=now&var-ds=fe9k7u07b1a0wc&var-filters=service_name%7C%3D%7Cweb_app_1&var-fields=&var-levels=&var-metadata=&var-patterns=&var-lineFilterV2=&var-lineFilters=&urlColumns=%5B%5D&visualizationType=%22logs%22&displayedFields=%5B%5D&timezone=browser&var-all-fields=&var-labelBy=$__all", - "id": "LABEL_BREAKDOWN_VALUES_detected_level", - "title": "detected_level", - "logoPath": "public/plugins/grafana-lokiexplore-app/img/img/logo.svg", - "createdAt": "2025-02-13T11:31:23.637Z" - } - ], - "createdAt": "2025-02-13T11:31:23.636Z", - "updatedAt": "2025-02-13T11:31:23.637Z", - "viewMode": { - "mode": "compact", - "showComments": true, - "showTooltips": false - } - }, - { - "id": "e9cf1958-d0ed-46b7-b597-9052c7648656", - "title": "Thursday morning investigation", - "hasCustomName": false, - "isFavorite": false, - "collectables": [ - { - "origin": "Explore Logs", - "type": "timeseries", - "queries": [ - { - "refId": "LABEL_BREAKDOWN_VALUES", - "queryType": "range", - "editorMode": "code", - "supportingQueryType": "grafana-lokiexplore-app", - "legendFormat": "{{detected_level}}", - "expr": "sum(count_over_time({service_name=\"web_app_1\"} | detected_level != \"\"[$__auto])) by (detected_level)" - } - ], - "timeRange": { - "to": "2025-02-13T11:31:20.536Z", - "from": "2025-02-13T11:16:20.536Z", - "raw": { - "from": "now-15m", - "to": "now" - } - }, - "datasource": { - "uid": "fe9k7u07b1a0wc" - }, - "url": "http://localhost:3000/a/grafana-lokiexplore-app/explore/service/web_app_1/labels?patterns=%5B%5D&from=now-15m&to=now&var-ds=fe9k7u07b1a0wc&var-filters=service_name%7C%3D%7Cweb_app_1&var-fields=&var-levels=&var-metadata=&var-patterns=&var-lineFilterV2=&var-lineFilters=&urlColumns=%5B%5D&visualizationType=%22logs%22&displayedFields=%5B%5D&timezone=browser&var-all-fields=&var-labelBy=$__all", - "id": "LABEL_BREAKDOWN_VALUES_detected_level", - "title": "detected_level", - "logoPath": "public/plugins/grafana-lokiexplore-app/img/img/logo.svg", - "createdAt": "2025-02-13T11:31:23.638Z" - }, - { - "origin": "Explore Logs", - "type": "timeseries", - "queries": [ - { - "refId": "LABEL_BREAKDOWN_VALUES", - "queryType": "range", - "editorMode": "code", - "supportingQueryType": "grafana-lokiexplore-app", - "legendFormat": "{{service_name}}", - "expr": "sum(count_over_time({service_name=\"web_app_1\",service_name != \"\"} [$__auto])) by (service_name)" - } - ], - "timeRange": { - "to": "2025-02-13T11:31:20.536Z", - "from": "2025-02-13T11:16:20.536Z", - "raw": { - "from": "now-15m", - "to": "now" - } - }, - "datasource": { - "uid": "fe9k7u07b1a0wc" - }, - "url": "http://localhost:3000/a/grafana-lokiexplore-app/explore/service/web_app_1/labels?patterns=%5B%5D&from=now-15m&to=now&var-ds=fe9k7u07b1a0wc&var-filters=service_name%7C%3D%7Cweb_app_1&var-fields=&var-levels=&var-metadata=&var-patterns=&var-lineFilterV2=&var-lineFilters=&urlColumns=%5B%5D&visualizationType=%22logs%22&displayedFields=%5B%5D&timezone=browser&var-all-fields=&var-labelBy=$__all", - "id": "LABEL_BREAKDOWN_VALUES_service_name", - "title": "service_name", - "logoPath": "public/plugins/grafana-lokiexplore-app/img/img/logo.svg", - "createdAt": "2025-02-13T11:31:41.507Z" - }, - { - "origin": "Explore Logs", - "type": "timeseries", - "queries": [ - { - "refId": "LABEL_BREAKDOWN_VALUES", - "queryType": "range", - "editorMode": "code", - "supportingQueryType": "grafana-lokiexplore-app", - "legendFormat": "{{service}}", - "expr": "sum(count_over_time({service_name=\"web_app_1\",service != \"\"} [$__auto])) by (service)" - } - ], - "timeRange": { - "to": "2025-02-13T11:31:20.536Z", - "from": "2025-02-13T11:16:20.536Z", - "raw": { - "from": "now-15m", - "to": "now" - } - }, - "datasource": { - "uid": "fe9k7u07b1a0wc" - }, - "url": "http://localhost:3000/a/grafana-lokiexplore-app/explore/service/web_app_1/labels?patterns=%5B%5D&from=now-15m&to=now&var-ds=fe9k7u07b1a0wc&var-filters=service_name%7C%3D%7Cweb_app_1&var-fields=&var-levels=&var-metadata=&var-patterns=&var-lineFilterV2=&var-lineFilters=&urlColumns=%5B%5D&visualizationType=%22logs%22&displayedFields=%5B%5D&timezone=browser&var-all-fields=&var-labelBy=$__all", - "id": "LABEL_BREAKDOWN_VALUES_service", - "title": "service", - "logoPath": "public/plugins/grafana-lokiexplore-app/img/img/logo.svg", - "createdAt": "2025-02-13T11:31:43.698Z" - } - ], - "createdAt": "2025-02-13T11:31:23.637Z", - "updatedAt": "2025-02-13T11:31:43.698Z", - "viewMode": { - "mode": "compact", - "showComments": true, - "showTooltips": false - } - } -] diff --git a/apps/investigations/go.mod b/apps/investigations/go.mod deleted file mode 100644 index 40677b56dab..00000000000 --- a/apps/investigations/go.mod +++ /dev/null @@ -1,102 +0,0 @@ -module github.com/grafana/grafana/apps/investigations - -go 1.25.5 - -require ( - 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-20251125145642-4e65d59e963e -) - -require ( - github.com/beorn7/perks v1.0.1 // 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 - github.com/emicklei/go-restful/v3 v3.13.0 // indirect - github.com/evanphx/json-patch v5.9.11+incompatible // indirect - github.com/fxamacker/cbor/v2 v2.9.0 // indirect - github.com/getkin/kin-openapi v0.133.0 // indirect - github.com/go-logr/logr v1.4.3 // indirect - github.com/go-logr/stdr v1.2.2 // 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.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.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.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/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/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.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.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.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.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-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.11 // indirect - gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // 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 deleted file mode 100644 index e5233ba82c9..00000000000 --- a/apps/investigations/go.sum +++ /dev/null @@ -1,264 +0,0 @@ -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-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= -github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes= -github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8= -github.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= -github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= -github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= -github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= -github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-openapi/jsonpointer v0.22.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.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/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= -github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/grafana/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= -github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= -github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= -github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= -github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/mailru/easyjson v0.9.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= -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/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= -github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= -github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= -github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= -github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= -github.com/prometheus/common v0.67.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= -github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= -github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= -github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/woodsbury/decimal128 v1.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.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= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= -go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= -go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= -go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.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.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.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.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.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= -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-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.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.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.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-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= -sigs.k8s.io/structured-merge-diff/v6 v6.3.1/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= -sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= -sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/apps/investigations/kinds/collectable.cue b/apps/investigations/kinds/collectable.cue deleted file mode 100644 index f9fc754a67c..00000000000 --- a/apps/investigations/kinds/collectable.cue +++ /dev/null @@ -1,43 +0,0 @@ -package investigations - -// Collectable represents an item collected during investigation -#Collectable: { - id: string - createdAt: string - - title: string - origin: string - type: string - queries: [...string] // +listType=atomic - timeRange: #TimeRange - datasource: #DatasourceRef - url: string - logoPath?: string - - note: string - noteUpdatedAt: string - - fieldConfig: string -} - -#CollectableSummary: { - id: string - title: string - logoPath: string - origin: string -} - -// TimeRange represents a time range with both absolute and relative values -#TimeRange: { - from: string - to: string - raw: { - from: string - to: string - } -} - -// DatasourceRef is a reference to a datasource -#DatasourceRef: { - uid: string -} diff --git a/apps/investigations/kinds/cue.mod/module.cue b/apps/investigations/kinds/cue.mod/module.cue deleted file mode 100644 index c592b1ce788..00000000000 --- a/apps/investigations/kinds/cue.mod/module.cue +++ /dev/null @@ -1,4 +0,0 @@ -module: "github.com/grafana/grafana/apps/investigations" -language: { - version: "v0.11.0" -} \ No newline at end of file diff --git a/apps/investigations/kinds/investigation.cue b/apps/investigations/kinds/investigation.cue deleted file mode 100644 index 1ade89416b9..00000000000 --- a/apps/investigations/kinds/investigation.cue +++ /dev/null @@ -1,43 +0,0 @@ -package investigations - -investigationV0alpha1: { - kind: "Investigation" - pluralName: "Investigations" - schema: { - spec: { - title: string - createdByProfile: #Person - hasCustomName: bool - isFavorite: bool - overviewNote: string - overviewNoteUpdatedAt: string - collectables: [...#Collectable] // +listType=atomic - viewMode: #ViewMode - } - } -} - -// Type definition for investigation summaries -#InvestigationSummary: { - title: string - createdByProfile: #Person - hasCustomName: bool - isFavorite: bool - overviewNote: string - overviewNoteUpdatedAt: string - viewMode: #ViewMode - collectableSummaries: [...#CollectableSummary] // +listType=atomic -} - -// Person represents a user profile with basic information -#Person: { - uid: string // Unique identifier for the user - name: string // Display name of the user - gravatarUrl: string // URL to user's Gravatar image -} - -#ViewMode: { - mode: "compact" | "full" - showComments: bool - showTooltips: bool -} diff --git a/apps/investigations/kinds/investigationindex.cue b/apps/investigations/kinds/investigationindex.cue deleted file mode 100644 index 65c5e3ae79f..00000000000 --- a/apps/investigations/kinds/investigationindex.cue +++ /dev/null @@ -1,18 +0,0 @@ -package investigations - -investigationIndexV0alpha1:{ - kind: "InvestigationIndex" - pluralName: "InvestigationIndexes" - schema: { - spec: { - // Title of the index, e.g. 'Favorites' or 'My Investigations' - title: string - - // The Person who owns this investigation index - owner: #Person - - // Array of investigation summaries - investigationSummaries: [...#InvestigationSummary] // +listType=atomic - } - } -} diff --git a/apps/investigations/kinds/manifest.cue b/apps/investigations/kinds/manifest.cue deleted file mode 100644 index 947d84be482..00000000000 --- a/apps/investigations/kinds/manifest.cue +++ /dev/null @@ -1,18 +0,0 @@ -package investigations - -manifest: { - appName: "investigations" - groupOverride: "investigations.grafana.app" - versions: { - "v0alpha1": { - codegen: { - ts: {enabled: false} - go: {enabled: true} - } - kinds: [ - investigationV0alpha1, - investigationIndexV0alpha1, - ] - } - } -} \ No newline at end of file diff --git a/apps/investigations/pkg/apis/investigations/v0alpha1/constants.go b/apps/investigations/pkg/apis/investigations/v0alpha1/constants.go deleted file mode 100644 index bd538eb9c30..00000000000 --- a/apps/investigations/pkg/apis/investigations/v0alpha1/constants.go +++ /dev/null @@ -1,18 +0,0 @@ -package v0alpha1 - -import "k8s.io/apimachinery/pkg/runtime/schema" - -const ( - // APIGroup is the API group used by all kinds in this package - APIGroup = "investigations.grafana.app" - // APIVersion is the API version used by all kinds in this package - APIVersion = "v0alpha1" -) - -var ( - // GroupVersion is a schema.GroupVersion consisting of the Group and Version constants for this package - GroupVersion = schema.GroupVersion{ - Group: APIGroup, - Version: APIVersion, - } -) diff --git a/apps/investigations/pkg/apis/investigations/v0alpha1/investigation_client_gen.go b/apps/investigations/pkg/apis/investigations/v0alpha1/investigation_client_gen.go deleted file mode 100644 index dea4d71802d..00000000000 --- a/apps/investigations/pkg/apis/investigations/v0alpha1/investigation_client_gen.go +++ /dev/null @@ -1,80 +0,0 @@ -package v0alpha1 - -import ( - "context" - - "github.com/grafana/grafana-app-sdk/resource" -) - -type InvestigationClient struct { - client *resource.TypedClient[*Investigation, *InvestigationList] -} - -func NewInvestigationClient(client resource.Client) *InvestigationClient { - return &InvestigationClient{ - client: resource.NewTypedClient[*Investigation, *InvestigationList](client, InvestigationKind()), - } -} - -func NewInvestigationClientFromGenerator(generator resource.ClientGenerator) (*InvestigationClient, error) { - c, err := generator.ClientFor(InvestigationKind()) - if err != nil { - return nil, err - } - return NewInvestigationClient(c), nil -} - -func (c *InvestigationClient) Get(ctx context.Context, identifier resource.Identifier) (*Investigation, error) { - return c.client.Get(ctx, identifier) -} - -func (c *InvestigationClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*InvestigationList, error) { - return c.client.List(ctx, namespace, opts) -} - -func (c *InvestigationClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*InvestigationList, error) { - resp, err := c.client.List(ctx, namespace, resource.ListOptions{ - ResourceVersion: opts.ResourceVersion, - Limit: opts.Limit, - LabelFilters: opts.LabelFilters, - FieldSelectors: opts.FieldSelectors, - }) - if err != nil { - return nil, err - } - for resp.GetContinue() != "" { - page, err := c.client.List(ctx, namespace, resource.ListOptions{ - Continue: resp.GetContinue(), - ResourceVersion: opts.ResourceVersion, - Limit: opts.Limit, - LabelFilters: opts.LabelFilters, - FieldSelectors: opts.FieldSelectors, - }) - if err != nil { - return nil, err - } - resp.SetContinue(page.GetContinue()) - resp.SetResourceVersion(page.GetResourceVersion()) - resp.SetItems(append(resp.GetItems(), page.GetItems()...)) - } - return resp, nil -} - -func (c *InvestigationClient) Create(ctx context.Context, obj *Investigation, opts resource.CreateOptions) (*Investigation, error) { - // Make sure apiVersion and kind are set - obj.APIVersion = GroupVersion.Identifier() - obj.Kind = InvestigationKind().Kind() - return c.client.Create(ctx, obj, opts) -} - -func (c *InvestigationClient) Update(ctx context.Context, obj *Investigation, opts resource.UpdateOptions) (*Investigation, error) { - return c.client.Update(ctx, obj, opts) -} - -func (c *InvestigationClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*Investigation, error) { - return c.client.Patch(ctx, identifier, req, opts) -} - -func (c *InvestigationClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error { - return c.client.Delete(ctx, identifier, opts) -} diff --git a/apps/investigations/pkg/apis/investigations/v0alpha1/investigation_codec_gen.go b/apps/investigations/pkg/apis/investigations/v0alpha1/investigation_codec_gen.go deleted file mode 100644 index 6bde81b50d3..00000000000 --- a/apps/investigations/pkg/apis/investigations/v0alpha1/investigation_codec_gen.go +++ /dev/null @@ -1,28 +0,0 @@ -// -// Code generated by grafana-app-sdk. DO NOT EDIT. -// - -package v0alpha1 - -import ( - "encoding/json" - "io" - - "github.com/grafana/grafana-app-sdk/resource" -) - -// InvestigationJSONCodec is an implementation of resource.Codec for kubernetes JSON encoding -type InvestigationJSONCodec struct{} - -// Read reads JSON-encoded bytes from `reader` and unmarshals them into `into` -func (*InvestigationJSONCodec) Read(reader io.Reader, into resource.Object) error { - return json.NewDecoder(reader).Decode(into) -} - -// Write writes JSON-encoded bytes into `writer` marshaled from `from` -func (*InvestigationJSONCodec) Write(writer io.Writer, from resource.Object) error { - return json.NewEncoder(writer).Encode(from) -} - -// Interface compliance checks -var _ resource.Codec = &InvestigationJSONCodec{} diff --git a/apps/investigations/pkg/apis/investigations/v0alpha1/investigation_metadata_gen.go b/apps/investigations/pkg/apis/investigations/v0alpha1/investigation_metadata_gen.go deleted file mode 100644 index ffd588fec5e..00000000000 --- a/apps/investigations/pkg/apis/investigations/v0alpha1/investigation_metadata_gen.go +++ /dev/null @@ -1,31 +0,0 @@ -// Code generated - EDITING IS FUTILE. DO NOT EDIT. - -package v0alpha1 - -import ( - time "time" -) - -// metadata contains embedded CommonMetadata and can be extended with custom string fields -// TODO: use CommonMetadata instead of redefining here; currently needs to be defined here -// without external reference as using the CommonMetadata reference breaks thema codegen. -type InvestigationMetadata struct { - UpdateTimestamp time.Time `json:"updateTimestamp"` - CreatedBy string `json:"createdBy"` - Uid string `json:"uid"` - CreationTimestamp time.Time `json:"creationTimestamp"` - DeletionTimestamp *time.Time `json:"deletionTimestamp,omitempty"` - Finalizers []string `json:"finalizers"` - ResourceVersion string `json:"resourceVersion"` - Generation int64 `json:"generation"` - UpdatedBy string `json:"updatedBy"` - Labels map[string]string `json:"labels"` -} - -// NewInvestigationMetadata creates a new InvestigationMetadata object. -func NewInvestigationMetadata() *InvestigationMetadata { - return &InvestigationMetadata{ - Finalizers: []string{}, - Labels: map[string]string{}, - } -} diff --git a/apps/investigations/pkg/apis/investigations/v0alpha1/investigation_object_gen.go b/apps/investigations/pkg/apis/investigations/v0alpha1/investigation_object_gen.go deleted file mode 100644 index f64d7b6e047..00000000000 --- a/apps/investigations/pkg/apis/investigations/v0alpha1/investigation_object_gen.go +++ /dev/null @@ -1,293 +0,0 @@ -// -// Code generated by grafana-app-sdk. DO NOT EDIT. -// - -package v0alpha1 - -import ( - "fmt" - "github.com/grafana/grafana-app-sdk/resource" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" - "time" -) - -// +k8s:openapi-gen=true -type Investigation struct { - metav1.TypeMeta `json:",inline" yaml:",inline"` - metav1.ObjectMeta `json:"metadata" yaml:"metadata"` - - // Spec is the spec of the Investigation - Spec InvestigationSpec `json:"spec" yaml:"spec"` -} - -func (o *Investigation) GetSpec() any { - return o.Spec -} - -func (o *Investigation) SetSpec(spec any) error { - cast, ok := spec.(InvestigationSpec) - if !ok { - return fmt.Errorf("cannot set spec type %#v, not of type Spec", spec) - } - o.Spec = cast - return nil -} - -func (o *Investigation) GetSubresources() map[string]any { - return map[string]any{} -} - -func (o *Investigation) GetSubresource(name string) (any, bool) { - switch name { - default: - return nil, false - } -} - -func (o *Investigation) SetSubresource(name string, value any) error { - switch name { - default: - return fmt.Errorf("subresource '%s' does not exist", name) - } -} - -func (o *Investigation) GetStaticMetadata() resource.StaticMetadata { - gvk := o.GroupVersionKind() - return resource.StaticMetadata{ - Name: o.ObjectMeta.Name, - Namespace: o.ObjectMeta.Namespace, - Group: gvk.Group, - Version: gvk.Version, - Kind: gvk.Kind, - } -} - -func (o *Investigation) SetStaticMetadata(metadata resource.StaticMetadata) { - o.Name = metadata.Name - o.Namespace = metadata.Namespace - o.SetGroupVersionKind(schema.GroupVersionKind{ - Group: metadata.Group, - Version: metadata.Version, - Kind: metadata.Kind, - }) -} - -func (o *Investigation) GetCommonMetadata() resource.CommonMetadata { - dt := o.DeletionTimestamp - var deletionTimestamp *time.Time - if dt != nil { - deletionTimestamp = &dt.Time - } - // Legacy ExtraFields support - extraFields := make(map[string]any) - if o.Annotations != nil { - extraFields["annotations"] = o.Annotations - } - if o.ManagedFields != nil { - extraFields["managedFields"] = o.ManagedFields - } - if o.OwnerReferences != nil { - extraFields["ownerReferences"] = o.OwnerReferences - } - return resource.CommonMetadata{ - UID: string(o.UID), - ResourceVersion: o.ResourceVersion, - Generation: o.Generation, - Labels: o.Labels, - CreationTimestamp: o.CreationTimestamp.Time, - DeletionTimestamp: deletionTimestamp, - Finalizers: o.Finalizers, - UpdateTimestamp: o.GetUpdateTimestamp(), - CreatedBy: o.GetCreatedBy(), - UpdatedBy: o.GetUpdatedBy(), - ExtraFields: extraFields, - } -} - -func (o *Investigation) SetCommonMetadata(metadata resource.CommonMetadata) { - o.UID = types.UID(metadata.UID) - o.ResourceVersion = metadata.ResourceVersion - o.Generation = metadata.Generation - o.Labels = metadata.Labels - o.CreationTimestamp = metav1.NewTime(metadata.CreationTimestamp) - if metadata.DeletionTimestamp != nil { - dt := metav1.NewTime(*metadata.DeletionTimestamp) - o.DeletionTimestamp = &dt - } else { - o.DeletionTimestamp = nil - } - o.Finalizers = metadata.Finalizers - if o.Annotations == nil { - o.Annotations = make(map[string]string) - } - if !metadata.UpdateTimestamp.IsZero() { - o.SetUpdateTimestamp(metadata.UpdateTimestamp) - } - if metadata.CreatedBy != "" { - o.SetCreatedBy(metadata.CreatedBy) - } - if metadata.UpdatedBy != "" { - o.SetUpdatedBy(metadata.UpdatedBy) - } - // Legacy support for setting Annotations, ManagedFields, and OwnerReferences via ExtraFields - if metadata.ExtraFields != nil { - if annotations, ok := metadata.ExtraFields["annotations"]; ok { - if cast, ok := annotations.(map[string]string); ok { - o.Annotations = cast - } - } - if managedFields, ok := metadata.ExtraFields["managedFields"]; ok { - if cast, ok := managedFields.([]metav1.ManagedFieldsEntry); ok { - o.ManagedFields = cast - } - } - if ownerReferences, ok := metadata.ExtraFields["ownerReferences"]; ok { - if cast, ok := ownerReferences.([]metav1.OwnerReference); ok { - o.OwnerReferences = cast - } - } - } -} - -func (o *Investigation) GetCreatedBy() string { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - return o.ObjectMeta.Annotations["grafana.com/createdBy"] -} - -func (o *Investigation) SetCreatedBy(createdBy string) { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - o.ObjectMeta.Annotations["grafana.com/createdBy"] = createdBy -} - -func (o *Investigation) GetUpdateTimestamp() time.Time { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - parsed, _ := time.Parse(time.RFC3339, o.ObjectMeta.Annotations["grafana.com/updateTimestamp"]) - return parsed -} - -func (o *Investigation) SetUpdateTimestamp(updateTimestamp time.Time) { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - o.ObjectMeta.Annotations["grafana.com/updateTimestamp"] = updateTimestamp.Format(time.RFC3339) -} - -func (o *Investigation) GetUpdatedBy() string { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - return o.ObjectMeta.Annotations["grafana.com/updatedBy"] -} - -func (o *Investigation) SetUpdatedBy(updatedBy string) { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - o.ObjectMeta.Annotations["grafana.com/updatedBy"] = updatedBy -} - -func (o *Investigation) Copy() resource.Object { - return resource.CopyObject(o) -} - -func (o *Investigation) DeepCopyObject() runtime.Object { - return o.Copy() -} - -func (o *Investigation) DeepCopy() *Investigation { - cpy := &Investigation{} - o.DeepCopyInto(cpy) - return cpy -} - -func (o *Investigation) DeepCopyInto(dst *Investigation) { - dst.TypeMeta.APIVersion = o.TypeMeta.APIVersion - dst.TypeMeta.Kind = o.TypeMeta.Kind - o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta) - o.Spec.DeepCopyInto(&dst.Spec) -} - -// Interface compliance compile-time check -var _ resource.Object = &Investigation{} - -// +k8s:openapi-gen=true -type InvestigationList struct { - metav1.TypeMeta `json:",inline" yaml:",inline"` - metav1.ListMeta `json:"metadata" yaml:"metadata"` - Items []Investigation `json:"items" yaml:"items"` -} - -func (o *InvestigationList) DeepCopyObject() runtime.Object { - return o.Copy() -} - -func (o *InvestigationList) Copy() resource.ListObject { - cpy := &InvestigationList{ - TypeMeta: o.TypeMeta, - Items: make([]Investigation, len(o.Items)), - } - o.ListMeta.DeepCopyInto(&cpy.ListMeta) - for i := 0; i < len(o.Items); i++ { - if item, ok := o.Items[i].Copy().(*Investigation); ok { - cpy.Items[i] = *item - } - } - return cpy -} - -func (o *InvestigationList) GetItems() []resource.Object { - items := make([]resource.Object, len(o.Items)) - for i := 0; i < len(o.Items); i++ { - items[i] = &o.Items[i] - } - return items -} - -func (o *InvestigationList) SetItems(items []resource.Object) { - o.Items = make([]Investigation, len(items)) - for i := 0; i < len(items); i++ { - o.Items[i] = *items[i].(*Investigation) - } -} - -func (o *InvestigationList) DeepCopy() *InvestigationList { - cpy := &InvestigationList{} - o.DeepCopyInto(cpy) - return cpy -} - -func (o *InvestigationList) DeepCopyInto(dst *InvestigationList) { - resource.CopyObjectInto(dst, o) -} - -// Interface compliance compile-time check -var _ resource.ListObject = &InvestigationList{} - -// Copy methods for all subresource types - -// DeepCopy creates a full deep copy of Spec -func (s *InvestigationSpec) DeepCopy() *InvestigationSpec { - cpy := &InvestigationSpec{} - s.DeepCopyInto(cpy) - return cpy -} - -// DeepCopyInto deep copies Spec into another Spec object -func (s *InvestigationSpec) DeepCopyInto(dst *InvestigationSpec) { - resource.CopyObjectInto(dst, s) -} diff --git a/apps/investigations/pkg/apis/investigations/v0alpha1/investigation_schema_gen.go b/apps/investigations/pkg/apis/investigations/v0alpha1/investigation_schema_gen.go deleted file mode 100644 index 2a1f03c884a..00000000000 --- a/apps/investigations/pkg/apis/investigations/v0alpha1/investigation_schema_gen.go +++ /dev/null @@ -1,34 +0,0 @@ -// -// Code generated by grafana-app-sdk. DO NOT EDIT. -// - -package v0alpha1 - -import ( - "github.com/grafana/grafana-app-sdk/resource" -) - -// schema is unexported to prevent accidental overwrites -var ( - schemaInvestigation = resource.NewSimpleSchema("investigations.grafana.app", "v0alpha1", &Investigation{}, &InvestigationList{}, resource.WithKind("Investigation"), - resource.WithPlural("investigations"), resource.WithScope(resource.NamespacedScope)) - kindInvestigation = resource.Kind{ - Schema: schemaInvestigation, - Codecs: map[resource.KindEncoding]resource.Codec{ - resource.KindEncodingJSON: &InvestigationJSONCodec{}, - }, - } -) - -// Kind returns a resource.Kind for this Schema with a JSON codec -func InvestigationKind() resource.Kind { - return kindInvestigation -} - -// Schema returns a resource.SimpleSchema representation of Investigation -func InvestigationSchema() *resource.SimpleSchema { - return schemaInvestigation -} - -// Interface compliance checks -var _ resource.Schema = kindInvestigation diff --git a/apps/investigations/pkg/apis/investigations/v0alpha1/investigation_spec_gen.go b/apps/investigations/pkg/apis/investigations/v0alpha1/investigation_spec_gen.go deleted file mode 100644 index 88d74be54eb..00000000000 --- a/apps/investigations/pkg/apis/investigations/v0alpha1/investigation_spec_gen.go +++ /dev/null @@ -1,126 +0,0 @@ -// Code generated - EDITING IS FUTILE. DO NOT EDIT. - -package v0alpha1 - -// Person represents a user profile with basic information -// +k8s:openapi-gen=true -type InvestigationPerson struct { - // Unique identifier for the user - Uid string `json:"uid"` - // Display name of the user - Name string `json:"name"` - // URL to user's Gravatar image - GravatarUrl string `json:"gravatarUrl"` -} - -// NewInvestigationPerson creates a new InvestigationPerson object. -func NewInvestigationPerson() *InvestigationPerson { - return &InvestigationPerson{} -} - -// Collectable represents an item collected during investigation -// +k8s:openapi-gen=true -type InvestigationCollectable struct { - Id string `json:"id"` - CreatedAt string `json:"createdAt"` - Title string `json:"title"` - Origin string `json:"origin"` - Type string `json:"type"` - // +listType=atomic - Queries []string `json:"queries"` - TimeRange InvestigationTimeRange `json:"timeRange"` - Datasource InvestigationDatasourceRef `json:"datasource"` - Url string `json:"url"` - LogoPath *string `json:"logoPath,omitempty"` - Note string `json:"note"` - NoteUpdatedAt string `json:"noteUpdatedAt"` - FieldConfig string `json:"fieldConfig"` -} - -// NewInvestigationCollectable creates a new InvestigationCollectable object. -func NewInvestigationCollectable() *InvestigationCollectable { - return &InvestigationCollectable{ - Queries: []string{}, - TimeRange: *NewInvestigationTimeRange(), - Datasource: *NewInvestigationDatasourceRef(), - } -} - -// TimeRange represents a time range with both absolute and relative values -// +k8s:openapi-gen=true -type InvestigationTimeRange struct { - From string `json:"from"` - To string `json:"to"` - Raw InvestigationV0alpha1TimeRangeRaw `json:"raw"` -} - -// NewInvestigationTimeRange creates a new InvestigationTimeRange object. -func NewInvestigationTimeRange() *InvestigationTimeRange { - return &InvestigationTimeRange{ - Raw: *NewInvestigationV0alpha1TimeRangeRaw(), - } -} - -// DatasourceRef is a reference to a datasource -// +k8s:openapi-gen=true -type InvestigationDatasourceRef struct { - Uid string `json:"uid"` -} - -// NewInvestigationDatasourceRef creates a new InvestigationDatasourceRef object. -func NewInvestigationDatasourceRef() *InvestigationDatasourceRef { - return &InvestigationDatasourceRef{} -} - -// +k8s:openapi-gen=true -type InvestigationViewMode struct { - Mode InvestigationViewModeMode `json:"mode"` - ShowComments bool `json:"showComments"` - ShowTooltips bool `json:"showTooltips"` -} - -// NewInvestigationViewMode creates a new InvestigationViewMode object. -func NewInvestigationViewMode() *InvestigationViewMode { - return &InvestigationViewMode{} -} - -// +k8s:openapi-gen=true -type InvestigationSpec struct { - Title string `json:"title"` - CreatedByProfile InvestigationPerson `json:"createdByProfile"` - HasCustomName bool `json:"hasCustomName"` - IsFavorite bool `json:"isFavorite"` - OverviewNote string `json:"overviewNote"` - OverviewNoteUpdatedAt string `json:"overviewNoteUpdatedAt"` - // +listType=atomic - Collectables []InvestigationCollectable `json:"collectables"` - ViewMode InvestigationViewMode `json:"viewMode"` -} - -// NewInvestigationSpec creates a new InvestigationSpec object. -func NewInvestigationSpec() *InvestigationSpec { - return &InvestigationSpec{ - CreatedByProfile: *NewInvestigationPerson(), - Collectables: []InvestigationCollectable{}, - ViewMode: *NewInvestigationViewMode(), - } -} - -// +k8s:openapi-gen=true -type InvestigationV0alpha1TimeRangeRaw struct { - From string `json:"from"` - To string `json:"to"` -} - -// NewInvestigationV0alpha1TimeRangeRaw creates a new InvestigationV0alpha1TimeRangeRaw object. -func NewInvestigationV0alpha1TimeRangeRaw() *InvestigationV0alpha1TimeRangeRaw { - return &InvestigationV0alpha1TimeRangeRaw{} -} - -// +k8s:openapi-gen=true -type InvestigationViewModeMode string - -const ( - InvestigationViewModeModeCompact InvestigationViewModeMode = "compact" - InvestigationViewModeModeFull InvestigationViewModeMode = "full" -) diff --git a/apps/investigations/pkg/apis/investigations/v0alpha1/investigationindex_client_gen.go b/apps/investigations/pkg/apis/investigations/v0alpha1/investigationindex_client_gen.go deleted file mode 100644 index dafe3e1012e..00000000000 --- a/apps/investigations/pkg/apis/investigations/v0alpha1/investigationindex_client_gen.go +++ /dev/null @@ -1,80 +0,0 @@ -package v0alpha1 - -import ( - "context" - - "github.com/grafana/grafana-app-sdk/resource" -) - -type InvestigationIndexClient struct { - client *resource.TypedClient[*InvestigationIndex, *InvestigationIndexList] -} - -func NewInvestigationIndexClient(client resource.Client) *InvestigationIndexClient { - return &InvestigationIndexClient{ - client: resource.NewTypedClient[*InvestigationIndex, *InvestigationIndexList](client, InvestigationIndexKind()), - } -} - -func NewInvestigationIndexClientFromGenerator(generator resource.ClientGenerator) (*InvestigationIndexClient, error) { - c, err := generator.ClientFor(InvestigationIndexKind()) - if err != nil { - return nil, err - } - return NewInvestigationIndexClient(c), nil -} - -func (c *InvestigationIndexClient) Get(ctx context.Context, identifier resource.Identifier) (*InvestigationIndex, error) { - return c.client.Get(ctx, identifier) -} - -func (c *InvestigationIndexClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*InvestigationIndexList, error) { - return c.client.List(ctx, namespace, opts) -} - -func (c *InvestigationIndexClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*InvestigationIndexList, error) { - resp, err := c.client.List(ctx, namespace, resource.ListOptions{ - ResourceVersion: opts.ResourceVersion, - Limit: opts.Limit, - LabelFilters: opts.LabelFilters, - FieldSelectors: opts.FieldSelectors, - }) - if err != nil { - return nil, err - } - for resp.GetContinue() != "" { - page, err := c.client.List(ctx, namespace, resource.ListOptions{ - Continue: resp.GetContinue(), - ResourceVersion: opts.ResourceVersion, - Limit: opts.Limit, - LabelFilters: opts.LabelFilters, - FieldSelectors: opts.FieldSelectors, - }) - if err != nil { - return nil, err - } - resp.SetContinue(page.GetContinue()) - resp.SetResourceVersion(page.GetResourceVersion()) - resp.SetItems(append(resp.GetItems(), page.GetItems()...)) - } - return resp, nil -} - -func (c *InvestigationIndexClient) Create(ctx context.Context, obj *InvestigationIndex, opts resource.CreateOptions) (*InvestigationIndex, error) { - // Make sure apiVersion and kind are set - obj.APIVersion = GroupVersion.Identifier() - obj.Kind = InvestigationIndexKind().Kind() - return c.client.Create(ctx, obj, opts) -} - -func (c *InvestigationIndexClient) Update(ctx context.Context, obj *InvestigationIndex, opts resource.UpdateOptions) (*InvestigationIndex, error) { - return c.client.Update(ctx, obj, opts) -} - -func (c *InvestigationIndexClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*InvestigationIndex, error) { - return c.client.Patch(ctx, identifier, req, opts) -} - -func (c *InvestigationIndexClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error { - return c.client.Delete(ctx, identifier, opts) -} diff --git a/apps/investigations/pkg/apis/investigations/v0alpha1/investigationindex_codec_gen.go b/apps/investigations/pkg/apis/investigations/v0alpha1/investigationindex_codec_gen.go deleted file mode 100644 index 0496ce4af6f..00000000000 --- a/apps/investigations/pkg/apis/investigations/v0alpha1/investigationindex_codec_gen.go +++ /dev/null @@ -1,28 +0,0 @@ -// -// Code generated by grafana-app-sdk. DO NOT EDIT. -// - -package v0alpha1 - -import ( - "encoding/json" - "io" - - "github.com/grafana/grafana-app-sdk/resource" -) - -// InvestigationIndexJSONCodec is an implementation of resource.Codec for kubernetes JSON encoding -type InvestigationIndexJSONCodec struct{} - -// Read reads JSON-encoded bytes from `reader` and unmarshals them into `into` -func (*InvestigationIndexJSONCodec) Read(reader io.Reader, into resource.Object) error { - return json.NewDecoder(reader).Decode(into) -} - -// Write writes JSON-encoded bytes into `writer` marshaled from `from` -func (*InvestigationIndexJSONCodec) Write(writer io.Writer, from resource.Object) error { - return json.NewEncoder(writer).Encode(from) -} - -// Interface compliance checks -var _ resource.Codec = &InvestigationIndexJSONCodec{} diff --git a/apps/investigations/pkg/apis/investigations/v0alpha1/investigationindex_metadata_gen.go b/apps/investigations/pkg/apis/investigations/v0alpha1/investigationindex_metadata_gen.go deleted file mode 100644 index e7bef02a137..00000000000 --- a/apps/investigations/pkg/apis/investigations/v0alpha1/investigationindex_metadata_gen.go +++ /dev/null @@ -1,31 +0,0 @@ -// Code generated - EDITING IS FUTILE. DO NOT EDIT. - -package v0alpha1 - -import ( - time "time" -) - -// metadata contains embedded CommonMetadata and can be extended with custom string fields -// TODO: use CommonMetadata instead of redefining here; currently needs to be defined here -// without external reference as using the CommonMetadata reference breaks thema codegen. -type InvestigationIndexMetadata struct { - UpdateTimestamp time.Time `json:"updateTimestamp"` - CreatedBy string `json:"createdBy"` - Uid string `json:"uid"` - CreationTimestamp time.Time `json:"creationTimestamp"` - DeletionTimestamp *time.Time `json:"deletionTimestamp,omitempty"` - Finalizers []string `json:"finalizers"` - ResourceVersion string `json:"resourceVersion"` - Generation int64 `json:"generation"` - UpdatedBy string `json:"updatedBy"` - Labels map[string]string `json:"labels"` -} - -// NewInvestigationIndexMetadata creates a new InvestigationIndexMetadata object. -func NewInvestigationIndexMetadata() *InvestigationIndexMetadata { - return &InvestigationIndexMetadata{ - Finalizers: []string{}, - Labels: map[string]string{}, - } -} diff --git a/apps/investigations/pkg/apis/investigations/v0alpha1/investigationindex_object_gen.go b/apps/investigations/pkg/apis/investigations/v0alpha1/investigationindex_object_gen.go deleted file mode 100644 index b8272b4fae7..00000000000 --- a/apps/investigations/pkg/apis/investigations/v0alpha1/investigationindex_object_gen.go +++ /dev/null @@ -1,293 +0,0 @@ -// -// Code generated by grafana-app-sdk. DO NOT EDIT. -// - -package v0alpha1 - -import ( - "fmt" - "github.com/grafana/grafana-app-sdk/resource" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" - "time" -) - -// +k8s:openapi-gen=true -type InvestigationIndex struct { - metav1.TypeMeta `json:",inline" yaml:",inline"` - metav1.ObjectMeta `json:"metadata" yaml:"metadata"` - - // Spec is the spec of the InvestigationIndex - Spec InvestigationIndexSpec `json:"spec" yaml:"spec"` -} - -func (o *InvestigationIndex) GetSpec() any { - return o.Spec -} - -func (o *InvestigationIndex) SetSpec(spec any) error { - cast, ok := spec.(InvestigationIndexSpec) - if !ok { - return fmt.Errorf("cannot set spec type %#v, not of type Spec", spec) - } - o.Spec = cast - return nil -} - -func (o *InvestigationIndex) GetSubresources() map[string]any { - return map[string]any{} -} - -func (o *InvestigationIndex) GetSubresource(name string) (any, bool) { - switch name { - default: - return nil, false - } -} - -func (o *InvestigationIndex) SetSubresource(name string, value any) error { - switch name { - default: - return fmt.Errorf("subresource '%s' does not exist", name) - } -} - -func (o *InvestigationIndex) GetStaticMetadata() resource.StaticMetadata { - gvk := o.GroupVersionKind() - return resource.StaticMetadata{ - Name: o.ObjectMeta.Name, - Namespace: o.ObjectMeta.Namespace, - Group: gvk.Group, - Version: gvk.Version, - Kind: gvk.Kind, - } -} - -func (o *InvestigationIndex) SetStaticMetadata(metadata resource.StaticMetadata) { - o.Name = metadata.Name - o.Namespace = metadata.Namespace - o.SetGroupVersionKind(schema.GroupVersionKind{ - Group: metadata.Group, - Version: metadata.Version, - Kind: metadata.Kind, - }) -} - -func (o *InvestigationIndex) GetCommonMetadata() resource.CommonMetadata { - dt := o.DeletionTimestamp - var deletionTimestamp *time.Time - if dt != nil { - deletionTimestamp = &dt.Time - } - // Legacy ExtraFields support - extraFields := make(map[string]any) - if o.Annotations != nil { - extraFields["annotations"] = o.Annotations - } - if o.ManagedFields != nil { - extraFields["managedFields"] = o.ManagedFields - } - if o.OwnerReferences != nil { - extraFields["ownerReferences"] = o.OwnerReferences - } - return resource.CommonMetadata{ - UID: string(o.UID), - ResourceVersion: o.ResourceVersion, - Generation: o.Generation, - Labels: o.Labels, - CreationTimestamp: o.CreationTimestamp.Time, - DeletionTimestamp: deletionTimestamp, - Finalizers: o.Finalizers, - UpdateTimestamp: o.GetUpdateTimestamp(), - CreatedBy: o.GetCreatedBy(), - UpdatedBy: o.GetUpdatedBy(), - ExtraFields: extraFields, - } -} - -func (o *InvestigationIndex) SetCommonMetadata(metadata resource.CommonMetadata) { - o.UID = types.UID(metadata.UID) - o.ResourceVersion = metadata.ResourceVersion - o.Generation = metadata.Generation - o.Labels = metadata.Labels - o.CreationTimestamp = metav1.NewTime(metadata.CreationTimestamp) - if metadata.DeletionTimestamp != nil { - dt := metav1.NewTime(*metadata.DeletionTimestamp) - o.DeletionTimestamp = &dt - } else { - o.DeletionTimestamp = nil - } - o.Finalizers = metadata.Finalizers - if o.Annotations == nil { - o.Annotations = make(map[string]string) - } - if !metadata.UpdateTimestamp.IsZero() { - o.SetUpdateTimestamp(metadata.UpdateTimestamp) - } - if metadata.CreatedBy != "" { - o.SetCreatedBy(metadata.CreatedBy) - } - if metadata.UpdatedBy != "" { - o.SetUpdatedBy(metadata.UpdatedBy) - } - // Legacy support for setting Annotations, ManagedFields, and OwnerReferences via ExtraFields - if metadata.ExtraFields != nil { - if annotations, ok := metadata.ExtraFields["annotations"]; ok { - if cast, ok := annotations.(map[string]string); ok { - o.Annotations = cast - } - } - if managedFields, ok := metadata.ExtraFields["managedFields"]; ok { - if cast, ok := managedFields.([]metav1.ManagedFieldsEntry); ok { - o.ManagedFields = cast - } - } - if ownerReferences, ok := metadata.ExtraFields["ownerReferences"]; ok { - if cast, ok := ownerReferences.([]metav1.OwnerReference); ok { - o.OwnerReferences = cast - } - } - } -} - -func (o *InvestigationIndex) GetCreatedBy() string { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - return o.ObjectMeta.Annotations["grafana.com/createdBy"] -} - -func (o *InvestigationIndex) SetCreatedBy(createdBy string) { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - o.ObjectMeta.Annotations["grafana.com/createdBy"] = createdBy -} - -func (o *InvestigationIndex) GetUpdateTimestamp() time.Time { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - parsed, _ := time.Parse(time.RFC3339, o.ObjectMeta.Annotations["grafana.com/updateTimestamp"]) - return parsed -} - -func (o *InvestigationIndex) SetUpdateTimestamp(updateTimestamp time.Time) { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - o.ObjectMeta.Annotations["grafana.com/updateTimestamp"] = updateTimestamp.Format(time.RFC3339) -} - -func (o *InvestigationIndex) GetUpdatedBy() string { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - return o.ObjectMeta.Annotations["grafana.com/updatedBy"] -} - -func (o *InvestigationIndex) SetUpdatedBy(updatedBy string) { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - o.ObjectMeta.Annotations["grafana.com/updatedBy"] = updatedBy -} - -func (o *InvestigationIndex) Copy() resource.Object { - return resource.CopyObject(o) -} - -func (o *InvestigationIndex) DeepCopyObject() runtime.Object { - return o.Copy() -} - -func (o *InvestigationIndex) DeepCopy() *InvestigationIndex { - cpy := &InvestigationIndex{} - o.DeepCopyInto(cpy) - return cpy -} - -func (o *InvestigationIndex) DeepCopyInto(dst *InvestigationIndex) { - dst.TypeMeta.APIVersion = o.TypeMeta.APIVersion - dst.TypeMeta.Kind = o.TypeMeta.Kind - o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta) - o.Spec.DeepCopyInto(&dst.Spec) -} - -// Interface compliance compile-time check -var _ resource.Object = &InvestigationIndex{} - -// +k8s:openapi-gen=true -type InvestigationIndexList struct { - metav1.TypeMeta `json:",inline" yaml:",inline"` - metav1.ListMeta `json:"metadata" yaml:"metadata"` - Items []InvestigationIndex `json:"items" yaml:"items"` -} - -func (o *InvestigationIndexList) DeepCopyObject() runtime.Object { - return o.Copy() -} - -func (o *InvestigationIndexList) Copy() resource.ListObject { - cpy := &InvestigationIndexList{ - TypeMeta: o.TypeMeta, - Items: make([]InvestigationIndex, len(o.Items)), - } - o.ListMeta.DeepCopyInto(&cpy.ListMeta) - for i := 0; i < len(o.Items); i++ { - if item, ok := o.Items[i].Copy().(*InvestigationIndex); ok { - cpy.Items[i] = *item - } - } - return cpy -} - -func (o *InvestigationIndexList) GetItems() []resource.Object { - items := make([]resource.Object, len(o.Items)) - for i := 0; i < len(o.Items); i++ { - items[i] = &o.Items[i] - } - return items -} - -func (o *InvestigationIndexList) SetItems(items []resource.Object) { - o.Items = make([]InvestigationIndex, len(items)) - for i := 0; i < len(items); i++ { - o.Items[i] = *items[i].(*InvestigationIndex) - } -} - -func (o *InvestigationIndexList) DeepCopy() *InvestigationIndexList { - cpy := &InvestigationIndexList{} - o.DeepCopyInto(cpy) - return cpy -} - -func (o *InvestigationIndexList) DeepCopyInto(dst *InvestigationIndexList) { - resource.CopyObjectInto(dst, o) -} - -// Interface compliance compile-time check -var _ resource.ListObject = &InvestigationIndexList{} - -// Copy methods for all subresource types - -// DeepCopy creates a full deep copy of Spec -func (s *InvestigationIndexSpec) DeepCopy() *InvestigationIndexSpec { - cpy := &InvestigationIndexSpec{} - s.DeepCopyInto(cpy) - return cpy -} - -// DeepCopyInto deep copies Spec into another Spec object -func (s *InvestigationIndexSpec) DeepCopyInto(dst *InvestigationIndexSpec) { - resource.CopyObjectInto(dst, s) -} diff --git a/apps/investigations/pkg/apis/investigations/v0alpha1/investigationindex_schema_gen.go b/apps/investigations/pkg/apis/investigations/v0alpha1/investigationindex_schema_gen.go deleted file mode 100644 index 3a0041dc6b8..00000000000 --- a/apps/investigations/pkg/apis/investigations/v0alpha1/investigationindex_schema_gen.go +++ /dev/null @@ -1,34 +0,0 @@ -// -// Code generated by grafana-app-sdk. DO NOT EDIT. -// - -package v0alpha1 - -import ( - "github.com/grafana/grafana-app-sdk/resource" -) - -// schema is unexported to prevent accidental overwrites -var ( - schemaInvestigationIndex = resource.NewSimpleSchema("investigations.grafana.app", "v0alpha1", &InvestigationIndex{}, &InvestigationIndexList{}, resource.WithKind("InvestigationIndex"), - resource.WithPlural("investigationindexes"), resource.WithScope(resource.NamespacedScope)) - kindInvestigationIndex = resource.Kind{ - Schema: schemaInvestigationIndex, - Codecs: map[resource.KindEncoding]resource.Codec{ - resource.KindEncodingJSON: &InvestigationIndexJSONCodec{}, - }, - } -) - -// Kind returns a resource.Kind for this Schema with a JSON codec -func InvestigationIndexKind() resource.Kind { - return kindInvestigationIndex -} - -// Schema returns a resource.SimpleSchema representation of InvestigationIndex -func InvestigationIndexSchema() *resource.SimpleSchema { - return schemaInvestigationIndex -} - -// Interface compliance checks -var _ resource.Schema = kindInvestigationIndex diff --git a/apps/investigations/pkg/apis/investigations/v0alpha1/investigationindex_spec_gen.go b/apps/investigations/pkg/apis/investigations/v0alpha1/investigationindex_spec_gen.go deleted file mode 100644 index 44be927c850..00000000000 --- a/apps/investigations/pkg/apis/investigations/v0alpha1/investigationindex_spec_gen.go +++ /dev/null @@ -1,94 +0,0 @@ -// Code generated - EDITING IS FUTILE. DO NOT EDIT. - -package v0alpha1 - -// Person represents a user profile with basic information -// +k8s:openapi-gen=true -type InvestigationIndexPerson struct { - // Unique identifier for the user - Uid string `json:"uid"` - // Display name of the user - Name string `json:"name"` - // URL to user's Gravatar image - GravatarUrl string `json:"gravatarUrl"` -} - -// NewInvestigationIndexPerson creates a new InvestigationIndexPerson object. -func NewInvestigationIndexPerson() *InvestigationIndexPerson { - return &InvestigationIndexPerson{} -} - -// Type definition for investigation summaries -// +k8s:openapi-gen=true -type InvestigationIndexInvestigationSummary struct { - Title string `json:"title"` - CreatedByProfile InvestigationIndexPerson `json:"createdByProfile"` - HasCustomName bool `json:"hasCustomName"` - IsFavorite bool `json:"isFavorite"` - OverviewNote string `json:"overviewNote"` - OverviewNoteUpdatedAt string `json:"overviewNoteUpdatedAt"` - ViewMode InvestigationIndexViewMode `json:"viewMode"` - // +listType=atomic - CollectableSummaries []InvestigationIndexCollectableSummary `json:"collectableSummaries"` -} - -// NewInvestigationIndexInvestigationSummary creates a new InvestigationIndexInvestigationSummary object. -func NewInvestigationIndexInvestigationSummary() *InvestigationIndexInvestigationSummary { - return &InvestigationIndexInvestigationSummary{ - CreatedByProfile: *NewInvestigationIndexPerson(), - ViewMode: *NewInvestigationIndexViewMode(), - CollectableSummaries: []InvestigationIndexCollectableSummary{}, - } -} - -// +k8s:openapi-gen=true -type InvestigationIndexViewMode struct { - Mode InvestigationIndexViewModeMode `json:"mode"` - ShowComments bool `json:"showComments"` - ShowTooltips bool `json:"showTooltips"` -} - -// NewInvestigationIndexViewMode creates a new InvestigationIndexViewMode object. -func NewInvestigationIndexViewMode() *InvestigationIndexViewMode { - return &InvestigationIndexViewMode{} -} - -// +k8s:openapi-gen=true -type InvestigationIndexCollectableSummary struct { - Id string `json:"id"` - Title string `json:"title"` - LogoPath string `json:"logoPath"` - Origin string `json:"origin"` -} - -// NewInvestigationIndexCollectableSummary creates a new InvestigationIndexCollectableSummary object. -func NewInvestigationIndexCollectableSummary() *InvestigationIndexCollectableSummary { - return &InvestigationIndexCollectableSummary{} -} - -// +k8s:openapi-gen=true -type InvestigationIndexSpec struct { - // Title of the index, e.g. 'Favorites' or 'My Investigations' - Title string `json:"title"` - // The Person who owns this investigation index - Owner InvestigationIndexPerson `json:"owner"` - // Array of investigation summaries - // +listType=atomic - InvestigationSummaries []InvestigationIndexInvestigationSummary `json:"investigationSummaries"` -} - -// NewInvestigationIndexSpec creates a new InvestigationIndexSpec object. -func NewInvestigationIndexSpec() *InvestigationIndexSpec { - return &InvestigationIndexSpec{ - Owner: *NewInvestigationIndexPerson(), - InvestigationSummaries: []InvestigationIndexInvestigationSummary{}, - } -} - -// +k8s:openapi-gen=true -type InvestigationIndexViewModeMode string - -const ( - InvestigationIndexViewModeModeCompact InvestigationIndexViewModeMode = "compact" - InvestigationIndexViewModeModeFull InvestigationIndexViewModeMode = "full" -) diff --git a/apps/investigations/pkg/apis/investigations/v0alpha1/investigationindex_status_gen.go b/apps/investigations/pkg/apis/investigations/v0alpha1/investigationindex_status_gen.go deleted file mode 100644 index 455d39bdb48..00000000000 --- a/apps/investigations/pkg/apis/investigations/v0alpha1/investigationindex_status_gen.go +++ /dev/null @@ -1,44 +0,0 @@ -// Code generated - EDITING IS FUTILE. DO NOT EDIT. - -package v0alpha1 - -// +k8s:openapi-gen=true -type InvestigationIndexstatusOperatorState struct { - // lastEvaluation is the ResourceVersion last evaluated - LastEvaluation string `json:"lastEvaluation"` - // state describes the state of the lastEvaluation. - // It is limited to three possible states for machine evaluation. - State InvestigationIndexStatusOperatorStateState `json:"state"` - // descriptiveState is an optional more descriptive state field which has no requirements on format - DescriptiveState *string `json:"descriptiveState,omitempty"` - // details contains any extra information that is operator-specific - Details map[string]interface{} `json:"details,omitempty"` -} - -// NewInvestigationIndexstatusOperatorState creates a new InvestigationIndexstatusOperatorState object. -func NewInvestigationIndexstatusOperatorState() *InvestigationIndexstatusOperatorState { - return &InvestigationIndexstatusOperatorState{} -} - -// +k8s:openapi-gen=true -type InvestigationIndexStatus struct { - // operatorStates is a map of operator ID to operator state evaluations. - // Any operator which consumes this kind SHOULD add its state evaluation information to this field. - OperatorStates map[string]InvestigationIndexstatusOperatorState `json:"operatorStates,omitempty"` - // additionalFields is reserved for future use - AdditionalFields map[string]interface{} `json:"additionalFields,omitempty"` -} - -// NewInvestigationIndexStatus creates a new InvestigationIndexStatus object. -func NewInvestigationIndexStatus() *InvestigationIndexStatus { - return &InvestigationIndexStatus{} -} - -// +k8s:openapi-gen=true -type InvestigationIndexStatusOperatorStateState string - -const ( - InvestigationIndexStatusOperatorStateStateSuccess InvestigationIndexStatusOperatorStateState = "success" - InvestigationIndexStatusOperatorStateStateInProgress InvestigationIndexStatusOperatorStateState = "in_progress" - InvestigationIndexStatusOperatorStateStateFailed InvestigationIndexStatusOperatorStateState = "failed" -) diff --git a/apps/investigations/pkg/apis/investigations/v0alpha1/zz_openapi_gen.go b/apps/investigations/pkg/apis/investigations/v0alpha1/zz_openapi_gen.go deleted file mode 100644 index 4a095da63fc..00000000000 --- a/apps/investigations/pkg/apis/investigations/v0alpha1/zz_openapi_gen.go +++ /dev/null @@ -1,1014 +0,0 @@ -//go:build !ignore_autogenerated -// +build !ignore_autogenerated - -// Code generated by grafana-app-sdk. DO NOT EDIT. - -package v0alpha1 - -import ( - common "k8s.io/kube-openapi/pkg/common" - spec "k8s.io/kube-openapi/pkg/validation/spec" -) - -func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition { - return map[string]common.OpenAPIDefinition{ - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.Investigation": schema_pkg_apis_investigations_v0alpha1_Investigation(ref), - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationCollectable": schema_pkg_apis_investigations_v0alpha1_InvestigationCollectable(ref), - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationDatasourceRef": schema_pkg_apis_investigations_v0alpha1_InvestigationDatasourceRef(ref), - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationIndex": schema_pkg_apis_investigations_v0alpha1_InvestigationIndex(ref), - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationIndexCollectableSummary": schema_pkg_apis_investigations_v0alpha1_InvestigationIndexCollectableSummary(ref), - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationIndexInvestigationSummary": schema_pkg_apis_investigations_v0alpha1_InvestigationIndexInvestigationSummary(ref), - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationIndexList": schema_pkg_apis_investigations_v0alpha1_InvestigationIndexList(ref), - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationIndexPerson": schema_pkg_apis_investigations_v0alpha1_InvestigationIndexPerson(ref), - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationIndexSpec": schema_pkg_apis_investigations_v0alpha1_InvestigationIndexSpec(ref), - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationIndexStatus": schema_pkg_apis_investigations_v0alpha1_InvestigationIndexStatus(ref), - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationIndexViewMode": schema_pkg_apis_investigations_v0alpha1_InvestigationIndexViewMode(ref), - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationIndexstatusOperatorState": schema_pkg_apis_investigations_v0alpha1_InvestigationIndexstatusOperatorState(ref), - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationList": schema_pkg_apis_investigations_v0alpha1_InvestigationList(ref), - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationPerson": schema_pkg_apis_investigations_v0alpha1_InvestigationPerson(ref), - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationSpec": schema_pkg_apis_investigations_v0alpha1_InvestigationSpec(ref), - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationStatus": schema_pkg_apis_investigations_v0alpha1_InvestigationStatus(ref), - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationTimeRange": schema_pkg_apis_investigations_v0alpha1_InvestigationTimeRange(ref), - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationV0alpha1TimeRangeRaw": schema_pkg_apis_investigations_v0alpha1_InvestigationV0alpha1TimeRangeRaw(ref), - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationViewMode": schema_pkg_apis_investigations_v0alpha1_InvestigationViewMode(ref), - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationstatusOperatorState": schema_pkg_apis_investigations_v0alpha1_InvestigationstatusOperatorState(ref), - } -} - -func schema_pkg_apis_investigations_v0alpha1_Investigation(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), - }, - }, - "spec": { - SchemaProps: spec.SchemaProps{ - Description: "Spec is the spec of the Investigation", - Default: map[string]interface{}{}, - Ref: ref("github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationSpec"), - }, - }, - "status": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationStatus"), - }, - }, - }, - Required: []string{"metadata", "spec", "status"}, - }, - }, - Dependencies: []string{ - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationSpec", "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, - } -} - -func schema_pkg_apis_investigations_v0alpha1_InvestigationCollectable(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "Collectable represents an item collected during investigation", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "id": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "createdAt": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "title": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "origin": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "type": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "queries": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, - }, - SchemaProps: spec.SchemaProps{ - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "timeRange": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationTimeRange"), - }, - }, - "datasource": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationDatasourceRef"), - }, - }, - "url": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "logoPath": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - "note": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "noteUpdatedAt": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "fieldConfig": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"id", "createdAt", "title", "origin", "type", "queries", "timeRange", "datasource", "url", "note", "noteUpdatedAt", "fieldConfig"}, - }, - }, - Dependencies: []string{ - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationDatasourceRef", "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationTimeRange"}, - } -} - -func schema_pkg_apis_investigations_v0alpha1_InvestigationDatasourceRef(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "DatasourceRef is a reference to a datasource", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "uid": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"uid"}, - }, - }, - } -} - -func schema_pkg_apis_investigations_v0alpha1_InvestigationIndex(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), - }, - }, - "spec": { - SchemaProps: spec.SchemaProps{ - Description: "Spec is the spec of the InvestigationIndex", - Default: map[string]interface{}{}, - Ref: ref("github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationIndexSpec"), - }, - }, - "status": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationIndexStatus"), - }, - }, - }, - Required: []string{"metadata", "spec", "status"}, - }, - }, - Dependencies: []string{ - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationIndexSpec", "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationIndexStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, - } -} - -func schema_pkg_apis_investigations_v0alpha1_InvestigationIndexCollectableSummary(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "id": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "title": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "logoPath": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "origin": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"id", "title", "logoPath", "origin"}, - }, - }, - } -} - -func schema_pkg_apis_investigations_v0alpha1_InvestigationIndexInvestigationSummary(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "Type definition for investigation summaries", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "title": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "createdByProfile": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationIndexPerson"), - }, - }, - "hasCustomName": { - SchemaProps: spec.SchemaProps{ - Default: false, - Type: []string{"boolean"}, - Format: "", - }, - }, - "isFavorite": { - SchemaProps: spec.SchemaProps{ - Default: false, - Type: []string{"boolean"}, - Format: "", - }, - }, - "overviewNote": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "overviewNoteUpdatedAt": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "viewMode": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationIndexViewMode"), - }, - }, - "collectableSummaries": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, - }, - SchemaProps: spec.SchemaProps{ - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationIndexCollectableSummary"), - }, - }, - }, - }, - }, - }, - Required: []string{"title", "createdByProfile", "hasCustomName", "isFavorite", "overviewNote", "overviewNoteUpdatedAt", "viewMode", "collectableSummaries"}, - }, - }, - Dependencies: []string{ - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationIndexCollectableSummary", "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationIndexPerson", "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationIndexViewMode"}, - } -} - -func schema_pkg_apis_investigations_v0alpha1_InvestigationIndexList(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), - }, - }, - "items": { - SchemaProps: spec.SchemaProps{ - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationIndex"), - }, - }, - }, - }, - }, - }, - Required: []string{"metadata", "items"}, - }, - }, - Dependencies: []string{ - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationIndex", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, - } -} - -func schema_pkg_apis_investigations_v0alpha1_InvestigationIndexPerson(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "Person represents a user profile with basic information", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "uid": { - SchemaProps: spec.SchemaProps{ - Description: "Unique identifier for the user", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "name": { - SchemaProps: spec.SchemaProps{ - Description: "Display name of the user", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "gravatarUrl": { - SchemaProps: spec.SchemaProps{ - Description: "URL to user's Gravatar image", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"uid", "name", "gravatarUrl"}, - }, - }, - } -} - -func schema_pkg_apis_investigations_v0alpha1_InvestigationIndexSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "title": { - SchemaProps: spec.SchemaProps{ - Description: "Title of the index, e.g. 'Favorites' or 'My Investigations'", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "owner": { - SchemaProps: spec.SchemaProps{ - Description: "The Person who owns this investigation index", - Default: map[string]interface{}{}, - Ref: ref("github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationIndexPerson"), - }, - }, - "investigationSummaries": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "Array of investigation summaries", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationIndexInvestigationSummary"), - }, - }, - }, - }, - }, - }, - Required: []string{"title", "owner", "investigationSummaries"}, - }, - }, - Dependencies: []string{ - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationIndexInvestigationSummary", "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationIndexPerson"}, - } -} - -func schema_pkg_apis_investigations_v0alpha1_InvestigationIndexStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "operatorStates": { - SchemaProps: spec.SchemaProps{ - Description: "operatorStates is a map of operator ID to operator state evaluations. Any operator which consumes this kind SHOULD add its state evaluation information to this field.", - Type: []string{"object"}, - AdditionalProperties: &spec.SchemaOrBool{ - Allows: true, - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationIndexstatusOperatorState"), - }, - }, - }, - }, - }, - "additionalFields": { - SchemaProps: spec.SchemaProps{ - Description: "additionalFields is reserved for future use", - Type: []string{"object"}, - AdditionalProperties: &spec.SchemaOrBool{ - Allows: true, - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Format: "", - }, - }, - }, - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationIndexstatusOperatorState"}, - } -} - -func schema_pkg_apis_investigations_v0alpha1_InvestigationIndexViewMode(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "mode": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "showComments": { - SchemaProps: spec.SchemaProps{ - Default: false, - Type: []string{"boolean"}, - Format: "", - }, - }, - "showTooltips": { - SchemaProps: spec.SchemaProps{ - Default: false, - Type: []string{"boolean"}, - Format: "", - }, - }, - }, - Required: []string{"mode", "showComments", "showTooltips"}, - }, - }, - } -} - -func schema_pkg_apis_investigations_v0alpha1_InvestigationIndexstatusOperatorState(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "lastEvaluation": { - SchemaProps: spec.SchemaProps{ - Description: "lastEvaluation is the ResourceVersion last evaluated", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "state": { - SchemaProps: spec.SchemaProps{ - Description: "state describes the state of the lastEvaluation. It is limited to three possible states for machine evaluation.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "descriptiveState": { - SchemaProps: spec.SchemaProps{ - Description: "descriptiveState is an optional more descriptive state field which has no requirements on format", - Type: []string{"string"}, - Format: "", - }, - }, - "details": { - SchemaProps: spec.SchemaProps{ - Description: "details contains any extra information that is operator-specific", - Type: []string{"object"}, - AdditionalProperties: &spec.SchemaOrBool{ - Allows: true, - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Format: "", - }, - }, - }, - }, - }, - }, - Required: []string{"lastEvaluation", "state"}, - }, - }, - } -} - -func schema_pkg_apis_investigations_v0alpha1_InvestigationList(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), - }, - }, - "items": { - SchemaProps: spec.SchemaProps{ - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.Investigation"), - }, - }, - }, - }, - }, - }, - Required: []string{"metadata", "items"}, - }, - }, - Dependencies: []string{ - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.Investigation", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, - } -} - -func schema_pkg_apis_investigations_v0alpha1_InvestigationPerson(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "Person represents a user profile with basic information", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "uid": { - SchemaProps: spec.SchemaProps{ - Description: "Unique identifier for the user", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "name": { - SchemaProps: spec.SchemaProps{ - Description: "Display name of the user", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "gravatarUrl": { - SchemaProps: spec.SchemaProps{ - Description: "URL to user's Gravatar image", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"uid", "name", "gravatarUrl"}, - }, - }, - } -} - -func schema_pkg_apis_investigations_v0alpha1_InvestigationSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "spec is the schema of our resource", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "title": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "createdByProfile": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationPerson"), - }, - }, - "hasCustomName": { - SchemaProps: spec.SchemaProps{ - Default: false, - Type: []string{"boolean"}, - Format: "", - }, - }, - "isFavorite": { - SchemaProps: spec.SchemaProps{ - Default: false, - Type: []string{"boolean"}, - Format: "", - }, - }, - "overviewNote": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "overviewNoteUpdatedAt": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "collectables": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, - }, - SchemaProps: spec.SchemaProps{ - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationCollectable"), - }, - }, - }, - }, - }, - "viewMode": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationViewMode"), - }, - }, - }, - Required: []string{"title", "createdByProfile", "hasCustomName", "isFavorite", "overviewNote", "overviewNoteUpdatedAt", "collectables", "viewMode"}, - }, - }, - Dependencies: []string{ - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationCollectable", "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationPerson", "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationViewMode"}, - } -} - -func schema_pkg_apis_investigations_v0alpha1_InvestigationStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "operatorStates": { - SchemaProps: spec.SchemaProps{ - Description: "operatorStates is a map of operator ID to operator state evaluations. Any operator which consumes this kind SHOULD add its state evaluation information to this field.", - Type: []string{"object"}, - AdditionalProperties: &spec.SchemaOrBool{ - Allows: true, - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationstatusOperatorState"), - }, - }, - }, - }, - }, - "additionalFields": { - SchemaProps: spec.SchemaProps{ - Description: "additionalFields is reserved for future use", - Type: []string{"object"}, - AdditionalProperties: &spec.SchemaOrBool{ - Allows: true, - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Format: "", - }, - }, - }, - }, - }, - }, - }, - }, - Dependencies: []string{ - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationstatusOperatorState"}, - } -} - -func schema_pkg_apis_investigations_v0alpha1_InvestigationTimeRange(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "TimeRange represents a time range with both absolute and relative values", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "from": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "to": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "raw": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationV0alpha1TimeRangeRaw"), - }, - }, - }, - Required: []string{"from", "to", "raw"}, - }, - }, - Dependencies: []string{ - "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1.InvestigationV0alpha1TimeRangeRaw"}, - } -} - -func schema_pkg_apis_investigations_v0alpha1_InvestigationV0alpha1TimeRangeRaw(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "from": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "to": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"from", "to"}, - }, - }, - } -} - -func schema_pkg_apis_investigations_v0alpha1_InvestigationViewMode(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "mode": { - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "showComments": { - SchemaProps: spec.SchemaProps{ - Default: false, - Type: []string{"boolean"}, - Format: "", - }, - }, - "showTooltips": { - SchemaProps: spec.SchemaProps{ - Default: false, - Type: []string{"boolean"}, - Format: "", - }, - }, - }, - Required: []string{"mode", "showComments", "showTooltips"}, - }, - }, - } -} - -func schema_pkg_apis_investigations_v0alpha1_InvestigationstatusOperatorState(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "lastEvaluation": { - SchemaProps: spec.SchemaProps{ - Description: "lastEvaluation is the ResourceVersion last evaluated", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "state": { - SchemaProps: spec.SchemaProps{ - Description: "state describes the state of the lastEvaluation. It is limited to three possible states for machine evaluation.", - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - "descriptiveState": { - SchemaProps: spec.SchemaProps{ - Description: "descriptiveState is an optional more descriptive state field which has no requirements on format", - Type: []string{"string"}, - Format: "", - }, - }, - "details": { - SchemaProps: spec.SchemaProps{ - Description: "details contains any extra information that is operator-specific", - Type: []string{"object"}, - AdditionalProperties: &spec.SchemaOrBool{ - Allows: true, - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Format: "", - }, - }, - }, - }, - }, - }, - Required: []string{"lastEvaluation", "state"}, - }, - }, - } -} diff --git a/apps/investigations/pkg/apis/investigations_manifest.go b/apps/investigations/pkg/apis/investigations_manifest.go deleted file mode 100644 index 249e9b49758..00000000000 --- a/apps/investigations/pkg/apis/investigations_manifest.go +++ /dev/null @@ -1,136 +0,0 @@ -// -// This file is generated by grafana-app-sdk -// DO NOT EDIT -// - -package apis - -import ( - "encoding/json" - "fmt" - "strings" - - "github.com/grafana/grafana-app-sdk/app" - "github.com/grafana/grafana-app-sdk/resource" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/kube-openapi/pkg/spec3" - "k8s.io/kube-openapi/pkg/validation/spec" - - v0alpha1 "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1" -) - -var ( - rawSchemaInvestigationv0alpha1 = []byte(`{"Collectable":{"additionalProperties":false,"description":"Collectable represents an item collected during investigation","properties":{"createdAt":{"type":"string"},"datasource":{"$ref":"#/components/schemas/DatasourceRef"},"fieldConfig":{"type":"string"},"id":{"type":"string"},"logoPath":{"type":"string"},"note":{"type":"string"},"noteUpdatedAt":{"type":"string"},"origin":{"type":"string"},"queries":{"description":"+listType=atomic","items":{"type":"string"},"type":"array"},"timeRange":{"$ref":"#/components/schemas/TimeRange"},"title":{"type":"string"},"type":{"type":"string"},"url":{"type":"string"}},"required":["id","createdAt","title","origin","type","queries","timeRange","datasource","url","note","noteUpdatedAt","fieldConfig"],"type":"object"},"DatasourceRef":{"additionalProperties":false,"description":"DatasourceRef is a reference to a datasource","properties":{"uid":{"type":"string"}},"required":["uid"],"type":"object"},"Investigation":{"properties":{"spec":{"$ref":"#/components/schemas/spec"}},"required":["spec"]},"Person":{"additionalProperties":false,"description":"Person represents a user profile with basic information","properties":{"gravatarUrl":{"description":"URL to user's Gravatar image","type":"string"},"name":{"description":"Display name of the user","type":"string"},"uid":{"description":"Unique identifier for the user","type":"string"}},"required":["uid","name","gravatarUrl"],"type":"object"},"TimeRange":{"additionalProperties":false,"description":"TimeRange represents a time range with both absolute and relative values","properties":{"from":{"type":"string"},"raw":{"additionalProperties":false,"properties":{"from":{"type":"string"},"to":{"type":"string"}},"required":["from","to"],"type":"object"},"to":{"type":"string"}},"required":["from","to","raw"],"type":"object"},"ViewMode":{"additionalProperties":false,"properties":{"mode":{"enum":["compact","full"],"type":"string"},"showComments":{"type":"boolean"},"showTooltips":{"type":"boolean"}},"required":["mode","showComments","showTooltips"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"collectables":{"description":"+listType=atomic","items":{"$ref":"#/components/schemas/Collectable"},"type":"array"},"createdByProfile":{"$ref":"#/components/schemas/Person"},"hasCustomName":{"type":"boolean"},"isFavorite":{"type":"boolean"},"overviewNote":{"type":"string"},"overviewNoteUpdatedAt":{"type":"string"},"title":{"type":"string"},"viewMode":{"$ref":"#/components/schemas/ViewMode"}},"required":["title","createdByProfile","hasCustomName","isFavorite","overviewNote","overviewNoteUpdatedAt","collectables","viewMode"],"type":"object"}}`) - versionSchemaInvestigationv0alpha1 app.VersionSchema - _ = json.Unmarshal(rawSchemaInvestigationv0alpha1, &versionSchemaInvestigationv0alpha1) - rawSchemaInvestigationIndexv0alpha1 = []byte(`{"CollectableSummary":{"additionalProperties":false,"properties":{"id":{"type":"string"},"logoPath":{"type":"string"},"origin":{"type":"string"},"title":{"type":"string"}},"required":["id","title","logoPath","origin"],"type":"object"},"InvestigationIndex":{"properties":{"spec":{"$ref":"#/components/schemas/spec"}},"required":["spec"]},"InvestigationSummary":{"additionalProperties":false,"description":"Type definition for investigation summaries","properties":{"collectableSummaries":{"description":"+listType=atomic","items":{"$ref":"#/components/schemas/CollectableSummary"},"type":"array"},"createdByProfile":{"$ref":"#/components/schemas/Person"},"hasCustomName":{"type":"boolean"},"isFavorite":{"type":"boolean"},"overviewNote":{"type":"string"},"overviewNoteUpdatedAt":{"type":"string"},"title":{"type":"string"},"viewMode":{"$ref":"#/components/schemas/ViewMode"}},"required":["title","createdByProfile","hasCustomName","isFavorite","overviewNote","overviewNoteUpdatedAt","viewMode","collectableSummaries"],"type":"object"},"Person":{"additionalProperties":false,"description":"Person represents a user profile with basic information","properties":{"gravatarUrl":{"description":"URL to user's Gravatar image","type":"string"},"name":{"description":"Display name of the user","type":"string"},"uid":{"description":"Unique identifier for the user","type":"string"}},"required":["uid","name","gravatarUrl"],"type":"object"},"ViewMode":{"additionalProperties":false,"properties":{"mode":{"enum":["compact","full"],"type":"string"},"showComments":{"type":"boolean"},"showTooltips":{"type":"boolean"}},"required":["mode","showComments","showTooltips"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"investigationSummaries":{"description":"Array of investigation summaries\n+listType=atomic","items":{"$ref":"#/components/schemas/InvestigationSummary"},"type":"array"},"owner":{"$ref":"#/components/schemas/Person","description":"The Person who owns this investigation index"},"title":{"description":"Title of the index, e.g. 'Favorites' or 'My Investigations'","type":"string"}},"required":["title","owner","investigationSummaries"],"type":"object"}}`) - versionSchemaInvestigationIndexv0alpha1 app.VersionSchema - _ = json.Unmarshal(rawSchemaInvestigationIndexv0alpha1, &versionSchemaInvestigationIndexv0alpha1) -) - -var appManifestData = app.ManifestData{ - AppName: "investigations", - Group: "investigations.grafana.app", - PreferredVersion: "v0alpha1", - Versions: []app.ManifestVersion{ - { - Name: "v0alpha1", - Served: true, - Kinds: []app.ManifestVersionKind{ - { - Kind: "Investigation", - Plural: "Investigations", - Scope: "Namespaced", - Conversion: false, - Schema: &versionSchemaInvestigationv0alpha1, - }, - - { - Kind: "InvestigationIndex", - Plural: "InvestigationIndexes", - Scope: "Namespaced", - Conversion: false, - Schema: &versionSchemaInvestigationIndexv0alpha1, - }, - }, - Routes: app.ManifestVersionRoutes{ - Namespaced: map[string]spec3.PathProps{}, - Cluster: map[string]spec3.PathProps{}, - Schemas: map[string]spec.Schema{}, - }, - }, - }, -} - -func LocalManifest() app.Manifest { - return app.NewEmbeddedManifest(appManifestData) -} - -func RemoteManifest() app.Manifest { - return app.NewAPIServerManifest("investigations") -} - -var kindVersionToGoType = map[string]resource.Kind{ - "Investigation/v0alpha1": v0alpha1.InvestigationKind(), - "InvestigationIndex/v0alpha1": v0alpha1.InvestigationIndexKind(), -} - -// 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/investigations/pkg/app/investigations_app.go b/apps/investigations/pkg/app/investigations_app.go deleted file mode 100644 index 516d278788d..00000000000 --- a/apps/investigations/pkg/app/investigations_app.go +++ /dev/null @@ -1,62 +0,0 @@ -package app - -import ( - "context" - - "github.com/grafana/grafana-app-sdk/app" - "github.com/grafana/grafana-app-sdk/operator" - "github.com/grafana/grafana-app-sdk/resource" - "github.com/grafana/grafana-app-sdk/simple" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/klog/v2" - - investigationsv0alpha1 "github.com/grafana/grafana/apps/investigations/pkg/apis/investigations/v0alpha1" -) - -func New(cfg app.Config) (app.App, error) { - var err error - simpleConfig := simple.AppConfig{ - Name: "investigation", - KubeConfig: cfg.KubeConfig, - InformerConfig: simple.AppInformerConfig{ - InformerOptions: operator.InformerOptions{ - ErrorHandler: func(_ context.Context, err error) { - klog.ErrorS(err, "Informer processing error") - }, - }, - }, - ManagedKinds: []simple.AppManagedKind{ - { - Kind: investigationsv0alpha1.InvestigationKind(), - }, - { - Kind: investigationsv0alpha1.InvestigationIndexKind(), - }, - }, - } - - a, err := simple.NewApp(simpleConfig) - if err != nil { - return nil, err - } - - err = a.ValidateManifest(cfg.ManifestData) - if err != nil { - return nil, err - } - - return a, nil -} - -func GetKinds() map[schema.GroupVersion][]resource.Kind { - gv := schema.GroupVersion{ - Group: investigationsv0alpha1.InvestigationKind().Group(), - Version: investigationsv0alpha1.InvestigationKind().Version(), - } - return map[schema.GroupVersion][]resource.Kind{ - gv: { - investigationsv0alpha1.InvestigationKind(), - investigationsv0alpha1.InvestigationIndexKind(), - }, - } -} diff --git a/apps/investigations/plugin/src/generated/investigation/v0alpha1/types.spec.gen.ts b/apps/investigations/plugin/src/generated/investigation/v0alpha1/types.spec.gen.ts deleted file mode 100644 index c46622cd502..00000000000 --- a/apps/investigations/plugin/src/generated/investigation/v0alpha1/types.spec.gen.ts +++ /dev/null @@ -1,115 +0,0 @@ -// Code generated - EDITING IS FUTILE. DO NOT EDIT. - -// Person represents a user profile with basic information -export interface Person { - // Unique identifier for the user - uid: string; - // Display name of the user - name: string; - // URL to user's Gravatar image - gravatarUrl: string; -} - -export const defaultPerson = (): Person => ({ - uid: "", - name: "", - gravatarUrl: "", -}); - -// Collectable represents an item collected during investigation -export interface Collectable { - id: string; - createdAt: string; - title: string; - origin: string; - type: string; - // +listType=atomic - queries: string[]; - timeRange: TimeRange; - datasource: DatasourceRef; - url: string; - logoPath?: string; - note: string; - noteUpdatedAt: string; - fieldConfig: string; -} - -export const defaultCollectable = (): Collectable => ({ - id: "", - createdAt: "", - title: "", - origin: "", - type: "", - queries: [], - timeRange: defaultTimeRange(), - datasource: defaultDatasourceRef(), - url: "", - note: "", - noteUpdatedAt: "", - fieldConfig: "", -}); - -// TimeRange represents a time range with both absolute and relative values -export interface TimeRange { - from: string; - to: string; - raw: { - from: string; - to: string; - }; -} - -export const defaultTimeRange = (): TimeRange => ({ - from: "", - to: "", - raw: { - from: "", - to: "", -}, -}); - -// DatasourceRef is a reference to a datasource -export interface DatasourceRef { - uid: string; -} - -export const defaultDatasourceRef = (): DatasourceRef => ({ - uid: "", -}); - -export interface ViewMode { - mode: "compact" | "full"; - showComments: boolean; - showTooltips: boolean; -} - -export const defaultViewMode = (): ViewMode => ({ - mode: "compact", - showComments: false, - showTooltips: false, -}); - -// spec is the schema of our resource -export interface Spec { - title: string; - createdByProfile: Person; - hasCustomName: boolean; - isFavorite: boolean; - overviewNote: string; - overviewNoteUpdatedAt: string; - // +listType=atomic - collectables: Collectable[]; - viewMode: ViewMode; -} - -export const defaultSpec = (): Spec => ({ - title: "", - createdByProfile: defaultPerson(), - hasCustomName: false, - isFavorite: false, - overviewNote: "", - overviewNoteUpdatedAt: "", - collectables: [], - viewMode: defaultViewMode(), -}); - diff --git a/apps/investigations/plugin/src/generated/investigationindex/v0alpha1/investigationindex_object_gen.ts b/apps/investigations/plugin/src/generated/investigationindex/v0alpha1/investigationindex_object_gen.ts deleted file mode 100644 index 7d88430d451..00000000000 --- a/apps/investigations/plugin/src/generated/investigationindex/v0alpha1/investigationindex_object_gen.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This file was generated by grafana-app-sdk. DO NOT EDIT. - */ -import { Spec } from './types.spec.gen'; -import { Status } from './types.status.gen'; - -export interface Metadata { - name: string; - namespace: string; - generateName?: string; - selfLink?: string; - uid?: string; - resourceVersion?: string; - generation?: number; - creationTimestamp?: string; - deletionTimestamp?: string; - deletionGracePeriodSeconds?: number; - labels?: Record; - annotations?: Record; - ownerReferences?: OwnerReference[]; - finalizers?: string[]; - managedFields?: ManagedFieldsEntry[]; -} - -export interface OwnerReference { - apiVersion: string; - kind: string; - name: string; - uid: string; - controller?: boolean; - blockOwnerDeletion?: boolean; -} - -export interface ManagedFieldsEntry { - manager?: string; - operation?: string; - apiVersion?: string; - time?: string; - fieldsType?: string; - subresource?: string; -} - -export interface InvestigationIndex { - kind: string; - apiVersion: string; - metadata: Metadata; - spec: Spec; - status: Status; -} diff --git a/apps/investigations/plugin/src/generated/investigationindex/v0alpha1/types.metadata.gen.ts b/apps/investigations/plugin/src/generated/investigationindex/v0alpha1/types.metadata.gen.ts deleted file mode 100644 index 4377f3c1d08..00000000000 --- a/apps/investigations/plugin/src/generated/investigationindex/v0alpha1/types.metadata.gen.ts +++ /dev/null @@ -1,30 +0,0 @@ -// Code generated - EDITING IS FUTILE. DO NOT EDIT. - -// metadata contains embedded CommonMetadata and can be extended with custom string fields -// TODO: use CommonMetadata instead of redefining here; currently needs to be defined here -// without external reference as using the CommonMetadata reference breaks thema codegen. -export interface Metadata { - updateTimestamp: string; - createdBy: string; - uid: string; - creationTimestamp: string; - deletionTimestamp?: string; - finalizers: string[]; - resourceVersion: string; - generation: number; - updatedBy: string; - labels: Record; -} - -export const defaultMetadata = (): Metadata => ({ - updateTimestamp: "", - createdBy: "", - uid: "", - creationTimestamp: "", - finalizers: [], - resourceVersion: "", - generation: 0, - updatedBy: "", - labels: {}, -}); - diff --git a/apps/investigations/plugin/src/generated/investigationindex/v0alpha1/types.spec.gen.ts b/apps/investigations/plugin/src/generated/investigationindex/v0alpha1/types.spec.gen.ts deleted file mode 100644 index f0d2f25d96b..00000000000 --- a/apps/investigations/plugin/src/generated/investigationindex/v0alpha1/types.spec.gen.ts +++ /dev/null @@ -1,84 +0,0 @@ -// Code generated - EDITING IS FUTILE. DO NOT EDIT. - -// Person represents a user profile with basic information -export interface Person { - // Unique identifier for the user - uid: string; - // Display name of the user - name: string; - // URL to user's Gravatar image - gravatarUrl: string; -} - -export const defaultPerson = (): Person => ({ - uid: "", - name: "", - gravatarUrl: "", -}); - -// Type definition for investigation summaries -export interface InvestigationSummary { - title: string; - createdByProfile: Person; - hasCustomName: boolean; - isFavorite: boolean; - overviewNote: string; - overviewNoteUpdatedAt: string; - viewMode: ViewMode; - // +listType=atomic - collectableSummaries: CollectableSummary[]; -} - -export const defaultInvestigationSummary = (): InvestigationSummary => ({ - title: "", - createdByProfile: defaultPerson(), - hasCustomName: false, - isFavorite: false, - overviewNote: "", - overviewNoteUpdatedAt: "", - viewMode: defaultViewMode(), - collectableSummaries: [], -}); - -export interface ViewMode { - mode: "compact" | "full"; - showComments: boolean; - showTooltips: boolean; -} - -export const defaultViewMode = (): ViewMode => ({ - mode: "compact", - showComments: false, - showTooltips: false, -}); - -export interface CollectableSummary { - id: string; - title: string; - logoPath: string; - origin: string; -} - -export const defaultCollectableSummary = (): CollectableSummary => ({ - id: "", - title: "", - logoPath: "", - origin: "", -}); - -export interface Spec { - // Title of the index, e.g. 'Favorites' or 'My Investigations' - title: string; - // The Person who owns this investigation index - owner: Person; - // Array of investigation summaries - // +listType=atomic - investigationSummaries: InvestigationSummary[]; -} - -export const defaultSpec = (): Spec => ({ - title: "", - owner: defaultPerson(), - investigationSummaries: [], -}); - diff --git a/apps/investigations/plugin/src/generated/investigationindex/v0alpha1/types.status.gen.ts b/apps/investigations/plugin/src/generated/investigationindex/v0alpha1/types.status.gen.ts deleted file mode 100644 index 01be8df7961..00000000000 --- a/apps/investigations/plugin/src/generated/investigationindex/v0alpha1/types.status.gen.ts +++ /dev/null @@ -1,30 +0,0 @@ -// Code generated - EDITING IS FUTILE. DO NOT EDIT. - -export interface OperatorState { - // lastEvaluation is the ResourceVersion last evaluated - lastEvaluation: string; - // state describes the state of the lastEvaluation. - // It is limited to three possible states for machine evaluation. - state: "success" | "in_progress" | "failed"; - // descriptiveState is an optional more descriptive state field which has no requirements on format - descriptiveState?: string; - // details contains any extra information that is operator-specific - details?: Record; -} - -export const defaultOperatorState = (): OperatorState => ({ - lastEvaluation: "", - state: "success", -}); - -export interface Status { - // operatorStates is a map of operator ID to operator state evaluations. - // Any operator which consumes this kind SHOULD add its state evaluation information to this field. - operatorStates?: Record; - // additionalFields is reserved for future use - additionalFields?: Record; -} - -export const defaultStatus = (): Status => ({ -}); - diff --git a/apps/logsdrilldown/definitions/logsdrilldown-manifest.json b/apps/logsdrilldown/definitions/logsdrilldown-manifest.json index da34c0c70f2..3ef92d3d5b8 100644 --- a/apps/logsdrilldown/definitions/logsdrilldown-manifest.json +++ b/apps/logsdrilldown/definitions/logsdrilldown-manifest.json @@ -191,7 +191,13 @@ } }, "conversion": false - }, + } + ] + }, + { + "name": "v1beta1", + "served": true, + "kinds": [ { "kind": "LogsDrilldownDefaultColumns", "plural": "LogsDrilldownDefaultColumns", @@ -314,6 +320,6 @@ ] } ], - "preferredVersion": "v1alpha1" + "preferredVersion": "v1beta1" } } diff --git a/apps/logsdrilldown/definitions/logsdrilldowndefaultcolumns.logsdrilldown.grafana.app.json b/apps/logsdrilldown/definitions/logsdrilldowndefaultcolumns.logsdrilldown.grafana.app.json index 28aa314311d..c8987741983 100644 --- a/apps/logsdrilldown/definitions/logsdrilldowndefaultcolumns.logsdrilldown.grafana.app.json +++ b/apps/logsdrilldown/definitions/logsdrilldowndefaultcolumns.logsdrilldown.grafana.app.json @@ -8,7 +8,7 @@ "group": "logsdrilldown.grafana.app", "versions": [ { - "name": "v1alpha1", + "name": "v1beta1", "served": true, "storage": true, "schema": { diff --git a/apps/logsdrilldown/kinds/logsdrilldown.cue b/apps/logsdrilldown/kinds/logsdrilldown.cue index d2752103820..4b2d815743d 100644 --- a/apps/logsdrilldown/kinds/logsdrilldown.cue +++ b/apps/logsdrilldown/kinds/logsdrilldown.cue @@ -1,7 +1,7 @@ package kinds import ( - "github.com/grafana/grafana/apps/logsdrilldown/kinds/v0alpha1" + "github.com/grafana/grafana/apps/logsdrilldown/kinds/v1beta1", ) LogsDrilldownSpecv1alpha1: { @@ -26,11 +26,11 @@ logsdrilldownDefaultsv1alpha1: { } } -// Default columns API -logsdrilldownDefaultColumnsv0alpha1: { +// Default columns API (beta) +logsdrilldownDefaultColumnsv1beta1: { kind: "LogsDrilldownDefaultColumns" pluralName: "LogsDrilldownDefaultColumns" schema: { - spec: v0alpha1.LogsDefaultColumns + spec: v1beta1.LogsDefaultColumns } } diff --git a/apps/logsdrilldown/kinds/manifest.cue b/apps/logsdrilldown/kinds/manifest.cue index ab717de6a92..cbd47ce2b65 100644 --- a/apps/logsdrilldown/kinds/manifest.cue +++ b/apps/logsdrilldown/kinds/manifest.cue @@ -15,6 +15,7 @@ manifest: { // If your app needs access to kinds managed by another app, use permissions.accessKinds to allow your app access. versions: { "v1alpha1": v1alpha1 + "v1beta1" : v1beta1 } // extraPermissions contains any additional permissions your app may require to function. // Your app will always have all permissions for each kind it manages (the items defined in 'kinds'). @@ -35,7 +36,40 @@ manifest: { // It includes kinds which the v1alpha1 API serves, and (future) custom routes served globally from the v1alpha1 version. v1alpha1: { // kinds is the list of kinds served by this version - kinds: [logsdrilldownv1alpha1, logsdrilldownDefaultsv1alpha1, logsdrilldownDefaultColumnsv0alpha1] + kinds: [logsdrilldownv1alpha1, logsdrilldownDefaultsv1alpha1] + // [OPTIONAL] + // served indicates whether this particular version is served by the API server. + // served should be set to false before a version is removed from the manifest entirely. + // served defaults to true if not present. + served: true + // [OPTIONAL] + // Codegen is a trait that tells the grafana-app-sdk, or other code generation tooling, how to process this kind. + // If not present, default values within the codegen trait are used. + // If you wish to specify codegen per-version, put this section in the version's object + // (for example, v1alpha1) instead. + codegen: { + // [OPTIONAL] + // ts contains TypeScript code generation properties for the kind + ts: { + // [OPTIONAL] + // enabled indicates whether the CLI should generate front-end TypeScript code for the kind. + // Defaults to true if not present. + enabled: true + } + // [OPTIONAL] + // go contains go code generation properties for the kind + go: { + // [OPTIONAL] + // enabled indicates whether the CLI should generate back-end go code for the kind. + // Defaults to true if not present. + enabled: true + } + } +} + +v1beta1: { + // kinds is the list of kinds served by this version + kinds: [logsdrilldownDefaultColumnsv1beta1] // [OPTIONAL] // served indicates whether this particular version is served by the API server. // served should be set to false before a version is removed from the manifest entirely. diff --git a/apps/logsdrilldown/kinds/v1beta1/defaultcolumns.cue b/apps/logsdrilldown/kinds/v1beta1/defaultcolumns.cue new file mode 100644 index 00000000000..a66e813766b --- /dev/null +++ b/apps/logsdrilldown/kinds/v1beta1/defaultcolumns.cue @@ -0,0 +1,19 @@ +package v1beta1 + +#LogsDefaultColumnsLabel: { + key: string + value: string +} + +#LogsDefaultColumnsLabels: [...#LogsDefaultColumnsLabel] + +#LogsDefaultColumnsRecord: { + columns: [...string] + labels: #LogsDefaultColumnsLabels +} + +#LogsDefaultColumnsRecords: [...#LogsDefaultColumnsRecord] + +LogsDefaultColumns: { + records: #LogsDefaultColumnsRecords +} diff --git a/apps/logsdrilldown/pkg/generated/logsdrilldown/v1alpha1/constants.go b/apps/logsdrilldown/pkg/apis/logsdrilldown/v1beta1/constants.go similarity index 91% rename from apps/logsdrilldown/pkg/generated/logsdrilldown/v1alpha1/constants.go rename to apps/logsdrilldown/pkg/apis/logsdrilldown/v1beta1/constants.go index 082bec7c874..ecfc11a456f 100644 --- a/apps/logsdrilldown/pkg/generated/logsdrilldown/v1alpha1/constants.go +++ b/apps/logsdrilldown/pkg/apis/logsdrilldown/v1beta1/constants.go @@ -1,4 +1,4 @@ -package v1alpha1 +package v1beta1 import "k8s.io/apimachinery/pkg/runtime/schema" @@ -6,7 +6,7 @@ const ( // APIGroup is the API group used by all kinds in this package APIGroup = "logsdrilldown.grafana.app" // APIVersion is the API version used by all kinds in this package - APIVersion = "v1alpha1" + APIVersion = "v1beta1" ) var ( diff --git a/apps/logsdrilldown/pkg/apis/logsdrilldown/v1alpha1/logsdrilldowndefaultcolumns_client_gen.go b/apps/logsdrilldown/pkg/apis/logsdrilldown/v1beta1/logsdrilldowndefaultcolumns_client_gen.go similarity index 99% rename from apps/logsdrilldown/pkg/apis/logsdrilldown/v1alpha1/logsdrilldowndefaultcolumns_client_gen.go rename to apps/logsdrilldown/pkg/apis/logsdrilldown/v1beta1/logsdrilldowndefaultcolumns_client_gen.go index b5d573bc1dc..856c3af291b 100644 --- a/apps/logsdrilldown/pkg/apis/logsdrilldown/v1alpha1/logsdrilldowndefaultcolumns_client_gen.go +++ b/apps/logsdrilldown/pkg/apis/logsdrilldown/v1beta1/logsdrilldowndefaultcolumns_client_gen.go @@ -1,4 +1,4 @@ -package v1alpha1 +package v1beta1 import ( "context" diff --git a/apps/logsdrilldown/pkg/apis/logsdrilldown/v1alpha1/logsdrilldowndefaultcolumns_codec_gen.go b/apps/logsdrilldown/pkg/apis/logsdrilldown/v1beta1/logsdrilldowndefaultcolumns_codec_gen.go similarity index 98% rename from apps/logsdrilldown/pkg/apis/logsdrilldown/v1alpha1/logsdrilldowndefaultcolumns_codec_gen.go rename to apps/logsdrilldown/pkg/apis/logsdrilldown/v1beta1/logsdrilldowndefaultcolumns_codec_gen.go index 311d2f02683..12622814e72 100644 --- a/apps/logsdrilldown/pkg/apis/logsdrilldown/v1alpha1/logsdrilldowndefaultcolumns_codec_gen.go +++ b/apps/logsdrilldown/pkg/apis/logsdrilldown/v1beta1/logsdrilldowndefaultcolumns_codec_gen.go @@ -2,7 +2,7 @@ // Code generated by grafana-app-sdk. DO NOT EDIT. // -package v1alpha1 +package v1beta1 import ( "encoding/json" diff --git a/apps/logsdrilldown/pkg/apis/logsdrilldown/v1alpha1/logsdrilldowndefaultcolumns_metadata_gen.go b/apps/logsdrilldown/pkg/apis/logsdrilldown/v1beta1/logsdrilldowndefaultcolumns_metadata_gen.go similarity index 98% rename from apps/logsdrilldown/pkg/apis/logsdrilldown/v1alpha1/logsdrilldowndefaultcolumns_metadata_gen.go rename to apps/logsdrilldown/pkg/apis/logsdrilldown/v1beta1/logsdrilldowndefaultcolumns_metadata_gen.go index a4bb052fe25..ee2d44fde2e 100644 --- a/apps/logsdrilldown/pkg/apis/logsdrilldown/v1alpha1/logsdrilldowndefaultcolumns_metadata_gen.go +++ b/apps/logsdrilldown/pkg/apis/logsdrilldown/v1beta1/logsdrilldowndefaultcolumns_metadata_gen.go @@ -1,6 +1,6 @@ // Code generated - EDITING IS FUTILE. DO NOT EDIT. -package v1alpha1 +package v1beta1 import ( time "time" diff --git a/apps/logsdrilldown/pkg/apis/logsdrilldown/v1alpha1/logsdrilldowndefaultcolumns_object_gen.go b/apps/logsdrilldown/pkg/apis/logsdrilldown/v1beta1/logsdrilldowndefaultcolumns_object_gen.go similarity index 99% rename from apps/logsdrilldown/pkg/apis/logsdrilldown/v1alpha1/logsdrilldowndefaultcolumns_object_gen.go rename to apps/logsdrilldown/pkg/apis/logsdrilldown/v1beta1/logsdrilldowndefaultcolumns_object_gen.go index 4340a27714e..6822fbfb4d7 100644 --- a/apps/logsdrilldown/pkg/apis/logsdrilldown/v1alpha1/logsdrilldowndefaultcolumns_object_gen.go +++ b/apps/logsdrilldown/pkg/apis/logsdrilldown/v1beta1/logsdrilldowndefaultcolumns_object_gen.go @@ -2,7 +2,7 @@ // Code generated by grafana-app-sdk. DO NOT EDIT. // -package v1alpha1 +package v1beta1 import ( "fmt" diff --git a/apps/logsdrilldown/pkg/apis/logsdrilldown/v1alpha1/logsdrilldowndefaultcolumns_schema_gen.go b/apps/logsdrilldown/pkg/apis/logsdrilldown/v1beta1/logsdrilldowndefaultcolumns_schema_gen.go similarity index 85% rename from apps/logsdrilldown/pkg/apis/logsdrilldown/v1alpha1/logsdrilldowndefaultcolumns_schema_gen.go rename to apps/logsdrilldown/pkg/apis/logsdrilldown/v1beta1/logsdrilldowndefaultcolumns_schema_gen.go index cc5363e16bb..49d234f47a5 100644 --- a/apps/logsdrilldown/pkg/apis/logsdrilldown/v1alpha1/logsdrilldowndefaultcolumns_schema_gen.go +++ b/apps/logsdrilldown/pkg/apis/logsdrilldown/v1beta1/logsdrilldowndefaultcolumns_schema_gen.go @@ -2,7 +2,7 @@ // Code generated by grafana-app-sdk. DO NOT EDIT. // -package v1alpha1 +package v1beta1 import ( "github.com/grafana/grafana-app-sdk/resource" @@ -10,7 +10,7 @@ import ( // schema is unexported to prevent accidental overwrites var ( - schemaLogsDrilldownDefaultColumns = resource.NewSimpleSchema("logsdrilldown.grafana.app", "v1alpha1", NewLogsDrilldownDefaultColumns(), &LogsDrilldownDefaultColumnsList{}, resource.WithKind("LogsDrilldownDefaultColumns"), + schemaLogsDrilldownDefaultColumns = resource.NewSimpleSchema("logsdrilldown.grafana.app", "v1beta1", NewLogsDrilldownDefaultColumns(), &LogsDrilldownDefaultColumnsList{}, resource.WithKind("LogsDrilldownDefaultColumns"), resource.WithPlural("logsdrilldowndefaultcolumns"), resource.WithScope(resource.NamespacedScope)) kindLogsDrilldownDefaultColumns = resource.Kind{ Schema: schemaLogsDrilldownDefaultColumns, diff --git a/apps/logsdrilldown/pkg/apis/logsdrilldown/v1alpha1/logsdrilldowndefaultcolumns_spec_gen.go b/apps/logsdrilldown/pkg/apis/logsdrilldown/v1beta1/logsdrilldowndefaultcolumns_spec_gen.go similarity index 99% rename from apps/logsdrilldown/pkg/apis/logsdrilldown/v1alpha1/logsdrilldowndefaultcolumns_spec_gen.go rename to apps/logsdrilldown/pkg/apis/logsdrilldown/v1beta1/logsdrilldowndefaultcolumns_spec_gen.go index ce12ebb0761..6163f66c52c 100644 --- a/apps/logsdrilldown/pkg/apis/logsdrilldown/v1alpha1/logsdrilldowndefaultcolumns_spec_gen.go +++ b/apps/logsdrilldown/pkg/apis/logsdrilldown/v1beta1/logsdrilldowndefaultcolumns_spec_gen.go @@ -1,6 +1,6 @@ // Code generated - EDITING IS FUTILE. DO NOT EDIT. -package v1alpha1 +package v1beta1 // +k8s:openapi-gen=true type LogsDrilldownDefaultColumnsLogsDefaultColumnsRecords []LogsDrilldownDefaultColumnsLogsDefaultColumnsRecord diff --git a/apps/logsdrilldown/pkg/apis/logsdrilldown/v1alpha1/logsdrilldowndefaultcolumns_status_gen.go b/apps/logsdrilldown/pkg/apis/logsdrilldown/v1beta1/logsdrilldowndefaultcolumns_status_gen.go similarity index 99% rename from apps/logsdrilldown/pkg/apis/logsdrilldown/v1alpha1/logsdrilldowndefaultcolumns_status_gen.go rename to apps/logsdrilldown/pkg/apis/logsdrilldown/v1beta1/logsdrilldowndefaultcolumns_status_gen.go index c2183832095..e109592eb09 100644 --- a/apps/logsdrilldown/pkg/apis/logsdrilldown/v1alpha1/logsdrilldowndefaultcolumns_status_gen.go +++ b/apps/logsdrilldown/pkg/apis/logsdrilldown/v1beta1/logsdrilldowndefaultcolumns_status_gen.go @@ -1,6 +1,6 @@ // Code generated - EDITING IS FUTILE. DO NOT EDIT. -package v1alpha1 +package v1beta1 // +k8s:openapi-gen=true type LogsDrilldownDefaultColumnsstatusOperatorState struct { diff --git a/apps/logsdrilldown/pkg/apis/logsdrilldown_manifest.go b/apps/logsdrilldown/pkg/apis/logsdrilldown_manifest.go index 2350b924dda..a242d11b2bf 100644 --- a/apps/logsdrilldown/pkg/apis/logsdrilldown_manifest.go +++ b/apps/logsdrilldown/pkg/apis/logsdrilldown_manifest.go @@ -17,24 +17,25 @@ import ( "k8s.io/kube-openapi/pkg/validation/spec" v1alpha1 "github.com/grafana/grafana/apps/logsdrilldown/pkg/apis/logsdrilldown/v1alpha1" + v1beta1 "github.com/grafana/grafana/apps/logsdrilldown/pkg/apis/logsdrilldown/v1beta1" ) var ( - rawSchemaLogsDrilldownv1alpha1 = []byte(`{"LogsDrilldown":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"defaultFields":{"items":{"type":"string"},"type":"array"},"interceptDismissed":{"type":"boolean"},"prettifyJSON":{"type":"boolean"},"wrapLogMessage":{"type":"boolean"}},"required":["defaultFields","prettifyJSON","wrapLogMessage","interceptDismissed"],"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"}}`) - versionSchemaLogsDrilldownv1alpha1 app.VersionSchema - _ = json.Unmarshal(rawSchemaLogsDrilldownv1alpha1, &versionSchemaLogsDrilldownv1alpha1) - rawSchemaLogsDrilldownDefaultsv1alpha1 = []byte(`{"LogsDrilldownDefaults":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"defaultFields":{"items":{"type":"string"},"type":"array"},"interceptDismissed":{"type":"boolean"},"prettifyJSON":{"type":"boolean"},"wrapLogMessage":{"type":"boolean"}},"required":["defaultFields","prettifyJSON","wrapLogMessage","interceptDismissed"],"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"}}`) - versionSchemaLogsDrilldownDefaultsv1alpha1 app.VersionSchema - _ = json.Unmarshal(rawSchemaLogsDrilldownDefaultsv1alpha1, &versionSchemaLogsDrilldownDefaultsv1alpha1) - rawSchemaLogsDrilldownDefaultColumnsv1alpha1 = []byte(`{"LogsDefaultColumnsLabel":{"additionalProperties":false,"properties":{"key":{"type":"string"},"value":{"type":"string"}},"required":["key","value"],"type":"object"},"LogsDefaultColumnsLabels":{"items":{"$ref":"#/components/schemas/LogsDefaultColumnsLabel"},"type":"array"},"LogsDefaultColumnsRecord":{"additionalProperties":false,"properties":{"columns":{"items":{"type":"string"},"type":"array"},"labels":{"$ref":"#/components/schemas/LogsDefaultColumnsLabels"}},"required":["columns","labels"],"type":"object"},"LogsDefaultColumnsRecords":{"items":{"$ref":"#/components/schemas/LogsDefaultColumnsRecord"},"type":"array"},"LogsDrilldownDefaultColumns":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"records":{"$ref":"#/components/schemas/LogsDefaultColumnsRecords"}},"required":["records"],"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"}}`) - versionSchemaLogsDrilldownDefaultColumnsv1alpha1 app.VersionSchema - _ = json.Unmarshal(rawSchemaLogsDrilldownDefaultColumnsv1alpha1, &versionSchemaLogsDrilldownDefaultColumnsv1alpha1) + rawSchemaLogsDrilldownv1alpha1 = []byte(`{"LogsDrilldown":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"defaultFields":{"items":{"type":"string"},"type":"array"},"interceptDismissed":{"type":"boolean"},"prettifyJSON":{"type":"boolean"},"wrapLogMessage":{"type":"boolean"}},"required":["defaultFields","prettifyJSON","wrapLogMessage","interceptDismissed"],"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"}}`) + versionSchemaLogsDrilldownv1alpha1 app.VersionSchema + _ = json.Unmarshal(rawSchemaLogsDrilldownv1alpha1, &versionSchemaLogsDrilldownv1alpha1) + rawSchemaLogsDrilldownDefaultsv1alpha1 = []byte(`{"LogsDrilldownDefaults":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"defaultFields":{"items":{"type":"string"},"type":"array"},"interceptDismissed":{"type":"boolean"},"prettifyJSON":{"type":"boolean"},"wrapLogMessage":{"type":"boolean"}},"required":["defaultFields","prettifyJSON","wrapLogMessage","interceptDismissed"],"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"}}`) + versionSchemaLogsDrilldownDefaultsv1alpha1 app.VersionSchema + _ = json.Unmarshal(rawSchemaLogsDrilldownDefaultsv1alpha1, &versionSchemaLogsDrilldownDefaultsv1alpha1) + rawSchemaLogsDrilldownDefaultColumnsv1beta1 = []byte(`{"LogsDefaultColumnsLabel":{"additionalProperties":false,"properties":{"key":{"type":"string"},"value":{"type":"string"}},"required":["key","value"],"type":"object"},"LogsDefaultColumnsLabels":{"items":{"$ref":"#/components/schemas/LogsDefaultColumnsLabel"},"type":"array"},"LogsDefaultColumnsRecord":{"additionalProperties":false,"properties":{"columns":{"items":{"type":"string"},"type":"array"},"labels":{"$ref":"#/components/schemas/LogsDefaultColumnsLabels"}},"required":["columns","labels"],"type":"object"},"LogsDefaultColumnsRecords":{"items":{"$ref":"#/components/schemas/LogsDefaultColumnsRecord"},"type":"array"},"LogsDrilldownDefaultColumns":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"records":{"$ref":"#/components/schemas/LogsDefaultColumnsRecords"}},"required":["records"],"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"}}`) + versionSchemaLogsDrilldownDefaultColumnsv1beta1 app.VersionSchema + _ = json.Unmarshal(rawSchemaLogsDrilldownDefaultColumnsv1beta1, &versionSchemaLogsDrilldownDefaultColumnsv1beta1) ) var appManifestData = app.ManifestData{ AppName: "logsdrilldown", Group: "logsdrilldown.grafana.app", - PreferredVersion: "v1alpha1", + PreferredVersion: "v1beta1", Versions: []app.ManifestVersion{ { Name: "v1alpha1", @@ -55,13 +56,24 @@ var appManifestData = app.ManifestData{ Conversion: false, Schema: &versionSchemaLogsDrilldownDefaultsv1alpha1, }, + }, + Routes: app.ManifestVersionRoutes{ + Namespaced: map[string]spec3.PathProps{}, + Cluster: map[string]spec3.PathProps{}, + Schemas: map[string]spec.Schema{}, + }, + }, + { + Name: "v1beta1", + Served: true, + Kinds: []app.ManifestVersionKind{ { Kind: "LogsDrilldownDefaultColumns", Plural: "LogsDrilldownDefaultColumns", Scope: "Namespaced", Conversion: false, - Schema: &versionSchemaLogsDrilldownDefaultColumnsv1alpha1, + Schema: &versionSchemaLogsDrilldownDefaultColumnsv1beta1, }, }, Routes: app.ManifestVersionRoutes{ @@ -82,9 +94,9 @@ func RemoteManifest() app.Manifest { } var kindVersionToGoType = map[string]resource.Kind{ - "LogsDrilldown/v1alpha1": v1alpha1.LogsDrilldownKind(), - "LogsDrilldownDefaults/v1alpha1": v1alpha1.LogsDrilldownDefaultsKind(), - "LogsDrilldownDefaultColumns/v1alpha1": v1alpha1.LogsDrilldownDefaultColumnsKind(), + "LogsDrilldown/v1alpha1": v1alpha1.LogsDrilldownKind(), + "LogsDrilldownDefaults/v1alpha1": v1alpha1.LogsDrilldownDefaultsKind(), + "LogsDrilldownDefaultColumns/v1beta1": v1beta1.LogsDrilldownDefaultColumnsKind(), } // ManifestGoTypeAssociator returns the associated resource.Kind instance for a given Kind and Version, if one exists. diff --git a/apps/logsdrilldown/pkg/app/app.go b/apps/logsdrilldown/pkg/app/app.go index 23260270207..1e3e37851e2 100644 --- a/apps/logsdrilldown/pkg/app/app.go +++ b/apps/logsdrilldown/pkg/app/app.go @@ -11,6 +11,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" logsdrilldownv1alpha1 "github.com/grafana/grafana/apps/logsdrilldown/pkg/apis/logsdrilldown/v1alpha1" + logsdrilldownv1beta1 "github.com/grafana/grafana/apps/logsdrilldown/pkg/apis/logsdrilldown/v1beta1" ) func New(cfg app.Config) (app.App, error) { @@ -32,7 +33,7 @@ func New(cfg app.Config) (app.App, error) { Kind: logsdrilldownv1alpha1.LogsDrilldownDefaultsKind(), }, { - Kind: logsdrilldownv1alpha1.LogsDrilldownDefaultColumnsKind(), + Kind: logsdrilldownv1beta1.LogsDrilldownDefaultColumnsKind(), }, }, } diff --git a/apps/logsdrilldown/pkg/generated/logsdrilldown/v1alpha1/logsdrilldown_client_gen.go b/apps/logsdrilldown/pkg/generated/logsdrilldown/v1alpha1/logsdrilldown_client_gen.go deleted file mode 100644 index c133b65f45b..00000000000 --- a/apps/logsdrilldown/pkg/generated/logsdrilldown/v1alpha1/logsdrilldown_client_gen.go +++ /dev/null @@ -1,99 +0,0 @@ -package v1alpha1 - -import ( - "context" - - "github.com/grafana/grafana-app-sdk/resource" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -type LogsDrilldownClient struct { - client *resource.TypedClient[*LogsDrilldown, *LogsDrilldownList] -} - -func NewLogsDrilldownClient(client resource.Client) *LogsDrilldownClient { - return &LogsDrilldownClient{ - client: resource.NewTypedClient[*LogsDrilldown, *LogsDrilldownList](client, Kind()), - } -} - -func NewLogsDrilldownClientFromGenerator(generator resource.ClientGenerator) (*LogsDrilldownClient, error) { - c, err := generator.ClientFor(Kind()) - if err != nil { - return nil, err - } - return NewLogsDrilldownClient(c), nil -} - -func (c *LogsDrilldownClient) Get(ctx context.Context, identifier resource.Identifier) (*LogsDrilldown, error) { - return c.client.Get(ctx, identifier) -} - -func (c *LogsDrilldownClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*LogsDrilldownList, error) { - return c.client.List(ctx, namespace, opts) -} - -func (c *LogsDrilldownClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*LogsDrilldownList, error) { - resp, err := c.client.List(ctx, namespace, resource.ListOptions{ - ResourceVersion: opts.ResourceVersion, - Limit: opts.Limit, - LabelFilters: opts.LabelFilters, - FieldSelectors: opts.FieldSelectors, - }) - if err != nil { - return nil, err - } - for resp.GetContinue() != "" { - page, err := c.client.List(ctx, namespace, resource.ListOptions{ - Continue: resp.GetContinue(), - ResourceVersion: opts.ResourceVersion, - Limit: opts.Limit, - LabelFilters: opts.LabelFilters, - FieldSelectors: opts.FieldSelectors, - }) - if err != nil { - return nil, err - } - resp.SetContinue(page.GetContinue()) - resp.SetResourceVersion(page.GetResourceVersion()) - resp.SetItems(append(resp.GetItems(), page.GetItems()...)) - } - return resp, nil -} - -func (c *LogsDrilldownClient) Create(ctx context.Context, obj *LogsDrilldown, opts resource.CreateOptions) (*LogsDrilldown, error) { - // Make sure apiVersion and kind are set - obj.APIVersion = GroupVersion.Identifier() - obj.Kind = Kind().Kind() - return c.client.Create(ctx, obj, opts) -} - -func (c *LogsDrilldownClient) Update(ctx context.Context, obj *LogsDrilldown, opts resource.UpdateOptions) (*LogsDrilldown, error) { - return c.client.Update(ctx, obj, opts) -} - -func (c *LogsDrilldownClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*LogsDrilldown, error) { - return c.client.Patch(ctx, identifier, req, opts) -} - -func (c *LogsDrilldownClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus Status, opts resource.UpdateOptions) (*LogsDrilldown, error) { - return c.client.Update(ctx, &LogsDrilldown{ - TypeMeta: metav1.TypeMeta{ - Kind: Kind().Kind(), - APIVersion: GroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - ResourceVersion: opts.ResourceVersion, - Namespace: identifier.Namespace, - Name: identifier.Name, - }, - Status: newStatus, - }, resource.UpdateOptions{ - Subresource: "status", - ResourceVersion: opts.ResourceVersion, - }) -} - -func (c *LogsDrilldownClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error { - return c.client.Delete(ctx, identifier, opts) -} diff --git a/apps/logsdrilldown/pkg/generated/logsdrilldown/v1alpha1/logsdrilldown_codec_gen.go b/apps/logsdrilldown/pkg/generated/logsdrilldown/v1alpha1/logsdrilldown_codec_gen.go deleted file mode 100644 index bb458caeb88..00000000000 --- a/apps/logsdrilldown/pkg/generated/logsdrilldown/v1alpha1/logsdrilldown_codec_gen.go +++ /dev/null @@ -1,28 +0,0 @@ -// -// Code generated by grafana-app-sdk. DO NOT EDIT. -// - -package v1alpha1 - -import ( - "encoding/json" - "io" - - "github.com/grafana/grafana-app-sdk/resource" -) - -// JSONCodec is an implementation of resource.Codec for kubernetes JSON encoding -type JSONCodec struct{} - -// Read reads JSON-encoded bytes from `reader` and unmarshals them into `into` -func (*JSONCodec) Read(reader io.Reader, into resource.Object) error { - return json.NewDecoder(reader).Decode(into) -} - -// Write writes JSON-encoded bytes into `writer` marshaled from `from` -func (*JSONCodec) Write(writer io.Writer, from resource.Object) error { - return json.NewEncoder(writer).Encode(from) -} - -// Interface compliance checks -var _ resource.Codec = &JSONCodec{} diff --git a/apps/logsdrilldown/pkg/generated/logsdrilldown/v1alpha1/logsdrilldown_metadata_gen.go b/apps/logsdrilldown/pkg/generated/logsdrilldown/v1alpha1/logsdrilldown_metadata_gen.go deleted file mode 100644 index cb7233b22ab..00000000000 --- a/apps/logsdrilldown/pkg/generated/logsdrilldown/v1alpha1/logsdrilldown_metadata_gen.go +++ /dev/null @@ -1,31 +0,0 @@ -// Code generated - EDITING IS FUTILE. DO NOT EDIT. - -package v1alpha1 - -import ( - time "time" -) - -// metadata contains embedded CommonMetadata and can be extended with custom string fields -// TODO: use CommonMetadata instead of redefining here; currently needs to be defined here -// without external reference as using the CommonMetadata reference breaks thema codegen. -type Metadata struct { - UpdateTimestamp time.Time `json:"updateTimestamp"` - CreatedBy string `json:"createdBy"` - Uid string `json:"uid"` - CreationTimestamp time.Time `json:"creationTimestamp"` - DeletionTimestamp *time.Time `json:"deletionTimestamp,omitempty"` - Finalizers []string `json:"finalizers"` - ResourceVersion string `json:"resourceVersion"` - Generation int64 `json:"generation"` - UpdatedBy string `json:"updatedBy"` - Labels map[string]string `json:"labels"` -} - -// NewMetadata creates a new Metadata object. -func NewMetadata() *Metadata { - return &Metadata{ - Finalizers: []string{}, - Labels: map[string]string{}, - } -} diff --git a/apps/logsdrilldown/pkg/generated/logsdrilldown/v1alpha1/logsdrilldown_object_gen.go b/apps/logsdrilldown/pkg/generated/logsdrilldown/v1alpha1/logsdrilldown_object_gen.go deleted file mode 100644 index 5d40a873e6b..00000000000 --- a/apps/logsdrilldown/pkg/generated/logsdrilldown/v1alpha1/logsdrilldown_object_gen.go +++ /dev/null @@ -1,319 +0,0 @@ -// -// Code generated by grafana-app-sdk. DO NOT EDIT. -// - -package v1alpha1 - -import ( - "fmt" - "github.com/grafana/grafana-app-sdk/resource" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" - "time" -) - -// +k8s:openapi-gen=true -type LogsDrilldown struct { - metav1.TypeMeta `json:",inline" yaml:",inline"` - metav1.ObjectMeta `json:"metadata" yaml:"metadata"` - - // Spec is the spec of the LogsDrilldown - Spec Spec `json:"spec" yaml:"spec"` - - Status Status `json:"status" yaml:"status"` -} - -func (o *LogsDrilldown) GetSpec() any { - return o.Spec -} - -func (o *LogsDrilldown) SetSpec(spec any) error { - cast, ok := spec.(Spec) - if !ok { - return fmt.Errorf("cannot set spec type %#v, not of type Spec", spec) - } - o.Spec = cast - return nil -} - -func (o *LogsDrilldown) GetSubresources() map[string]any { - return map[string]any{ - "status": o.Status, - } -} - -func (o *LogsDrilldown) GetSubresource(name string) (any, bool) { - switch name { - case "status": - return o.Status, true - default: - return nil, false - } -} - -func (o *LogsDrilldown) SetSubresource(name string, value any) error { - switch name { - case "status": - cast, ok := value.(Status) - if !ok { - return fmt.Errorf("cannot set status type %#v, not of type Status", value) - } - o.Status = cast - return nil - default: - return fmt.Errorf("subresource '%s' does not exist", name) - } -} - -func (o *LogsDrilldown) GetStaticMetadata() resource.StaticMetadata { - gvk := o.GroupVersionKind() - return resource.StaticMetadata{ - Name: o.ObjectMeta.Name, - Namespace: o.ObjectMeta.Namespace, - Group: gvk.Group, - Version: gvk.Version, - Kind: gvk.Kind, - } -} - -func (o *LogsDrilldown) SetStaticMetadata(metadata resource.StaticMetadata) { - o.Name = metadata.Name - o.Namespace = metadata.Namespace - o.SetGroupVersionKind(schema.GroupVersionKind{ - Group: metadata.Group, - Version: metadata.Version, - Kind: metadata.Kind, - }) -} - -func (o *LogsDrilldown) GetCommonMetadata() resource.CommonMetadata { - dt := o.DeletionTimestamp - var deletionTimestamp *time.Time - if dt != nil { - deletionTimestamp = &dt.Time - } - // Legacy ExtraFields support - extraFields := make(map[string]any) - if o.Annotations != nil { - extraFields["annotations"] = o.Annotations - } - if o.ManagedFields != nil { - extraFields["managedFields"] = o.ManagedFields - } - if o.OwnerReferences != nil { - extraFields["ownerReferences"] = o.OwnerReferences - } - return resource.CommonMetadata{ - UID: string(o.UID), - ResourceVersion: o.ResourceVersion, - Generation: o.Generation, - Labels: o.Labels, - CreationTimestamp: o.CreationTimestamp.Time, - DeletionTimestamp: deletionTimestamp, - Finalizers: o.Finalizers, - UpdateTimestamp: o.GetUpdateTimestamp(), - CreatedBy: o.GetCreatedBy(), - UpdatedBy: o.GetUpdatedBy(), - ExtraFields: extraFields, - } -} - -func (o *LogsDrilldown) SetCommonMetadata(metadata resource.CommonMetadata) { - o.UID = types.UID(metadata.UID) - o.ResourceVersion = metadata.ResourceVersion - o.Generation = metadata.Generation - o.Labels = metadata.Labels - o.CreationTimestamp = metav1.NewTime(metadata.CreationTimestamp) - if metadata.DeletionTimestamp != nil { - dt := metav1.NewTime(*metadata.DeletionTimestamp) - o.DeletionTimestamp = &dt - } else { - o.DeletionTimestamp = nil - } - o.Finalizers = metadata.Finalizers - if o.Annotations == nil { - o.Annotations = make(map[string]string) - } - if !metadata.UpdateTimestamp.IsZero() { - o.SetUpdateTimestamp(metadata.UpdateTimestamp) - } - if metadata.CreatedBy != "" { - o.SetCreatedBy(metadata.CreatedBy) - } - if metadata.UpdatedBy != "" { - o.SetUpdatedBy(metadata.UpdatedBy) - } - // Legacy support for setting Annotations, ManagedFields, and OwnerReferences via ExtraFields - if metadata.ExtraFields != nil { - if annotations, ok := metadata.ExtraFields["annotations"]; ok { - if cast, ok := annotations.(map[string]string); ok { - o.Annotations = cast - } - } - if managedFields, ok := metadata.ExtraFields["managedFields"]; ok { - if cast, ok := managedFields.([]metav1.ManagedFieldsEntry); ok { - o.ManagedFields = cast - } - } - if ownerReferences, ok := metadata.ExtraFields["ownerReferences"]; ok { - if cast, ok := ownerReferences.([]metav1.OwnerReference); ok { - o.OwnerReferences = cast - } - } - } -} - -func (o *LogsDrilldown) GetCreatedBy() string { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - return o.ObjectMeta.Annotations["grafana.com/createdBy"] -} - -func (o *LogsDrilldown) SetCreatedBy(createdBy string) { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - o.ObjectMeta.Annotations["grafana.com/createdBy"] = createdBy -} - -func (o *LogsDrilldown) GetUpdateTimestamp() time.Time { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - parsed, _ := time.Parse(time.RFC3339, o.ObjectMeta.Annotations["grafana.com/updateTimestamp"]) - return parsed -} - -func (o *LogsDrilldown) SetUpdateTimestamp(updateTimestamp time.Time) { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - o.ObjectMeta.Annotations["grafana.com/updateTimestamp"] = updateTimestamp.Format(time.RFC3339) -} - -func (o *LogsDrilldown) GetUpdatedBy() string { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - return o.ObjectMeta.Annotations["grafana.com/updatedBy"] -} - -func (o *LogsDrilldown) SetUpdatedBy(updatedBy string) { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - o.ObjectMeta.Annotations["grafana.com/updatedBy"] = updatedBy -} - -func (o *LogsDrilldown) Copy() resource.Object { - return resource.CopyObject(o) -} - -func (o *LogsDrilldown) DeepCopyObject() runtime.Object { - return o.Copy() -} - -func (o *LogsDrilldown) DeepCopy() *LogsDrilldown { - cpy := &LogsDrilldown{} - o.DeepCopyInto(cpy) - return cpy -} - -func (o *LogsDrilldown) DeepCopyInto(dst *LogsDrilldown) { - dst.TypeMeta.APIVersion = o.TypeMeta.APIVersion - dst.TypeMeta.Kind = o.TypeMeta.Kind - o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta) - o.Spec.DeepCopyInto(&dst.Spec) - o.Status.DeepCopyInto(&dst.Status) -} - -// Interface compliance compile-time check -var _ resource.Object = &LogsDrilldown{} - -// +k8s:openapi-gen=true -type LogsDrilldownList struct { - metav1.TypeMeta `json:",inline" yaml:",inline"` - metav1.ListMeta `json:"metadata" yaml:"metadata"` - Items []LogsDrilldown `json:"items" yaml:"items"` -} - -func (o *LogsDrilldownList) DeepCopyObject() runtime.Object { - return o.Copy() -} - -func (o *LogsDrilldownList) Copy() resource.ListObject { - cpy := &LogsDrilldownList{ - TypeMeta: o.TypeMeta, - Items: make([]LogsDrilldown, len(o.Items)), - } - o.ListMeta.DeepCopyInto(&cpy.ListMeta) - for i := 0; i < len(o.Items); i++ { - if item, ok := o.Items[i].Copy().(*LogsDrilldown); ok { - cpy.Items[i] = *item - } - } - return cpy -} - -func (o *LogsDrilldownList) GetItems() []resource.Object { - items := make([]resource.Object, len(o.Items)) - for i := 0; i < len(o.Items); i++ { - items[i] = &o.Items[i] - } - return items -} - -func (o *LogsDrilldownList) SetItems(items []resource.Object) { - o.Items = make([]LogsDrilldown, len(items)) - for i := 0; i < len(items); i++ { - o.Items[i] = *items[i].(*LogsDrilldown) - } -} - -func (o *LogsDrilldownList) DeepCopy() *LogsDrilldownList { - cpy := &LogsDrilldownList{} - o.DeepCopyInto(cpy) - return cpy -} - -func (o *LogsDrilldownList) DeepCopyInto(dst *LogsDrilldownList) { - resource.CopyObjectInto(dst, o) -} - -// Interface compliance compile-time check -var _ resource.ListObject = &LogsDrilldownList{} - -// Copy methods for all subresource types - -// DeepCopy creates a full deep copy of Spec -func (s *Spec) DeepCopy() *Spec { - cpy := &Spec{} - s.DeepCopyInto(cpy) - return cpy -} - -// DeepCopyInto deep copies Spec into another Spec object -func (s *Spec) DeepCopyInto(dst *Spec) { - resource.CopyObjectInto(dst, s) -} - -// DeepCopy creates a full deep copy of Status -func (s *Status) DeepCopy() *Status { - cpy := &Status{} - s.DeepCopyInto(cpy) - return cpy -} - -// DeepCopyInto deep copies Status into another Status object -func (s *Status) DeepCopyInto(dst *Status) { - resource.CopyObjectInto(dst, s) -} diff --git a/apps/logsdrilldown/pkg/generated/logsdrilldown/v1alpha1/logsdrilldown_schema_gen.go b/apps/logsdrilldown/pkg/generated/logsdrilldown/v1alpha1/logsdrilldown_schema_gen.go deleted file mode 100644 index 942794416e8..00000000000 --- a/apps/logsdrilldown/pkg/generated/logsdrilldown/v1alpha1/logsdrilldown_schema_gen.go +++ /dev/null @@ -1,34 +0,0 @@ -// -// Code generated by grafana-app-sdk. DO NOT EDIT. -// - -package v1alpha1 - -import ( - "github.com/grafana/grafana-app-sdk/resource" -) - -// schema is unexported to prevent accidental overwrites -var ( - schemaLogsDrilldown = resource.NewSimpleSchema("logsdrilldown.grafana.app", "v1alpha1", &LogsDrilldown{}, &LogsDrilldownList{}, resource.WithKind("LogsDrilldown"), - resource.WithPlural("logsdrilldowns"), resource.WithScope(resource.NamespacedScope)) - kindLogsDrilldown = resource.Kind{ - Schema: schemaLogsDrilldown, - Codecs: map[resource.KindEncoding]resource.Codec{ - resource.KindEncodingJSON: &JSONCodec{}, - }, - } -) - -// Kind returns a resource.Kind for this Schema with a JSON codec -func Kind() resource.Kind { - return kindLogsDrilldown -} - -// Schema returns a resource.SimpleSchema representation of LogsDrilldown -func Schema() *resource.SimpleSchema { - return schemaLogsDrilldown -} - -// Interface compliance checks -var _ resource.Schema = kindLogsDrilldown diff --git a/apps/logsdrilldown/pkg/generated/logsdrilldown/v1alpha1/logsdrilldown_spec_gen.go b/apps/logsdrilldown/pkg/generated/logsdrilldown/v1alpha1/logsdrilldown_spec_gen.go deleted file mode 100644 index faff5c108dd..00000000000 --- a/apps/logsdrilldown/pkg/generated/logsdrilldown/v1alpha1/logsdrilldown_spec_gen.go +++ /dev/null @@ -1,18 +0,0 @@ -// Code generated - EDITING IS FUTILE. DO NOT EDIT. - -package v1alpha1 - -// +k8s:openapi-gen=true -type Spec struct { - DefaultFields []string `json:"defaultFields"` - PrettifyJSON bool `json:"prettifyJSON"` - WrapLogMessage bool `json:"wrapLogMessage"` - InterceptDismissed bool `json:"interceptDismissed"` -} - -// NewSpec creates a new Spec object. -func NewSpec() *Spec { - return &Spec{ - DefaultFields: []string{}, - } -} diff --git a/apps/logsdrilldown/pkg/generated/logsdrilldown/v1alpha1/logsdrilldown_status_gen.go b/apps/logsdrilldown/pkg/generated/logsdrilldown/v1alpha1/logsdrilldown_status_gen.go deleted file mode 100644 index 9b227b00f44..00000000000 --- a/apps/logsdrilldown/pkg/generated/logsdrilldown/v1alpha1/logsdrilldown_status_gen.go +++ /dev/null @@ -1,44 +0,0 @@ -// Code generated - EDITING IS FUTILE. DO NOT EDIT. - -package v1alpha1 - -// +k8s:openapi-gen=true -type StatusOperatorState struct { - // lastEvaluation is the ResourceVersion last evaluated - LastEvaluation string `json:"lastEvaluation"` - // state describes the state of the lastEvaluation. - // It is limited to three possible states for machine evaluation. - State StatusOperatorStateState `json:"state"` - // descriptiveState is an optional more descriptive state field which has no requirements on format - DescriptiveState *string `json:"descriptiveState,omitempty"` - // details contains any extra information that is operator-specific - Details map[string]interface{} `json:"details,omitempty"` -} - -// NewStatusOperatorState creates a new StatusOperatorState object. -func NewStatusOperatorState() *StatusOperatorState { - return &StatusOperatorState{} -} - -// +k8s:openapi-gen=true -type Status struct { - // operatorStates is a map of operator ID to operator state evaluations. - // Any operator which consumes this kind SHOULD add its state evaluation information to this field. - OperatorStates map[string]StatusOperatorState `json:"operatorStates,omitempty"` - // additionalFields is reserved for future use - AdditionalFields map[string]interface{} `json:"additionalFields,omitempty"` -} - -// NewStatus creates a new Status object. -func NewStatus() *Status { - return &Status{} -} - -// +k8s:openapi-gen=true -type StatusOperatorStateState string - -const ( - StatusOperatorStateStateSuccess StatusOperatorStateState = "success" - StatusOperatorStateStateInProgress StatusOperatorStateState = "in_progress" - StatusOperatorStateStateFailed StatusOperatorStateState = "failed" -) diff --git a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaultcolumns/v1alpha1/constants.go b/apps/logsdrilldown/pkg/generated/logsdrilldowndefaultcolumns/v1alpha1/constants.go deleted file mode 100644 index 082bec7c874..00000000000 --- a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaultcolumns/v1alpha1/constants.go +++ /dev/null @@ -1,18 +0,0 @@ -package v1alpha1 - -import "k8s.io/apimachinery/pkg/runtime/schema" - -const ( - // APIGroup is the API group used by all kinds in this package - APIGroup = "logsdrilldown.grafana.app" - // APIVersion is the API version used by all kinds in this package - APIVersion = "v1alpha1" -) - -var ( - // GroupVersion is a schema.GroupVersion consisting of the Group and Version constants for this package - GroupVersion = schema.GroupVersion{ - Group: APIGroup, - Version: APIVersion, - } -) diff --git a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaultcolumns/v1alpha1/logsdrilldowndefaultcolumns_client_gen.go b/apps/logsdrilldown/pkg/generated/logsdrilldowndefaultcolumns/v1alpha1/logsdrilldowndefaultcolumns_client_gen.go deleted file mode 100644 index b66471eb4ba..00000000000 --- a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaultcolumns/v1alpha1/logsdrilldowndefaultcolumns_client_gen.go +++ /dev/null @@ -1,99 +0,0 @@ -package v1alpha1 - -import ( - "context" - - "github.com/grafana/grafana-app-sdk/resource" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -type LogsDrilldownDefaultColumnsClient struct { - client *resource.TypedClient[*LogsDrilldownDefaultColumns, *LogsDrilldownDefaultColumnsList] -} - -func NewLogsDrilldownDefaultColumnsClient(client resource.Client) *LogsDrilldownDefaultColumnsClient { - return &LogsDrilldownDefaultColumnsClient{ - client: resource.NewTypedClient[*LogsDrilldownDefaultColumns, *LogsDrilldownDefaultColumnsList](client, Kind()), - } -} - -func NewLogsDrilldownDefaultColumnsClientFromGenerator(generator resource.ClientGenerator) (*LogsDrilldownDefaultColumnsClient, error) { - c, err := generator.ClientFor(Kind()) - if err != nil { - return nil, err - } - return NewLogsDrilldownDefaultColumnsClient(c), nil -} - -func (c *LogsDrilldownDefaultColumnsClient) Get(ctx context.Context, identifier resource.Identifier) (*LogsDrilldownDefaultColumns, error) { - return c.client.Get(ctx, identifier) -} - -func (c *LogsDrilldownDefaultColumnsClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*LogsDrilldownDefaultColumnsList, error) { - return c.client.List(ctx, namespace, opts) -} - -func (c *LogsDrilldownDefaultColumnsClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*LogsDrilldownDefaultColumnsList, error) { - resp, err := c.client.List(ctx, namespace, resource.ListOptions{ - ResourceVersion: opts.ResourceVersion, - Limit: opts.Limit, - LabelFilters: opts.LabelFilters, - FieldSelectors: opts.FieldSelectors, - }) - if err != nil { - return nil, err - } - for resp.GetContinue() != "" { - page, err := c.client.List(ctx, namespace, resource.ListOptions{ - Continue: resp.GetContinue(), - ResourceVersion: opts.ResourceVersion, - Limit: opts.Limit, - LabelFilters: opts.LabelFilters, - FieldSelectors: opts.FieldSelectors, - }) - if err != nil { - return nil, err - } - resp.SetContinue(page.GetContinue()) - resp.SetResourceVersion(page.GetResourceVersion()) - resp.SetItems(append(resp.GetItems(), page.GetItems()...)) - } - return resp, nil -} - -func (c *LogsDrilldownDefaultColumnsClient) Create(ctx context.Context, obj *LogsDrilldownDefaultColumns, opts resource.CreateOptions) (*LogsDrilldownDefaultColumns, error) { - // Make sure apiVersion and kind are set - obj.APIVersion = GroupVersion.Identifier() - obj.Kind = Kind().Kind() - return c.client.Create(ctx, obj, opts) -} - -func (c *LogsDrilldownDefaultColumnsClient) Update(ctx context.Context, obj *LogsDrilldownDefaultColumns, opts resource.UpdateOptions) (*LogsDrilldownDefaultColumns, error) { - return c.client.Update(ctx, obj, opts) -} - -func (c *LogsDrilldownDefaultColumnsClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*LogsDrilldownDefaultColumns, error) { - return c.client.Patch(ctx, identifier, req, opts) -} - -func (c *LogsDrilldownDefaultColumnsClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus Status, opts resource.UpdateOptions) (*LogsDrilldownDefaultColumns, error) { - return c.client.Update(ctx, &LogsDrilldownDefaultColumns{ - TypeMeta: metav1.TypeMeta{ - Kind: Kind().Kind(), - APIVersion: GroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - ResourceVersion: opts.ResourceVersion, - Namespace: identifier.Namespace, - Name: identifier.Name, - }, - Status: newStatus, - }, resource.UpdateOptions{ - Subresource: "status", - ResourceVersion: opts.ResourceVersion, - }) -} - -func (c *LogsDrilldownDefaultColumnsClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error { - return c.client.Delete(ctx, identifier, opts) -} diff --git a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaultcolumns/v1alpha1/logsdrilldowndefaultcolumns_codec_gen.go b/apps/logsdrilldown/pkg/generated/logsdrilldowndefaultcolumns/v1alpha1/logsdrilldowndefaultcolumns_codec_gen.go deleted file mode 100644 index bb458caeb88..00000000000 --- a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaultcolumns/v1alpha1/logsdrilldowndefaultcolumns_codec_gen.go +++ /dev/null @@ -1,28 +0,0 @@ -// -// Code generated by grafana-app-sdk. DO NOT EDIT. -// - -package v1alpha1 - -import ( - "encoding/json" - "io" - - "github.com/grafana/grafana-app-sdk/resource" -) - -// JSONCodec is an implementation of resource.Codec for kubernetes JSON encoding -type JSONCodec struct{} - -// Read reads JSON-encoded bytes from `reader` and unmarshals them into `into` -func (*JSONCodec) Read(reader io.Reader, into resource.Object) error { - return json.NewDecoder(reader).Decode(into) -} - -// Write writes JSON-encoded bytes into `writer` marshaled from `from` -func (*JSONCodec) Write(writer io.Writer, from resource.Object) error { - return json.NewEncoder(writer).Encode(from) -} - -// Interface compliance checks -var _ resource.Codec = &JSONCodec{} diff --git a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaultcolumns/v1alpha1/logsdrilldowndefaultcolumns_metadata_gen.go b/apps/logsdrilldown/pkg/generated/logsdrilldowndefaultcolumns/v1alpha1/logsdrilldowndefaultcolumns_metadata_gen.go deleted file mode 100644 index cb7233b22ab..00000000000 --- a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaultcolumns/v1alpha1/logsdrilldowndefaultcolumns_metadata_gen.go +++ /dev/null @@ -1,31 +0,0 @@ -// Code generated - EDITING IS FUTILE. DO NOT EDIT. - -package v1alpha1 - -import ( - time "time" -) - -// metadata contains embedded CommonMetadata and can be extended with custom string fields -// TODO: use CommonMetadata instead of redefining here; currently needs to be defined here -// without external reference as using the CommonMetadata reference breaks thema codegen. -type Metadata struct { - UpdateTimestamp time.Time `json:"updateTimestamp"` - CreatedBy string `json:"createdBy"` - Uid string `json:"uid"` - CreationTimestamp time.Time `json:"creationTimestamp"` - DeletionTimestamp *time.Time `json:"deletionTimestamp,omitempty"` - Finalizers []string `json:"finalizers"` - ResourceVersion string `json:"resourceVersion"` - Generation int64 `json:"generation"` - UpdatedBy string `json:"updatedBy"` - Labels map[string]string `json:"labels"` -} - -// NewMetadata creates a new Metadata object. -func NewMetadata() *Metadata { - return &Metadata{ - Finalizers: []string{}, - Labels: map[string]string{}, - } -} diff --git a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaultcolumns/v1alpha1/logsdrilldowndefaultcolumns_object_gen.go b/apps/logsdrilldown/pkg/generated/logsdrilldowndefaultcolumns/v1alpha1/logsdrilldowndefaultcolumns_object_gen.go deleted file mode 100644 index 3173c28330e..00000000000 --- a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaultcolumns/v1alpha1/logsdrilldowndefaultcolumns_object_gen.go +++ /dev/null @@ -1,319 +0,0 @@ -// -// Code generated by grafana-app-sdk. DO NOT EDIT. -// - -package v1alpha1 - -import ( - "fmt" - "github.com/grafana/grafana-app-sdk/resource" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" - "time" -) - -// +k8s:openapi-gen=true -type LogsDrilldownDefaultColumns struct { - metav1.TypeMeta `json:",inline" yaml:",inline"` - metav1.ObjectMeta `json:"metadata" yaml:"metadata"` - - // Spec is the spec of the LogsDrilldownDefaultColumns - Spec Spec `json:"spec" yaml:"spec"` - - Status Status `json:"status" yaml:"status"` -} - -func (o *LogsDrilldownDefaultColumns) GetSpec() any { - return o.Spec -} - -func (o *LogsDrilldownDefaultColumns) SetSpec(spec any) error { - cast, ok := spec.(Spec) - if !ok { - return fmt.Errorf("cannot set spec type %#v, not of type Spec", spec) - } - o.Spec = cast - return nil -} - -func (o *LogsDrilldownDefaultColumns) GetSubresources() map[string]any { - return map[string]any{ - "status": o.Status, - } -} - -func (o *LogsDrilldownDefaultColumns) GetSubresource(name string) (any, bool) { - switch name { - case "status": - return o.Status, true - default: - return nil, false - } -} - -func (o *LogsDrilldownDefaultColumns) SetSubresource(name string, value any) error { - switch name { - case "status": - cast, ok := value.(Status) - if !ok { - return fmt.Errorf("cannot set status type %#v, not of type Status", value) - } - o.Status = cast - return nil - default: - return fmt.Errorf("subresource '%s' does not exist", name) - } -} - -func (o *LogsDrilldownDefaultColumns) GetStaticMetadata() resource.StaticMetadata { - gvk := o.GroupVersionKind() - return resource.StaticMetadata{ - Name: o.ObjectMeta.Name, - Namespace: o.ObjectMeta.Namespace, - Group: gvk.Group, - Version: gvk.Version, - Kind: gvk.Kind, - } -} - -func (o *LogsDrilldownDefaultColumns) SetStaticMetadata(metadata resource.StaticMetadata) { - o.Name = metadata.Name - o.Namespace = metadata.Namespace - o.SetGroupVersionKind(schema.GroupVersionKind{ - Group: metadata.Group, - Version: metadata.Version, - Kind: metadata.Kind, - }) -} - -func (o *LogsDrilldownDefaultColumns) GetCommonMetadata() resource.CommonMetadata { - dt := o.DeletionTimestamp - var deletionTimestamp *time.Time - if dt != nil { - deletionTimestamp = &dt.Time - } - // Legacy ExtraFields support - extraFields := make(map[string]any) - if o.Annotations != nil { - extraFields["annotations"] = o.Annotations - } - if o.ManagedFields != nil { - extraFields["managedFields"] = o.ManagedFields - } - if o.OwnerReferences != nil { - extraFields["ownerReferences"] = o.OwnerReferences - } - return resource.CommonMetadata{ - UID: string(o.UID), - ResourceVersion: o.ResourceVersion, - Generation: o.Generation, - Labels: o.Labels, - CreationTimestamp: o.CreationTimestamp.Time, - DeletionTimestamp: deletionTimestamp, - Finalizers: o.Finalizers, - UpdateTimestamp: o.GetUpdateTimestamp(), - CreatedBy: o.GetCreatedBy(), - UpdatedBy: o.GetUpdatedBy(), - ExtraFields: extraFields, - } -} - -func (o *LogsDrilldownDefaultColumns) SetCommonMetadata(metadata resource.CommonMetadata) { - o.UID = types.UID(metadata.UID) - o.ResourceVersion = metadata.ResourceVersion - o.Generation = metadata.Generation - o.Labels = metadata.Labels - o.CreationTimestamp = metav1.NewTime(metadata.CreationTimestamp) - if metadata.DeletionTimestamp != nil { - dt := metav1.NewTime(*metadata.DeletionTimestamp) - o.DeletionTimestamp = &dt - } else { - o.DeletionTimestamp = nil - } - o.Finalizers = metadata.Finalizers - if o.Annotations == nil { - o.Annotations = make(map[string]string) - } - if !metadata.UpdateTimestamp.IsZero() { - o.SetUpdateTimestamp(metadata.UpdateTimestamp) - } - if metadata.CreatedBy != "" { - o.SetCreatedBy(metadata.CreatedBy) - } - if metadata.UpdatedBy != "" { - o.SetUpdatedBy(metadata.UpdatedBy) - } - // Legacy support for setting Annotations, ManagedFields, and OwnerReferences via ExtraFields - if metadata.ExtraFields != nil { - if annotations, ok := metadata.ExtraFields["annotations"]; ok { - if cast, ok := annotations.(map[string]string); ok { - o.Annotations = cast - } - } - if managedFields, ok := metadata.ExtraFields["managedFields"]; ok { - if cast, ok := managedFields.([]metav1.ManagedFieldsEntry); ok { - o.ManagedFields = cast - } - } - if ownerReferences, ok := metadata.ExtraFields["ownerReferences"]; ok { - if cast, ok := ownerReferences.([]metav1.OwnerReference); ok { - o.OwnerReferences = cast - } - } - } -} - -func (o *LogsDrilldownDefaultColumns) GetCreatedBy() string { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - return o.ObjectMeta.Annotations["grafana.com/createdBy"] -} - -func (o *LogsDrilldownDefaultColumns) SetCreatedBy(createdBy string) { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - o.ObjectMeta.Annotations["grafana.com/createdBy"] = createdBy -} - -func (o *LogsDrilldownDefaultColumns) GetUpdateTimestamp() time.Time { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - parsed, _ := time.Parse(time.RFC3339, o.ObjectMeta.Annotations["grafana.com/updateTimestamp"]) - return parsed -} - -func (o *LogsDrilldownDefaultColumns) SetUpdateTimestamp(updateTimestamp time.Time) { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - o.ObjectMeta.Annotations["grafana.com/updateTimestamp"] = updateTimestamp.Format(time.RFC3339) -} - -func (o *LogsDrilldownDefaultColumns) GetUpdatedBy() string { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - return o.ObjectMeta.Annotations["grafana.com/updatedBy"] -} - -func (o *LogsDrilldownDefaultColumns) SetUpdatedBy(updatedBy string) { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - o.ObjectMeta.Annotations["grafana.com/updatedBy"] = updatedBy -} - -func (o *LogsDrilldownDefaultColumns) Copy() resource.Object { - return resource.CopyObject(o) -} - -func (o *LogsDrilldownDefaultColumns) DeepCopyObject() runtime.Object { - return o.Copy() -} - -func (o *LogsDrilldownDefaultColumns) DeepCopy() *LogsDrilldownDefaultColumns { - cpy := &LogsDrilldownDefaultColumns{} - o.DeepCopyInto(cpy) - return cpy -} - -func (o *LogsDrilldownDefaultColumns) DeepCopyInto(dst *LogsDrilldownDefaultColumns) { - dst.TypeMeta.APIVersion = o.TypeMeta.APIVersion - dst.TypeMeta.Kind = o.TypeMeta.Kind - o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta) - o.Spec.DeepCopyInto(&dst.Spec) - o.Status.DeepCopyInto(&dst.Status) -} - -// Interface compliance compile-time check -var _ resource.Object = &LogsDrilldownDefaultColumns{} - -// +k8s:openapi-gen=true -type LogsDrilldownDefaultColumnsList struct { - metav1.TypeMeta `json:",inline" yaml:",inline"` - metav1.ListMeta `json:"metadata" yaml:"metadata"` - Items []LogsDrilldownDefaultColumns `json:"items" yaml:"items"` -} - -func (o *LogsDrilldownDefaultColumnsList) DeepCopyObject() runtime.Object { - return o.Copy() -} - -func (o *LogsDrilldownDefaultColumnsList) Copy() resource.ListObject { - cpy := &LogsDrilldownDefaultColumnsList{ - TypeMeta: o.TypeMeta, - Items: make([]LogsDrilldownDefaultColumns, len(o.Items)), - } - o.ListMeta.DeepCopyInto(&cpy.ListMeta) - for i := 0; i < len(o.Items); i++ { - if item, ok := o.Items[i].Copy().(*LogsDrilldownDefaultColumns); ok { - cpy.Items[i] = *item - } - } - return cpy -} - -func (o *LogsDrilldownDefaultColumnsList) GetItems() []resource.Object { - items := make([]resource.Object, len(o.Items)) - for i := 0; i < len(o.Items); i++ { - items[i] = &o.Items[i] - } - return items -} - -func (o *LogsDrilldownDefaultColumnsList) SetItems(items []resource.Object) { - o.Items = make([]LogsDrilldownDefaultColumns, len(items)) - for i := 0; i < len(items); i++ { - o.Items[i] = *items[i].(*LogsDrilldownDefaultColumns) - } -} - -func (o *LogsDrilldownDefaultColumnsList) DeepCopy() *LogsDrilldownDefaultColumnsList { - cpy := &LogsDrilldownDefaultColumnsList{} - o.DeepCopyInto(cpy) - return cpy -} - -func (o *LogsDrilldownDefaultColumnsList) DeepCopyInto(dst *LogsDrilldownDefaultColumnsList) { - resource.CopyObjectInto(dst, o) -} - -// Interface compliance compile-time check -var _ resource.ListObject = &LogsDrilldownDefaultColumnsList{} - -// Copy methods for all subresource types - -// DeepCopy creates a full deep copy of Spec -func (s *Spec) DeepCopy() *Spec { - cpy := &Spec{} - s.DeepCopyInto(cpy) - return cpy -} - -// DeepCopyInto deep copies Spec into another Spec object -func (s *Spec) DeepCopyInto(dst *Spec) { - resource.CopyObjectInto(dst, s) -} - -// DeepCopy creates a full deep copy of Status -func (s *Status) DeepCopy() *Status { - cpy := &Status{} - s.DeepCopyInto(cpy) - return cpy -} - -// DeepCopyInto deep copies Status into another Status object -func (s *Status) DeepCopyInto(dst *Status) { - resource.CopyObjectInto(dst, s) -} diff --git a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaultcolumns/v1alpha1/logsdrilldowndefaultcolumns_schema_gen.go b/apps/logsdrilldown/pkg/generated/logsdrilldowndefaultcolumns/v1alpha1/logsdrilldowndefaultcolumns_schema_gen.go deleted file mode 100644 index b50be391fc7..00000000000 --- a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaultcolumns/v1alpha1/logsdrilldowndefaultcolumns_schema_gen.go +++ /dev/null @@ -1,34 +0,0 @@ -// -// Code generated by grafana-app-sdk. DO NOT EDIT. -// - -package v1alpha1 - -import ( - "github.com/grafana/grafana-app-sdk/resource" -) - -// schema is unexported to prevent accidental overwrites -var ( - schemaLogsDrilldownDefaultColumns = resource.NewSimpleSchema("logsdrilldown.grafana.app", "v1alpha1", &LogsDrilldownDefaultColumns{}, &LogsDrilldownDefaultColumnsList{}, resource.WithKind("LogsDrilldownDefaultColumns"), - resource.WithPlural("logsdrilldowndefaultcolumns"), resource.WithScope(resource.NamespacedScope)) - kindLogsDrilldownDefaultColumns = resource.Kind{ - Schema: schemaLogsDrilldownDefaultColumns, - Codecs: map[resource.KindEncoding]resource.Codec{ - resource.KindEncodingJSON: &JSONCodec{}, - }, - } -) - -// Kind returns a resource.Kind for this Schema with a JSON codec -func Kind() resource.Kind { - return kindLogsDrilldownDefaultColumns -} - -// Schema returns a resource.SimpleSchema representation of LogsDrilldownDefaultColumns -func Schema() *resource.SimpleSchema { - return schemaLogsDrilldownDefaultColumns -} - -// Interface compliance checks -var _ resource.Schema = kindLogsDrilldownDefaultColumns diff --git a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaultcolumns/v1alpha1/logsdrilldowndefaultcolumns_spec_gen.go b/apps/logsdrilldown/pkg/generated/logsdrilldowndefaultcolumns/v1alpha1/logsdrilldowndefaultcolumns_spec_gen.go deleted file mode 100644 index d9cd977aeb9..00000000000 --- a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaultcolumns/v1alpha1/logsdrilldowndefaultcolumns_spec_gen.go +++ /dev/null @@ -1,43 +0,0 @@ -// Code generated - EDITING IS FUTILE. DO NOT EDIT. - -package v1alpha1 - -// +k8s:openapi-gen=true -type LogsDefaultColumnsRecords []LogsDefaultColumnsRecord - -// +k8s:openapi-gen=true -type LogsDefaultColumnsRecord struct { - Columns []string `json:"columns"` - Labels LogsDefaultColumnsLabels `json:"labels"` -} - -// NewLogsDefaultColumnsRecord creates a new LogsDefaultColumnsRecord object. -func NewLogsDefaultColumnsRecord() *LogsDefaultColumnsRecord { - return &LogsDefaultColumnsRecord{ - Columns: []string{}, - } -} - -// +k8s:openapi-gen=true -type LogsDefaultColumnsLabels []LogsDefaultColumnsLabel - -// +k8s:openapi-gen=true -type LogsDefaultColumnsLabel struct { - Key string `json:"key"` - Value string `json:"value"` -} - -// NewLogsDefaultColumnsLabel creates a new LogsDefaultColumnsLabel object. -func NewLogsDefaultColumnsLabel() *LogsDefaultColumnsLabel { - return &LogsDefaultColumnsLabel{} -} - -// +k8s:openapi-gen=true -type Spec struct { - Records LogsDefaultColumnsRecords `json:"records"` -} - -// NewSpec creates a new Spec object. -func NewSpec() *Spec { - return &Spec{} -} diff --git a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaultcolumns/v1alpha1/logsdrilldowndefaultcolumns_status_gen.go b/apps/logsdrilldown/pkg/generated/logsdrilldowndefaultcolumns/v1alpha1/logsdrilldowndefaultcolumns_status_gen.go deleted file mode 100644 index 9b227b00f44..00000000000 --- a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaultcolumns/v1alpha1/logsdrilldowndefaultcolumns_status_gen.go +++ /dev/null @@ -1,44 +0,0 @@ -// Code generated - EDITING IS FUTILE. DO NOT EDIT. - -package v1alpha1 - -// +k8s:openapi-gen=true -type StatusOperatorState struct { - // lastEvaluation is the ResourceVersion last evaluated - LastEvaluation string `json:"lastEvaluation"` - // state describes the state of the lastEvaluation. - // It is limited to three possible states for machine evaluation. - State StatusOperatorStateState `json:"state"` - // descriptiveState is an optional more descriptive state field which has no requirements on format - DescriptiveState *string `json:"descriptiveState,omitempty"` - // details contains any extra information that is operator-specific - Details map[string]interface{} `json:"details,omitempty"` -} - -// NewStatusOperatorState creates a new StatusOperatorState object. -func NewStatusOperatorState() *StatusOperatorState { - return &StatusOperatorState{} -} - -// +k8s:openapi-gen=true -type Status struct { - // operatorStates is a map of operator ID to operator state evaluations. - // Any operator which consumes this kind SHOULD add its state evaluation information to this field. - OperatorStates map[string]StatusOperatorState `json:"operatorStates,omitempty"` - // additionalFields is reserved for future use - AdditionalFields map[string]interface{} `json:"additionalFields,omitempty"` -} - -// NewStatus creates a new Status object. -func NewStatus() *Status { - return &Status{} -} - -// +k8s:openapi-gen=true -type StatusOperatorStateState string - -const ( - StatusOperatorStateStateSuccess StatusOperatorStateState = "success" - StatusOperatorStateStateInProgress StatusOperatorStateState = "in_progress" - StatusOperatorStateStateFailed StatusOperatorStateState = "failed" -) diff --git a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaults/v1alpha1/constants.go b/apps/logsdrilldown/pkg/generated/logsdrilldowndefaults/v1alpha1/constants.go deleted file mode 100644 index 082bec7c874..00000000000 --- a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaults/v1alpha1/constants.go +++ /dev/null @@ -1,18 +0,0 @@ -package v1alpha1 - -import "k8s.io/apimachinery/pkg/runtime/schema" - -const ( - // APIGroup is the API group used by all kinds in this package - APIGroup = "logsdrilldown.grafana.app" - // APIVersion is the API version used by all kinds in this package - APIVersion = "v1alpha1" -) - -var ( - // GroupVersion is a schema.GroupVersion consisting of the Group and Version constants for this package - GroupVersion = schema.GroupVersion{ - Group: APIGroup, - Version: APIVersion, - } -) diff --git a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaults/v1alpha1/logsdrilldowndefaults_client_gen.go b/apps/logsdrilldown/pkg/generated/logsdrilldowndefaults/v1alpha1/logsdrilldowndefaults_client_gen.go deleted file mode 100644 index cc06a10b1e7..00000000000 --- a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaults/v1alpha1/logsdrilldowndefaults_client_gen.go +++ /dev/null @@ -1,99 +0,0 @@ -package v1alpha1 - -import ( - "context" - - "github.com/grafana/grafana-app-sdk/resource" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -type LogsDrilldownDefaultsClient struct { - client *resource.TypedClient[*LogsDrilldownDefaults, *LogsDrilldownDefaultsList] -} - -func NewLogsDrilldownDefaultsClient(client resource.Client) *LogsDrilldownDefaultsClient { - return &LogsDrilldownDefaultsClient{ - client: resource.NewTypedClient[*LogsDrilldownDefaults, *LogsDrilldownDefaultsList](client, Kind()), - } -} - -func NewLogsDrilldownDefaultsClientFromGenerator(generator resource.ClientGenerator) (*LogsDrilldownDefaultsClient, error) { - c, err := generator.ClientFor(Kind()) - if err != nil { - return nil, err - } - return NewLogsDrilldownDefaultsClient(c), nil -} - -func (c *LogsDrilldownDefaultsClient) Get(ctx context.Context, identifier resource.Identifier) (*LogsDrilldownDefaults, error) { - return c.client.Get(ctx, identifier) -} - -func (c *LogsDrilldownDefaultsClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*LogsDrilldownDefaultsList, error) { - return c.client.List(ctx, namespace, opts) -} - -func (c *LogsDrilldownDefaultsClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*LogsDrilldownDefaultsList, error) { - resp, err := c.client.List(ctx, namespace, resource.ListOptions{ - ResourceVersion: opts.ResourceVersion, - Limit: opts.Limit, - LabelFilters: opts.LabelFilters, - FieldSelectors: opts.FieldSelectors, - }) - if err != nil { - return nil, err - } - for resp.GetContinue() != "" { - page, err := c.client.List(ctx, namespace, resource.ListOptions{ - Continue: resp.GetContinue(), - ResourceVersion: opts.ResourceVersion, - Limit: opts.Limit, - LabelFilters: opts.LabelFilters, - FieldSelectors: opts.FieldSelectors, - }) - if err != nil { - return nil, err - } - resp.SetContinue(page.GetContinue()) - resp.SetResourceVersion(page.GetResourceVersion()) - resp.SetItems(append(resp.GetItems(), page.GetItems()...)) - } - return resp, nil -} - -func (c *LogsDrilldownDefaultsClient) Create(ctx context.Context, obj *LogsDrilldownDefaults, opts resource.CreateOptions) (*LogsDrilldownDefaults, error) { - // Make sure apiVersion and kind are set - obj.APIVersion = GroupVersion.Identifier() - obj.Kind = Kind().Kind() - return c.client.Create(ctx, obj, opts) -} - -func (c *LogsDrilldownDefaultsClient) Update(ctx context.Context, obj *LogsDrilldownDefaults, opts resource.UpdateOptions) (*LogsDrilldownDefaults, error) { - return c.client.Update(ctx, obj, opts) -} - -func (c *LogsDrilldownDefaultsClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*LogsDrilldownDefaults, error) { - return c.client.Patch(ctx, identifier, req, opts) -} - -func (c *LogsDrilldownDefaultsClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus Status, opts resource.UpdateOptions) (*LogsDrilldownDefaults, error) { - return c.client.Update(ctx, &LogsDrilldownDefaults{ - TypeMeta: metav1.TypeMeta{ - Kind: Kind().Kind(), - APIVersion: GroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - ResourceVersion: opts.ResourceVersion, - Namespace: identifier.Namespace, - Name: identifier.Name, - }, - Status: newStatus, - }, resource.UpdateOptions{ - Subresource: "status", - ResourceVersion: opts.ResourceVersion, - }) -} - -func (c *LogsDrilldownDefaultsClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error { - return c.client.Delete(ctx, identifier, opts) -} diff --git a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaults/v1alpha1/logsdrilldowndefaults_codec_gen.go b/apps/logsdrilldown/pkg/generated/logsdrilldowndefaults/v1alpha1/logsdrilldowndefaults_codec_gen.go deleted file mode 100644 index bb458caeb88..00000000000 --- a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaults/v1alpha1/logsdrilldowndefaults_codec_gen.go +++ /dev/null @@ -1,28 +0,0 @@ -// -// Code generated by grafana-app-sdk. DO NOT EDIT. -// - -package v1alpha1 - -import ( - "encoding/json" - "io" - - "github.com/grafana/grafana-app-sdk/resource" -) - -// JSONCodec is an implementation of resource.Codec for kubernetes JSON encoding -type JSONCodec struct{} - -// Read reads JSON-encoded bytes from `reader` and unmarshals them into `into` -func (*JSONCodec) Read(reader io.Reader, into resource.Object) error { - return json.NewDecoder(reader).Decode(into) -} - -// Write writes JSON-encoded bytes into `writer` marshaled from `from` -func (*JSONCodec) Write(writer io.Writer, from resource.Object) error { - return json.NewEncoder(writer).Encode(from) -} - -// Interface compliance checks -var _ resource.Codec = &JSONCodec{} diff --git a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaults/v1alpha1/logsdrilldowndefaults_metadata_gen.go b/apps/logsdrilldown/pkg/generated/logsdrilldowndefaults/v1alpha1/logsdrilldowndefaults_metadata_gen.go deleted file mode 100644 index cb7233b22ab..00000000000 --- a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaults/v1alpha1/logsdrilldowndefaults_metadata_gen.go +++ /dev/null @@ -1,31 +0,0 @@ -// Code generated - EDITING IS FUTILE. DO NOT EDIT. - -package v1alpha1 - -import ( - time "time" -) - -// metadata contains embedded CommonMetadata and can be extended with custom string fields -// TODO: use CommonMetadata instead of redefining here; currently needs to be defined here -// without external reference as using the CommonMetadata reference breaks thema codegen. -type Metadata struct { - UpdateTimestamp time.Time `json:"updateTimestamp"` - CreatedBy string `json:"createdBy"` - Uid string `json:"uid"` - CreationTimestamp time.Time `json:"creationTimestamp"` - DeletionTimestamp *time.Time `json:"deletionTimestamp,omitempty"` - Finalizers []string `json:"finalizers"` - ResourceVersion string `json:"resourceVersion"` - Generation int64 `json:"generation"` - UpdatedBy string `json:"updatedBy"` - Labels map[string]string `json:"labels"` -} - -// NewMetadata creates a new Metadata object. -func NewMetadata() *Metadata { - return &Metadata{ - Finalizers: []string{}, - Labels: map[string]string{}, - } -} diff --git a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaults/v1alpha1/logsdrilldowndefaults_object_gen.go b/apps/logsdrilldown/pkg/generated/logsdrilldowndefaults/v1alpha1/logsdrilldowndefaults_object_gen.go deleted file mode 100644 index d9354522dd7..00000000000 --- a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaults/v1alpha1/logsdrilldowndefaults_object_gen.go +++ /dev/null @@ -1,319 +0,0 @@ -// -// Code generated by grafana-app-sdk. DO NOT EDIT. -// - -package v1alpha1 - -import ( - "fmt" - "github.com/grafana/grafana-app-sdk/resource" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" - "time" -) - -// +k8s:openapi-gen=true -type LogsDrilldownDefaults struct { - metav1.TypeMeta `json:",inline" yaml:",inline"` - metav1.ObjectMeta `json:"metadata" yaml:"metadata"` - - // Spec is the spec of the LogsDrilldownDefaults - Spec Spec `json:"spec" yaml:"spec"` - - Status Status `json:"status" yaml:"status"` -} - -func (o *LogsDrilldownDefaults) GetSpec() any { - return o.Spec -} - -func (o *LogsDrilldownDefaults) SetSpec(spec any) error { - cast, ok := spec.(Spec) - if !ok { - return fmt.Errorf("cannot set spec type %#v, not of type Spec", spec) - } - o.Spec = cast - return nil -} - -func (o *LogsDrilldownDefaults) GetSubresources() map[string]any { - return map[string]any{ - "status": o.Status, - } -} - -func (o *LogsDrilldownDefaults) GetSubresource(name string) (any, bool) { - switch name { - case "status": - return o.Status, true - default: - return nil, false - } -} - -func (o *LogsDrilldownDefaults) SetSubresource(name string, value any) error { - switch name { - case "status": - cast, ok := value.(Status) - if !ok { - return fmt.Errorf("cannot set status type %#v, not of type Status", value) - } - o.Status = cast - return nil - default: - return fmt.Errorf("subresource '%s' does not exist", name) - } -} - -func (o *LogsDrilldownDefaults) GetStaticMetadata() resource.StaticMetadata { - gvk := o.GroupVersionKind() - return resource.StaticMetadata{ - Name: o.ObjectMeta.Name, - Namespace: o.ObjectMeta.Namespace, - Group: gvk.Group, - Version: gvk.Version, - Kind: gvk.Kind, - } -} - -func (o *LogsDrilldownDefaults) SetStaticMetadata(metadata resource.StaticMetadata) { - o.Name = metadata.Name - o.Namespace = metadata.Namespace - o.SetGroupVersionKind(schema.GroupVersionKind{ - Group: metadata.Group, - Version: metadata.Version, - Kind: metadata.Kind, - }) -} - -func (o *LogsDrilldownDefaults) GetCommonMetadata() resource.CommonMetadata { - dt := o.DeletionTimestamp - var deletionTimestamp *time.Time - if dt != nil { - deletionTimestamp = &dt.Time - } - // Legacy ExtraFields support - extraFields := make(map[string]any) - if o.Annotations != nil { - extraFields["annotations"] = o.Annotations - } - if o.ManagedFields != nil { - extraFields["managedFields"] = o.ManagedFields - } - if o.OwnerReferences != nil { - extraFields["ownerReferences"] = o.OwnerReferences - } - return resource.CommonMetadata{ - UID: string(o.UID), - ResourceVersion: o.ResourceVersion, - Generation: o.Generation, - Labels: o.Labels, - CreationTimestamp: o.CreationTimestamp.Time, - DeletionTimestamp: deletionTimestamp, - Finalizers: o.Finalizers, - UpdateTimestamp: o.GetUpdateTimestamp(), - CreatedBy: o.GetCreatedBy(), - UpdatedBy: o.GetUpdatedBy(), - ExtraFields: extraFields, - } -} - -func (o *LogsDrilldownDefaults) SetCommonMetadata(metadata resource.CommonMetadata) { - o.UID = types.UID(metadata.UID) - o.ResourceVersion = metadata.ResourceVersion - o.Generation = metadata.Generation - o.Labels = metadata.Labels - o.CreationTimestamp = metav1.NewTime(metadata.CreationTimestamp) - if metadata.DeletionTimestamp != nil { - dt := metav1.NewTime(*metadata.DeletionTimestamp) - o.DeletionTimestamp = &dt - } else { - o.DeletionTimestamp = nil - } - o.Finalizers = metadata.Finalizers - if o.Annotations == nil { - o.Annotations = make(map[string]string) - } - if !metadata.UpdateTimestamp.IsZero() { - o.SetUpdateTimestamp(metadata.UpdateTimestamp) - } - if metadata.CreatedBy != "" { - o.SetCreatedBy(metadata.CreatedBy) - } - if metadata.UpdatedBy != "" { - o.SetUpdatedBy(metadata.UpdatedBy) - } - // Legacy support for setting Annotations, ManagedFields, and OwnerReferences via ExtraFields - if metadata.ExtraFields != nil { - if annotations, ok := metadata.ExtraFields["annotations"]; ok { - if cast, ok := annotations.(map[string]string); ok { - o.Annotations = cast - } - } - if managedFields, ok := metadata.ExtraFields["managedFields"]; ok { - if cast, ok := managedFields.([]metav1.ManagedFieldsEntry); ok { - o.ManagedFields = cast - } - } - if ownerReferences, ok := metadata.ExtraFields["ownerReferences"]; ok { - if cast, ok := ownerReferences.([]metav1.OwnerReference); ok { - o.OwnerReferences = cast - } - } - } -} - -func (o *LogsDrilldownDefaults) GetCreatedBy() string { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - return o.ObjectMeta.Annotations["grafana.com/createdBy"] -} - -func (o *LogsDrilldownDefaults) SetCreatedBy(createdBy string) { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - o.ObjectMeta.Annotations["grafana.com/createdBy"] = createdBy -} - -func (o *LogsDrilldownDefaults) GetUpdateTimestamp() time.Time { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - parsed, _ := time.Parse(time.RFC3339, o.ObjectMeta.Annotations["grafana.com/updateTimestamp"]) - return parsed -} - -func (o *LogsDrilldownDefaults) SetUpdateTimestamp(updateTimestamp time.Time) { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - o.ObjectMeta.Annotations["grafana.com/updateTimestamp"] = updateTimestamp.Format(time.RFC3339) -} - -func (o *LogsDrilldownDefaults) GetUpdatedBy() string { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - return o.ObjectMeta.Annotations["grafana.com/updatedBy"] -} - -func (o *LogsDrilldownDefaults) SetUpdatedBy(updatedBy string) { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - o.ObjectMeta.Annotations["grafana.com/updatedBy"] = updatedBy -} - -func (o *LogsDrilldownDefaults) Copy() resource.Object { - return resource.CopyObject(o) -} - -func (o *LogsDrilldownDefaults) DeepCopyObject() runtime.Object { - return o.Copy() -} - -func (o *LogsDrilldownDefaults) DeepCopy() *LogsDrilldownDefaults { - cpy := &LogsDrilldownDefaults{} - o.DeepCopyInto(cpy) - return cpy -} - -func (o *LogsDrilldownDefaults) DeepCopyInto(dst *LogsDrilldownDefaults) { - dst.TypeMeta.APIVersion = o.TypeMeta.APIVersion - dst.TypeMeta.Kind = o.TypeMeta.Kind - o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta) - o.Spec.DeepCopyInto(&dst.Spec) - o.Status.DeepCopyInto(&dst.Status) -} - -// Interface compliance compile-time check -var _ resource.Object = &LogsDrilldownDefaults{} - -// +k8s:openapi-gen=true -type LogsDrilldownDefaultsList struct { - metav1.TypeMeta `json:",inline" yaml:",inline"` - metav1.ListMeta `json:"metadata" yaml:"metadata"` - Items []LogsDrilldownDefaults `json:"items" yaml:"items"` -} - -func (o *LogsDrilldownDefaultsList) DeepCopyObject() runtime.Object { - return o.Copy() -} - -func (o *LogsDrilldownDefaultsList) Copy() resource.ListObject { - cpy := &LogsDrilldownDefaultsList{ - TypeMeta: o.TypeMeta, - Items: make([]LogsDrilldownDefaults, len(o.Items)), - } - o.ListMeta.DeepCopyInto(&cpy.ListMeta) - for i := 0; i < len(o.Items); i++ { - if item, ok := o.Items[i].Copy().(*LogsDrilldownDefaults); ok { - cpy.Items[i] = *item - } - } - return cpy -} - -func (o *LogsDrilldownDefaultsList) GetItems() []resource.Object { - items := make([]resource.Object, len(o.Items)) - for i := 0; i < len(o.Items); i++ { - items[i] = &o.Items[i] - } - return items -} - -func (o *LogsDrilldownDefaultsList) SetItems(items []resource.Object) { - o.Items = make([]LogsDrilldownDefaults, len(items)) - for i := 0; i < len(items); i++ { - o.Items[i] = *items[i].(*LogsDrilldownDefaults) - } -} - -func (o *LogsDrilldownDefaultsList) DeepCopy() *LogsDrilldownDefaultsList { - cpy := &LogsDrilldownDefaultsList{} - o.DeepCopyInto(cpy) - return cpy -} - -func (o *LogsDrilldownDefaultsList) DeepCopyInto(dst *LogsDrilldownDefaultsList) { - resource.CopyObjectInto(dst, o) -} - -// Interface compliance compile-time check -var _ resource.ListObject = &LogsDrilldownDefaultsList{} - -// Copy methods for all subresource types - -// DeepCopy creates a full deep copy of Spec -func (s *Spec) DeepCopy() *Spec { - cpy := &Spec{} - s.DeepCopyInto(cpy) - return cpy -} - -// DeepCopyInto deep copies Spec into another Spec object -func (s *Spec) DeepCopyInto(dst *Spec) { - resource.CopyObjectInto(dst, s) -} - -// DeepCopy creates a full deep copy of Status -func (s *Status) DeepCopy() *Status { - cpy := &Status{} - s.DeepCopyInto(cpy) - return cpy -} - -// DeepCopyInto deep copies Status into another Status object -func (s *Status) DeepCopyInto(dst *Status) { - resource.CopyObjectInto(dst, s) -} diff --git a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaults/v1alpha1/logsdrilldowndefaults_schema_gen.go b/apps/logsdrilldown/pkg/generated/logsdrilldowndefaults/v1alpha1/logsdrilldowndefaults_schema_gen.go deleted file mode 100644 index bda3e49377d..00000000000 --- a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaults/v1alpha1/logsdrilldowndefaults_schema_gen.go +++ /dev/null @@ -1,34 +0,0 @@ -// -// Code generated by grafana-app-sdk. DO NOT EDIT. -// - -package v1alpha1 - -import ( - "github.com/grafana/grafana-app-sdk/resource" -) - -// schema is unexported to prevent accidental overwrites -var ( - schemaLogsDrilldownDefaults = resource.NewSimpleSchema("logsdrilldown.grafana.app", "v1alpha1", &LogsDrilldownDefaults{}, &LogsDrilldownDefaultsList{}, resource.WithKind("LogsDrilldownDefaults"), - resource.WithPlural("logsdrilldowndefaults"), resource.WithScope(resource.NamespacedScope)) - kindLogsDrilldownDefaults = resource.Kind{ - Schema: schemaLogsDrilldownDefaults, - Codecs: map[resource.KindEncoding]resource.Codec{ - resource.KindEncodingJSON: &JSONCodec{}, - }, - } -) - -// Kind returns a resource.Kind for this Schema with a JSON codec -func Kind() resource.Kind { - return kindLogsDrilldownDefaults -} - -// Schema returns a resource.SimpleSchema representation of LogsDrilldownDefaults -func Schema() *resource.SimpleSchema { - return schemaLogsDrilldownDefaults -} - -// Interface compliance checks -var _ resource.Schema = kindLogsDrilldownDefaults diff --git a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaults/v1alpha1/logsdrilldowndefaults_spec_gen.go b/apps/logsdrilldown/pkg/generated/logsdrilldowndefaults/v1alpha1/logsdrilldowndefaults_spec_gen.go deleted file mode 100644 index faff5c108dd..00000000000 --- a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaults/v1alpha1/logsdrilldowndefaults_spec_gen.go +++ /dev/null @@ -1,18 +0,0 @@ -// Code generated - EDITING IS FUTILE. DO NOT EDIT. - -package v1alpha1 - -// +k8s:openapi-gen=true -type Spec struct { - DefaultFields []string `json:"defaultFields"` - PrettifyJSON bool `json:"prettifyJSON"` - WrapLogMessage bool `json:"wrapLogMessage"` - InterceptDismissed bool `json:"interceptDismissed"` -} - -// NewSpec creates a new Spec object. -func NewSpec() *Spec { - return &Spec{ - DefaultFields: []string{}, - } -} diff --git a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaults/v1alpha1/logsdrilldowndefaults_status_gen.go b/apps/logsdrilldown/pkg/generated/logsdrilldowndefaults/v1alpha1/logsdrilldowndefaults_status_gen.go deleted file mode 100644 index 9b227b00f44..00000000000 --- a/apps/logsdrilldown/pkg/generated/logsdrilldowndefaults/v1alpha1/logsdrilldowndefaults_status_gen.go +++ /dev/null @@ -1,44 +0,0 @@ -// Code generated - EDITING IS FUTILE. DO NOT EDIT. - -package v1alpha1 - -// +k8s:openapi-gen=true -type StatusOperatorState struct { - // lastEvaluation is the ResourceVersion last evaluated - LastEvaluation string `json:"lastEvaluation"` - // state describes the state of the lastEvaluation. - // It is limited to three possible states for machine evaluation. - State StatusOperatorStateState `json:"state"` - // descriptiveState is an optional more descriptive state field which has no requirements on format - DescriptiveState *string `json:"descriptiveState,omitempty"` - // details contains any extra information that is operator-specific - Details map[string]interface{} `json:"details,omitempty"` -} - -// NewStatusOperatorState creates a new StatusOperatorState object. -func NewStatusOperatorState() *StatusOperatorState { - return &StatusOperatorState{} -} - -// +k8s:openapi-gen=true -type Status struct { - // operatorStates is a map of operator ID to operator state evaluations. - // Any operator which consumes this kind SHOULD add its state evaluation information to this field. - OperatorStates map[string]StatusOperatorState `json:"operatorStates,omitempty"` - // additionalFields is reserved for future use - AdditionalFields map[string]interface{} `json:"additionalFields,omitempty"` -} - -// NewStatus creates a new Status object. -func NewStatus() *Status { - return &Status{} -} - -// +k8s:openapi-gen=true -type StatusOperatorStateState string - -const ( - StatusOperatorStateStateSuccess StatusOperatorStateState = "success" - StatusOperatorStateStateInProgress StatusOperatorStateState = "in_progress" - StatusOperatorStateStateFailed StatusOperatorStateState = "failed" -) diff --git a/apps/logsdrilldown/pkg/generated/manifestdata/logsdrilldown_manifest.go b/apps/logsdrilldown/pkg/generated/manifestdata/logsdrilldown_manifest.go deleted file mode 100644 index 9deb5d5d3a1..00000000000 --- a/apps/logsdrilldown/pkg/generated/manifestdata/logsdrilldown_manifest.go +++ /dev/null @@ -1,150 +0,0 @@ -// -// This file is generated by grafana-app-sdk -// DO NOT EDIT -// - -package manifestdata - -import ( - "encoding/json" - "fmt" - "strings" - - "github.com/grafana/grafana-app-sdk/app" - "github.com/grafana/grafana-app-sdk/resource" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/kube-openapi/pkg/spec3" - "k8s.io/kube-openapi/pkg/validation/spec" - - logsdrilldownv1alpha1 "github.com/grafana/grafana/apps/logsdrilldown/pkg/generated/logsdrilldown/v1alpha1" - logsdrilldowndefaultcolumnsv1alpha1 "github.com/grafana/grafana/apps/logsdrilldown/pkg/generated/logsdrilldowndefaultcolumns/v1alpha1" - logsdrilldowndefaultsv1alpha1 "github.com/grafana/grafana/apps/logsdrilldown/pkg/generated/logsdrilldowndefaults/v1alpha1" -) - -var ( - rawSchemaLogsDrilldownv1alpha1 = []byte(`{"LogsDrilldown":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"defaultFields":{"items":{"type":"string"},"type":"array"},"interceptDismissed":{"type":"boolean"},"prettifyJSON":{"type":"boolean"},"wrapLogMessage":{"type":"boolean"}},"required":["defaultFields","prettifyJSON","wrapLogMessage","interceptDismissed"],"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"}}`) - versionSchemaLogsDrilldownv1alpha1 app.VersionSchema - _ = json.Unmarshal(rawSchemaLogsDrilldownv1alpha1, &versionSchemaLogsDrilldownv1alpha1) - rawSchemaLogsDrilldownDefaultsv1alpha1 = []byte(`{"LogsDrilldownDefaults":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"defaultFields":{"items":{"type":"string"},"type":"array"},"interceptDismissed":{"type":"boolean"},"prettifyJSON":{"type":"boolean"},"wrapLogMessage":{"type":"boolean"}},"required":["defaultFields","prettifyJSON","wrapLogMessage","interceptDismissed"],"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"}}`) - versionSchemaLogsDrilldownDefaultsv1alpha1 app.VersionSchema - _ = json.Unmarshal(rawSchemaLogsDrilldownDefaultsv1alpha1, &versionSchemaLogsDrilldownDefaultsv1alpha1) - rawSchemaLogsDrilldownDefaultColumnsv1alpha1 = []byte(`{"LogsDefaultColumnsLabel":{"additionalProperties":false,"properties":{"key":{"type":"string"},"value":{"type":"string"}},"required":["key","value"],"type":"object"},"LogsDefaultColumnsLabels":{"items":{"$ref":"#/components/schemas/LogsDefaultColumnsLabel"},"type":"array"},"LogsDefaultColumnsRecord":{"additionalProperties":false,"properties":{"columns":{"items":{"type":"string"},"type":"array"},"labels":{"$ref":"#/components/schemas/LogsDefaultColumnsLabels"}},"required":["columns","labels"],"type":"object"},"LogsDefaultColumnsRecords":{"items":{"$ref":"#/components/schemas/LogsDefaultColumnsRecord"},"type":"array"},"LogsDrilldownDefaultColumns":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"records":{"$ref":"#/components/schemas/LogsDefaultColumnsRecords"}},"required":["records"],"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"}}`) - versionSchemaLogsDrilldownDefaultColumnsv1alpha1 app.VersionSchema - _ = json.Unmarshal(rawSchemaLogsDrilldownDefaultColumnsv1alpha1, &versionSchemaLogsDrilldownDefaultColumnsv1alpha1) -) - -var appManifestData = app.ManifestData{ - AppName: "logsdrilldown", - Group: "logsdrilldown.grafana.app", - PreferredVersion: "v1alpha1", - Versions: []app.ManifestVersion{ - { - Name: "v1alpha1", - Served: true, - Kinds: []app.ManifestVersionKind{ - { - Kind: "LogsDrilldown", - Plural: "LogsDrilldowns", - Scope: "Namespaced", - Conversion: false, - Schema: &versionSchemaLogsDrilldownv1alpha1, - }, - - { - Kind: "LogsDrilldownDefaults", - Plural: "LogsDrilldownDefaults", - Scope: "Namespaced", - Conversion: false, - Schema: &versionSchemaLogsDrilldownDefaultsv1alpha1, - }, - - { - Kind: "LogsDrilldownDefaultColumns", - Plural: "LogsDrilldownDefaultColumns", - Scope: "Namespaced", - Conversion: false, - Schema: &versionSchemaLogsDrilldownDefaultColumnsv1alpha1, - }, - }, - Routes: app.ManifestVersionRoutes{ - Namespaced: map[string]spec3.PathProps{}, - Cluster: map[string]spec3.PathProps{}, - Schemas: map[string]spec.Schema{}, - }, - }, - }, -} - -func LocalManifest() app.Manifest { - return app.NewEmbeddedManifest(appManifestData) -} - -func RemoteManifest() app.Manifest { - return app.NewAPIServerManifest("logsdrilldown") -} - -var kindVersionToGoType = map[string]resource.Kind{ - "LogsDrilldown/v1alpha1": logsdrilldownv1alpha1.Kind(), - "LogsDrilldownDefaults/v1alpha1": logsdrilldowndefaultsv1alpha1.Kind(), - "LogsDrilldownDefaultColumns/v1alpha1": logsdrilldowndefaultcolumnsv1alpha1.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/investigations/plugin/src/generated/investigation/v0alpha1/investigation_object_gen.ts b/apps/logsdrilldown/plugin/src/generated/logsdrilldowndefaultcolumns/v1beta1/logsdrilldowndefaultcolumns_object_gen.ts similarity index 95% rename from apps/investigations/plugin/src/generated/investigation/v0alpha1/investigation_object_gen.ts rename to apps/logsdrilldown/plugin/src/generated/logsdrilldowndefaultcolumns/v1beta1/logsdrilldowndefaultcolumns_object_gen.ts index 3c7cf0874f8..f7ba7b0f223 100644 --- a/apps/investigations/plugin/src/generated/investigation/v0alpha1/investigation_object_gen.ts +++ b/apps/logsdrilldown/plugin/src/generated/logsdrilldowndefaultcolumns/v1beta1/logsdrilldowndefaultcolumns_object_gen.ts @@ -40,7 +40,7 @@ export interface ManagedFieldsEntry { subresource?: string; } -export interface Investigation { +export interface LogsDrilldownDefaultColumns { kind: string; apiVersion: string; metadata: Metadata; diff --git a/apps/investigations/plugin/src/generated/investigation/v0alpha1/types.metadata.gen.ts b/apps/logsdrilldown/plugin/src/generated/logsdrilldowndefaultcolumns/v1beta1/types.metadata.gen.ts similarity index 100% rename from apps/investigations/plugin/src/generated/investigation/v0alpha1/types.metadata.gen.ts rename to apps/logsdrilldown/plugin/src/generated/logsdrilldowndefaultcolumns/v1beta1/types.metadata.gen.ts diff --git a/apps/logsdrilldown/plugin/src/generated/logsdrilldowndefaultcolumns/v1beta1/types.spec.gen.ts b/apps/logsdrilldown/plugin/src/generated/logsdrilldowndefaultcolumns/v1beta1/types.spec.gen.ts new file mode 100644 index 00000000000..fde99894776 --- /dev/null +++ b/apps/logsdrilldown/plugin/src/generated/logsdrilldowndefaultcolumns/v1beta1/types.spec.gen.ts @@ -0,0 +1,38 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +export type LogsDefaultColumnsRecords = LogsDefaultColumnsRecord[]; + +export const defaultLogsDefaultColumnsRecords = (): LogsDefaultColumnsRecords => ([]); + +export interface LogsDefaultColumnsRecord { + columns: string[]; + labels: LogsDefaultColumnsLabels; +} + +export const defaultLogsDefaultColumnsRecord = (): LogsDefaultColumnsRecord => ({ + columns: [], + labels: defaultLogsDefaultColumnsLabels(), +}); + +export type LogsDefaultColumnsLabels = LogsDefaultColumnsLabel[]; + +export const defaultLogsDefaultColumnsLabels = (): LogsDefaultColumnsLabels => ([]); + +export interface LogsDefaultColumnsLabel { + key: string; + value: string; +} + +export const defaultLogsDefaultColumnsLabel = (): LogsDefaultColumnsLabel => ({ + key: "", + value: "", +}); + +export interface Spec { + records: LogsDefaultColumnsRecords; +} + +export const defaultSpec = (): Spec => ({ + records: defaultLogsDefaultColumnsRecords(), +}); + diff --git a/apps/investigations/plugin/src/generated/investigation/v0alpha1/types.status.gen.ts b/apps/logsdrilldown/plugin/src/generated/logsdrilldowndefaultcolumns/v1beta1/types.status.gen.ts similarity index 100% rename from apps/investigations/plugin/src/generated/investigation/v0alpha1/types.status.gen.ts rename to apps/logsdrilldown/plugin/src/generated/logsdrilldowndefaultcolumns/v1beta1/types.status.gen.ts diff --git a/apps/plugins/README.md b/apps/plugins/README.md new file mode 100644 index 00000000000..7f91dd6ea12 --- /dev/null +++ b/apps/plugins/README.md @@ -0,0 +1,20 @@ +# Plugins App + +API documentation is available at http://localhost:3000/swagger?api=plugins.grafana.app-v0alpha1 + +## Codegen + +- Go: `make generate` +- Frontend: Follow instructions in this [README](../..//packages/grafana-api-clients/README.md) + +## Plugin sync + +The plugin sync pushes the plugins loaded from disk to the plugins API. + +To enable, add these feature toggles in your `custom.ini`: + +```ini +[feature_toggles] +pluginInstallAPISync = true +pluginStoreServiceLoading = true +``` diff --git a/apps/plugins/go.mod b/apps/plugins/go.mod index edcf18ea3e3..7e9e5f47876 100644 --- a/apps/plugins/go.mod +++ b/apps/plugins/go.mod @@ -8,11 +8,17 @@ replace github.com/grafana/grafana/pkg/apimachinery => ../../pkg/apimachinery replace github.com/grafana/grafana/pkg/apiserver => ../../pkg/apiserver +replace github.com/grafana/grafana/pkg/plugins => ../../pkg/plugins + +replace github.com/grafana/grafana/pkg/semconv => ../../pkg/semconv + 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.7 github.com/grafana/grafana-app-sdk/logging v0.48.7 + github.com/grafana/grafana/pkg/apimachinery v0.0.0 + github.com/grafana/grafana/pkg/plugins v0.0.0 github.com/stretchr/testify v1.11.1 k8s.io/apimachinery v0.34.3 k8s.io/apiserver v0.34.3 @@ -23,19 +29,20 @@ require ( require ( cel.dev/expr v0.25.1 // indirect + github.com/Machiel/slugify v1.0.1 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect - github.com/ProtonMail/go-crypto v1.1.6 // indirect + github.com/ProtonMail/go-crypto v1.3.0 // 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 - github.com/aws/aws-sdk-go-v2 v1.39.1 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.18.14 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.8 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.8 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1 // indirect - 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/aws/aws-sdk-go-v2 v1.40.0 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.18.21 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.39.1 // indirect + github.com/aws/smithy-go v1.23.2 // 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 @@ -90,20 +97,19 @@ require ( 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 + github.com/grafana/alerting v0.0.0-20260112172717-98a49ed9557f // indirect github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f // indirect github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4 // indirect github.com/grafana/dataplane/sdata v0.0.9 // indirect github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 // indirect - github.com/grafana/grafana-aws-sdk v1.3.0 // indirect + github.com/grafana/grafana-aws-sdk v1.4.2 // indirect github.com/grafana/grafana-azure-sdk-go/v2 v2.3.1 // indirect 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/grafana/pkg/semconv v0.0.0 // 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 + github.com/grafana/sqlds/v5 v5.0.3 // indirect github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 // indirect 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 @@ -191,7 +197,6 @@ require ( 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.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 diff --git a/apps/plugins/go.sum b/apps/plugins/go.sum index c5fbc7a39a5..c991111f90e 100644 --- a/apps/plugins/go.sum +++ b/apps/plugins/go.sum @@ -7,10 +7,12 @@ filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4 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/Machiel/slugify v1.0.1 h1:EfWSlRWstMadsgzmiV7d0yVd2IFlagWH68Q+DcYCm4E= +github.com/Machiel/slugify v1.0.1/go.mod h1:fTFGn5uWEynW4CUMG7sWkYXOf1UgDxyTM3DbR6Qfg3k= 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/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw= +github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE= 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= @@ -26,22 +28,22 @@ github.com/apache/thrift v0.22.0 h1:r7mTJdj51TMDe6RtcmNdQxgn9XcyfGDOzegMDRg47uc= github.com/apache/thrift v0.22.0/go.mod h1:1e7J/O1Ae6ZQMTYdy9xa3w9k+XHWPfRvdPyJeynQ+/g= github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= -github.com/aws/aws-sdk-go-v2 v1.39.1 h1:fWZhGAwVRK/fAN2tmt7ilH4PPAE11rDj7HytrmbZ2FE= -github.com/aws/aws-sdk-go-v2 v1.39.1/go.mod h1:sDioUELIUO9Znk23YVmIk86/9DOpkbyyVb1i/gUNFXY= -github.com/aws/aws-sdk-go-v2/credentials v1.18.14 h1:TxkI7QI+sFkTItN/6cJuMZEIVMFXeu2dI1ZffkXngKI= -github.com/aws/aws-sdk-go-v2/credentials v1.18.14/go.mod h1:12x4Uw/vijC11XkctTjy92TNCQ+UnNJkT7fzX0Yd93E= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.8 h1:6bgAZgRyT4RoFWhxS+aoGMFyE0cD1bSzFnEEi4bFPGI= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.8/go.mod h1:KcGkXFVU8U28qS4KvLEcPxytPZPBcRawaH2Pf/0jptE= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.8 h1:HhJYoES3zOz34yWEpGENqJvRVPqpmJyR3+AFg9ybhdY= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.8/go.mod h1:JnA+hPWeYAVbDssp83tv+ysAG8lTfLVXvSsyKg/7xNA= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1 h1:oegbebPEMA/1Jny7kvwejowCaHz1FWZAQ94WXFNCyTM= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1/go.mod h1:kemo5Myr9ac0U9JfSjMo9yHLtw+pECEHsFtJ9tqCEI8= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.8 h1:M6JI2aGFEzYxsF6CXIuRBnkge9Wf9a2xU39rNeXgu10= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.8/go.mod h1:Fw+MyTwlwjFsSTE31mH211Np+CUslml8mzc0AFEG09s= -github.com/aws/aws-sdk-go-v2/service/sts v1.38.5 h1:+LVB0xBqEgjQoqr9bGZbRzvg212B0f17JdflleJRNR4= -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/aws/aws-sdk-go-v2 v1.40.0 h1:/WMUA0kjhZExjOQN2z3oLALDREea1A7TobfuiBrKlwc= +github.com/aws/aws-sdk-go-v2 v1.40.0/go.mod h1:c9pm7VwuW0UPxAEYGyTmyurVcNrbF6Rt/wixFqDhcjE= +github.com/aws/aws-sdk-go-v2/credentials v1.18.21 h1:56HGpsgnmD+2/KpG0ikvvR8+3v3COCwaF4r+oWwOeNA= +github.com/aws/aws-sdk-go-v2/credentials v1.18.21/go.mod h1:3YELwedmQbw7cXNaII2Wywd+YY58AmLPwX4LzARgmmA= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14 h1:PZHqQACxYb8mYgms4RZbhZG0a7dPW06xOjmaH0EJC/I= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14/go.mod h1:VymhrMJUWs69D8u0/lZ7jSB6WgaG/NqHi3gX0aYf6U0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14 h1:bOS19y6zlJwagBfHxs0ESzr1XCOU2KXJCWcq3E2vfjY= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14/go.mod h1:1ipeGBMAxZ0xcTm6y6paC2C/J6f6OO7LBODV9afuAyM= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 h1:x2Ibm/Af8Fi+BH+Hsn9TXGdT+hKbDd5XOTZxTMxDk7o= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3/go.mod h1:IW1jwyrQgMdhisceG8fQLmQIydcT/jWY21rFhzgaKwo= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13 h1:kDqdFvMY4AtKoACfzIGD8A0+hbT41KTKF//gq7jITfM= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13/go.mod h1:lmKuogqSU3HzQCwZ9ZtcqOc5XGMqtDK7OIc2+DxiUEg= +github.com/aws/aws-sdk-go-v2/service/sts v1.39.1 h1:mLlUgHn02ue8whiR4BmxxGJLR2gwU6s6ZzJ5wDamBUs= +github.com/aws/aws-sdk-go-v2/service/sts v1.39.1/go.mod h1:E19xDjpzPZC7LS2knI9E6BaRFDK43Eul7vd6rSq2HWk= +github.com/aws/smithy-go v1.23.2 h1:Crv0eatJUQhaManss33hS5r40CG3ZFH+21XSkqMrIUM= +github.com/aws/smithy-go v1.23.2/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= @@ -213,8 +215,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/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/alerting v0.0.0-20251212143239-491433b332b7 h1:ZzG/gCclEit9w0QUfQt9GURcOycAIGcsQAhY1u0AEX0= -github.com/grafana/alerting v0.0.0-20251212143239-491433b332b7/go.mod h1:l7v67cgP7x72ajB9UPZlumdrHqNztpKoqQ52cU8T3LU= +github.com/grafana/alerting v0.0.0-20260112172717-98a49ed9557f h1:3bXOyht68qkfvD6Y8z8XoenFbytSSOIkr/s+AqRzj0o= +github.com/grafana/alerting v0.0.0-20260112172717-98a49ed9557f/go.mod h1:Ji0SfJChcwjgq8ljy6Y5CcYfHfAYKXjKYeysOoDS/6s= github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f h1:Cbm6OKkOcJ+7CSZsGsEJzktC/SIa5bxVeYKQLuYK86o= github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f/go.mod h1:axY0cdOg3q0TZHwpHnIz5x16xZ8ZBxJHShsSHHXcHQg= github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4 h1:Muoy+FMGrHj3GdFbvsMzUT7eusgii9PKf9L1ZaXDDbY= @@ -227,22 +229,20 @@ github.com/grafana/grafana-app-sdk v0.48.7 h1:9mF7nqkqP0QUYYDlznoOt+GIyjzj45wGfU 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-aws-sdk v1.4.2 h1:GrUEoLbs46r8rG/GZL4L2b63Bo+rkIYKdtCT7kT5KkM= +github.com/grafana/grafana-aws-sdk v1.4.2/go.mod h1:1qnZdYs6gQzxxF0dDodaE7Rn9fiMzuhwvtaAZ7ySnhY= 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= github.com/grafana/prometheus-alertmanager v0.25.1-0.20250911094103-5456b6e45604/go.mod h1:O/QP1BCm0HHIzbKvgMzqb5sSyH88rzkFk84F4TfJjBU= github.com/grafana/pyroscope-go/godeltaprof v0.1.9 h1:c1Us8i6eSmkW+Ez05d3co8kasnuOY813tbMN8i/a3Og= github.com/grafana/pyroscope-go/godeltaprof v0.1.9/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU= -github.com/grafana/sqlds/v4 v4.2.7 h1:sFQhsS7DBakNMdxa++yOfJ9BVvkZwFJ0B95o57K0/XA= -github.com/grafana/sqlds/v4 v4.2.7/go.mod h1:BQRjUG8rOqrBI4NAaeoWrIMuoNgfi8bdhCJ+5cgEfLU= +github.com/grafana/sqlds/v5 v5.0.3 h1:+yUMUxfa0WANQsmS9xtTFSRX1Q55Iv1B9EjlrW4VlBU= +github.com/grafana/sqlds/v5 v5.0.3/go.mod h1:GKeTTiC+GeR1X0z3f0Iee+hZnNgN62uQpj5XVMx5Uew= 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= @@ -541,8 +541,6 @@ go.opentelemetry.io/contrib/samplers/jaegerremote v0.32.0/go.mod h1:B9Oka5QVD0bn go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= 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= diff --git a/apps/plugins/kinds/meta.cue b/apps/plugins/kinds/meta.cue index d29308e2ca2..479a9111d24 100644 --- a/apps/plugins/kinds/meta.cue +++ b/apps/plugins/kinds/meta.cue @@ -18,9 +18,6 @@ metaV0Alpha1: { type?: "grafana" | "commercial" | "community" | "private" | "private-glob" org?: string } - angular?: { - detected: bool - } translations?: [string]: string // +listType=atomic children?: [...string] @@ -137,7 +134,7 @@ metaV0Alpha1: { type?: "dashboard" | "page" | "panel" | "datasource" name?: string component?: string - role?: "Admin" | "Editor" | "Viewer" + role?: "Admin" | "Editor" | "Viewer" | "None" action?: string path?: string addToNav?: bool @@ -217,6 +214,13 @@ metaV0Alpha1: { title: string description?: string }] + // +listType=atomic + addedFunctions?: [...{ + // +listType=set + targets: [...string] + title: string + description?: string + }] // +listType=set // +listMapKey=id exposedComponents?: [...{ 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 f3671a040db..141e9e5ad82 100644 --- a/apps/plugins/pkg/apis/plugins/v0alpha1/meta_spec_gen.go +++ b/apps/plugins/pkg/apis/plugins/v0alpha1/meta_spec_gen.go @@ -193,6 +193,8 @@ type MetaExtensions struct { AddedComponents []MetaV0alpha1ExtensionsAddedComponents `json:"addedComponents,omitempty"` // +listType=atomic AddedLinks []MetaV0alpha1ExtensionsAddedLinks `json:"addedLinks,omitempty"` + // +listType=atomic + AddedFunctions []MetaV0alpha1ExtensionsAddedFunctions `json:"addedFunctions,omitempty"` // +listType=set // +listMapKey=id ExposedComponents []MetaV0alpha1ExtensionsExposedComponents `json:"exposedComponents,omitempty"` @@ -213,7 +215,6 @@ type MetaSpec struct { 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"` @@ -396,6 +397,21 @@ func NewMetaV0alpha1ExtensionsAddedLinks() *MetaV0alpha1ExtensionsAddedLinks { } } +// +k8s:openapi-gen=true +type MetaV0alpha1ExtensionsAddedFunctions struct { + // +listType=set + Targets []string `json:"targets"` + Title string `json:"title"` + Description *string `json:"description,omitempty"` +} + +// NewMetaV0alpha1ExtensionsAddedFunctions creates a new MetaV0alpha1ExtensionsAddedFunctions object. +func NewMetaV0alpha1ExtensionsAddedFunctions() *MetaV0alpha1ExtensionsAddedFunctions { + return &MetaV0alpha1ExtensionsAddedFunctions{ + Targets: []string{}, + } +} + // +k8s:openapi-gen=true type MetaV0alpha1ExtensionsExposedComponents struct { Id string `json:"id"` @@ -444,16 +460,6 @@ 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 @@ -504,6 +510,7 @@ const ( MetaIncludeRoleAdmin MetaIncludeRole = "Admin" MetaIncludeRoleEditor MetaIncludeRole = "Editor" MetaIncludeRoleViewer MetaIncludeRole = "Viewer" + MetaIncludeRoleNone MetaIncludeRole = "None" ) // +k8s:openapi-gen=true diff --git a/apps/plugins/pkg/apis/plugins_manifest.go b/apps/plugins/pkg/apis/plugins_manifest.go index 7b87dcf0ea7..f37c14ed0cf 100644 --- a/apps/plugins/pkg/apis/plugins_manifest.go +++ b/apps/plugins/pkg/apis/plugins_manifest.go @@ -23,7 +23,7 @@ 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":{"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":{"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"}}`) + 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"},"addedFunctions":{"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","None"],"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":{"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/meta/converter.go b/apps/plugins/pkg/app/meta/converter.go index 28180a263bd..70a1bc78b0c 100644 --- a/apps/plugins/pkg/app/meta/converter.go +++ b/apps/plugins/pkg/app/meta/converter.go @@ -5,6 +5,7 @@ import ( "time" pluginsv0alpha1 "github.com/grafana/grafana/apps/plugins/pkg/apis/plugins/v0alpha1" + "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore" ) @@ -253,12 +254,14 @@ func jsonDataToMetaJSONData(jsonData plugins.JSONData) pluginsv0alpha1.MetaJSOND if include.Role != "" { var role pluginsv0alpha1.MetaIncludeRole switch include.Role { - case "Admin": + case identity.RoleAdmin: role = pluginsv0alpha1.MetaIncludeRoleAdmin - case "Editor": + case identity.RoleEditor: role = pluginsv0alpha1.MetaIncludeRoleEditor - case "Viewer": + case identity.RoleViewer: role = pluginsv0alpha1.MetaIncludeRoleViewer + case identity.RoleNone: + role = pluginsv0alpha1.MetaIncludeRoleNone } v0Include.Role = &role } @@ -364,7 +367,8 @@ func jsonDataToMetaJSONData(jsonData plugins.JSONData) pluginsv0alpha1.MetaJSOND // Map Extensions if len(jsonData.Extensions.AddedLinks) > 0 || len(jsonData.Extensions.AddedComponents) > 0 || - len(jsonData.Extensions.ExposedComponents) > 0 || len(jsonData.Extensions.ExtensionPoints) > 0 { + len(jsonData.Extensions.ExposedComponents) > 0 || len(jsonData.Extensions.ExtensionPoints) > 0 || + len(jsonData.Extensions.AddedFunctions) > 0 { extensions := &pluginsv0alpha1.MetaExtensions{} if len(jsonData.Extensions.AddedLinks) > 0 { @@ -395,6 +399,20 @@ func jsonDataToMetaJSONData(jsonData plugins.JSONData) pluginsv0alpha1.MetaJSOND } } + if len(jsonData.Extensions.AddedFunctions) > 0 { + extensions.AddedFunctions = make([]pluginsv0alpha1.MetaV0alpha1ExtensionsAddedFunctions, 0, len(jsonData.Extensions.AddedFunctions)) + for _, comp := range jsonData.Extensions.AddedFunctions { + v0Comp := pluginsv0alpha1.MetaV0alpha1ExtensionsAddedFunctions{ + Targets: comp.Targets, + Title: comp.Title, + } + if comp.Description != "" { + v0Comp.Description = &comp.Description + } + extensions.AddedFunctions = append(extensions.AddedFunctions, v0Comp) + } + } + if len(jsonData.Extensions.ExposedComponents) > 0 { extensions.ExposedComponents = make([]pluginsv0alpha1.MetaV0alpha1ExtensionsExposedComponents, 0, len(jsonData.Extensions.ExposedComponents)) for _, comp := range jsonData.Extensions.ExposedComponents { @@ -547,10 +565,6 @@ func pluginStorePluginToMeta(plugin pluginstore.Plugin, loadingStrategy plugins. metaSpec.Children = plugin.Children } - metaSpec.Angular = &pluginsv0alpha1.MetaV0alpha1SpecAngular{ - Detected: plugin.Angular.Detected, - } - if len(plugin.Translations) > 0 { metaSpec.Translations = plugin.Translations } @@ -650,10 +664,6 @@ func pluginToMetaSpec(plugin *plugins.Plugin) pluginsv0alpha1.MetaSpec { metaSpec.Children = children } - metaSpec.Angular = &pluginsv0alpha1.MetaV0alpha1SpecAngular{ - Detected: plugin.Angular.Detected, - } - if len(plugin.Translations) > 0 { metaSpec.Translations = plugin.Translations } @@ -694,8 +704,7 @@ type grafanaComPluginVersionMeta struct { Rel string `json:"rel"` Href string `json:"href"` } `json:"links"` - AngularDetected bool `json:"angularDetected"` - Scopes []string `json:"scopes"` + Scopes []string `json:"scopes"` } // grafanaComPluginVersionMetaToMetaSpec converts a grafanaComPluginVersionMeta to a pluginsv0alpha1.MetaSpec. @@ -735,10 +744,5 @@ func grafanaComPluginVersionMetaToMetaSpec(gcomMeta grafanaComPluginVersionMeta) 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 9fb167d5578..1837386f7a3 100644 --- a/apps/plugins/pkg/app/meta/core.go +++ b/apps/plugins/pkg/app/meta/core.go @@ -20,7 +20,7 @@ import ( "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" + "github.com/grafana/grafana/pkg/plugins/pluginerrs" ) const ( diff --git a/apps/provisioning/pkg/apis/provisioning/v0alpha1/connections.go b/apps/provisioning/pkg/apis/provisioning/v0alpha1/connections.go index 228523f598e..2738af49db1 100644 --- a/apps/provisioning/pkg/apis/provisioning/v0alpha1/connections.go +++ b/apps/provisioning/pkg/apis/provisioning/v0alpha1/connections.go @@ -32,7 +32,7 @@ type ConnectionSecure struct { // Token is the reference of the token used to act as the Connection. // This value is stored securely and cannot be read back - Token common.InlineSecureValue `json:"webhook,omitzero,omitempty"` + Token common.InlineSecureValue `json:"token,omitzero,omitempty"` } func (v ConnectionSecure) IsZero() bool { @@ -116,3 +116,26 @@ type ConnectionList struct { // +listType=atomic Items []Connection `json:"items"` } + +// ExternalRepositoryList lists repositories from an external git provider +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type ExternalRepositoryList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + + // +listType=atomic + Items []ExternalRepository `json:"items"` +} + +type ExternalRepository struct { + // Name of the repository + Name string `json:"name"` + // Owner is the user, organization, or workspace that owns the repository + // For GitHub: organization or user + // For GitLab: namespace (user or group) + // For Bitbucket: workspace + // For pure Git: empty + Owner string `json:"owner,omitempty"` + // URL of the repository + URL string `json:"url"` +} diff --git a/apps/provisioning/pkg/apis/provisioning/v0alpha1/register.go b/apps/provisioning/pkg/apis/provisioning/v0alpha1/register.go index f06798c0ddd..c1785a048d1 100644 --- a/apps/provisioning/pkg/apis/provisioning/v0alpha1/register.go +++ b/apps/provisioning/pkg/apis/provisioning/v0alpha1/register.go @@ -197,6 +197,7 @@ func AddKnownTypes(gv schema.GroupVersion, scheme *runtime.Scheme) error { &HistoricJobList{}, &Connection{}, &ConnectionList{}, + &ExternalRepositoryList{}, ) return nil } 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 48d03d23f99..97b1e752f68 100644 --- a/apps/provisioning/pkg/apis/provisioning/v0alpha1/zz_generated.deepcopy.go +++ b/apps/provisioning/pkg/apis/provisioning/v0alpha1/zz_generated.deepcopy.go @@ -262,6 +262,53 @@ func (in *ExportJobOptions) DeepCopy() *ExportJobOptions { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExternalRepository) DeepCopyInto(out *ExternalRepository) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalRepository. +func (in *ExternalRepository) DeepCopy() *ExternalRepository { + if in == nil { + return nil + } + out := new(ExternalRepository) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExternalRepositoryList) DeepCopyInto(out *ExternalRepositoryList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ExternalRepository, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalRepositoryList. +func (in *ExternalRepositoryList) DeepCopy() *ExternalRepositoryList { + if in == nil { + return nil + } + out := new(ExternalRepositoryList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ExternalRepositoryList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *FileItem) DeepCopyInto(out *FileItem) { *out = *in 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 a96fa2d8a6b..4db11489c98 100644 --- a/apps/provisioning/pkg/apis/provisioning/v0alpha1/zz_generated.openapi.go +++ b/apps/provisioning/pkg/apis/provisioning/v0alpha1/zz_generated.openapi.go @@ -26,6 +26,8 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.DeleteJobOptions": schema_pkg_apis_provisioning_v0alpha1_DeleteJobOptions(ref), "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.ErrorDetails": schema_pkg_apis_provisioning_v0alpha1_ErrorDetails(ref), "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.ExportJobOptions": schema_pkg_apis_provisioning_v0alpha1_ExportJobOptions(ref), + "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.ExternalRepository": schema_pkg_apis_provisioning_v0alpha1_ExternalRepository(ref), + "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.ExternalRepositoryList": schema_pkg_apis_provisioning_v0alpha1_ExternalRepositoryList(ref), "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.FileItem": schema_pkg_apis_provisioning_v0alpha1_FileItem(ref), "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.FileList": schema_pkg_apis_provisioning_v0alpha1_FileList(ref), "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.GitHubConnectionConfig": schema_pkg_apis_provisioning_v0alpha1_GitHubConnectionConfig(ref), @@ -318,7 +320,7 @@ func schema_pkg_apis_provisioning_v0alpha1_ConnectionSecure(ref common.Reference Ref: ref("github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.InlineSecureValue"), }, }, - "webhook": { + "token": { SchemaProps: spec.SchemaProps{ Description: "Token is the reference of the token used to act as the Connection. This value is stored securely and cannot be read back", Default: map[string]interface{}{}, @@ -544,6 +546,96 @@ func schema_pkg_apis_provisioning_v0alpha1_ExportJobOptions(ref common.Reference } } +func schema_pkg_apis_provisioning_v0alpha1_ExternalRepository(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{ + Description: "Name of the repository", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "owner": { + SchemaProps: spec.SchemaProps{ + Description: "Owner is the user, organization, or workspace that owns the repository For GitHub: organization or user For GitLab: namespace (user or group) For Bitbucket: workspace For pure Git: empty", + Type: []string{"string"}, + Format: "", + }, + }, + "url": { + SchemaProps: spec.SchemaProps{ + Description: "URL of the repository", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"name", "url"}, + }, + }, + } +} + +func schema_pkg_apis_provisioning_v0alpha1_ExternalRepositoryList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ExternalRepositoryList lists repositories from an external git provider", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.ExternalRepository"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.ExternalRepository", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + } +} + func schema_pkg_apis_provisioning_v0alpha1_FileItem(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/apps/provisioning/pkg/apis/provisioning/v0alpha1/zz_generated.openapi_violation_exceptions.list b/apps/provisioning/pkg/apis/provisioning/v0alpha1/zz_generated.openapi_violation_exceptions.list index b9504855b80..72567e04b90 100644 --- a/apps/provisioning/pkg/apis/provisioning/v0alpha1/zz_generated.openapi_violation_exceptions.list +++ b/apps/provisioning/pkg/apis/provisioning/v0alpha1/zz_generated.openapi_violation_exceptions.list @@ -1,6 +1,7 @@ API rule violation: list_type_missing,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,ConnectionList,Items API rule violation: list_type_missing,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,DeleteJobOptions,Paths API rule violation: list_type_missing,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,DeleteJobOptions,Resources +API rule violation: list_type_missing,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,ExternalRepositoryList,Items API rule violation: list_type_missing,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,FileList,Items API rule violation: list_type_missing,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,HistoryList,Items API rule violation: list_type_missing,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,JobResourceSummary,Errors @@ -21,7 +22,6 @@ API rule violation: list_type_missing,github.com/grafana/grafana/apps/provisioni API rule violation: list_type_missing,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,ResourceList,Items API rule violation: list_type_missing,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,TestResults,Errors API rule violation: list_type_missing,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,WebhookStatus,SubscribedEvents -API rule violation: names_match,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,ConnectionSecure,Token API rule violation: names_match,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,ConnectionSpec,GitHub API rule violation: names_match,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,JobSpec,PullRequest API rule violation: names_match,github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1,JobStatus,URLs diff --git a/apps/provisioning/pkg/connection/connection.go b/apps/provisioning/pkg/connection/connection.go new file mode 100644 index 00000000000..d2043b5af4a --- /dev/null +++ b/apps/provisioning/pkg/connection/connection.go @@ -0,0 +1,16 @@ +package connection + +import ( + "context" +) + +//go:generate mockery --name Connection --structname MockConnection --inpackage --filename connection_mock.go --with-expecter +type Connection interface { + // Validate ensures the resource _looks_ correct. + // It should be called before trying to upsert a resource into the Kubernetes API server. + // This is not an indication that the connection information works, just that they are reasonably configured. + Validate(ctx context.Context) error + + // Mutate performs in place mutation of the underneath resource. + Mutate(context.Context) error +} diff --git a/apps/provisioning/pkg/connection/connection_mock.go b/apps/provisioning/pkg/connection/connection_mock.go new file mode 100644 index 00000000000..3867059d432 --- /dev/null +++ b/apps/provisioning/pkg/connection/connection_mock.go @@ -0,0 +1,128 @@ +// Code generated by mockery v2.53.4. DO NOT EDIT. + +package connection + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" +) + +// MockConnection is an autogenerated mock type for the Connection type +type MockConnection struct { + mock.Mock +} + +type MockConnection_Expecter struct { + mock *mock.Mock +} + +func (_m *MockConnection) EXPECT() *MockConnection_Expecter { + return &MockConnection_Expecter{mock: &_m.Mock} +} + +// Mutate provides a mock function with given fields: _a0 +func (_m *MockConnection) Mutate(_a0 context.Context) error { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for Mutate") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(_a0) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockConnection_Mutate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Mutate' +type MockConnection_Mutate_Call struct { + *mock.Call +} + +// Mutate is a helper method to define mock.On call +// - _a0 context.Context +func (_e *MockConnection_Expecter) Mutate(_a0 interface{}) *MockConnection_Mutate_Call { + return &MockConnection_Mutate_Call{Call: _e.mock.On("Mutate", _a0)} +} + +func (_c *MockConnection_Mutate_Call) Run(run func(_a0 context.Context)) *MockConnection_Mutate_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *MockConnection_Mutate_Call) Return(_a0 error) *MockConnection_Mutate_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockConnection_Mutate_Call) RunAndReturn(run func(context.Context) error) *MockConnection_Mutate_Call { + _c.Call.Return(run) + return _c +} + +// Validate provides a mock function with given fields: ctx +func (_m *MockConnection) Validate(ctx context.Context) error { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for Validate") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockConnection_Validate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Validate' +type MockConnection_Validate_Call struct { + *mock.Call +} + +// Validate is a helper method to define mock.On call +// - ctx context.Context +func (_e *MockConnection_Expecter) Validate(ctx interface{}) *MockConnection_Validate_Call { + return &MockConnection_Validate_Call{Call: _e.mock.On("Validate", ctx)} +} + +func (_c *MockConnection_Validate_Call) Run(run func(ctx context.Context)) *MockConnection_Validate_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *MockConnection_Validate_Call) Return(_a0 error) *MockConnection_Validate_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockConnection_Validate_Call) RunAndReturn(run func(context.Context) error) *MockConnection_Validate_Call { + _c.Call.Return(run) + return _c +} + +// NewMockConnection creates a new instance of MockConnection. 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 NewMockConnection(t interface { + mock.TestingT + Cleanup(func()) +}) *MockConnection { + mock := &MockConnection{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/apps/provisioning/pkg/connection/extra_mock.go b/apps/provisioning/pkg/connection/extra_mock.go new file mode 100644 index 00000000000..cc2a1f3d5e2 --- /dev/null +++ b/apps/provisioning/pkg/connection/extra_mock.go @@ -0,0 +1,141 @@ +// Code generated by mockery v2.53.4. DO NOT EDIT. + +package connection + +import ( + context "context" + + v0alpha1 "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1" + mock "github.com/stretchr/testify/mock" +) + +// MockExtra is an autogenerated mock type for the Extra type +type MockExtra struct { + mock.Mock +} + +type MockExtra_Expecter struct { + mock *mock.Mock +} + +func (_m *MockExtra) EXPECT() *MockExtra_Expecter { + return &MockExtra_Expecter{mock: &_m.Mock} +} + +// Build provides a mock function with given fields: ctx, r +func (_m *MockExtra) Build(ctx context.Context, r *v0alpha1.Connection) (Connection, error) { + ret := _m.Called(ctx, r) + + if len(ret) == 0 { + panic("no return value specified for Build") + } + + var r0 Connection + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *v0alpha1.Connection) (Connection, error)); ok { + return rf(ctx, r) + } + if rf, ok := ret.Get(0).(func(context.Context, *v0alpha1.Connection) Connection); ok { + r0 = rf(ctx, r) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(Connection) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *v0alpha1.Connection) error); ok { + r1 = rf(ctx, r) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockExtra_Build_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Build' +type MockExtra_Build_Call struct { + *mock.Call +} + +// Build is a helper method to define mock.On call +// - ctx context.Context +// - r *v0alpha1.Connection +func (_e *MockExtra_Expecter) Build(ctx interface{}, r interface{}) *MockExtra_Build_Call { + return &MockExtra_Build_Call{Call: _e.mock.On("Build", ctx, r)} +} + +func (_c *MockExtra_Build_Call) Run(run func(ctx context.Context, r *v0alpha1.Connection)) *MockExtra_Build_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*v0alpha1.Connection)) + }) + return _c +} + +func (_c *MockExtra_Build_Call) Return(_a0 Connection, _a1 error) *MockExtra_Build_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockExtra_Build_Call) RunAndReturn(run func(context.Context, *v0alpha1.Connection) (Connection, error)) *MockExtra_Build_Call { + _c.Call.Return(run) + return _c +} + +// Type provides a mock function with no fields +func (_m *MockExtra) Type() v0alpha1.ConnectionType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Type") + } + + var r0 v0alpha1.ConnectionType + if rf, ok := ret.Get(0).(func() v0alpha1.ConnectionType); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(v0alpha1.ConnectionType) + } + + return r0 +} + +// MockExtra_Type_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Type' +type MockExtra_Type_Call struct { + *mock.Call +} + +// Type is a helper method to define mock.On call +func (_e *MockExtra_Expecter) Type() *MockExtra_Type_Call { + return &MockExtra_Type_Call{Call: _e.mock.On("Type")} +} + +func (_c *MockExtra_Type_Call) Run(run func()) *MockExtra_Type_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockExtra_Type_Call) Return(_a0 v0alpha1.ConnectionType) *MockExtra_Type_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockExtra_Type_Call) RunAndReturn(run func() v0alpha1.ConnectionType) *MockExtra_Type_Call { + _c.Call.Return(run) + return _c +} + +// NewMockExtra creates a new instance of MockExtra. 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 NewMockExtra(t interface { + mock.TestingT + Cleanup(func()) +}) *MockExtra { + mock := &MockExtra{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/apps/provisioning/pkg/connection/factory.go b/apps/provisioning/pkg/connection/factory.go new file mode 100644 index 00000000000..4a0e46d84d2 --- /dev/null +++ b/apps/provisioning/pkg/connection/factory.go @@ -0,0 +1,75 @@ +package connection + +import ( + "context" + "fmt" + "sort" + + provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1" +) + +//go:generate mockery --name=Extra --structname=MockExtra --inpackage --filename=extra_mock.go --with-expecter +type Extra interface { + Type() provisioning.ConnectionType + Build(ctx context.Context, r *provisioning.Connection) (Connection, error) +} + +//go:generate mockery --name=Factory --structname=MockFactory --inpackage --filename=factory_mock.go --with-expecter +type Factory interface { + Types() []provisioning.ConnectionType + Build(ctx context.Context, r *provisioning.Connection) (Connection, error) +} + +type factory struct { + extras map[provisioning.ConnectionType]Extra + enabled map[provisioning.ConnectionType]struct{} +} + +func ProvideFactory(enabled map[provisioning.ConnectionType]struct{}, extras []Extra) (Factory, error) { + f := &factory{ + enabled: enabled, + extras: make(map[provisioning.ConnectionType]Extra, len(extras)), + } + + for _, e := range extras { + if _, exists := f.extras[e.Type()]; exists { + return nil, fmt.Errorf("connection type %q is already registered", e.Type()) + } + f.extras[e.Type()] = e + } + + return f, nil +} + +func (f *factory) Types() []provisioning.ConnectionType { + var types []provisioning.ConnectionType + for t := range f.enabled { + if _, exists := f.extras[t]; exists { + types = append(types, t) + } + } + + sort.Slice(types, func(i, j int) bool { + return string(types[i]) < string(types[j]) + }) + + return types +} + +func (f *factory) Build(ctx context.Context, c *provisioning.Connection) (Connection, error) { + for _, e := range f.extras { + if e.Type() == c.Spec.Type { + if _, enabled := f.enabled[e.Type()]; !enabled { + return nil, fmt.Errorf("connection type %q is not enabled", e.Type()) + } + + return e.Build(ctx, c) + } + } + + return nil, fmt.Errorf("connection type %q is not supported", c.Spec.Type) +} + +var ( + _ Factory = (*factory)(nil) +) diff --git a/apps/provisioning/pkg/connection/factory_mock.go b/apps/provisioning/pkg/connection/factory_mock.go new file mode 100644 index 00000000000..8fd7023920f --- /dev/null +++ b/apps/provisioning/pkg/connection/factory_mock.go @@ -0,0 +1,143 @@ +// Code generated by mockery v2.53.4. DO NOT EDIT. + +package connection + +import ( + context "context" + + v0alpha1 "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1" + mock "github.com/stretchr/testify/mock" +) + +// MockFactory is an autogenerated mock type for the Factory type +type MockFactory struct { + mock.Mock +} + +type MockFactory_Expecter struct { + mock *mock.Mock +} + +func (_m *MockFactory) EXPECT() *MockFactory_Expecter { + return &MockFactory_Expecter{mock: &_m.Mock} +} + +// Build provides a mock function with given fields: ctx, r +func (_m *MockFactory) Build(ctx context.Context, r *v0alpha1.Connection) (Connection, error) { + ret := _m.Called(ctx, r) + + if len(ret) == 0 { + panic("no return value specified for Build") + } + + var r0 Connection + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *v0alpha1.Connection) (Connection, error)); ok { + return rf(ctx, r) + } + if rf, ok := ret.Get(0).(func(context.Context, *v0alpha1.Connection) Connection); ok { + r0 = rf(ctx, r) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(Connection) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *v0alpha1.Connection) error); ok { + r1 = rf(ctx, r) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockFactory_Build_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Build' +type MockFactory_Build_Call struct { + *mock.Call +} + +// Build is a helper method to define mock.On call +// - ctx context.Context +// - r *v0alpha1.Connection +func (_e *MockFactory_Expecter) Build(ctx interface{}, r interface{}) *MockFactory_Build_Call { + return &MockFactory_Build_Call{Call: _e.mock.On("Build", ctx, r)} +} + +func (_c *MockFactory_Build_Call) Run(run func(ctx context.Context, r *v0alpha1.Connection)) *MockFactory_Build_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*v0alpha1.Connection)) + }) + return _c +} + +func (_c *MockFactory_Build_Call) Return(_a0 Connection, _a1 error) *MockFactory_Build_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockFactory_Build_Call) RunAndReturn(run func(context.Context, *v0alpha1.Connection) (Connection, error)) *MockFactory_Build_Call { + _c.Call.Return(run) + return _c +} + +// Types provides a mock function with no fields +func (_m *MockFactory) Types() []v0alpha1.ConnectionType { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Types") + } + + var r0 []v0alpha1.ConnectionType + if rf, ok := ret.Get(0).(func() []v0alpha1.ConnectionType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]v0alpha1.ConnectionType) + } + } + + return r0 +} + +// MockFactory_Types_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Types' +type MockFactory_Types_Call struct { + *mock.Call +} + +// Types is a helper method to define mock.On call +func (_e *MockFactory_Expecter) Types() *MockFactory_Types_Call { + return &MockFactory_Types_Call{Call: _e.mock.On("Types")} +} + +func (_c *MockFactory_Types_Call) Run(run func()) *MockFactory_Types_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockFactory_Types_Call) Return(_a0 []v0alpha1.ConnectionType) *MockFactory_Types_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockFactory_Types_Call) RunAndReturn(run func() []v0alpha1.ConnectionType) *MockFactory_Types_Call { + _c.Call.Return(run) + return _c +} + +// NewMockFactory creates a new instance of MockFactory. 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 NewMockFactory(t interface { + mock.TestingT + Cleanup(func()) +}) *MockFactory { + mock := &MockFactory{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/apps/provisioning/pkg/connection/factory_test.go b/apps/provisioning/pkg/connection/factory_test.go new file mode 100644 index 00000000000..4ce6bc96e0e --- /dev/null +++ b/apps/provisioning/pkg/connection/factory_test.go @@ -0,0 +1,309 @@ +package connection + +import ( + "context" + "errors" + "testing" + + provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestProvideFactory(t *testing.T) { + t.Run("should create factory with valid extras", func(t *testing.T) { + extra1 := NewMockExtra(t) + extra1.EXPECT().Type().Return(provisioning.GithubConnectionType) + + extra2 := NewMockExtra(t) + extra2.EXPECT().Type().Return(provisioning.GitlabConnectionType) + + enabled := map[provisioning.ConnectionType]struct{}{ + provisioning.GithubConnectionType: {}, + provisioning.GitlabConnectionType: {}, + } + + factory, err := ProvideFactory(enabled, []Extra{extra1, extra2}) + require.NoError(t, err) + require.NotNil(t, factory) + }) + + t.Run("should create factory with empty extras", func(t *testing.T) { + enabled := map[provisioning.ConnectionType]struct{}{} + + factory, err := ProvideFactory(enabled, []Extra{}) + require.NoError(t, err) + require.NotNil(t, factory) + }) + + t.Run("should create factory with nil enabled map", func(t *testing.T) { + extra1 := NewMockExtra(t) + extra1.EXPECT().Type().Return(provisioning.GithubConnectionType) + + factory, err := ProvideFactory(nil, []Extra{extra1}) + require.NoError(t, err) + require.NotNil(t, factory) + }) + + t.Run("should return error when duplicate repository types", func(t *testing.T) { + extra1 := NewMockExtra(t) + extra1.EXPECT().Type().Return(provisioning.GithubConnectionType) + + extra2 := NewMockExtra(t) + extra2.EXPECT().Type().Return(provisioning.GithubConnectionType) + + enabled := map[provisioning.ConnectionType]struct{}{ + provisioning.GithubConnectionType: {}, + } + + factory, err := ProvideFactory(enabled, []Extra{extra1, extra2}) + require.Error(t, err) + assert.Nil(t, factory) + assert.Contains(t, err.Error(), "connection type \"github\" is already registered") + }) +} + +func TestFactory_Types(t *testing.T) { + t.Run("should return only enabled types that have extras", func(t *testing.T) { + extra1 := NewMockExtra(t) + extra1.EXPECT().Type().Return(provisioning.GithubConnectionType) + + extra2 := NewMockExtra(t) + extra2.EXPECT().Type().Return(provisioning.GitlabConnectionType) + + enabled := map[provisioning.ConnectionType]struct{}{ + provisioning.GithubConnectionType: {}, + provisioning.GitlabConnectionType: {}, + } + + factory, err := ProvideFactory(enabled, []Extra{extra1, extra2}) + require.NoError(t, err) + + types := factory.Types() + assert.Len(t, types, 2) + assert.Contains(t, types, provisioning.GithubConnectionType) + assert.Contains(t, types, provisioning.GitlabConnectionType) + }) + + t.Run("should return sorted list of types", func(t *testing.T) { + extra1 := NewMockExtra(t) + extra1.EXPECT().Type().Return(provisioning.GitlabConnectionType) + + extra2 := NewMockExtra(t) + extra2.EXPECT().Type().Return(provisioning.GithubConnectionType) + + enabled := map[provisioning.ConnectionType]struct{}{ + provisioning.GithubConnectionType: {}, + provisioning.GitlabConnectionType: {}, + } + + factory, err := ProvideFactory(enabled, []Extra{extra1, extra2}) + require.NoError(t, err) + + types := factory.Types() + assert.Len(t, types, 2) + // github should come before gitlab alphabetically + assert.Equal(t, provisioning.GithubConnectionType, types[0]) + assert.Equal(t, provisioning.GitlabConnectionType, types[1]) + }) + + t.Run("should return empty list when no types are enabled", func(t *testing.T) { + extra1 := NewMockExtra(t) + extra1.EXPECT().Type().Return(provisioning.GithubConnectionType) + + enabled := map[provisioning.ConnectionType]struct{}{} + + factory, err := ProvideFactory(enabled, []Extra{extra1}) + require.NoError(t, err) + + types := factory.Types() + assert.Empty(t, types) + }) + + t.Run("should not return types that are enabled but have no extras", func(t *testing.T) { + extra1 := NewMockExtra(t) + extra1.EXPECT().Type().Return(provisioning.GithubConnectionType) + + enabled := map[provisioning.ConnectionType]struct{}{ + provisioning.GithubConnectionType: {}, + provisioning.GitlabConnectionType: {}, + } + + factory, err := ProvideFactory(enabled, []Extra{extra1}) + require.NoError(t, err) + + types := factory.Types() + assert.Len(t, types, 1) + assert.Contains(t, types, provisioning.GithubConnectionType) + assert.NotContains(t, types, provisioning.GitlabConnectionType) + }) + + t.Run("should not return types that have extras but are not enabled", func(t *testing.T) { + extra1 := NewMockExtra(t) + extra1.EXPECT().Type().Return(provisioning.GithubConnectionType) + + extra2 := NewMockExtra(t) + extra2.EXPECT().Type().Return(provisioning.GitlabConnectionType) + + enabled := map[provisioning.ConnectionType]struct{}{ + provisioning.GithubConnectionType: {}, + } + + factory, err := ProvideFactory(enabled, []Extra{extra1, extra2}) + require.NoError(t, err) + + types := factory.Types() + assert.Len(t, types, 1) + assert.Contains(t, types, provisioning.GithubConnectionType) + assert.NotContains(t, types, provisioning.GitlabConnectionType) + }) + + t.Run("should return empty list when no extras are provided", func(t *testing.T) { + enabled := map[provisioning.ConnectionType]struct{}{ + provisioning.GithubConnectionType: {}, + } + + factory, err := ProvideFactory(enabled, []Extra{}) + require.NoError(t, err) + + types := factory.Types() + assert.Empty(t, types) + }) +} + +func TestFactory_Build(t *testing.T) { + t.Run("should successfully build connection when type is enabled and has extra", func(t *testing.T) { + ctx := context.Background() + conn := &provisioning.Connection{ + ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, + Spec: provisioning.ConnectionSpec{ + Type: provisioning.GithubConnectionType, + }, + } + + mockConnection := NewMockConnection(t) + extra := NewMockExtra(t) + extra.EXPECT().Type().Return(provisioning.GithubConnectionType) + extra.EXPECT().Build(ctx, conn).Return(mockConnection, nil) + + enabled := map[provisioning.ConnectionType]struct{}{ + provisioning.GithubConnectionType: {}, + } + + factory, err := ProvideFactory(enabled, []Extra{extra}) + require.NoError(t, err) + + result, err := factory.Build(ctx, conn) + require.NoError(t, err) + assert.Equal(t, mockConnection, result) + }) + + t.Run("should return error when type is not enabled", func(t *testing.T) { + ctx := context.Background() + conn := &provisioning.Connection{ + ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, + Spec: provisioning.ConnectionSpec{ + Type: provisioning.GitlabConnectionType, + }, + } + + extra := NewMockExtra(t) + extra.EXPECT().Type().Return(provisioning.GitlabConnectionType) + + enabled := map[provisioning.ConnectionType]struct{}{ + provisioning.GithubConnectionType: {}, + } + + factory, err := ProvideFactory(enabled, []Extra{extra}) + require.NoError(t, err) + + result, err := factory.Build(ctx, conn) + require.Error(t, err) + assert.Nil(t, result) + assert.Contains(t, err.Error(), "connection type \"gitlab\" is not enabled") + }) + + t.Run("should return error when type is not supported", func(t *testing.T) { + ctx := context.Background() + conn := &provisioning.Connection{ + ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, + Spec: provisioning.ConnectionSpec{ + Type: provisioning.GitlabConnectionType, + }, + } + + extra := NewMockExtra(t) + extra.EXPECT().Type().Return(provisioning.GithubConnectionType) + + enabled := map[provisioning.ConnectionType]struct{}{ + provisioning.GithubConnectionType: {}, + } + + factory, err := ProvideFactory(enabled, []Extra{extra}) + require.NoError(t, err) + + result, err := factory.Build(ctx, conn) + require.Error(t, err) + assert.Nil(t, result) + assert.Contains(t, err.Error(), "connection type \"gitlab\" is not supported") + }) + + t.Run("should pass through errors from extra.Build()", func(t *testing.T) { + ctx := context.Background() + conn := &provisioning.Connection{ + ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, + Spec: provisioning.ConnectionSpec{ + Type: provisioning.GithubConnectionType, + }, + } + + expectedErr := errors.New("build error") + extra := NewMockExtra(t) + extra.EXPECT().Type().Return(provisioning.GithubConnectionType) + extra.EXPECT().Build(ctx, conn).Return(nil, expectedErr) + + enabled := map[provisioning.ConnectionType]struct{}{ + provisioning.GithubConnectionType: {}, + } + + factory, err := ProvideFactory(enabled, []Extra{extra}) + require.NoError(t, err) + + result, err := factory.Build(ctx, conn) + require.Error(t, err) + assert.Nil(t, result) + assert.Equal(t, expectedErr, err) + }) + + t.Run("should build with multiple extras registered", func(t *testing.T) { + ctx := context.Background() + conn := &provisioning.Connection{ + ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, + Spec: provisioning.ConnectionSpec{ + Type: provisioning.GitlabConnectionType, + }, + } + + mockConnection := NewMockConnection(t) + + extra1 := NewMockExtra(t) + extra1.EXPECT().Type().Return(provisioning.GithubConnectionType) + + extra2 := NewMockExtra(t) + extra2.EXPECT().Type().Return(provisioning.GitlabConnectionType) + extra2.EXPECT().Build(ctx, conn).Return(mockConnection, nil) + + enabled := map[provisioning.ConnectionType]struct{}{ + provisioning.GithubConnectionType: {}, + provisioning.GitlabConnectionType: {}, + } + + factory, err := ProvideFactory(enabled, []Extra{extra1, extra2}) + require.NoError(t, err) + + result, err := factory.Build(ctx, conn) + require.NoError(t, err) + assert.Equal(t, mockConnection, result) + }) +} diff --git a/apps/provisioning/pkg/connection/github/client.go b/apps/provisioning/pkg/connection/github/client.go new file mode 100644 index 00000000000..7ddb9a4665e --- /dev/null +++ b/apps/provisioning/pkg/connection/github/client.go @@ -0,0 +1,93 @@ +package github + +import ( + "context" + "errors" + "fmt" + "net/http" + "strconv" + + "github.com/google/go-github/v70/github" + apierrors "k8s.io/apimachinery/pkg/api/errors" +) + +// API errors that we need to convey after parsing real GH errors (or faking them). +var ( + //lint:ignore ST1005 this is not punctuation + ErrServiceUnavailable = apierrors.NewServiceUnavailable("github is unavailable") +) + +//go:generate mockery --name Client --structname MockClient --inpackage --filename client_mock.go --with-expecter +type Client interface { + // Apps and installations + GetApp(ctx context.Context) (App, error) + GetAppInstallation(ctx context.Context, installationID string) (AppInstallation, error) +} + +// App represents a Github App. +type App struct { + // ID represents the GH app ID. + ID int64 + // Slug represents the GH app slug. + Slug string + // Owner represents the GH account/org owning the app + Owner string +} + +// AppInstallation represents a Github App Installation. +type AppInstallation struct { + // ID represents the GH installation ID. + ID int64 + // Whether the installation is enabled or not. + Enabled bool +} + +type githubClient struct { + gh *github.Client +} + +func NewClient(client *github.Client) Client { + return &githubClient{client} +} + +// GetApp gets the app by using the given token. +func (r *githubClient) GetApp(ctx context.Context) (App, error) { + app, _, err := r.gh.Apps.Get(ctx, "") + if err != nil { + var ghErr *github.ErrorResponse + if errors.As(err, &ghErr) && ghErr.Response.StatusCode == http.StatusServiceUnavailable { + return App{}, ErrServiceUnavailable + } + return App{}, err + } + + // TODO(ferruvich): do we need any other info? + return App{ + ID: app.GetID(), + Slug: app.GetSlug(), + Owner: app.GetOwner().GetLogin(), + }, nil +} + +// GetAppInstallation gets the installation of the app related to the given token. +func (r *githubClient) GetAppInstallation(ctx context.Context, installationID string) (AppInstallation, error) { + id, err := strconv.Atoi(installationID) + if err != nil { + return AppInstallation{}, fmt.Errorf("invalid installation ID: %s", installationID) + } + + installation, _, err := r.gh.Apps.GetInstallation(ctx, int64(id)) + if err != nil { + var ghErr *github.ErrorResponse + if errors.As(err, &ghErr) && ghErr.Response.StatusCode == http.StatusServiceUnavailable { + return AppInstallation{}, ErrServiceUnavailable + } + return AppInstallation{}, err + } + + // TODO(ferruvich): do we need any other info? + return AppInstallation{ + ID: installation.GetID(), + Enabled: installation.GetSuspendedAt().IsZero(), + }, nil +} diff --git a/apps/provisioning/pkg/connection/github/client_mock.go b/apps/provisioning/pkg/connection/github/client_mock.go new file mode 100644 index 00000000000..c9f009f5021 --- /dev/null +++ b/apps/provisioning/pkg/connection/github/client_mock.go @@ -0,0 +1,149 @@ +// Code generated by mockery v2.53.4. DO NOT EDIT. + +package github + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" +) + +// MockClient is an autogenerated mock type for the Client type +type MockClient struct { + mock.Mock +} + +type MockClient_Expecter struct { + mock *mock.Mock +} + +func (_m *MockClient) EXPECT() *MockClient_Expecter { + return &MockClient_Expecter{mock: &_m.Mock} +} + +// GetApp provides a mock function with given fields: ctx +func (_m *MockClient) GetApp(ctx context.Context) (App, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetApp") + } + + var r0 App + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (App, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) App); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(App) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockClient_GetApp_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetApp' +type MockClient_GetApp_Call struct { + *mock.Call +} + +// GetApp is a helper method to define mock.On call +// - ctx context.Context +func (_e *MockClient_Expecter) GetApp(ctx interface{}) *MockClient_GetApp_Call { + return &MockClient_GetApp_Call{Call: _e.mock.On("GetApp", ctx)} +} + +func (_c *MockClient_GetApp_Call) Run(run func(ctx context.Context)) *MockClient_GetApp_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *MockClient_GetApp_Call) Return(_a0 App, _a1 error) *MockClient_GetApp_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockClient_GetApp_Call) RunAndReturn(run func(context.Context) (App, error)) *MockClient_GetApp_Call { + _c.Call.Return(run) + return _c +} + +// GetAppInstallation provides a mock function with given fields: ctx, installationID +func (_m *MockClient) GetAppInstallation(ctx context.Context, installationID string) (AppInstallation, error) { + ret := _m.Called(ctx, installationID) + + if len(ret) == 0 { + panic("no return value specified for GetAppInstallation") + } + + var r0 AppInstallation + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (AppInstallation, error)); ok { + return rf(ctx, installationID) + } + if rf, ok := ret.Get(0).(func(context.Context, string) AppInstallation); ok { + r0 = rf(ctx, installationID) + } else { + r0 = ret.Get(0).(AppInstallation) + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, installationID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockClient_GetAppInstallation_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAppInstallation' +type MockClient_GetAppInstallation_Call struct { + *mock.Call +} + +// GetAppInstallation is a helper method to define mock.On call +// - ctx context.Context +// - installationID string +func (_e *MockClient_Expecter) GetAppInstallation(ctx interface{}, installationID interface{}) *MockClient_GetAppInstallation_Call { + return &MockClient_GetAppInstallation_Call{Call: _e.mock.On("GetAppInstallation", ctx, installationID)} +} + +func (_c *MockClient_GetAppInstallation_Call) Run(run func(ctx context.Context, installationID string)) *MockClient_GetAppInstallation_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string)) + }) + return _c +} + +func (_c *MockClient_GetAppInstallation_Call) Return(_a0 AppInstallation, _a1 error) *MockClient_GetAppInstallation_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockClient_GetAppInstallation_Call) RunAndReturn(run func(context.Context, string) (AppInstallation, error)) *MockClient_GetAppInstallation_Call { + _c.Call.Return(run) + return _c +} + +// NewMockClient creates a new instance of MockClient. 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 NewMockClient(t interface { + mock.TestingT + Cleanup(func()) +}) *MockClient { + mock := &MockClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/apps/provisioning/pkg/connection/github/client_test.go b/apps/provisioning/pkg/connection/github/client_test.go new file mode 100644 index 00000000000..bae6d6ac1e9 --- /dev/null +++ b/apps/provisioning/pkg/connection/github/client_test.go @@ -0,0 +1,297 @@ +package github_test + +import ( + "context" + "encoding/json" + "net/http" + "testing" + "time" + + "github.com/google/go-github/v70/github" + conngh "github.com/grafana/grafana/apps/provisioning/pkg/connection/github" + mockhub "github.com/migueleliasweb/go-github-mock/src/mock" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestGithubClient_GetApp(t *testing.T) { + tests := []struct { + name string + mockHandler *http.Client + token string + wantApp conngh.App + wantErr error + }{ + { + name: "get app successfully", + mockHandler: mockhub.NewMockedHTTPClient( + mockhub.WithRequestMatchHandler( + mockhub.GetApp, + http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + app := &github.App{ + ID: github.Ptr(int64(12345)), + Slug: github.Ptr("my-test-app"), + Owner: &github.User{ + Login: github.Ptr("grafana"), + }, + } + w.WriteHeader(http.StatusOK) + require.NoError(t, json.NewEncoder(w).Encode(app)) + }), + ), + ), + token: "test-token", + wantApp: conngh.App{ + ID: 12345, + Slug: "my-test-app", + Owner: "grafana", + }, + wantErr: nil, + }, + { + name: "service unavailable", + mockHandler: mockhub.NewMockedHTTPClient( + mockhub.WithRequestMatchHandler( + mockhub.GetApp, + http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusServiceUnavailable) + require.NoError(t, json.NewEncoder(w).Encode(github.ErrorResponse{ + Response: &http.Response{ + StatusCode: http.StatusServiceUnavailable, + }, + Message: "Service unavailable", + })) + }), + ), + ), + token: "test-token", + wantApp: conngh.App{}, + wantErr: conngh.ErrServiceUnavailable, + }, + { + name: "other error", + mockHandler: mockhub.NewMockedHTTPClient( + mockhub.WithRequestMatchHandler( + mockhub.GetApp, + http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + require.NoError(t, json.NewEncoder(w).Encode(github.ErrorResponse{ + Response: &http.Response{ + StatusCode: http.StatusInternalServerError, + }, + Message: "Internal server error", + })) + }), + ), + ), + token: "test-token", + wantApp: conngh.App{}, + wantErr: &github.ErrorResponse{ + Response: &http.Response{ + StatusCode: http.StatusInternalServerError, + }, + Message: "Internal server error", + }, + }, + { + name: "unauthorized error", + mockHandler: mockhub.NewMockedHTTPClient( + mockhub.WithRequestMatchHandler( + mockhub.GetApp, + http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusUnauthorized) + require.NoError(t, json.NewEncoder(w).Encode(github.ErrorResponse{ + Response: &http.Response{ + StatusCode: http.StatusUnauthorized, + }, + Message: "Bad credentials", + })) + }), + ), + ), + token: "invalid-token", + wantApp: conngh.App{}, + wantErr: &github.ErrorResponse{ + Response: &http.Response{ + StatusCode: http.StatusUnauthorized, + }, + Message: "Bad credentials", + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a mock client + ghClient := github.NewClient(tt.mockHandler) + client := conngh.NewClient(ghClient) + + // Call the method being tested + app, err := client.GetApp(context.Background()) + + // Check the error + if tt.wantErr != nil { + assert.Error(t, err) + assert.Equal(t, tt.wantApp, app) + } else { + assert.NoError(t, err) + assert.Equal(t, tt.wantApp, app) + } + }) + } +} + +func TestGithubClient_GetAppInstallation(t *testing.T) { + tests := []struct { + name string + mockHandler *http.Client + appToken string + installationID string + wantInstallation conngh.AppInstallation + wantErr bool + errContains string + }{ + { + name: "get disabled app installation successfully", + mockHandler: mockhub.NewMockedHTTPClient( + mockhub.WithRequestMatchHandler( + mockhub.GetAppInstallationsByInstallationId, + http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + installation := &github.Installation{ + ID: github.Ptr(int64(67890)), + SuspendedAt: github.Ptr(github.Timestamp{Time: time.Now()}), + } + w.WriteHeader(http.StatusOK) + require.NoError(t, json.NewEncoder(w).Encode(installation)) + }), + ), + ), + appToken: "test-app-token", + installationID: "67890", + wantInstallation: conngh.AppInstallation{ + ID: 67890, + Enabled: false, + }, + wantErr: false, + }, + { + name: "get enabled app installation successfully", + mockHandler: mockhub.NewMockedHTTPClient( + mockhub.WithRequestMatchHandler( + mockhub.GetAppInstallationsByInstallationId, + http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + installation := &github.Installation{ + ID: github.Ptr(int64(67890)), + SuspendedAt: nil, + } + w.WriteHeader(http.StatusOK) + require.NoError(t, json.NewEncoder(w).Encode(installation)) + }), + ), + ), + appToken: "test-app-token", + installationID: "67890", + wantInstallation: conngh.AppInstallation{ + ID: 67890, + Enabled: true, + }, + wantErr: false, + }, + { + name: "invalid installation ID", + mockHandler: mockhub.NewMockedHTTPClient(), + appToken: "test-app-token", + installationID: "not-a-number", + wantInstallation: conngh.AppInstallation{}, + wantErr: true, + errContains: "invalid installation ID", + }, + { + name: "service unavailable", + mockHandler: mockhub.NewMockedHTTPClient( + mockhub.WithRequestMatchHandler( + mockhub.GetAppInstallationsByInstallationId, + http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusServiceUnavailable) + require.NoError(t, json.NewEncoder(w).Encode(github.ErrorResponse{ + Response: &http.Response{ + StatusCode: http.StatusServiceUnavailable, + }, + Message: "Service unavailable", + })) + }), + ), + ), + appToken: "test-app-token", + installationID: "67890", + wantInstallation: conngh.AppInstallation{}, + wantErr: true, + }, + { + name: "installation not found", + mockHandler: mockhub.NewMockedHTTPClient( + mockhub.WithRequestMatchHandler( + mockhub.GetAppInstallationsByInstallationId, + http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusNotFound) + require.NoError(t, json.NewEncoder(w).Encode(github.ErrorResponse{ + Response: &http.Response{ + StatusCode: http.StatusNotFound, + }, + Message: "Not Found", + })) + }), + ), + ), + appToken: "test-app-token", + installationID: "99999", + wantInstallation: conngh.AppInstallation{}, + wantErr: true, + }, + { + name: "other error", + mockHandler: mockhub.NewMockedHTTPClient( + mockhub.WithRequestMatchHandler( + mockhub.GetAppInstallationsByInstallationId, + http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + require.NoError(t, json.NewEncoder(w).Encode(github.ErrorResponse{ + Response: &http.Response{ + StatusCode: http.StatusInternalServerError, + }, + Message: "Internal server error", + })) + }), + ), + ), + appToken: "test-app-token", + installationID: "67890", + wantInstallation: conngh.AppInstallation{}, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a mock client + ghClient := github.NewClient(tt.mockHandler) + client := conngh.NewClient(ghClient) + + // Call the method being tested + installation, err := client.GetAppInstallation(context.Background(), tt.installationID) + + // Check the error + if tt.wantErr { + assert.Error(t, err) + if tt.errContains != "" { + assert.Contains(t, err.Error(), tt.errContains) + } + } else { + assert.NoError(t, err) + } + + // Check the result + assert.Equal(t, tt.wantInstallation, installation) + }) + } +} diff --git a/apps/provisioning/pkg/connection/github/connection.go b/apps/provisioning/pkg/connection/github/connection.go new file mode 100644 index 00000000000..6a2da98ac8d --- /dev/null +++ b/apps/provisioning/pkg/connection/github/connection.go @@ -0,0 +1,192 @@ +package github + +import ( + "context" + "encoding/base64" + "errors" + "fmt" + "time" + + "github.com/golang-jwt/jwt/v4" + provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1" + "github.com/grafana/grafana/apps/provisioning/pkg/connection" + common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/util/validation/field" +) + +//go:generate mockery --name GithubFactory --structname MockGithubFactory --inpackage --filename factory_mock.go --with-expecter +type GithubFactory interface { + New(ctx context.Context, ghToken common.RawSecureValue) Client +} + +type Connection struct { + obj *provisioning.Connection + ghFactory GithubFactory +} + +func NewConnection( + obj *provisioning.Connection, + factory GithubFactory, +) Connection { + return Connection{ + obj: obj, + ghFactory: factory, + } +} + +const ( + //TODO(ferruvich): these probably need to be setup in API configuration. + githubInstallationURL = "https://github.com/settings/installations" + jwtExpirationMinutes = 10 // GitHub Apps JWT tokens expire in 10 minutes maximum +) + +// Mutate performs in place mutation of the underneath resource. +func (c *Connection) Mutate(_ context.Context) error { + // Do nothing in case spec.Github is nil. + // If this field is required, we should fail at validation time. + if c.obj.Spec.GitHub == nil { + return nil + } + + c.obj.Spec.URL = fmt.Sprintf("%s/%s", githubInstallationURL, c.obj.Spec.GitHub.InstallationID) + + // Generate JWT token if private key is being provided. + // Same as for the spec.Github, if such a field is required, Validation will take care of that. + if !c.obj.Secure.PrivateKey.Create.IsZero() { + token, err := generateToken(c.obj.Spec.GitHub.AppID, c.obj.Secure.PrivateKey.Create) + if err != nil { + return fmt.Errorf("failed to generate JWT token: %w", err) + } + + // Store the generated token + c.obj.Secure.Token = common.InlineSecureValue{Create: token} + } + + return nil +} + +// Token generates and returns the Connection token. +func generateToken(appID string, privateKey common.RawSecureValue) (common.RawSecureValue, error) { + // Decode base64-encoded private key + privateKeyPEM, err := base64.StdEncoding.DecodeString(string(privateKey)) + if err != nil { + return "", fmt.Errorf("failed to decode base64 private key: %w", err) + } + + // Parse the private key + key, err := jwt.ParseRSAPrivateKeyFromPEM(privateKeyPEM) + if err != nil { + return "", fmt.Errorf("failed to parse private key: %w", err) + } + + // Create the JWT token + now := time.Now() + claims := jwt.RegisteredClaims{ + IssuedAt: jwt.NewNumericDate(now), + ExpiresAt: jwt.NewNumericDate(now.Add(time.Duration(jwtExpirationMinutes) * time.Minute)), + Issuer: appID, + } + + token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims) + signedToken, err := token.SignedString(key) + if err != nil { + return "", fmt.Errorf("failed to sign JWT token: %w", err) + } + + return common.RawSecureValue(signedToken), nil +} + +// Validate ensures the resource _looks_ correct. +func (c *Connection) Validate(ctx context.Context) error { + list := field.ErrorList{} + + if c.obj.Spec.Type != provisioning.GithubConnectionType { + list = append(list, field.Invalid(field.NewPath("spec", "type"), c.obj.Spec.Type, "invalid connection type")) + + // Doesn't make much sense to continue validating a connection which is not a Github one. + return toError(c.obj.GetName(), list) + } + + if c.obj.Spec.GitHub == nil { + list = append( + list, field.Required(field.NewPath("spec", "github"), "github info must be specified for GitHub connection"), + ) + + // Doesn't make much sense to continue validating a connection with no information. + return toError(c.obj.GetName(), list) + } + + if c.obj.Secure.PrivateKey.IsZero() { + list = append(list, field.Required(field.NewPath("secure", "privateKey"), "privateKey must be specified for GitHub connection")) + } + if c.obj.Secure.Token.IsZero() { + list = append(list, field.Required(field.NewPath("secure", "token"), "token must be specified for GitHub connection")) + } + if !c.obj.Secure.ClientSecret.IsZero() { + list = append(list, field.Forbidden(field.NewPath("secure", "clientSecret"), "clientSecret is forbidden in GitHub connection")) + } + + // Validate GitHub configuration fields + if c.obj.Spec.GitHub.AppID == "" { + list = append(list, field.Required(field.NewPath("spec", "github", "appID"), "appID must be specified for GitHub connection")) + } + if c.obj.Spec.GitHub.InstallationID == "" { + list = append(list, field.Required(field.NewPath("spec", "github", "installationID"), "installationID must be specified for GitHub connection")) + } + + // In case we have any error above, we don't go forward with the validation, and return the errors. + if len(list) > 0 { + return toError(c.obj.GetName(), list) + } + + // Validating app content via GH API + if err := c.validateAppAndInstallation(ctx); err != nil { + list = append(list, err) + } + + return toError(c.obj.GetName(), list) +} + +// validateAppAndInstallation validates the appID and installationID against the given github token. +func (c *Connection) validateAppAndInstallation(ctx context.Context) *field.Error { + ghClient := c.ghFactory.New(ctx, c.obj.Secure.Token.Create) + + app, err := ghClient.GetApp(ctx) + if err != nil { + if errors.Is(err, ErrServiceUnavailable) { + return field.InternalError(field.NewPath("spec", "token"), ErrServiceUnavailable) + } + return field.Invalid(field.NewPath("spec", "token"), "[REDACTED]", "invalid token") + } + + if fmt.Sprintf("%d", app.ID) != c.obj.Spec.GitHub.AppID { + return field.Invalid(field.NewPath("spec", "appID"), c.obj.Spec.GitHub.AppID, "appID mismatch") + } + + _, err = ghClient.GetAppInstallation(ctx, c.obj.Spec.GitHub.InstallationID) + if err != nil { + if errors.Is(err, ErrServiceUnavailable) { + return field.InternalError(field.NewPath("spec", "token"), ErrServiceUnavailable) + } + return field.Invalid(field.NewPath("spec", "installationID"), c.obj.Spec.GitHub.InstallationID, "invalid installation ID") + } + + return nil +} + +// toError converts a field.ErrorList to an error, returning nil if the list is empty +func toError(name string, list field.ErrorList) error { + if len(list) == 0 { + return nil + } + return apierrors.NewInvalid( + provisioning.ConnectionResourceInfo.GroupVersionKind().GroupKind(), + name, + list, + ) +} + +var ( + _ connection.Connection = (*Connection)(nil) +) diff --git a/apps/provisioning/pkg/connection/github/connection_test.go b/apps/provisioning/pkg/connection/github/connection_test.go new file mode 100644 index 00000000000..6a916db730e --- /dev/null +++ b/apps/provisioning/pkg/connection/github/connection_test.go @@ -0,0 +1,434 @@ +package github + +import ( + "context" + "encoding/base64" + "testing" + + provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1" + common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +//nolint:gosec // Test RSA private key (generated for testing purposes only) +const testPrivateKeyPEM = `-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAoInVbLY9io2Q/wHvUIXlEHg2Qyvd8eRzBAVEJ92DS6fx9H10 +06V0VRm78S0MXyo6i+n8ZAbZ0/R+GWpP2Ephxm0Gs2zo+iO2mpB19xQFI4o6ZTOw +b2WyjSaa2Vr4oyDkqti6AvfjW4VUAu932e08GkgwmmQSHXj7FX2CMWjgUwTTcuaX +65SHNKLNYLUP0HTumLzoZeqDTdoMMpKNdgH9Avr4/8vkVJ0mD6rqvxnw3JHsseNO +WdQTxf2aApBNHIIKxWZ2i/ZmjLNey7kltgjEquGiBdJvip3fHhH5XHdkrXcjRtnw +OJDnDmi5lQwv5yUBOSkbvbXRv/L/m0YLoD/fbwIDAQABAoIBAFfl//hM8/cnuesV ++R1Con/ZAgTXQOdPqPXbmEyniVrkMqMmCdBUOBTcST4s5yg36+RtkeaGpb/ajyyF +PAB2AYDucwvMpudGpJWOYTiOOp4R8hU1LvZfXVrRd1lo6NgQi4NLtNUpOtACeVQ+ +H4Yv0YemXQ47mnuOoRNMK/u3q5NoIdSahWptXBgUno8KklNpUrH3IYWaUxfBzDN3 +2xsVRTn2SfTSyoDmTDdTgptJONmoK1/sV7UsgWksdFc6XyYhsFAZgOGEJrBABRvF +546dyQ0cWxuPyVXpM7CN3tqC5ssvLjElg3LicK1V6gnjpdRnnvX88d1Eh3Uc/9IM +OZInT2ECgYEA6W8sQXTWinyEwl8SDKKMbB2ApIghAcFgdRxprZE4WFxjsYNCNL70 +dnSB7MRuzmxf5W77cV0N7JhH66N8HvY6Xq9olrpQ5dNttR4w8Pyv3wavDe8x7seL +5L2Xtbu7ihDr8Dk27MjiBSin3IxhBP5CJS910+pR6LrAWtEuU+FzFfECgYEAsA6y +qxHhCMXlTnauXhsnmPd1g61q7chW8kLQFYtHMLlQlgjHTW7irDZ9cPbPYDNjwRLO +7KLorcpv2NKe7rqq2ZyCm6hf1b9WnlQjo3dLpNWMu6fhy/smK8MgbRqcWpX+oTKF +79mK6hbY7o6eBzsQHBl7Z+LBNuwYmp9qOodPa18CgYEArv6ipKdcNhFGzRfMRiCN +OHederp6VACNuP2F05IsNUF9kxOdTEFirnKE++P+VU01TqA2azOhPp6iO+ohIGzi +MR06QNSH1OL9OWvasK4dggpWrRGF00VQgDgJRTnpS4WH+lxJ6pRlrAxgWpv6F24s +VAgSQr1Ejj2B+hMasdMvHWECgYBJ4uE4yhgXBnZlp4kmFV9Y4wF+cZkekaVrpn6N +jBYkbKFVVfnOlWqru3KJpgsB5I9IyAvvY68iwIKQDFSG+/AXw4dMrC0MF3DSoZ0T +TU2Br92QI7SvVod+djV1lGVp3ukt3XY4YqPZ+hywgUnw3uiz4j3YK2HLGup4ec6r +IX5DIQKBgHRLzvT3zqtlR1Oh0vv098clLwt+pGzXOxzJpxioOa5UqK13xIpFXbcg +iWUVh5YXCcuqaICUv4RLIEac5xQitk9Is/9IhP0NJ/81rHniosvdSpCeFXzxTImS +B8Uc0WUgheB4+yVKGnYpYaSOgFFI5+1BYUva/wDHLy2pWHz39Usb +-----END RSA PRIVATE KEY-----` + +func TestConnection_Mutate(t *testing.T) { + t.Run("should add URL to Github connection", func(t *testing.T) { + c := &provisioning.Connection{ + ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, + Spec: provisioning.ConnectionSpec{ + Type: provisioning.GithubConnectionType, + GitHub: &provisioning.GitHubConnectionConfig{ + AppID: "123", + InstallationID: "456", + }, + }, + Secure: provisioning.ConnectionSecure{ + PrivateKey: common.InlineSecureValue{ + Name: "test-private-key", + }, + }, + } + + mockFactory := NewMockGithubFactory(t) + conn := NewConnection(c, mockFactory) + + require.NoError(t, conn.Mutate(context.Background())) + assert.Equal(t, "https://github.com/settings/installations/456", c.Spec.URL) + }) + + t.Run("should generate JWT token when private key is provided", func(t *testing.T) { + privateKeyBase64 := base64.StdEncoding.EncodeToString([]byte(testPrivateKeyPEM)) + + c := &provisioning.Connection{ + ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, + Spec: provisioning.ConnectionSpec{ + Type: provisioning.GithubConnectionType, + GitHub: &provisioning.GitHubConnectionConfig{ + AppID: "123", + InstallationID: "456", + }, + }, + Secure: provisioning.ConnectionSecure{ + PrivateKey: common.InlineSecureValue{ + Create: common.NewSecretValue(privateKeyBase64), + }, + }, + } + + mockFactory := NewMockGithubFactory(t) + conn := NewConnection(c, mockFactory) + + require.NoError(t, conn.Mutate(context.Background())) + assert.Equal(t, "https://github.com/settings/installations/456", c.Spec.URL) + assert.False(t, c.Secure.Token.Create.IsZero(), "JWT token should be generated") + }) + + t.Run("should do nothing when GitHub config is nil", func(t *testing.T) { + c := &provisioning.Connection{ + ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, + Spec: provisioning.ConnectionSpec{ + Type: provisioning.GitlabConnectionType, + Gitlab: &provisioning.GitlabConnectionConfig{ + ClientID: "clientID", + }, + }, + } + + mockFactory := NewMockGithubFactory(t) + conn := NewConnection(c, mockFactory) + + require.NoError(t, conn.Mutate(context.Background())) + }) + + t.Run("should fail when private key is not base64", func(t *testing.T) { + c := &provisioning.Connection{ + ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, + Spec: provisioning.ConnectionSpec{ + Type: provisioning.GithubConnectionType, + GitHub: &provisioning.GitHubConnectionConfig{ + AppID: "123", + InstallationID: "456", + }, + }, + Secure: provisioning.ConnectionSecure{ + PrivateKey: common.InlineSecureValue{ + Create: common.NewSecretValue("invalid-key"), + }, + }, + } + + mockFactory := NewMockGithubFactory(t) + conn := NewConnection(c, mockFactory) + + err := conn.Mutate(context.Background()) + require.Error(t, err) + assert.Contains(t, err.Error(), "failed to generate JWT token") + assert.Contains(t, err.Error(), "failed to decode base64 private key") + }) + + t.Run("should fail when private key is invalid", func(t *testing.T) { + c := &provisioning.Connection{ + ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, + Spec: provisioning.ConnectionSpec{ + Type: provisioning.GithubConnectionType, + GitHub: &provisioning.GitHubConnectionConfig{ + AppID: "123", + InstallationID: "456", + }, + }, + Secure: provisioning.ConnectionSecure{ + PrivateKey: common.InlineSecureValue{ + Create: common.NewSecretValue(base64.StdEncoding.EncodeToString([]byte("invalid-key"))), + }, + }, + } + + mockFactory := NewMockGithubFactory(t) + conn := NewConnection(c, mockFactory) + + err := conn.Mutate(context.Background()) + require.Error(t, err) + assert.Contains(t, err.Error(), "failed to generate JWT token") + assert.Contains(t, err.Error(), "failed to parse private key") + }) +} + +func TestConnection_Validate(t *testing.T) { + tests := []struct { + name string + connection *provisioning.Connection + setupMock func(*MockGithubFactory) + wantErr bool + errMsgContains []string + }{ + { + name: "invalid type returns error", + connection: &provisioning.Connection{ + ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, + Spec: provisioning.ConnectionSpec{ + Type: "invalid", + }, + }, + wantErr: true, + errMsgContains: []string{"spec.type"}, + }, + { + name: "github type without github config returns error", + connection: &provisioning.Connection{ + ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, + Spec: provisioning.ConnectionSpec{ + Type: provisioning.GithubConnectionType, + }, + }, + wantErr: true, + errMsgContains: []string{"spec.github"}, + }, + { + name: "github type without private key returns error", + connection: &provisioning.Connection{ + ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, + Spec: provisioning.ConnectionSpec{ + Type: provisioning.GithubConnectionType, + GitHub: &provisioning.GitHubConnectionConfig{ + AppID: "123", + InstallationID: "456", + }, + }, + }, + wantErr: true, + errMsgContains: []string{"secure.privateKey"}, + }, + { + name: "github type without token returns error", + connection: &provisioning.Connection{ + ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, + Spec: provisioning.ConnectionSpec{ + Type: provisioning.GithubConnectionType, + GitHub: &provisioning.GitHubConnectionConfig{ + AppID: "123", + InstallationID: "456", + }, + }, + Secure: provisioning.ConnectionSecure{ + PrivateKey: common.InlineSecureValue{ + Create: common.NewSecretValue("test-private-key"), + }, + }, + }, + wantErr: true, + errMsgContains: []string{"secure.token"}, + }, + { + name: "github type with client secret returns error", + connection: &provisioning.Connection{ + ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, + Spec: provisioning.ConnectionSpec{ + Type: provisioning.GithubConnectionType, + GitHub: &provisioning.GitHubConnectionConfig{ + AppID: "123", + InstallationID: "456", + }, + }, + Secure: provisioning.ConnectionSecure{ + ClientSecret: common.InlineSecureValue{ + Create: common.NewSecretValue("test-client-secret"), + }, + }, + }, + wantErr: true, + errMsgContains: []string{"secure.clientSecret"}, + }, + { + name: "github type without appID returns error", + connection: &provisioning.Connection{ + ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, + Spec: provisioning.ConnectionSpec{ + Type: provisioning.GithubConnectionType, + GitHub: &provisioning.GitHubConnectionConfig{ + InstallationID: "456", + }, + }, + Secure: provisioning.ConnectionSecure{ + PrivateKey: common.InlineSecureValue{ + Create: common.NewSecretValue("test-private-key"), + }, + Token: common.InlineSecureValue{ + Create: common.NewSecretValue("test-token"), + }, + }, + }, + wantErr: true, + errMsgContains: []string{"spec.github.appID"}, + }, + { + name: "github type without installationID returns error", + connection: &provisioning.Connection{ + ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, + Spec: provisioning.ConnectionSpec{ + Type: provisioning.GithubConnectionType, + GitHub: &provisioning.GitHubConnectionConfig{ + AppID: "123", + }, + }, + Secure: provisioning.ConnectionSecure{ + PrivateKey: common.InlineSecureValue{ + Name: "test-private-key", + }, + Token: common.InlineSecureValue{ + Name: "test-token", + }, + }, + }, + wantErr: true, + errMsgContains: []string{"spec.github.installationID"}, + }, + { + name: "github type with valid config is valid", + connection: &provisioning.Connection{ + ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, + Spec: provisioning.ConnectionSpec{ + Type: provisioning.GithubConnectionType, + GitHub: &provisioning.GitHubConnectionConfig{ + AppID: "123", + InstallationID: "456", + }, + }, + Secure: provisioning.ConnectionSecure{ + PrivateKey: common.InlineSecureValue{ + Create: common.NewSecretValue("test-private-key"), + }, + Token: common.InlineSecureValue{ + Create: common.NewSecretValue("test-token"), + }, + }, + }, + wantErr: false, + setupMock: func(mockFactory *MockGithubFactory) { + mockClient := NewMockClient(t) + + mockFactory.EXPECT().New(mock.Anything, common.RawSecureValue("test-token")).Return(mockClient) + mockClient.EXPECT().GetApp(mock.Anything).Return(App{ID: 123, Slug: "test-app"}, nil) + mockClient.EXPECT().GetAppInstallation(mock.Anything, "456").Return(AppInstallation{ID: 456}, nil) + }, + }, + { + name: "problem getting app returns error", + connection: &provisioning.Connection{ + ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, + Spec: provisioning.ConnectionSpec{ + Type: provisioning.GithubConnectionType, + GitHub: &provisioning.GitHubConnectionConfig{ + AppID: "123", + InstallationID: "456", + }, + }, + Secure: provisioning.ConnectionSecure{ + PrivateKey: common.InlineSecureValue{ + Create: common.NewSecretValue("test-private-key"), + }, + Token: common.InlineSecureValue{ + Create: common.NewSecretValue("test-token"), + }, + }, + }, + wantErr: true, + errMsgContains: []string{"spec.token", "[REDACTED]"}, + setupMock: func(mockFactory *MockGithubFactory) { + mockClient := NewMockClient(t) + + mockFactory.EXPECT().New(mock.Anything, common.RawSecureValue("test-token")).Return(mockClient) + mockClient.EXPECT().GetApp(mock.Anything).Return(App{}, assert.AnError) + }, + }, + { + name: "mismatched app ID returns error", + connection: &provisioning.Connection{ + ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, + Spec: provisioning.ConnectionSpec{ + Type: provisioning.GithubConnectionType, + GitHub: &provisioning.GitHubConnectionConfig{ + AppID: "123", + InstallationID: "456", + }, + }, + Secure: provisioning.ConnectionSecure{ + PrivateKey: common.InlineSecureValue{ + Create: common.NewSecretValue("test-private-key"), + }, + Token: common.InlineSecureValue{ + Create: common.NewSecretValue("test-token"), + }, + }, + }, + wantErr: true, + errMsgContains: []string{"spec.appID"}, + setupMock: func(mockFactory *MockGithubFactory) { + mockClient := NewMockClient(t) + + mockFactory.EXPECT().New(mock.Anything, common.RawSecureValue("test-token")).Return(mockClient) + mockClient.EXPECT().GetApp(mock.Anything).Return(App{ID: 444, Slug: "test-app"}, nil) + }, + }, + { + name: "problem when getting installation returns error", + connection: &provisioning.Connection{ + ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, + Spec: provisioning.ConnectionSpec{ + Type: provisioning.GithubConnectionType, + GitHub: &provisioning.GitHubConnectionConfig{ + AppID: "123", + InstallationID: "456", + }, + }, + Secure: provisioning.ConnectionSecure{ + PrivateKey: common.InlineSecureValue{ + Create: common.NewSecretValue("test-private-key"), + }, + Token: common.InlineSecureValue{ + Create: common.NewSecretValue("test-token"), + }, + }, + }, + wantErr: true, + errMsgContains: []string{"spec.installationID", "456"}, + setupMock: func(mockFactory *MockGithubFactory) { + mockClient := NewMockClient(t) + + mockFactory.EXPECT().New(mock.Anything, common.RawSecureValue("test-token")).Return(mockClient) + mockClient.EXPECT().GetApp(mock.Anything).Return(App{ID: 123, Slug: "test-app"}, nil) + mockClient.EXPECT().GetAppInstallation(mock.Anything, "456").Return(AppInstallation{}, assert.AnError) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockFactory := NewMockGithubFactory(t) + if tt.setupMock != nil { + tt.setupMock(mockFactory) + } + + conn := NewConnection(tt.connection, mockFactory) + err := conn.Validate(context.Background()) + if tt.wantErr { + assert.Error(t, err) + for _, msg := range tt.errMsgContains { + assert.Contains(t, err.Error(), msg) + } + } else { + assert.NoError(t, err) + } + }) + } +} diff --git a/apps/provisioning/pkg/connection/github/extra.go b/apps/provisioning/pkg/connection/github/extra.go new file mode 100644 index 00000000000..2c207637c61 --- /dev/null +++ b/apps/provisioning/pkg/connection/github/extra.go @@ -0,0 +1,36 @@ +package github + +import ( + "context" + "fmt" + + "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/connection" +) + +type extra struct { + factory GithubFactory +} + +func (e *extra) Type() provisioning.ConnectionType { + return provisioning.GithubConnectionType +} + +func (e *extra) Build(ctx context.Context, connection *provisioning.Connection) (connection.Connection, error) { + logger := logging.FromContext(ctx) + if connection == nil || connection.Spec.GitHub == nil { + logger.Error("connection is nil or github info is nil") + + return nil, fmt.Errorf("invalid github connection") + } + + c := NewConnection(connection, e.factory) + return &c, nil +} + +func Extra(factory GithubFactory) connection.Extra { + return &extra{ + factory: factory, + } +} diff --git a/apps/provisioning/pkg/connection/github/extra_test.go b/apps/provisioning/pkg/connection/github/extra_test.go new file mode 100644 index 00000000000..c5bcc8279d9 --- /dev/null +++ b/apps/provisioning/pkg/connection/github/extra_test.go @@ -0,0 +1,126 @@ +package github_test + +import ( + "context" + "testing" + + provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1" + "github.com/grafana/grafana/apps/provisioning/pkg/connection/github" + common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestExtra_Type(t *testing.T) { + t.Run("should return GithubConnectionType", func(t *testing.T) { + mockFactory := github.NewMockGithubFactory(t) + e := github.Extra(mockFactory) + result := e.Type() + assert.Equal(t, provisioning.GithubConnectionType, result) + }) +} + +func TestExtra_Build(t *testing.T) { + t.Run("should successfully build connection", func(t *testing.T) { + ctx := context.Background() + conn := &provisioning.Connection{ + ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, + Spec: provisioning.ConnectionSpec{ + Type: provisioning.GithubConnectionType, + GitHub: &provisioning.GitHubConnectionConfig{ + AppID: "123", + InstallationID: "456", + }, + }, + Secure: provisioning.ConnectionSecure{ + PrivateKey: common.InlineSecureValue{ + Create: common.NewSecretValue("test-private-key"), + }, + }, + } + + mockFactory := github.NewMockGithubFactory(t) + + e := github.Extra(mockFactory) + + result, err := e.Build(ctx, conn) + require.NoError(t, err) + require.NotNil(t, result) + }) + + t.Run("should handle different connection configurations", func(t *testing.T) { + ctx := context.Background() + conn := &provisioning.Connection{ + ObjectMeta: metav1.ObjectMeta{Name: "another-connection"}, + Spec: provisioning.ConnectionSpec{ + Type: provisioning.GithubConnectionType, + GitHub: &provisioning.GitHubConnectionConfig{ + AppID: "789", + InstallationID: "101112", + }, + }, + Secure: provisioning.ConnectionSecure{ + PrivateKey: common.InlineSecureValue{ + Name: "existing-private-key", + }, + Token: common.InlineSecureValue{ + Name: "existing-token", + }, + }, + } + + mockFactory := github.NewMockGithubFactory(t) + + e := github.Extra(mockFactory) + + result, err := e.Build(ctx, conn) + require.NoError(t, err) + require.NotNil(t, result) + }) + + t.Run("should build connection with background context", func(t *testing.T) { + ctx := context.Background() + conn := &provisioning.Connection{ + ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, + Spec: provisioning.ConnectionSpec{ + Type: provisioning.GithubConnectionType, + GitHub: &provisioning.GitHubConnectionConfig{ + AppID: "123", + InstallationID: "456", + }, + }, + } + + mockFactory := github.NewMockGithubFactory(t) + e := github.Extra(mockFactory) + result, err := e.Build(ctx, conn) + require.NoError(t, err) + require.NotNil(t, result) + }) + + t.Run("should always pass empty token to factory.New", func(t *testing.T) { + ctx := context.Background() + conn := &provisioning.Connection{ + ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, + Spec: provisioning.ConnectionSpec{ + Type: provisioning.GithubConnectionType, + GitHub: &provisioning.GitHubConnectionConfig{ + AppID: "123", + InstallationID: "456", + }, + }, + Secure: provisioning.ConnectionSecure{ + Token: common.InlineSecureValue{ + Create: common.NewSecretValue("some-token"), + }, + }, + } + + mockFactory := github.NewMockGithubFactory(t) + e := github.Extra(mockFactory) + result, err := e.Build(ctx, conn) + require.NoError(t, err) + require.NotNil(t, result) + }) +} diff --git a/apps/provisioning/pkg/connection/github/factory.go b/apps/provisioning/pkg/connection/github/factory.go new file mode 100644 index 00000000000..2399f3c9f69 --- /dev/null +++ b/apps/provisioning/pkg/connection/github/factory.go @@ -0,0 +1,39 @@ +package github + +import ( + "context" + "net/http" + + "github.com/google/go-github/v70/github" + "golang.org/x/oauth2" + + common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1" +) + +// Factory creates new GitHub clients. +// It exists only for the ability to test the code easily. +type Factory struct { + // Client allows overriding the client to use in the GH client returned. It exists primarily for testing. + // FIXME: we should replace in this way. We should add some options pattern for the factory. + Client *http.Client +} + +func ProvideFactory() GithubFactory { + return &Factory{} +} + +func (r *Factory) New(ctx context.Context, ghToken common.RawSecureValue) Client { + if r.Client != nil { + return NewClient(github.NewClient(r.Client)) + } + + if !ghToken.IsZero() { + tokenSrc := oauth2.StaticTokenSource( + &oauth2.Token{AccessToken: string(ghToken)}, + ) + tokenClient := oauth2.NewClient(ctx, tokenSrc) + return NewClient(github.NewClient(tokenClient)) + } + + return NewClient(github.NewClient(&http.Client{})) +} diff --git a/apps/provisioning/pkg/connection/github/factory_mock.go b/apps/provisioning/pkg/connection/github/factory_mock.go new file mode 100644 index 00000000000..a9e1424b62d --- /dev/null +++ b/apps/provisioning/pkg/connection/github/factory_mock.go @@ -0,0 +1,86 @@ +// Code generated by mockery v2.53.4. DO NOT EDIT. + +package github + +import ( + context "context" + + v0alpha1 "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1" + mock "github.com/stretchr/testify/mock" +) + +// MockGithubFactory is an autogenerated mock type for the GithubFactory type +type MockGithubFactory struct { + mock.Mock +} + +type MockGithubFactory_Expecter struct { + mock *mock.Mock +} + +func (_m *MockGithubFactory) EXPECT() *MockGithubFactory_Expecter { + return &MockGithubFactory_Expecter{mock: &_m.Mock} +} + +// New provides a mock function with given fields: ctx, ghToken +func (_m *MockGithubFactory) New(ctx context.Context, ghToken v0alpha1.RawSecureValue) Client { + ret := _m.Called(ctx, ghToken) + + if len(ret) == 0 { + panic("no return value specified for New") + } + + var r0 Client + if rf, ok := ret.Get(0).(func(context.Context, v0alpha1.RawSecureValue) Client); ok { + r0 = rf(ctx, ghToken) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(Client) + } + } + + return r0 +} + +// MockGithubFactory_New_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'New' +type MockGithubFactory_New_Call struct { + *mock.Call +} + +// New is a helper method to define mock.On call +// - ctx context.Context +// - ghToken v0alpha1.RawSecureValue +func (_e *MockGithubFactory_Expecter) New(ctx interface{}, ghToken interface{}) *MockGithubFactory_New_Call { + return &MockGithubFactory_New_Call{Call: _e.mock.On("New", ctx, ghToken)} +} + +func (_c *MockGithubFactory_New_Call) Run(run func(ctx context.Context, ghToken v0alpha1.RawSecureValue)) *MockGithubFactory_New_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(v0alpha1.RawSecureValue)) + }) + return _c +} + +func (_c *MockGithubFactory_New_Call) Return(_a0 Client) *MockGithubFactory_New_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockGithubFactory_New_Call) RunAndReturn(run func(context.Context, v0alpha1.RawSecureValue) Client) *MockGithubFactory_New_Call { + _c.Call.Return(run) + return _c +} + +// NewMockGithubFactory creates a new instance of MockGithubFactory. 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 NewMockGithubFactory(t interface { + mock.TestingT + Cleanup(func()) +}) *MockGithubFactory { + mock := &MockGithubFactory{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/apps/provisioning/pkg/connection/mutator.go b/apps/provisioning/pkg/connection/mutator.go deleted file mode 100644 index 30291669905..00000000000 --- a/apps/provisioning/pkg/connection/mutator.go +++ /dev/null @@ -1,28 +0,0 @@ -package connection - -import ( - "fmt" - - provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1" -) - -const ( - githubInstallationURL = "https://github.com/settings/installations" -) - -func MutateConnection(connection *provisioning.Connection) error { - switch connection.Spec.Type { - case provisioning.GithubConnectionType: - // Do nothing in case spec.Github is nil. - // If this field is required, we should fail at validation time. - if connection.Spec.GitHub == nil { - return nil - } - - connection.Spec.URL = fmt.Sprintf("%s/%s", githubInstallationURL, connection.Spec.GitHub.InstallationID) - return nil - default: - // TODO: we need to setup the URL for bitbucket and gitlab. - return nil - } -} diff --git a/apps/provisioning/pkg/connection/mutator_test.go b/apps/provisioning/pkg/connection/mutator_test.go deleted file mode 100644 index a25aabd10a1..00000000000 --- a/apps/provisioning/pkg/connection/mutator_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package connection_test - -import ( - "testing" - - provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1" - "github.com/grafana/grafana/apps/provisioning/pkg/connection" - common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func TestMutateConnection(t *testing.T) { - t.Run("should add URL to Github connection", func(t *testing.T) { - c := &provisioning.Connection{ - ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, - Spec: provisioning.ConnectionSpec{ - Type: provisioning.GithubConnectionType, - GitHub: &provisioning.GitHubConnectionConfig{ - AppID: "123", - InstallationID: "456", - }, - }, - Secure: provisioning.ConnectionSecure{ - PrivateKey: common.InlineSecureValue{ - Name: "test-private-key", - }, - }, - } - - require.NoError(t, connection.MutateConnection(c)) - assert.Equal(t, "https://github.com/settings/installations/456", c.Spec.URL) - }) -} diff --git a/apps/provisioning/pkg/connection/validator.go b/apps/provisioning/pkg/connection/validator.go deleted file mode 100644 index c2537e3af2f..00000000000 --- a/apps/provisioning/pkg/connection/validator.go +++ /dev/null @@ -1,104 +0,0 @@ -package connection - -import ( - provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/util/validation/field" -) - -func ValidateConnection(connection *provisioning.Connection) error { - list := field.ErrorList{} - - if connection.Spec.Type == "" { - list = append(list, field.Required(field.NewPath("spec", "type"), "type must be specified")) - } - - switch connection.Spec.Type { - case provisioning.GithubConnectionType: - list = append(list, validateGithubConnection(connection)...) - case provisioning.BitbucketConnectionType: - list = append(list, validateBitbucketConnection(connection)...) - case provisioning.GitlabConnectionType: - list = append(list, validateGitlabConnection(connection)...) - default: - list = append( - list, field.NotSupported( - field.NewPath("spec", "type"), - connection.Spec.Type, - []provisioning.ConnectionType{ - provisioning.GithubConnectionType, - provisioning.BitbucketConnectionType, - provisioning.GitlabConnectionType, - }), - ) - } - - return toError(connection.GetName(), list) -} - -func validateGithubConnection(connection *provisioning.Connection) field.ErrorList { - list := field.ErrorList{} - - if connection.Spec.GitHub == nil { - list = append( - list, field.Required(field.NewPath("spec", "github"), "github info must be specified for GitHub connection"), - ) - } - - if connection.Secure.PrivateKey.IsZero() { - list = append(list, field.Required(field.NewPath("secure", "privateKey"), "privateKey must be specified for GitHub connection")) - } - if !connection.Secure.ClientSecret.IsZero() { - list = append(list, field.Forbidden(field.NewPath("secure", "clientSecret"), "clientSecret is forbidden in GitHub connection")) - } - - return list -} - -func validateBitbucketConnection(connection *provisioning.Connection) field.ErrorList { - list := field.ErrorList{} - - if connection.Spec.Bitbucket == nil { - list = append( - list, field.Required(field.NewPath("spec", "bitbucket"), "bitbucket info must be specified in Bitbucket connection"), - ) - } - if connection.Secure.ClientSecret.IsZero() { - list = append(list, field.Required(field.NewPath("secure", "clientSecret"), "clientSecret must be specified for Bitbucket connection")) - } - if !connection.Secure.PrivateKey.IsZero() { - list = append(list, field.Forbidden(field.NewPath("secure", "privateKey"), "privateKey is forbidden in Bitbucket connection")) - } - - return list -} - -func validateGitlabConnection(connection *provisioning.Connection) field.ErrorList { - list := field.ErrorList{} - - if connection.Spec.Gitlab == nil { - list = append( - list, field.Required(field.NewPath("spec", "gitlab"), "gitlab info must be specified in Gitlab connection"), - ) - } - if connection.Secure.ClientSecret.IsZero() { - list = append(list, field.Required(field.NewPath("secure", "clientSecret"), "clientSecret must be specified for Gitlab connection")) - } - if !connection.Secure.PrivateKey.IsZero() { - list = append(list, field.Forbidden(field.NewPath("secure", "privateKey"), "privateKey is forbidden in Gitlab connection")) - } - - return list -} - -// toError converts a field.ErrorList to an error, returning nil if the list is empty -func toError(name string, list field.ErrorList) error { - if len(list) == 0 { - return nil - } - return apierrors.NewInvalid( - provisioning.ConnectionResourceInfo.GroupVersionKind().GroupKind(), - name, - list, - ) -} diff --git a/apps/provisioning/pkg/connection/validator_test.go b/apps/provisioning/pkg/connection/validator_test.go deleted file mode 100644 index 23d4b01b800..00000000000 --- a/apps/provisioning/pkg/connection/validator_test.go +++ /dev/null @@ -1,253 +0,0 @@ -package connection_test - -import ( - "testing" - - provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1" - "github.com/grafana/grafana/apps/provisioning/pkg/connection" - common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1" - "github.com/stretchr/testify/assert" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func TestValidateConnection(t *testing.T) { - tests := []struct { - name string - connection *provisioning.Connection - wantErr bool - errMsg string - }{ - { - name: "empty type returns error", - connection: &provisioning.Connection{ - ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, - Spec: provisioning.ConnectionSpec{}, - }, - wantErr: true, - errMsg: "spec.type", - }, - { - name: "invalid type returns error", - connection: &provisioning.Connection{ - ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, - Spec: provisioning.ConnectionSpec{ - Type: "invalid", - }, - }, - wantErr: true, - errMsg: "spec.type", - }, - { - name: "github type without github config returns error", - connection: &provisioning.Connection{ - ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, - Spec: provisioning.ConnectionSpec{ - Type: provisioning.GithubConnectionType, - }, - }, - wantErr: true, - errMsg: "spec.github", - }, - { - name: "github type without private key returns error", - connection: &provisioning.Connection{ - ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, - Spec: provisioning.ConnectionSpec{ - Type: provisioning.GithubConnectionType, - GitHub: &provisioning.GitHubConnectionConfig{ - AppID: "123", - InstallationID: "456", - }, - }, - }, - wantErr: true, - errMsg: "secure.privateKey", - }, - { - name: "github type with client secret returns error", - connection: &provisioning.Connection{ - ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, - Spec: provisioning.ConnectionSpec{ - Type: provisioning.GithubConnectionType, - GitHub: &provisioning.GitHubConnectionConfig{ - AppID: "123", - InstallationID: "456", - }, - }, - Secure: provisioning.ConnectionSecure{ - PrivateKey: common.InlineSecureValue{ - Name: "test-private-key", - }, - ClientSecret: common.InlineSecureValue{ - Name: "test-client-secret", - }, - }, - }, - wantErr: true, - errMsg: "secure.clientSecret", - }, - { - name: "github type with github config is valid", - connection: &provisioning.Connection{ - ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, - Spec: provisioning.ConnectionSpec{ - Type: provisioning.GithubConnectionType, - GitHub: &provisioning.GitHubConnectionConfig{ - AppID: "123", - InstallationID: "456", - }, - }, - Secure: provisioning.ConnectionSecure{ - PrivateKey: common.InlineSecureValue{ - Name: "test-private-key", - }, - }, - }, - wantErr: false, - }, - { - name: "bitbucket type without bitbucket config returns error", - connection: &provisioning.Connection{ - ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, - Spec: provisioning.ConnectionSpec{ - Type: provisioning.BitbucketConnectionType, - }, - }, - wantErr: true, - errMsg: "spec.bitbucket", - }, - { - name: "bitbucket type without client secret returns error", - connection: &provisioning.Connection{ - ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, - Spec: provisioning.ConnectionSpec{ - Type: provisioning.BitbucketConnectionType, - Bitbucket: &provisioning.BitbucketConnectionConfig{ - ClientID: "client-123", - }, - }, - }, - wantErr: true, - errMsg: "secure.clientSecret", - }, - { - name: "bitbucket type with private key returns error", - connection: &provisioning.Connection{ - ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, - Spec: provisioning.ConnectionSpec{ - Type: provisioning.BitbucketConnectionType, - Bitbucket: &provisioning.BitbucketConnectionConfig{ - ClientID: "client-123", - }, - }, - Secure: provisioning.ConnectionSecure{ - PrivateKey: common.InlineSecureValue{ - Name: "test-private-key", - }, - ClientSecret: common.InlineSecureValue{ - Name: "test-client-secret", - }, - }, - }, - wantErr: true, - errMsg: "secure.privateKey", - }, - { - name: "bitbucket type with bitbucket config is valid", - connection: &provisioning.Connection{ - ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, - Spec: provisioning.ConnectionSpec{ - Type: provisioning.BitbucketConnectionType, - Bitbucket: &provisioning.BitbucketConnectionConfig{ - ClientID: "client-123", - }, - }, - Secure: provisioning.ConnectionSecure{ - ClientSecret: common.InlineSecureValue{ - Name: "test-client-secret", - }, - }, - }, - wantErr: false, - }, - { - name: "gitlab type without gitlab config returns error", - connection: &provisioning.Connection{ - ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, - Spec: provisioning.ConnectionSpec{ - Type: provisioning.GitlabConnectionType, - }, - }, - wantErr: true, - errMsg: "spec.gitlab", - }, - { - name: "gitlab type without client secret returns error", - connection: &provisioning.Connection{ - ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, - Spec: provisioning.ConnectionSpec{ - Type: provisioning.GitlabConnectionType, - Gitlab: &provisioning.GitlabConnectionConfig{ - ClientID: "client-456", - }, - }, - }, - wantErr: true, - errMsg: "secure.clientSecret", - }, - { - name: "gitlab type with private key returns error", - connection: &provisioning.Connection{ - ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, - Spec: provisioning.ConnectionSpec{ - Type: provisioning.GitlabConnectionType, - Gitlab: &provisioning.GitlabConnectionConfig{ - ClientID: "client-456", - }, - }, - Secure: provisioning.ConnectionSecure{ - PrivateKey: common.InlineSecureValue{ - Name: "test-private-key", - }, - ClientSecret: common.InlineSecureValue{ - Name: "test-client-secret", - }, - }, - }, - wantErr: true, - errMsg: "secure.privateKey", - }, - { - name: "gitlab type with gitlab config is valid", - connection: &provisioning.Connection{ - ObjectMeta: metav1.ObjectMeta{Name: "test-connection"}, - Spec: provisioning.ConnectionSpec{ - Type: provisioning.GitlabConnectionType, - Gitlab: &provisioning.GitlabConnectionConfig{ - ClientID: "client-456", - }, - }, - Secure: provisioning.ConnectionSecure{ - ClientSecret: common.InlineSecureValue{ - Name: "test-client-secret", - }, - }, - }, - wantErr: false, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := connection.ValidateConnection(tt.connection) - if tt.wantErr { - assert.Error(t, err) - if tt.errMsg != "" { - assert.Contains(t, err.Error(), tt.errMsg) - } - } else { - assert.NoError(t, err) - } - }) - } -} diff --git a/apps/provisioning/pkg/controller/connection_status.go b/apps/provisioning/pkg/controller/connection_status.go new file mode 100644 index 00000000000..0d8a0002f41 --- /dev/null +++ b/apps/provisioning/pkg/controller/connection_status.go @@ -0,0 +1,40 @@ +package controller + +import ( + "context" + "encoding/json" + "fmt" + + provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1" + client "github.com/grafana/grafana/apps/provisioning/pkg/generated/clientset/versioned/typed/provisioning/v0alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" +) + +// ConnectionStatusPatcher provides methods to patch Connection status subresources. +type ConnectionStatusPatcher struct { + client client.ProvisioningV0alpha1Interface +} + +// NewConnectionStatusPatcher creates a new ConnectionStatusPatcher. +func NewConnectionStatusPatcher(client client.ProvisioningV0alpha1Interface) *ConnectionStatusPatcher { + return &ConnectionStatusPatcher{ + client: client, + } +} + +// Patch applies JSON patch operations to a Connection's status subresource. +func (p *ConnectionStatusPatcher) Patch(ctx context.Context, conn *provisioning.Connection, patchOperations ...map[string]interface{}) error { + patch, err := json.Marshal(patchOperations) + if err != nil { + return fmt.Errorf("unable to marshal patch data: %w", err) + } + + _, err = p.client.Connections(conn.Namespace). + Patch(ctx, conn.Name, types.JSONPatchType, patch, metav1.PatchOptions{}, "status") + if err != nil { + return fmt.Errorf("unable to update connection status: %w", err) + } + + return nil +} diff --git a/apps/provisioning/pkg/generated/applyconfiguration/provisioning/v0alpha1/connectionsecure.go b/apps/provisioning/pkg/generated/applyconfiguration/provisioning/v0alpha1/connectionsecure.go index 8ac26b192c9..f5be635560d 100644 --- a/apps/provisioning/pkg/generated/applyconfiguration/provisioning/v0alpha1/connectionsecure.go +++ b/apps/provisioning/pkg/generated/applyconfiguration/provisioning/v0alpha1/connectionsecure.go @@ -13,7 +13,7 @@ import ( type ConnectionSecureApplyConfiguration struct { PrivateKey *commonv0alpha1.InlineSecureValue `json:"privateKey,omitempty"` ClientSecret *commonv0alpha1.InlineSecureValue `json:"clientSecret,omitempty"` - Token *commonv0alpha1.InlineSecureValue `json:"webhook,omitempty"` + Token *commonv0alpha1.InlineSecureValue `json:"token,omitempty"` } // ConnectionSecureApplyConfiguration constructs a declarative configuration of the ConnectionSecure type for use with diff --git a/apps/secret/kinds/v1beta1/keeper.cue b/apps/secret/kinds/v1beta1/keeper.cue index 36e20198ab7..4ade465d1b5 100644 --- a/apps/secret/kinds/v1beta1/keeper.cue +++ b/apps/secret/kinds/v1beta1/keeper.cue @@ -30,11 +30,22 @@ KeeperSpec: { } #AWSConfig: { - accessKeyID: #CredentialValue - secretAccessKey: #CredentialValue + region: string + accessKey?: #AWSAccessKey + assumeRole?: #AWSAssumeRole kmsKeyID?: string } +#AWSAccessKey: { + accessKeyID: #CredentialValue + secretAccessKey: #CredentialValue +} + +#AWSAssumeRole: { + assumeRoleArn: string + externalID: string +} + #AzureConfig: { keyVaultName: string tenantID: string diff --git a/apps/secret/pkg/apis/secret/v1beta1/keeper_spec_gen.go b/apps/secret/pkg/apis/secret/v1beta1/keeper_spec_gen.go index 76d232465c8..806a3df8294 100644 --- a/apps/secret/pkg/apis/secret/v1beta1/keeper_spec_gen.go +++ b/apps/secret/pkg/apis/secret/v1beta1/keeper_spec_gen.go @@ -4,14 +4,26 @@ package v1beta1 // +k8s:openapi-gen=true type KeeperAWSConfig struct { - AccessKeyID KeeperCredentialValue `json:"accessKeyID"` - SecretAccessKey KeeperCredentialValue `json:"secretAccessKey"` - KmsKeyID *string `json:"kmsKeyID,omitempty"` + Region string `json:"region"` + AccessKey *KeeperAWSAccessKey `json:"accessKey,omitempty"` + AssumeRole *KeeperAWSAssumeRole `json:"assumeRole,omitempty"` + KmsKeyID *string `json:"kmsKeyID,omitempty"` } // NewKeeperAWSConfig creates a new KeeperAWSConfig object. func NewKeeperAWSConfig() *KeeperAWSConfig { - return &KeeperAWSConfig{ + return &KeeperAWSConfig{} +} + +// +k8s:openapi-gen=true +type KeeperAWSAccessKey struct { + AccessKeyID KeeperCredentialValue `json:"accessKeyID"` + SecretAccessKey KeeperCredentialValue `json:"secretAccessKey"` +} + +// NewKeeperAWSAccessKey creates a new KeeperAWSAccessKey object. +func NewKeeperAWSAccessKey() *KeeperAWSAccessKey { + return &KeeperAWSAccessKey{ AccessKeyID: *NewKeeperCredentialValue(), SecretAccessKey: *NewKeeperCredentialValue(), } @@ -36,6 +48,17 @@ func NewKeeperCredentialValue() *KeeperCredentialValue { return &KeeperCredentialValue{} } +// +k8s:openapi-gen=true +type KeeperAWSAssumeRole struct { + AssumeRoleArn string `json:"assumeRoleArn"` + ExternalID string `json:"externalID"` +} + +// NewKeeperAWSAssumeRole creates a new KeeperAWSAssumeRole object. +func NewKeeperAWSAssumeRole() *KeeperAWSAssumeRole { + return &KeeperAWSAssumeRole{} +} + // +k8s:openapi-gen=true type KeeperAzureConfig struct { KeyVaultName string `json:"keyVaultName"` diff --git a/apps/secret/pkg/apis/secret/v1beta1/keeper_type.go b/apps/secret/pkg/apis/secret/v1beta1/keeper_type.go index 0feeac75dd1..6f61acf1a77 100644 --- a/apps/secret/pkg/apis/secret/v1beta1/keeper_type.go +++ b/apps/secret/pkg/apis/secret/v1beta1/keeper_type.go @@ -12,6 +12,7 @@ const ( AzureKeeperType KeeperType = "azure" GCPKeeperType KeeperType = "gcp" HashiCorpKeeperType KeeperType = "hashicorp" + SystemKeeperType KeeperType = "system" ) func (kt KeeperType) String() string { @@ -20,9 +21,31 @@ func (kt KeeperType) String() string { // KeeperConfig is an interface that all keeper config types must implement. type KeeperConfig interface { + // Returns the name of the keeper + GetName() string Type() KeeperType } +type NamedKeeperConfig[T interface { + Type() KeeperType +}] struct { + Name string + Cfg T +} + +func NewNamedKeeperConfig[T interface { + Type() KeeperType +}](keeperName string, cfg T) *NamedKeeperConfig[T] { + return &NamedKeeperConfig[T]{Name: keeperName, Cfg: cfg} +} + +func (c *NamedKeeperConfig[T]) GetName() string { + return c.Name +} +func (c *NamedKeeperConfig[T]) Type() KeeperType { + return c.Cfg.Type() +} + func (s *KeeperSpec) GetType() KeeperType { if s.Aws != nil { return AWSKeeperType @@ -43,7 +66,7 @@ func (s *KeeperSpec) GetType() KeeperType { type SystemKeeperConfig struct{} func (*SystemKeeperConfig) Type() KeeperType { - return "system" + return SystemKeeperType } func (s *KeeperAWSConfig) Type() KeeperType { diff --git a/apps/secret/pkg/apis/secret/v1beta1/zz_openapi_gen.go b/apps/secret/pkg/apis/secret/v1beta1/zz_openapi_gen.go index 101e4bb55b3..4d295874224 100644 --- a/apps/secret/pkg/apis/secret/v1beta1/zz_openapi_gen.go +++ b/apps/secret/pkg/apis/secret/v1beta1/zz_openapi_gen.go @@ -14,6 +14,8 @@ import ( func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition { return map[string]common.OpenAPIDefinition{ "github.com/grafana/grafana/apps/secret/pkg/apis/secret/v1beta1.Keeper": schema_pkg_apis_secret_v1beta1_Keeper(ref), + "github.com/grafana/grafana/apps/secret/pkg/apis/secret/v1beta1.KeeperAWSAccessKey": schema_pkg_apis_secret_v1beta1_KeeperAWSAccessKey(ref), + "github.com/grafana/grafana/apps/secret/pkg/apis/secret/v1beta1.KeeperAWSAssumeRole": schema_pkg_apis_secret_v1beta1_KeeperAWSAssumeRole(ref), "github.com/grafana/grafana/apps/secret/pkg/apis/secret/v1beta1.KeeperAWSConfig": schema_pkg_apis_secret_v1beta1_KeeperAWSConfig(ref), "github.com/grafana/grafana/apps/secret/pkg/apis/secret/v1beta1.KeeperAzureConfig": schema_pkg_apis_secret_v1beta1_KeeperAzureConfig(ref), "github.com/grafana/grafana/apps/secret/pkg/apis/secret/v1beta1.KeeperCredentialValue": schema_pkg_apis_secret_v1beta1_KeeperCredentialValue(ref), @@ -79,7 +81,7 @@ func schema_pkg_apis_secret_v1beta1_Keeper(ref common.ReferenceCallback) common. } } -func schema_pkg_apis_secret_v1beta1_KeeperAWSConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_pkg_apis_secret_v1beta1_KeeperAWSAccessKey(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ @@ -97,6 +99,65 @@ func schema_pkg_apis_secret_v1beta1_KeeperAWSConfig(ref common.ReferenceCallback Ref: ref("github.com/grafana/grafana/apps/secret/pkg/apis/secret/v1beta1.KeeperCredentialValue"), }, }, + }, + Required: []string{"accessKeyID", "secretAccessKey"}, + }, + }, + Dependencies: []string{ + "github.com/grafana/grafana/apps/secret/pkg/apis/secret/v1beta1.KeeperCredentialValue"}, + } +} + +func schema_pkg_apis_secret_v1beta1_KeeperAWSAssumeRole(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "assumeRoleArn": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "externalID": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"assumeRoleArn", "externalID"}, + }, + }, + } +} + +func schema_pkg_apis_secret_v1beta1_KeeperAWSConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "region": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "accessKey": { + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/grafana/grafana/apps/secret/pkg/apis/secret/v1beta1.KeeperAWSAccessKey"), + }, + }, + "assumeRole": { + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/grafana/grafana/apps/secret/pkg/apis/secret/v1beta1.KeeperAWSAssumeRole"), + }, + }, "kmsKeyID": { SchemaProps: spec.SchemaProps{ Type: []string{"string"}, @@ -104,11 +165,11 @@ func schema_pkg_apis_secret_v1beta1_KeeperAWSConfig(ref common.ReferenceCallback }, }, }, - Required: []string{"accessKeyID", "secretAccessKey"}, + Required: []string{"region"}, }, }, Dependencies: []string{ - "github.com/grafana/grafana/apps/secret/pkg/apis/secret/v1beta1.KeeperCredentialValue"}, + "github.com/grafana/grafana/apps/secret/pkg/apis/secret/v1beta1.KeeperAWSAccessKey", "github.com/grafana/grafana/apps/secret/pkg/apis/secret/v1beta1.KeeperAWSAssumeRole"}, } } diff --git a/conf/defaults.ini b/conf/defaults.ini index 363ca39d0c4..080d4e62fe0 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -336,7 +336,7 @@ rudderstack_data_plane_url = 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_v3_sdk_url = # Rudderstack Config url, optional, used by Rudderstack SDK to fetch source config rudderstack_config_url = @@ -2079,8 +2079,14 @@ enable = # To enable features by default, set `Expression: "true"` in: # https://github.com/grafana/grafana/blob/main/pkg/services/featuremgmt/registry.go +# The feature_toggles section supports feature flags of a number of types, +# including boolean, string, integer, float, and structured values, following the OpenFeature specification. +# # feature1 = true # feature2 = false +# feature3 = "foobar" +# feature4 = 1.5 +# feature5 = { "foo": "bar" } [feature_toggles.openfeature] # This is EXPERIMENTAL. Please, do not use this section @@ -2234,6 +2240,8 @@ encryption_provider = secret_key.v1 # These flags are required in on-prem installations for GitSync to work # +# Whether to register the MT CRUD API +register_api_server = true # Whether to create the MT secrets management database run_secrets_db_migrations = true # Whether to run the data key id migration. Requires that RunSecretsDBMigrations is also true. @@ -2279,3 +2287,10 @@ allow_image_rendering = true # will check if there has been any changes to the repository not propagated by a webhook. # The minimum value is 10 seconds. min_sync_interval = 10s + +#################################### Unified Storage #################################### +[unified_storage] +# index_path is the path where unified storage can store its index files for search. +# If empty, defaults to "/unified-search/bleve" (see [paths] section). +# Please note that sharing the same index_path between multiple running Grafana instances is not supported. +index_path = diff --git a/conf/sample.ini b/conf/sample.ini index 530b14c87ac..b4bc6027abf 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -323,7 +323,7 @@ ;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_v3_sdk_url = # Rudderstack Config url, optional, used by Rudderstack SDK to fetch source config ;rudderstack_config_url = @@ -1913,7 +1913,7 @@ default_datasource_uid = # client_queue_max_size is the maximum size in bytes of the client queue # for Live connections. Defaults to 4MB. -;client_queue_max_size = +;client_queue_max_size = #################################### Grafana Image Renderer Plugin ########################## [plugin.grafana-image-renderer] @@ -1996,9 +1996,14 @@ default_datasource_uid = ;enable = feature1,feature2 +# The feature_toggles section supports feature flags of a number of types, +# including boolean, string, integer, float, and structured values, following the OpenFeature specification. + ;feature1 = true ;feature2 = false - +;feature3 = "foobar" +;feature4 = 1.5 +;feature5 = { "foo": "bar" } [date_formats] # For information on what formatting patterns that are supported https://momentjs.com/docs/#/displaying/ @@ -2123,6 +2128,8 @@ default_datasource_uid = # These flags are required in on-prem installations for GitSync to work # +# Whether to register the MT CRUD API +;register_api_server = true # Whether to create the MT secrets management database ;run_secrets_db_migrations = true # Whether to run the data key id migration. Requires that RunSecretsDBMigrations is also true. diff --git a/devenv/dev-dashboards/datasource-loki/loki_query_splitting.json b/devenv/dev-dashboards/datasource-loki/loki_query_splitting.json index 0cc5135a0f4..44577d49ac4 100644 --- a/devenv/dev-dashboards/datasource-loki/loki_query_splitting.json +++ b/devenv/dev-dashboards/datasource-loki/loki_query_splitting.json @@ -216,8 +216,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -311,8 +310,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -493,8 +491,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -584,8 +581,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -675,8 +671,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -789,8 +784,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -903,8 +897,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -1018,8 +1011,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, diff --git a/devenv/dev-dashboards/panel-canvas/canvas_kitchen_sink.json b/devenv/dev-dashboards/panel-canvas/canvas_kitchen_sink.json new file mode 100644 index 00000000000..069a43c0888 --- /dev/null +++ b/devenv/dev-dashboards/panel-canvas/canvas_kitchen_sink.json @@ -0,0 +1,582 @@ +{ + "annotations": { + "list": [] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "1": { + "color": "green", + "icon": "img/icons/unicons/check-circle.svg", + "index": 0, + "text": "Success" + }, + "2": { + "color": "orange", + "icon": "img/icons/unicons/exclamation-triangle.svg", + "index": 1, + "text": "Warning" + }, + "3": { + "color": "red", + "icon": "img/icons/unicons/times-circle.svg", + "index": 2, + "text": "Error" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "success" + }, + "properties": [ + { + "id": "mappings", + "value": [ + { + "options": { + "1": { + "color": "green", + "icon": "img/icons/unicons/check-circle.svg", + "index": 0, + "text": "Success" + } + }, + "type": "value" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "warning" + }, + "properties": [ + { + "id": "mappings", + "value": [ + { + "options": { + "2": { + "color": "orange", + "icon": "img/icons/unicons/exclamation-triangle.svg", + "index": 1, + "text": "Warning" + } + }, + "type": "value" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "error" + }, + "properties": [ + { + "id": "mappings", + "value": [ + { + "options": { + "3": { + "color": "red", + "icon": "img/icons/unicons/times-circle.svg", + "index": 2, + "text": "Error" + } + }, + "type": "value" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "unmapped" + }, + "properties": [ + { + "id": "mappings", + "value": [ + { + "options": { + "1": { + "color": "green", + "icon": "img/icons/unicons/check-circle.svg", + "index": 0, + "text": "Success" + }, + "2": { + "color": "orange", + "icon": "img/icons/unicons/exclamation-triangle.svg", + "index": 1, + "text": "Warning" + }, + "3": { + "color": "red", + "icon": "img/icons/unicons/times-circle.svg", + "index": 2, + "text": "Error" + } + }, + "type": "value" + } + ] + } + ] + } + ] + }, + "gridPos": { + "h": 12, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 1, + "options": { + "inlineEditing": true, + "root": { + "background": { + "color": { + "fixed": "transparent" + } + }, + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "elements": [ + { + "config": { + "align": "center", + "color": { + "fixed": "text" + }, + "size": 16, + "text": { + "fixed": "Field-based Icons (from value mappings):", + "mode": "fixed" + }, + "valign": "middle" + }, + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "name": "Header", + "placement": { + "height": 40, + "left": 20, + "top": 10, + "width": 400 + }, + "type": "text" + }, + { + "config": { + "fill": { + "field": "success", + "fixed": "green" + }, + "path": { + "field": "success", + "mode": "field" + } + }, + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "name": "Success Icon", + "placement": { + "height": 50, + "left": 50, + "top": 60, + "width": 50 + }, + "type": "icon" + }, + { + "config": { + "align": "center", + "color": { + "field": "success", + "fixed": "text" + }, + "size": 12, + "text": { + "field": "success", + "mode": "field" + }, + "valign": "middle" + }, + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "name": "Success Text", + "placement": { + "height": 25, + "left": 30, + "top": 115, + "width": 90 + }, + "type": "text" + }, + { + "config": { + "fill": { + "field": "warning", + "fixed": "orange" + }, + "path": { + "field": "warning", + "mode": "field" + } + }, + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "name": "Warning Icon", + "placement": { + "height": 50, + "left": 180, + "top": 60, + "width": 50 + }, + "type": "icon" + }, + { + "config": { + "align": "center", + "color": { + "field": "warning", + "fixed": "text" + }, + "size": 12, + "text": { + "field": "warning", + "mode": "field" + }, + "valign": "middle" + }, + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "name": "Warning Text", + "placement": { + "height": 25, + "left": 160, + "top": 115, + "width": 90 + }, + "type": "text" + }, + { + "config": { + "fill": { + "field": "error", + "fixed": "red" + }, + "path": { + "field": "error", + "mode": "field" + } + }, + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "name": "Error Icon", + "placement": { + "height": 50, + "left": 310, + "top": 60, + "width": 50 + }, + "type": "icon" + }, + { + "config": { + "align": "center", + "color": { + "field": "error", + "fixed": "text" + }, + "size": 12, + "text": { + "field": "error", + "mode": "field" + }, + "valign": "middle" + }, + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "name": "Error Text", + "placement": { + "height": 25, + "left": 290, + "top": 115, + "width": 90 + }, + "type": "text" + }, + { + "config": { + "fill": { + "field": "unmapped", + "fixed": "#808080" + }, + "path": { + "field": "unmapped", + "fixed": "img/icons/unicons/question-circle.svg", + "mode": "field" + } + }, + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "name": "Unmapped Icon", + "placement": { + "height": 50, + "left": 440, + "top": 60, + "width": 50 + }, + "type": "icon" + }, + { + "config": { + "align": "center", + "color": { + "field": "unmapped", + "fixed": "text" + }, + "size": 12, + "text": { + "fixed": "No mapping (14)", + "mode": "fixed" + }, + "valign": "middle" + }, + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "name": "Unmapped Text", + "placement": { + "height": 25, + "left": 410, + "top": 115, + "width": 110 + }, + "type": "text" + }, + { + "config": { + "align": "center", + "color": { + "fixed": "text" + }, + "size": 14, + "text": { + "fixed": "Fixed Relative Path:", + "mode": "fixed" + }, + "valign": "middle" + }, + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "name": "Relative Label", + "placement": { + "height": 30, + "left": 50, + "top": 170, + "width": 200 + }, + "type": "text" + }, + { + "config": { + "fill": { + "fixed": "blue" + }, + "path": { + "fixed": "img/icons/unicons/cloud.svg", + "mode": "fixed" + } + }, + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "name": "Relative Icon", + "placement": { + "height": 50, + "left": 260, + "top": 165, + "width": 50 + }, + "type": "icon" + }, + { + "config": { + "align": "center", + "color": { + "fixed": "text" + }, + "size": 14, + "text": { + "fixed": "Fixed Absolute URL:", + "mode": "fixed" + }, + "valign": "middle" + }, + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "name": "Absolute Label", + "placement": { + "height": 30, + "left": 50, + "top": 240, + "width": 200 + }, + "type": "text" + }, + { + "config": { + "fill": { + "fixed": "purple" + }, + "path": { + "fixed": "https://grafana.com/static/assets/img/grafana_icon.svg", + "mode": "fixed" + } + }, + "constraint": { + "horizontal": "left", + "vertical": "top" + }, + "name": "Absolute Icon", + "placement": { + "height": 50, + "left": 260, + "top": 235, + "width": 50 + }, + "type": "icon" + } + ], + "name": "Canvas Root", + "placement": { + "height": 100, + "left": 0, + "top": 0, + "width": 100 + }, + "type": "frame" + } + }, + "pluginVersion": "12.1.0", + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_content", + "csvContent": "success\n1" + }, + { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "PD8C576611E62080A" + }, + "refId": "B", + "scenarioId": "csv_content", + "csvContent": "warning\n2" + }, + { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "PD8C576611E62080A" + }, + "refId": "C", + "scenarioId": "csv_content", + "csvContent": "error\n3" + }, + { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "PD8C576611E62080A" + }, + "refId": "D", + "scenarioId": "csv_content", + "csvContent": "unmapped\n14" + } + ], + "title": "Various SVG icons", + "type": "canvas" + } + ], + "schemaVersion": 39, + "tags": ["canvas", "icons", "test", "v2"], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Panel tests - Canvas - Kitchen sink", + "uid": "canvas-icon-fix-test-v2", + "version": 1, + "weekStart": "" +} diff --git a/devenv/dev-dashboards/panel-gauge/gauge_tests.json b/devenv/dev-dashboards/panel-gauge/gauge_tests.json index 0c8e2651e67..f76f5d8809a 100644 --- a/devenv/dev-dashboards/panel-gauge/gauge_tests.json +++ b/devenv/dev-dashboards/panel-gauge/gauge_tests.json @@ -51,17 +51,14 @@ "steps": [ { "color": "#7EB26D", - "index": 0, "value": null }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -122,17 +119,14 @@ "steps": [ { "color": "#7EB26D", - "index": 0, "value": null }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -193,17 +187,14 @@ "steps": [ { "color": "#7EB26D", - "index": 0, "value": null }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -255,7 +246,6 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "", "mappings": [], "max": 100, "min": 0, @@ -264,17 +254,14 @@ "steps": [ { "color": "#7EB26D", - "index": 0, "value": null }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -326,7 +313,6 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "", "mappings": [], "max": 100, "min": 0, @@ -335,17 +321,14 @@ "steps": [ { "color": "#7EB26D", - "index": 0, "value": null }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -397,7 +380,6 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "", "mappings": [], "max": 100, "min": 0, @@ -406,17 +388,14 @@ "steps": [ { "color": "#7EB26D", - "index": 0, "value": null }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -468,7 +447,6 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "", "mappings": [], "max": 100, "min": 0, @@ -477,17 +455,14 @@ "steps": [ { "color": "#7EB26D", - "index": 0, "value": null }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -600,6 +575,20 @@ "stringInput": "null,null" } ], + "transformations": [ + { + "id": "convertFieldType", + "options": { + "fields": {}, + "conversions": [ + { + "targetField": "A-series", + "destinationType": "number" + } + ] + } + } + ], "title": "Only nulls and no user set min & max", "type": "gauge" }, @@ -627,7 +616,6 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "", "mappings": [ { "from": "", @@ -646,17 +634,14 @@ "steps": [ { "color": "#7EB26D", - "index": 0, "value": null }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -709,7 +694,6 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "", "mappings": [ { "from": "", @@ -728,17 +712,14 @@ "steps": [ { "color": "#7EB26D", - "index": 0, "value": null }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -791,7 +772,6 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "", "mappings": [ { "from": "0", @@ -810,17 +790,14 @@ "steps": [ { "color": "#7EB26D", - "index": 0, "value": null }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -873,7 +850,6 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "", "mappings": [ { "from": "0", @@ -901,17 +877,14 @@ "steps": [ { "color": "#7EB26D", - "index": 0, "value": null }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -977,7 +950,7 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "2", + "decimals": 2, "mappings": [], "max": 100, "min": 0, @@ -986,17 +959,14 @@ "steps": [ { "color": "#7EB26D", - "index": 0, "value": null }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -1057,7 +1027,7 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "2", + "decimals": 2, "mappings": [], "max": 100, "min": 0, @@ -1066,17 +1036,14 @@ "steps": [ { "color": "#7EB26D", - "index": 0, "value": null }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -1138,7 +1105,7 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "2", + "decimals": 2, "mappings": [], "max": 100, "min": 0, @@ -1147,17 +1114,14 @@ "steps": [ { "color": "#7EB26D", - "index": 0, "value": null }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] @@ -1219,7 +1183,7 @@ "mode": "thresholds" }, "custom": {}, - "decimals": "2", + "decimals": 2, "mappings": [], "max": 100, "min": 0, @@ -1228,17 +1192,14 @@ "steps": [ { "color": "#7EB26D", - "index": 0, "value": null }, { "color": "#ef843c", - "index": 1, "value": 75 }, { "color": "#e24d42", - "index": 2, "value": 90 } ] diff --git a/devenv/dev-dashboards/panel-gauge/gauge_tests_new.json b/devenv/dev-dashboards/panel-gauge/gauge_tests_new.json index 65cc0b0a5ae..ff69226fdf5 100644 --- a/devenv/dev-dashboards/panel-gauge/gauge_tests_new.json +++ b/devenv/dev-dashboards/panel-gauge/gauge_tests_new.json @@ -1718,6 +1718,22 @@ "startValue": 0 } ], + "transformations": [ + { + "id": "calculateField", + "options": { + "mode": "unary", + "reduce": { + "reducer": "sum" + }, + "replaceFields": true, + "unary": { + "operator": "round", + "fieldName": "A-series" + } + } + } + ], "title": "Active gateways", "type": "radialbar" }, @@ -1799,6 +1815,22 @@ "startValue": 0 } ], + "transformations": [ + { + "id": "calculateField", + "options": { + "mode": "unary", + "reduce": { + "reducer": "sum" + }, + "replaceFields": true, + "unary": { + "operator": "round", + "fieldName": "A-series" + } + } + } + ], "title": "Active pods", "type": "radialbar" }, diff --git a/devenv/dev-dashboards/panel-gauge/gauge_tests_old_to_new.json b/devenv/dev-dashboards/panel-gauge/gauge_tests_old_to_new.json index bee1ece914e..3ca00ad5b63 100644 --- a/devenv/dev-dashboards/panel-gauge/gauge_tests_old_to_new.json +++ b/devenv/dev-dashboards/panel-gauge/gauge_tests_old_to_new.json @@ -474,6 +474,7 @@ }, "id": 12, "options": { + "displayName": "My gauge", "minVizHeight": 75, "minVizWidth": 75, "orientation": "auto", diff --git a/devenv/dev-dashboards/panel-histogram/histogram_tests.json b/devenv/dev-dashboards/panel-histogram/histogram_tests.json index af6127cb447..7d6a684417e 100644 --- a/devenv/dev-dashboards/panel-histogram/histogram_tests.json +++ b/devenv/dev-dashboards/panel-histogram/histogram_tests.json @@ -58,8 +58,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -125,8 +124,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -192,8 +190,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -269,8 +266,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -343,8 +339,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -432,8 +427,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -516,8 +510,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [ { @@ -597,8 +590,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [ { @@ -678,8 +670,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [ { @@ -759,8 +750,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -824,8 +814,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [ { diff --git a/devenv/dev-dashboards/panel-piechart/panel_test_piechart.json b/devenv/dev-dashboards/panel-piechart/panel_test_piechart.json index 4333993ea8e..ac11fd803b9 100644 --- a/devenv/dev-dashboards/panel-piechart/panel_test_piechart.json +++ b/devenv/dev-dashboards/panel-piechart/panel_test_piechart.json @@ -248,7 +248,7 @@ "legend": { "values": ["percent"], "displayMode": "table", - "placement": "bottom" + "placement": "right" }, "pieType": "pie", "reduceOptions": { @@ -256,7 +256,7 @@ "fields": "", "values": false }, - "showLegend": false, + "showLegend": true, "strokeWidth": 1, "text": {} }, @@ -272,6 +272,15 @@ "timeFrom": null, "timeShift": null, "title": "Percent", + "transformations": [ + { + "id": "renameByRegex", + "options": { + "regex": "^Backend-(.*)$", + "renamePattern": "b-$1" + } + } + ], "type": "piechart" }, { @@ -311,7 +320,7 @@ "legend": { "values": ["value"], "displayMode": "table", - "placement": "bottom" + "placement": "right" }, "pieType": "pie", "reduceOptions": { @@ -319,7 +328,7 @@ "fields": "", "values": false }, - "showLegend": false, + "showLegend": true, "strokeWidth": 1, "text": {} }, @@ -335,6 +344,15 @@ "timeFrom": null, "timeShift": null, "title": "Value", + "transformations": [ + { + "id": "renameByRegex", + "options": { + "regex": "(.*)", + "renamePattern": "$1-how-much-wood-could-a-woodchuck-chuck-if-a-woodchuck-could-chuck-wood" + } + } + ], "type": "piechart" }, { diff --git a/devenv/dev-dashboards/panel-xychart/xychart-tooltip-color-test.json b/devenv/dev-dashboards/panel-xychart/xychart-tooltip-color-test.json index b0ae2a9d76b..15fda5d6316 100644 --- a/devenv/dev-dashboards/panel-xychart/xychart-tooltip-color-test.json +++ b/devenv/dev-dashboards/panel-xychart/xychart-tooltip-color-test.json @@ -62,8 +62,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -150,8 +149,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -238,8 +236,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -326,8 +323,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -421,8 +417,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -516,8 +511,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, @@ -611,8 +605,7 @@ "value": 80 } ] - }, - "unitScale": true + } }, "overrides": [] }, diff --git a/devenv/jsonnet/dev-dashboards.libsonnet b/devenv/jsonnet/dev-dashboards.libsonnet index cac117cd4e7..98eb14e9217 100644 --- a/devenv/jsonnet/dev-dashboards.libsonnet +++ b/devenv/jsonnet/dev-dashboards.libsonnet @@ -24,6 +24,7 @@ "canvas-connection-examples": (import '../dev-dashboards/panel-canvas/canvas-connection-examples.json'), "canvas-datalinks": (import '../dev-dashboards/panel-canvas/canvas-datalinks.json'), "canvas-examples": (import '../dev-dashboards/panel-canvas/canvas-examples.json'), + "canvas_kitchen_sink": (import '../dev-dashboards/panel-canvas/canvas_kitchen_sink.json'), "color_modes": (import '../dev-dashboards/panel-common/color_modes.json'), "config-from-query": (import '../dev-dashboards/transforms/config-from-query.json'), "dashlist": (import '../dev-dashboards/panel-dashlist/dashlist.json'), diff --git a/devenv/scopes/scopes-config.yaml b/devenv/scopes/scopes-config.yaml index ef800415547..66ba7b6988c 100644 --- a/devenv/scopes/scopes-config.yaml +++ b/devenv/scopes/scopes-config.yaml @@ -48,6 +48,23 @@ scopes: operator: equals value: kids + # This scope appears in multiple places in the tree. + # The defaultPath determines which path is shown when this scope is selected + # (e.g., from a URL or programmatically), even if another path also links to it. + shared-service: + title: Shared Service + # Path from the root node down to the direct scopeNode. + # Node names are hierarchical (parent-child), so use the full names. + # This points to: gdev-scopes > production > shared-service-prod + defaultPath: + - gdev-scopes + - gdev-scopes-production + - gdev-scopes-production-shared-service-prod + filters: + - key: service + operator: equals + value: shared + tree: gdev-scopes: title: gdev-scopes @@ -68,6 +85,13 @@ tree: nodeType: leaf linkId: app2 linkType: scope + # This node links to 'shared-service' scope. + # The scope's defaultPath points here (production > gdev-scopes). + shared-service-prod: + title: Shared Service + nodeType: leaf + linkId: shared-service + linkType: scope test-cases: title: Test cases nodeType: container @@ -83,6 +107,15 @@ tree: nodeType: leaf linkId: test-case-2 linkType: scope + # This node also links to the same 'shared-service' scope. + # However, the scope's defaultPath points to the production path, + # so selecting this scope will expand the tree to production > shared-service-prod. + shared-service-test: + title: Shared Service (also in Production) + subTitle: defaultPath points to Production + nodeType: leaf + linkId: shared-service + linkType: scope test-case-redirect: title: Test case with redirect nodeType: leaf diff --git a/devenv/scopes/scopes.go b/devenv/scopes/scopes.go index e3f4de80d21..4487c5b69ef 100644 --- a/devenv/scopes/scopes.go +++ b/devenv/scopes/scopes.go @@ -51,8 +51,9 @@ type Config struct { // ScopeConfig is used for YAML parsing - converts to v0alpha1.ScopeSpec type ScopeConfig struct { - Title string `yaml:"title"` - Filters []ScopeFilterConfig `yaml:"filters"` + Title string `yaml:"title"` + DefaultPath []string `yaml:"defaultPath,omitempty"` + Filters []ScopeFilterConfig `yaml:"filters"` } // ScopeFilterConfig is used for YAML parsing - converts to v0alpha1.ScopeFilter @@ -116,9 +117,20 @@ func convertScopeSpec(cfg ScopeConfig) v0alpha1.ScopeSpec { for i, f := range cfg.Filters { filters[i] = convertFilter(f) } + + // Prefix defaultPath elements with the gdev prefix + var defaultPath []string + if len(cfg.DefaultPath) > 0 { + defaultPath = make([]string, len(cfg.DefaultPath)) + for i, p := range cfg.DefaultPath { + defaultPath[i] = prefix + "-" + p + } + } + return v0alpha1.ScopeSpec{ - Title: cfg.Title, - Filters: filters, + Title: cfg.Title, + DefaultPath: defaultPath, + Filters: filters, } } diff --git a/docs/sources/administration/plugin-management/plugin-sign.md b/docs/sources/administration/plugin-management/plugin-sign.md index 7850996d0f6..54d65baacde 100644 --- a/docs/sources/administration/plugin-management/plugin-sign.md +++ b/docs/sources/administration/plugin-management/plugin-sign.md @@ -25,7 +25,7 @@ Plugin signature verification, also known as _signing_, is a security measure to Learn more at [plugin policies](https://grafana.com/legal/plugins/). -## How does verifiction work? +## How does verification work? At startup, Grafana verifies the signatures of every plugin in the plugin directory. diff --git a/docs/sources/administration/provisioning/index.md b/docs/sources/administration/provisioning/index.md index 15215275b53..29347497881 100644 --- a/docs/sources/administration/provisioning/index.md +++ b/docs/sources/administration/provisioning/index.md @@ -428,12 +428,25 @@ Or using a Kubernetes format, for example `kubernetes-dashboard.json`: You _must_ use the Kubernetes resource format to provision dashboards v2 / dynamic dashboards. -It later polls that path every `updateIntervalSeconds` for updates to the dashboard files and updates its database. - {{< admonition type="note" >}} Grafana installs dashboards at the root level if you don't set the `folder` field. {{< /admonition >}} +#### Detect updates to provisioned dashboards files + +After Grafana provisions your dashboards, it checks the filesystem for changes and updates dashboards as needed. + +The mechanism Grafana uses to do this depends on your `updateIntervalSeconds` value: + +- **More than 10 seconds**: Grafana polls the path at that interval. +- **10 seconds or less**: Grafana watches the filesystem for changes and updates dashboards when it detects them. + +{{< admonition type="note" >}} +When `updateIntervalSeconds` is 10 or less, Grafana relies on filesystem watch events to detect changes. +Depending on your filesystem and how you mount or sync dashboard files (for example, Docker bind mounts or some network filesystems), those events might not reach Grafana. +To work around this, set `updateIntervalSeconds` to more than 10 to force polling, or update your setup so filesystem watch events are propagated. +{{< /admonition >}} + #### Make changes to a provisioned dashboard You can make changes to a provisioned dashboard in the Grafana UI but its not possible to automatically save the changes back to the provisioning source. diff --git a/docs/sources/administration/roles-and-permissions/_index.md b/docs/sources/administration/roles-and-permissions/_index.md index c8135836fa1..7a33d940a15 100644 --- a/docs/sources/administration/roles-and-permissions/_index.md +++ b/docs/sources/administration/roles-and-permissions/_index.md @@ -35,10 +35,10 @@ For Grafana Cloud users, Grafana Support is not authorised to make org role chan ## Grafana server administrators -A Grafana server administrator manages server-wide settings and access to resources such as organizations, users, and licenses. Grafana includes a default server administrator that you can use to manage all of Grafana, or you can divide that responsibility among other server administrators that you create. +A Grafana server administrator (sometimes referred to as a **Grafana Admin**) manages server-wide settings and access to resources such as organizations, users, and licenses. Grafana includes a default server administrator that you can use to manage all of Grafana, or you can divide that responsibility among other server administrators that you create. -{{< admonition type="note" >}} -The server administrator role does not mean that the user is also a Grafana [organization administrator](#organization-roles). +{{< admonition type="caution" >}} +The server administrator role is distinct from the [organization administrator](#organization-roles) role. {{< /admonition >}} A server administrator can perform the following tasks: @@ -50,7 +50,7 @@ A server administrator can perform the following tasks: - Upgrade the server to Grafana Enterprise. {{< admonition type="note" >}} -The server administrator role does not exist in Grafana Cloud. +The server administrator (Grafana Admin) role does not exist in Grafana Cloud. {{< /admonition >}} To assign or remove server administrator privileges, see [Server user management](../user-management/server-user-management/assign-remove-server-admin-privileges/). diff --git a/docs/sources/administration/roles-and-permissions/access-control/manage-rbac-roles/index.md b/docs/sources/administration/roles-and-permissions/access-control/manage-rbac-roles/index.md index 40a6d3645af..b0f35087efc 100644 --- a/docs/sources/administration/roles-and-permissions/access-control/manage-rbac-roles/index.md +++ b/docs/sources/administration/roles-and-permissions/access-control/manage-rbac-roles/index.md @@ -53,6 +53,11 @@ refs: destination: /docs/grafana//administration/roles-and-permissions/access-control/custom-role-actions-scopes/ - pattern: /docs/grafana-cloud/ destination: /docs/grafana-cloud/account-management/authentication-and-permissions/access-control/custom-role-actions-scopes/ + rbac-terraform-provisioning: + - pattern: /docs/grafana/ + destination: /docs/grafana//administration/roles-and-permissions/access-control/rbac-terraform-provisioning/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana-cloud/account-management/authentication-and-permissions/access-control/rbac-terraform-provisioning/ rbac-grafana-provisioning: - pattern: /docs/grafana/ destination: /docs/grafana//administration/roles-and-permissions/access-control/rbac-grafana-provisioning/ @@ -145,7 +150,13 @@ Refer to the [RBAC HTTP API](ref:api-rbac-get-a-role) for more details. ## Create custom roles -This section shows you how to create a custom RBAC role using Grafana provisioning and the HTTP API. +This section shows you how to create a custom RBAC role using Grafana provisioning or the HTTP API. + +Creating and editing custom roles is not currently possible in the Grafana UI. To manage custom roles, use one of the following methods: + +- [Provisioning](ref:rbac-grafana-provisioning) (for self-managed instances) +- [HTTP API](ref:api-rbac-create-a-new-custom-role) +- [Terraform](ref:rbac-terraform-provisioning) Create a custom role when basic roles and fixed roles do not meet your permissions requirements. @@ -153,14 +164,101 @@ Create a custom role when basic roles and fixed roles do not meet your permissio - [Plan your RBAC rollout strategy](ref:plan-rbac-rollout-strategy). - Determine which permissions you want to add to the custom role. To see a list of actions and scope, refer to [RBAC permissions, actions, and scopes](ref:custom-role-actions-scopes). -- [Enable role provisioning](ref:rbac-grafana-provisioning). - Ensure that you have permissions to create a custom role. - By default, the Grafana Admin role has permission to create custom roles. - A Grafana Admin can delegate the custom role privilege to another user by creating a custom role with the relevant permissions and adding the `permissions:type:delegate` scope. -### Create custom roles using provisioning +### Create custom roles using the HTTP API -[File-based provisioning](ref:rbac-grafana-provisioning) is one method you can use to create custom roles. +The following examples show you how to create a custom role using the Grafana HTTP API. For more information about the HTTP API, refer to [Create a new custom role](ref:api-rbac-create-a-new-custom-role). + +{{< admonition type="note" >}} +When you create a custom role you can only give it the same permissions you already have. For example, if you only have `users:create` permissions, then you can't create a role that includes other permissions. +{{< /admonition >}} + +The following example creates a `custom:users:admin` role and assigns the `users:create` action to it. + +**Example request** + +``` +curl --location --request POST '/api/access-control/roles/' \ +--header 'Authorization: Basic YWRtaW46cGFzc3dvcmQ=' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "version": 1, + "uid": "jZrmlLCkGksdka", + "name": "custom:users:admin", + "displayName": "custom users admin", + "description": "My custom role which gives users permissions to create users", + "global": true, + "permissions": [ + { + "action": "users:create" + } + ] +}' +``` + +**Example response** + +``` +{ + "version": 1, + "uid": "jZrmlLCkGksdka", + "name": "custom:users:admin", + "displayName": "custom users admin", + "description": "My custom role which gives users permissions to create users", + "global": true, + "permissions": [ + { + "action": "users:create" + "updated": "2021-05-17T22:07:31.569936+02:00", + "created": "2021-05-17T22:07:31.569935+02:00" + } + ], + "updated": "2021-05-17T22:07:31.564403+02:00", + "created": "2021-05-17T22:07:31.564403+02:00" +} +``` + +Refer to the [RBAC HTTP API](ref:api-rbac-create-a-new-custom-role) for more details. + +### Create custom roles using Terraform + +You can use the [Grafana Terraform provider](https://registry.terraform.io/providers/grafana/grafana/latest/docs) to manage custom roles and their assignments. This is the recommended method for Grafana Cloud users who want to manage RBAC as code. For more information, refer to [Provisioning RBAC with Terraform](ref:rbac-terraform-provisioning). + +The following example creates a custom role and assigns it to a team: + +```terraform +resource "grafana_role" "custom_folder_manager" { + name = "custom:folders:manager" + description = "Custom role for reading and creating folders" + uid = "custom-folders-manager" + version = 1 + global = true + + permissions { + action = "folders:read" + scope = "folders:*" + } + + permissions { + action = "folders:create" + scope = "folders:uid:general" # Allows creating folders at the root level + } +} + +resource "grafana_role_assignment" "custom_folder_manager_assignment" { + role_uid = grafana_role.custom_folder_manager.uid + teams = [""] +} +``` + +For more information, refer to the [`grafana_role`](https://registry.terraform.io/providers/grafana/grafana/latest/docs/resources/role) and [`grafana_role_assignment`](https://registry.terraform.io/providers/grafana/grafana/latest/docs/resources/role_assignment) documentation in the Terraform Registry. + +### Create custom roles using file-based provisioning + +You can use [file-based provisioning](ref:rbac-grafana-provisioning) to create custom roles for self-managed instances. 1. Open the YAML configuration file and locate the `roles` section. @@ -251,61 +349,6 @@ roles: state: 'absent' ``` -### Create custom roles using the HTTP API - -The following examples show you how to create a custom role using the Grafana HTTP API. For more information about the HTTP API, refer to [Create a new custom role](ref:api-rbac-create-a-new-custom-role). - -{{< admonition type="note" >}} -You cannot create a custom role with permissions that you do not have. For example, if you only have `users:create` permissions, then you cannot create a role that includes other permissions. -{{< /admonition >}} - -The following example creates a `custom:users:admin` role and assigns the `users:create` action to it. - -**Example request** - -``` -curl --location --request POST '/api/access-control/roles/' \ ---header 'Authorization: Basic YWRtaW46cGFzc3dvcmQ=' \ ---header 'Content-Type: application/json' \ ---data-raw '{ - "version": 1, - "uid": "jZrmlLCkGksdka", - "name": "custom:users:admin", - "displayName": "custom users admin", - "description": "My custom role which gives users permissions to create users", - "global": true, - "permissions": [ - { - "action": "users:create" - } - ] -}' -``` - -**Example response** - -``` -{ - "version": 1, - "uid": "jZrmlLCkGksdka", - "name": "custom:users:admin", - "displayName": "custom users admin", - "description": "My custom role which gives users permissions to create users", - "global": true, - "permissions": [ - { - "action": "users:create" - "updated": "2021-05-17T22:07:31.569936+02:00", - "created": "2021-05-17T22:07:31.569935+02:00" - } - ], - "updated": "2021-05-17T22:07:31.564403+02:00", - "created": "2021-05-17T22:07:31.564403+02:00" -} -``` - -Refer to the [RBAC HTTP API](ref:api-rbac-create-a-new-custom-role) for more details. - ## Update basic role permissions If the default basic role definitions do not meet your requirements, you can change their permissions. diff --git a/docs/sources/administration/roles-and-permissions/access-control/rbac-for-app-plugins/index.md b/docs/sources/administration/roles-and-permissions/access-control/rbac-for-app-plugins/index.md index 15cf895a5e8..465880919ca 100644 --- a/docs/sources/administration/roles-and-permissions/access-control/rbac-for-app-plugins/index.md +++ b/docs/sources/administration/roles-and-permissions/access-control/rbac-for-app-plugins/index.md @@ -66,17 +66,18 @@ Please refer to plugin documentation to see what RBAC permissions the plugin has The following list contains app plugins that have fine-grained RBAC support. -| App plugin | App plugin ID | App plugin permission documentation | -| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| [Access policies](https://grafana.com/docs/grafana-cloud/account-management/authentication-and-permissions/access-policies/) | `grafana-auth-app` | [RBAC actions for Access Policies](ref:cloud-access-policies-action-definitions) | -| [Adaptive Metrics](https://grafana.com/docs/grafana-cloud/cost-management-and-billing/reduce-costs/metrics-costs/control-metrics-usage-via-adaptive-metrics/adaptive-metrics-plugin/) | `grafana-adaptive-metrics-app` | [RBAC actions for Adaptive Metrics](ref:adaptive-metrics-permissions) | -| [Cloud Provider](https://grafana.com/docs/grafana-cloud/monitor-infrastructure/monitor-cloud-provider/) | `grafana-csp-app` | [Cloud Provider Observability role-based access control](https://grafana.com/docs/grafana-cloud/monitor-infrastructure/monitor-cloud-provider/rbac/) | -| [Incident](https://grafana.com/docs/grafana-cloud/alerting-and-irm/irm/incident/) | `grafana-incident-app` | n/a | -| [Kubernetes Monitoring](/docs/grafana-cloud/monitor-infrastructure/kubernetes-monitoring/) | `grafana-k8s-app` | [Kubernetes Monitoring role-based access control](/docs/grafana-cloud/monitor-infrastructure/kubernetes-monitoring/configuration/control-access/#precision-access-with-rbac-custom-plugin-roles) | -| [OnCall](https://grafana.com/docs/grafana-cloud/alerting-and-irm/irm/oncall/) | `grafana-oncall-app` | [Configure RBAC for OnCall](https://grafana.com/docs/grafana-cloud/alerting-and-irm/irm/oncall/manage/user-and-team-management/#manage-users-and-teams-for-grafana-oncall) | -| [Performance Testing (K6)](https://grafana.com/docs/grafana-cloud/testing/k6/) | `k6-app` | [Configure RBAC for K6](https://grafana.com/docs/grafana-cloud/testing/k6/projects-and-users/configure-rbac/) | -| [Private data source connect (PDC)](https://grafana.com/docs/grafana-cloud/connect-externally-hosted/private-data-source-connect/) | `grafana-pdc-app` | n/a | -| [Service Level Objective (SLO)](https://grafana.com/docs/grafana-cloud/alerting-and-irm/slo/) | `grafana-slo-app` | [Configure RBAC for SLO](https://grafana.com/docs/grafana-cloud/alerting-and-irm/slo/set-up/rbac/) | +| App plugin | App plugin ID | App plugin permission documentation | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| [Access policies](https://grafana.com/docs/grafana-cloud/account-management/authentication-and-permissions/access-policies/) | `grafana-auth-app` | [RBAC actions for Access Policies](ref:cloud-access-policies-action-definitions) | +| [Adaptive Metrics](https://grafana.com/docs/grafana-cloud/cost-management-and-billing/reduce-costs/metrics-costs/control-metrics-usage-via-adaptive-metrics/adaptive-metrics-plugin/) | `grafana-adaptive-metrics-app` | [RBAC actions for Adaptive Metrics](ref:adaptive-metrics-permissions) | +| [Cloud Provider](https://grafana.com/docs/grafana-cloud/monitor-infrastructure/monitor-cloud-provider/) | `grafana-csp-app` | [Cloud Provider Observability role-based access control](https://grafana.com/docs/grafana-cloud/monitor-infrastructure/monitor-cloud-provider/rbac/) | +| [Incident](https://grafana.com/docs/grafana-cloud/alerting-and-irm/irm/incident/) | `grafana-incident-app` | n/a | +| [Kubernetes Monitoring](/docs/grafana-cloud/monitor-infrastructure/kubernetes-monitoring/) | `grafana-k8s-app` | [Kubernetes Monitoring role-based access control](/docs/grafana-cloud/monitor-infrastructure/kubernetes-monitoring/configuration/control-access/#precision-access-with-rbac-custom-plugin-roles) | +| [OnCall](https://grafana.com/docs/grafana-cloud/alerting-and-irm/irm/oncall/) | `grafana-oncall-app` | [Configure RBAC for OnCall](https://grafana.com/docs/grafana-cloud/alerting-and-irm/irm/oncall/manage/user-and-team-management/#manage-users-and-teams-for-grafana-oncall) | +| [Performance Testing (K6)](https://grafana.com/docs/grafana-cloud/testing/k6/) | `k6-app` | [Configure RBAC for K6](https://grafana.com/docs/grafana-cloud/testing/k6/projects-and-users/configure-rbac/) | +| [Private data source connect (PDC)](https://grafana.com/docs/grafana-cloud/connect-externally-hosted/private-data-source-connect/) | `grafana-pdc-app` | n/a | +| [Service Level Objective (SLO)](https://grafana.com/docs/grafana-cloud/alerting-and-irm/slo/) | `grafana-slo-app` | [Configure RBAC for SLO](https://grafana.com/docs/grafana-cloud/alerting-and-irm/slo/set-up/rbac/) | +| [Synthetic Monitoring](https://grafana.com/docs/grafana-cloud/testing/synthetic-monitoring/) | `grafana-synthetic-monitoring-app` | [Configure RBAC for Synthetic Monitoring](https://grafana.com/docs/grafana-cloud/testing/synthetic-monitoring/user-and-team-management/) | ### Revoke fine-grained access from app plugins diff --git a/docs/sources/administration/roles-and-permissions/access-control/rbac-grafana-provisioning/index.md b/docs/sources/administration/roles-and-permissions/access-control/rbac-grafana-provisioning/index.md index 06f9699533b..fe45a620bc5 100644 --- a/docs/sources/administration/roles-and-permissions/access-control/rbac-grafana-provisioning/index.md +++ b/docs/sources/administration/roles-and-permissions/access-control/rbac-grafana-provisioning/index.md @@ -6,7 +6,6 @@ description: Learn about RBAC Grafana provisioning and view an example YAML prov file that configures Grafana role assignments. labels: products: - - cloud - enterprise menuTitle: Provisioning RBAC with Grafana title: Provisioning RBAC with Grafana @@ -52,11 +51,13 @@ refs: # Provisioning RBAC with Grafana {{< admonition type="note" >}} -Available in [Grafana Enterprise](/docs/grafana//introduction/grafana-enterprise/) and [Grafana Cloud](/docs/grafana-cloud). +Available in [Grafana Enterprise](/docs/grafana//introduction/grafana-enterprise/) for self-managed instances. This feature is not available in Grafana Cloud. {{< /admonition >}} You can create, change or remove [Custom roles](ref:manage-rbac-roles-create-custom-roles-using-provisioning) and create or remove [basic role assignments](ref:assign-rbac-roles-assign-a-fixed-role-to-a-basic-role-using-provisioning), by adding one or more YAML configuration files in the `provisioning/access-control/` directory. +Because this method requires access to the file system where Grafana is running, it's only available for self-managed Grafana instances. To provision RBAC in Grafana Cloud, use [Terraform](ref:rbac-terraform-provisioning) or the [HTTP API](ref:api-rbac-create-and-manage-custom-roles). + Grafana performs provisioning during startup. After you make a change to the configuration file, you can reload it during runtime. You do not need to restart the Grafana server for your changes to take effect. **Before you begin:** diff --git a/docs/sources/alerting/alerting-rules/alerting-migration.md b/docs/sources/alerting/alerting-rules/alerting-migration.md index ab2a5e995cd..320b04b4643 100644 --- a/docs/sources/alerting/alerting-rules/alerting-migration.md +++ b/docs/sources/alerting/alerting-rules/alerting-migration.md @@ -134,7 +134,7 @@ To convert data source-managed alert rules to Grafana managed alerts: Pausing stops alert rule evaluation behavior for the newly created Grafana-managed alert rules. -9. (Optional) In the **Target data source** of the **Recording rules** section, you can select the data source that the imported recording rules will query. By default, it is the data source selected in the **Data source** dropdown. +9. (Optional) In the **Target data source** of the **Recording rules** section, you can select the data source to which the imported recording rules will write metrics. By default, it is the data source selected in the **Data source** dropdown. 10. Click **Import**. diff --git a/docs/sources/alerting/alerting-rules/create-recording-rules/_index.md b/docs/sources/alerting/alerting-rules/create-recording-rules/_index.md index a56d3ac5bb2..bcf9663aca9 100644 --- a/docs/sources/alerting/alerting-rules/create-recording-rules/_index.md +++ b/docs/sources/alerting/alerting-rules/create-recording-rules/_index.md @@ -48,6 +48,14 @@ Recording rules can be helpful in various scenarios, such as: The evaluation group of the recording rule determines how often the metric is pre-computed. +## Recommendations + +- **Use frequent evaluation intervals**. Set frequent evaluation intervals for recording rules. Long intervals, such as an hour, can cause the recorded metric to be stale and lead to misaligned alert rule evaluations, especially when combined with a long pending period. +- **Align alert evaluation with recording frequency**. The evaluation interval of an alert rule that depends on a recorded metric should be aligned with the recording rule's interval. If a recording rule runs every 3 minutes, the alert rule should also be evaluated at a similar frequency to ensure it acts on fresh data. +- **Use `_over_time` functions for instant queries**. Since all alert rules are ultimately executed as an instant query, you can use functions like `max_over_time(my_metric[5m])` as an instant query. This allows you to get an aggregated value over a period without using a range query and a reduce expression. + +## Types of recording rules + Similar to alert rules, Grafana supports two types of recording rules: 1. [Grafana-managed recording rules](ref:grafana-managed-recording-rules), which can query any Grafana data source supported by alerting. It's the recommended option. diff --git a/docs/sources/alerting/best-practices/_index.md b/docs/sources/alerting/best-practices/_index.md deleted file mode 100644 index 4e08dd8ef37..00000000000 --- a/docs/sources/alerting/best-practices/_index.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -canonical: https://grafana.com/docs/grafana/latest/alerting/best-practices/ -description: This section provides a set of guides for useful alerting practices and recommendations -keywords: - - grafana -labels: - products: - - cloud - - enterprise - - oss -menuTitle: Best practices -title: Grafana Alerting best practices -weight: 170 ---- - -# Grafana Alerting best practices - -This section provides a set of guides and examples of best practices for Grafana Alerting. Here you can learn more about how to handle common alert management problems and you can see examples of more advanced usage of Grafana Alerting. - -{{< section >}} - -Designing and configuring an alert management set up that works takes time. Here are some additional tips on how to create an effective alert management set up: - -{{< shared id="alert-planning-fundamentals" >}} - -**Which are the key metrics for your business that you want to monitor and alert on?** - -- Find events that are important to know about and not so trivial or frequent that recipients ignore them. -- Alerts should only be created for big events that require immediate attention or intervention. -- Consider quality over quantity. - -**How do you want to organize your alerts and notifications?** - -- Be selective about who you set to receive alerts. Consider sending them to the right teams, whoever is on call, and the specific channels. -- Think carefully about priority and severity levels. -- Automate as far as possible provisioning Alerting resources with the API or Terraform. - -**Which information should you include in notifications?** - -- Consider who the alert receivers and responders are. -- Share information that helps responders identify and address potential issues. -- Link alerts to dashboards to guide responders on which data to investigate. - -**How can you reduce alert fatigue?** - -- Avoid noisy, unnecessary alerts by using silences, mute timings, or pausing alert rule evaluation. -- Continually tune your alert rules to review effectiveness. Remove alert rules to avoid duplication or ineffective alerts. -- Continually review your thresholds and evaluation rules. - -**How should you configure recording rules?** - -- Use frequent evaluation intervals. It is recommended to set a frequent evaluation interval for recording rules. Long intervals, such as an hour, can cause the recorded metric to be stale and lead to misaligned alert rule evaluations, especially when combined with a long pending period. -- Understand query types. Grafana Alerting uses both **Instant** and **Range** queries. Instant queries fetch a single data point, while Range queries fetch a series of data points over time. When using a Range query in an alert condition, you must use a Reduce expression to aggregate the series into a single value. -- Align alert evaluation with recording frequency. The evaluation interval of an alert rule that depends on a recorded metric should be aligned with the recording rule's interval. If a recording rule runs every 3 minutes, the alert rule should also be evaluated at a similar frequency to ensure it acts on fresh data. -- Use `_over_time` functions for instant queries. Since all alert rules are ultimately executed as an instant query, you can use functions like `max_over_time(my_metric[1h])` as an instant query. This allows you to get an aggregated value over a period without using a range query and a reduce expression. - -{{< /shared >}} diff --git a/docs/sources/alerting/examples/_index.md b/docs/sources/alerting/examples/_index.md new file mode 100644 index 00000000000..3b46838b78a --- /dev/null +++ b/docs/sources/alerting/examples/_index.md @@ -0,0 +1,22 @@ +--- +canonical: https://grafana.com/docs/grafana/latest/alerting/examples/ +description: This section provides a set of guides for useful alerting practices and recommendations +keywords: + - grafana +labels: + products: + - cloud + - enterprise + - oss +menuTitle: Examples +title: Examples +weight: 180 +--- + +# Examples + +This section provides practical examples that show how to work with different types of alerting data, apply alert design patterns, reuse alert logic, and take advantage of specific Grafana Alerting features. + +This section includes: + +{{< section >}} diff --git a/docs/sources/alerting/best-practices/dynamic-labels.md b/docs/sources/alerting/examples/dynamic-labels.md similarity index 98% rename from docs/sources/alerting/best-practices/dynamic-labels.md rename to docs/sources/alerting/examples/dynamic-labels.md index 7a9586ea6d9..6223e7ebff6 100644 --- a/docs/sources/alerting/best-practices/dynamic-labels.md +++ b/docs/sources/alerting/examples/dynamic-labels.md @@ -1,5 +1,7 @@ --- -canonical: https://grafana.com/docs/grafana/latest/alerting/best-practices/dynamic-labels +aliases: + - ../best-practices/dynamic-labels/ # /docs/grafana//alerting/best-practices/dynamic-labels/ +canonical: https://grafana.com/docs/grafana/latest/alerting/examples/dynamic-labels description: This example shows how to define dynamic labels based on query values, along with important behavior to keep in mind when using them. keywords: - grafana @@ -10,7 +12,7 @@ labels: - cloud - enterprise - oss -menuTitle: Examples of dynamic labels +menuTitle: Dynamic labels title: Example of dynamic labels in alert instances weight: 1104 refs: diff --git a/docs/sources/alerting/best-practices/dynamic-thresholds.md b/docs/sources/alerting/examples/dynamic-thresholds.md similarity index 97% rename from docs/sources/alerting/best-practices/dynamic-thresholds.md rename to docs/sources/alerting/examples/dynamic-thresholds.md index e749bc1d943..5ce850842a4 100644 --- a/docs/sources/alerting/best-practices/dynamic-thresholds.md +++ b/docs/sources/alerting/examples/dynamic-thresholds.md @@ -1,5 +1,7 @@ --- -canonical: https://grafana.com/docs/grafana/latest/alerting/best-practices/dynamic-thresholds +aliases: + - ../best-practices/dynamic-thresholds/ # /docs/grafana//alerting/best-practices/dynamic-thresholds/ +canonical: https://grafana.com/docs/grafana/latest/alerting/examples/dynamic-thresholds description: This example shows how to use a distinct threshold value per dimension using multi-dimensional alerts and a Math expression. keywords: - grafana @@ -10,7 +12,7 @@ labels: - cloud - enterprise - oss -menuTitle: Examples of dynamic thresholds +menuTitle: Dynamic thresholds title: Example of dynamic thresholds per dimension weight: 1105 refs: diff --git a/docs/sources/alerting/best-practices/high-cardinality-alerts.md b/docs/sources/alerting/examples/high-cardinality-alerts.md similarity index 97% rename from docs/sources/alerting/best-practices/high-cardinality-alerts.md rename to docs/sources/alerting/examples/high-cardinality-alerts.md index 9df60ac6bc6..74d080fbee5 100644 --- a/docs/sources/alerting/best-practices/high-cardinality-alerts.md +++ b/docs/sources/alerting/examples/high-cardinality-alerts.md @@ -1,5 +1,7 @@ --- -canonical: https://grafana.com/docs/grafana/latest/alerting/best-practices/high-cardinality-alerts/ +aliases: + - ../best-practices/high-cardinality-alerts/ # /docs/grafana//alerting/best-practices/high-cardinality-alerts/ +canonical: https://grafana.com/docs/grafana/latest/alerting/examples/high-cardinality-alerts/ description: Learn how to detect and alert on high-cardinality metrics that can overload your metrics backend and increase observability costs. keywords: - grafana @@ -8,7 +10,7 @@ labels: - cloud - enterprise - oss -menuTitle: Examples of high-cardinality alerts +menuTitle: High-cardinality alerts title: Examples of high-cardinality alerts weight: 1105 refs: diff --git a/docs/sources/alerting/best-practices/multi-dimensional-alerts.md b/docs/sources/alerting/examples/multi-dimensional-alerts.md similarity index 96% rename from docs/sources/alerting/best-practices/multi-dimensional-alerts.md rename to docs/sources/alerting/examples/multi-dimensional-alerts.md index f612df6aa37..fa6d7dd04c1 100644 --- a/docs/sources/alerting/best-practices/multi-dimensional-alerts.md +++ b/docs/sources/alerting/examples/multi-dimensional-alerts.md @@ -1,5 +1,7 @@ --- -canonical: https://grafana.com/docs/grafana/latest/alerting/best-practices/multi-dimensional-alerts/ +aliases: + - ../best-practices/multi-dimensional-alerts/ # /docs/grafana//alerting/best-practices/multi-dimensional-alerts/ +canonical: https://grafana.com/docs/grafana/latest/alerting/examples/multi-dimensional-alerts/ description: This example shows how a single alert rule can generate multiple alert instances using time series data. keywords: - grafana @@ -8,7 +10,7 @@ labels: - cloud - enterprise - oss -menuTitle: Examples of multi-dimensional alerts +menuTitle: Multi-dimensional alerts title: Example of multi-dimensional alerts on time series data weight: 1101 refs: diff --git a/docs/sources/alerting/best-practices/table-data.md b/docs/sources/alerting/examples/table-data.md similarity index 96% rename from docs/sources/alerting/best-practices/table-data.md rename to docs/sources/alerting/examples/table-data.md index a39530ef5a8..342475cb7fa 100644 --- a/docs/sources/alerting/best-practices/table-data.md +++ b/docs/sources/alerting/examples/table-data.md @@ -1,5 +1,7 @@ --- -canonical: https://grafana.com/docs/grafana/latest/alerting/best-practices/table-data +aliases: + - ../best-practices/table-data/ # /docs/grafana//alerting/best-practices/table-data/ +canonical: https://grafana.com/docs/grafana/latest/alerting/examples/table-data description: This example shows how to create an alert rule using table data. keywords: - grafana @@ -8,7 +10,7 @@ labels: - cloud - enterprise - oss -menuTitle: Examples of table data +menuTitle: Table data title: Example of alerting on tabular data weight: 1102 refs: diff --git a/docs/sources/alerting/best-practices/trace-based-alerts.md b/docs/sources/alerting/examples/trace-based-alerts.md similarity index 98% rename from docs/sources/alerting/best-practices/trace-based-alerts.md rename to docs/sources/alerting/examples/trace-based-alerts.md index d908ecd7385..974089b4643 100644 --- a/docs/sources/alerting/best-practices/trace-based-alerts.md +++ b/docs/sources/alerting/examples/trace-based-alerts.md @@ -1,5 +1,7 @@ --- -canonical: https://grafana.com/docs/grafana/latest/alerting/best-practices/trace-based-alerts/ +aliases: + - ../best-practices/trace-based-alerts/ # /docs/grafana//alerting/best-practices/trace-based-alerts/ +canonical: https://grafana.com/docs/grafana/latest/alerting/examples/trace-based-alerts/ description: This guide provides introductory examples and distinct approaches for setting up trace-based alerts in Grafana. keywords: - grafana @@ -8,7 +10,7 @@ labels: - cloud - enterprise - oss -title: Examples of trace-based alerts +title: Trace-based alerts weight: 1103 refs: testdata-data-source: diff --git a/docs/sources/alerting/best-practices/tutorials.md b/docs/sources/alerting/examples/tutorials.md similarity index 87% rename from docs/sources/alerting/best-practices/tutorials.md rename to docs/sources/alerting/examples/tutorials.md index fbef5f36797..97fa7d6a754 100644 --- a/docs/sources/alerting/best-practices/tutorials.md +++ b/docs/sources/alerting/examples/tutorials.md @@ -1,5 +1,7 @@ --- -canonical: https://grafana.com/docs/grafana/latest/alerting/best-practices/tutorials/ +aliases: + - ../best-practices/tutorials/ # /docs/grafana//alerting/best-practices/tutorials/ +canonical: https://grafana.com/docs/grafana/latest/alerting/examples/tutorials/ description: This section provides a set of step-by-step tutorials guides to get started with Grafana Aletings. keywords: - grafana diff --git a/docs/sources/alerting/guides/_index.md b/docs/sources/alerting/guides/_index.md new file mode 100644 index 00000000000..69875878533 --- /dev/null +++ b/docs/sources/alerting/guides/_index.md @@ -0,0 +1,35 @@ +--- +canonical: https://grafana.com/docs/grafana/latest/alerting/guides/ +description: This section provides a set of guides for useful alerting practices and recommendations +keywords: + - grafana +labels: + products: + - cloud + - enterprise + - oss +menuTitle: Guides +title: Guides +weight: 170 +refs: + examples: + - pattern: /docs/grafana/ + destination: /docs/grafana//alerting/examples/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana-cloud/alerting-and-irm/alerting/examples/ + tutorials: + - pattern: /docs/grafana/ + destination: /docs/grafana//alerting/examples/tutorials/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana-cloud/alerting-and-irm/alerting/examples/tutorials/ +--- + +# Guides + +Guides in the Grafana Alerting documentation provide best practices and practical recommendations to help you move from a basic alerting setup to real-world use cases. + +These guides cover topics such as: + +{{< section >}} + +For more hands-on examples, refer to [Examples](ref:examples) and [Tutorials](ref:tutorials). diff --git a/docs/sources/alerting/guides/best-practices.md b/docs/sources/alerting/guides/best-practices.md new file mode 100644 index 00000000000..d1010390569 --- /dev/null +++ b/docs/sources/alerting/guides/best-practices.md @@ -0,0 +1,201 @@ +--- +aliases: + - ../best-practices/ # /docs/grafana//alerting/best-practices/ +canonical: https://grafana.com/docs/grafana/latest/alerting/guides/best-practices/ +description: Designing and configuring an effective alerting system takes time. This guide focuses on building alerting systems that scale with real-world operations. +keywords: + - grafana + - alerting + - guide +labels: + products: + - cloud + - enterprise + - oss +menuTitle: Best practices +title: Best practices +weight: 1010 +refs: + recovery-threshold: + - pattern: /docs/grafana/ + destination: /docs/grafana//alerting/fundamentals/alert-rules/queries-conditions/#recovery-threshold + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana-cloud/alerting-and-irm/fundamentals/alert-rules/queries-conditions/#recovery-threshold + keep-firing-for: + - pattern: /docs/grafana/ + destination: /docs/grafana//alerting/fundamentals/alert-rule-evaluation/#keep-firing-for + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana-cloud/alerting-and-irm/fundamentals/alert-rule-evaluation/#keep-firing-for + pending-period: + - pattern: /docs/grafana/ + destination: /docs/grafana//alerting/fundamentals/alert-rule-evaluation/#pending-period + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana-cloud/alerting-and-irm/fundamentals/alert-rule-evaluation/#pending-period + silences: + - pattern: /docs/grafana/ + destination: /docs/grafana//alerting/configure-notifications/create-silence/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana-cloud/alerting-and-irm/alerting/configure-notifications/create-silence/ + timing-options: + - pattern: /docs/grafana/ + destination: /docs/grafana//alerting/fundamentals/notifications/group-alert-notifications/#timing-options + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana-cloud/alerting-and-irm/alerting/fundamentals/notifications/group-alert-notifications/#timing-options + group-alert-notifications: + - pattern: /docs/grafana/ + destination: /docs/grafana//alerting/fundamentals/notifications/group-alert-notifications/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana-cloud/alerting-and-irm/alerting/fundamentals/notifications/group-alert-notifications/ + notification-policies: + - pattern: /docs/grafana/ + destination: /docs/grafana//alerting/fundamentals/notifications/notification-policies/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana-cloud/alerting-and-irm/alerting/fundamentals/notifications/notification-policies/ + annotations: + - pattern: /docs/grafana/ + destination: /docs/grafana//alerting/fundamentals/alert-rules/annotation-label/#annotations + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana-cloud/alerting-and-irm/alerting/fundamentals/alert-rules/annotation-label/#annotations + multi-dimensional-alerts: + - pattern: /docs/grafana/ + destination: /docs/grafana//alerting/examples/multi-dimensional-alerts/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana-cloud/alerting-and-irm/alerting/examples/multi-dimensional-alerts/ +--- + +# Alerting best practices + +Designing and configuring an effective alerting system takes time. This guide focuses on building alerting systems that scale with real-world operations. + +The practices described here are intentionally high-level and apply regardless of tooling. Whether you use Prometheus, Grafana Alerting, or another stack, the same constraints apply: complex systems, imperfect signals, and humans on call. + +Alerting is never finished. It evolves with incidents, organizational changes, and the systems it’s meant to protect. + +{{< shared id="alert-planning-fundamentals" >}} + +## Prioritize symptoms, but don’t ignore infrastructure signals + +Alerts should primarily detect user-facing failures, not internal component behavior. Users don't care that a pod restarted; they care when the application is slow or failing. Symptom-based alerts tie directly to user impact. + +Reliability metrics that impact users—latency, errors, availability—are better paging signals than infrastructure events or internal errors. + +That said, infrastructure signals still matter. They can act as early warning indicators and are often useful when alerting maturity is low. A sustained spike in CPU or memory usage might not justify a page, but it can help explain or anticipate symptom-based failures. + +Infrastructure alerts tend to be noisy and are often ignored when treated like paging signals. They are usually better suited for lower-severity channels such as dashboards, alert lists, or non-paging destinations like a dedicated Slack channel, where they can be monitored without interrupting on-call. + +The key is balance as your alerting matures. Use infrastructure alerts to support diagnosis and prevention, not as a replacement for symptom-based alerts. + +## Escalate priority based on confidence + +Alert priority is often tied to user impact and the urgency to respond, but confidence should determine when escalation is necessary. + +In this context, escalation defines how responders are notified as confidence grows. This can include increasing alert priority, widening notification, paging additional responders, or opening an incident once intervention is clearly required. + +Early signals are often ambiguous, and confidence in a non-transient failure is usually low. Paging too early creates noise; paging too late means users are impacted for longer before anyone acts. A small or sudden increase in latency may not justify immediate action, but it can indicate a failure in progress. + +Confidence increases as signals become stronger or begin to correlate. + +Escalation is justified when issues are sustained or reinforced by multiple signals. For example, high latency combined with a rising error rate, or the same event firing over a sustained period. These patterns reduce the chance of transient noise and increase the likelihood of real impact. + +Use confidence in user impact to drive escalation and avoid unnecessary pages. + +## Scope alerts for scalability and actionability + +In distributed systems, avoid creating separate alert rules for every host, service, or endpoint. Instead, define alert rules that scale automatically using [multi-dimensional alert rules](ref:multi-dimensional-alerts). This reduces rule duplication and allows alerting to scale as the system grows. + +Start simple. Default to a single dimension such as `service` or `endpoint` to keep alerts manageable. Add dimensions only when they improve actionability. For example, when missing a dimension like `region` hides failures or doesn't provide enough information to act quickly. + +Additional dimensions like `region` or `instance` can help identify the root cause, but more isn't always better. + +## Design alerts for first responders and clear actions + +Alerts should be designed for the first responder, not the person who created the alert. Anyone on call should be able to understand what's wrong and what to do next without deep knowledge of the system or alert configuration. + +Avoid vague alerts that force responders to spend time figuring out context. Every alert should clearly explain why it exists, what triggered it, and how to investigate. Use [annotations](ref:annotations) to link to relevant dashboards and runbooks, which are essential for faster resolution. + +Alerts should indicate a real problem and be actionable, even if the impact is low. Informational alerts add noise without improving reliability. + +If no action is possible, it shouldn't be an alert—consider using a dashboard instead. Over time, alerts behave like technical debt: easy to create, costly to maintain, and hard to remove. + +Review alerts often and remove those that don’t lead to action. + +## Alerts should have an owner and system scope + +Alerts without ownership are often ignored. Every alert must have an owner: a team responsible for maintaining the alert and responding when it fires. + +Alerts must also define a system scope, such as a service or infrastructure component. Scope provides organizational context and connects alerts with ownership. Defining clear scopes is easier when services are treated as first-class entities, and organizations are built around service ownership. + +> [Service Center in Grafana Cloud](/docs/grafana-cloud/alerting-and-irm/service-center/) can help operate a service-oriented view of your system and align alert scope with ownership. + +After scope, ownership, and alert priority are defined, routing determines where alerts go and how they escalate. **Notification routing is as important as the alerts**. + +Alerts should be delivered to the right team and channel based on priority, ownership, and team workflows. Use [notification policies](ref:notification-policies) to define a routing tree that matches the context of your service or scope: + +- Define a parent policy for default routing within the scope. +- Define nested policies for specific cases or higher-priority issues. + +## Prevent notification overload with alert grouping + +Without alert grouping, responders can receive many notifications for the same underlying problem. + +For example, a database failure can trigger several alerts at the same time like increased latency, higher error rates, and internal errors. Paging separately for each symptom quickly turns into notification spam, even though there is a single root cause. + +[Notification grouping](ref:group-alert-notifications) consolidates related alerts into a single notification. Instead of receiving multiple pages for the same issue, responders get one alert that represents the incident and includes all related firing alerts. + +Grouping should follow operational boundaries such as service or owner, as defined by notification policies. Downstream or cascading failures should be grouped together so they surface as one issue rather than many. + +## Mitigate flapping alerts + +Short-lived failure spikes often trigger alerts that auto-resolve quickly. Alerting on transient failures creates noise and leads responders to ignore them. + +Require issues to persist before alerting. Set a [pending period](ref:pending-period) to define how long a condition must remain true before firing. For example, instead of alerting immediately on high error rate, require it to stay above the threshold for some minutes. + +Also, stabilize alerts by tuning query ranges and aggregations. Using raw data makes alerts sensitive to noise. Instead, evaluate over a time window and aggregate the data to smooth short spikes. + +```promql +# Reacts to transient spikes. Avoid this. +cpu_usage > 90 + +# Smooth fluctuations. +avg_over_time(cpu_usage[5m]) > 90 +``` + +For latency and error-based alerts, percentiles are often more useful than averages: + +```promql +quantile_over_time(0.95, http_duration_seconds[5m]) > 3 +``` + +Finally, avoid rapid resolve-and-fire notifications by using [`keep_firing_for`](ref:keep-firing-for) or [recovery thresholds](ref:recovery-threshold) to keep alerts active briefly during recovery. Both options reduce flapping and unnecessary notifications. + +## Graduate symptom-based alerts into SLOs + +When a symptom-based alert fires frequently, it usually indicates a reliability concern that should be measured and managed more deliberately. This is often a sign that the alert could evolve into an [SLO](/docs/grafana-cloud/alerting-and-irm/slo/). + +Traditional alerts create pressure to react immediately, while error budgets introduce a buffer of time to act, changing how urgency is handled. Alerts can then be defined in terms of error budget burn rate rather than reacting to every minor deviation. + +SLOs also align distinct teams around common reliability goals by providing a shared definition of what "good" looks like. They help consolidate multiple symptom alerts into a single user-facing objective. + +For example, instead of several teams alerting on high latency, a single SLO can be used across teams to capture overall API performance. + +## Integrate alerting into incident post-mortems + +Every incident is an opportunity to improve alerting. After each incident, evaluate whether alerts helped responders act quickly or added unnecessary noise. + +Assess which alerts fired, and how they influenced incident response. Review whether alerts triggered too late, too early, or without enough context, and adjust thresholds, priority, or escalation based on what actually happened. + +Use [silences](ref:silences) during active incidents to reduce repeated notifications, but scope them carefully to avoid silencing unrelated alerts. + +Post-mortems should evaluate alerts with root causes and lessons learned. If responders lacked key information during the incident, enrich alerts with additional context, dashboards, or better guidance. + +## Alerts should be continuously improved + +Alerting is an iterative process. Alerts that aren’t reviewed and refined lose effectiveness as systems and traffic patterns change. + +Schedule regular reviews of existing alerts. Remove alerts that don’t lead to action, and tune alerts or thresholds that fire too often without providing useful signal. Reduce false positives to combat alert fatigue. + +Prioritize clarity and simplicity in alert design. Simpler alerts are easier to understand, maintain, and trust under pressure. Favor fewer high-quality, actionable alerts over a large number of low-value ones. + +Use dashboards and observability tools for investigation, not alerts. + +{{< /shared >}} diff --git a/docs/sources/alerting/best-practices/connectivity-errors.md b/docs/sources/alerting/guides/connectivity-errors.md similarity index 98% rename from docs/sources/alerting/best-practices/connectivity-errors.md rename to docs/sources/alerting/guides/connectivity-errors.md index 42d992b0cb0..18e12f5bc49 100644 --- a/docs/sources/alerting/best-practices/connectivity-errors.md +++ b/docs/sources/alerting/guides/connectivity-errors.md @@ -1,5 +1,7 @@ --- -canonical: https://grafana.com/docs/grafana/latest/alerting/best-practices/connectivity-errors/ +aliases: + - ../best-practices/connectivity-errors/ # /docs/grafana//alerting/best-practices/connectivity-errors/ +canonical: https://grafana.com/docs/grafana/latest/alerting/guides/connectivity-errors/ description: Learn how to detect and handle connectivity issues in alerts using Prometheus, Grafana Alerting, or both. keywords: - grafana @@ -14,7 +16,7 @@ labels: - oss menuTitle: Handle connectivity errors title: Handle connectivity errors in alerts -weight: 1010 +weight: 1020 refs: pending-period: - pattern: /docs/grafana/ diff --git a/docs/sources/alerting/best-practices/missing-data.md b/docs/sources/alerting/guides/missing-data.md similarity index 98% rename from docs/sources/alerting/best-practices/missing-data.md rename to docs/sources/alerting/guides/missing-data.md index 06346ce3d05..c2d2500cdfd 100644 --- a/docs/sources/alerting/best-practices/missing-data.md +++ b/docs/sources/alerting/guides/missing-data.md @@ -1,5 +1,7 @@ --- -canonical: https://grafana.com/docs/grafana/latest/alerting/best-practices/missing-data/ +aliases: + - ../best-practices/missing-data/ # /docs/grafana//alerting/best-practices/missing-data/ +canonical: https://grafana.com/docs/grafana/latest/alerting/guides/missing-data/ description: Learn how to detect missing metrics and design alerts that handle gaps in data in Prometheus and Grafana Alerting. keywords: - grafana @@ -14,7 +16,7 @@ labels: - oss menuTitle: Handle missing data title: Handle missing data in Grafana Alerting -weight: 1020 +weight: 1030 refs: connectivity-errors-guide: - pattern: /docs/grafana/ diff --git a/docs/sources/alerting/monitor-status/view-alert-rules.md b/docs/sources/alerting/monitor-status/view-alert-rules.md index b60ede12328..e5410d48765 100644 --- a/docs/sources/alerting/monitor-status/view-alert-rules.md +++ b/docs/sources/alerting/monitor-status/view-alert-rules.md @@ -41,9 +41,13 @@ Select a group to expand it and view the list of alert rules within that group. The list view includes a number of filters to simplify managing large volumes of alerts. +## Filter and save searches + Click the **Filter** button to open the filter popup. You can filter by name, label, folder/namespace, evaluation group, data source, contact point, rule source, rule state, rule type, and the health of the alert rule from the popup menu. Click **Apply** at the bottom of the filter popup to enact the filters as you search. -{{< figure src="/media/docs/alerting/alerting-list-view-filter.png" max-width="750px" alt="Alert rule filter options" >}} +Click the **Saved searches** button to open the list of previously saved searches, or click **+ Save current search** to add your current search to the saved searches list. You can also rename a saved search or set it as a default search. When you set a saved search as the default search, the Alert rules page opens with the search applied. + +{{< figure src="/media/docs/alerting/alerting-saved-searches.png" max-width="750px" alt="Alert rule filter options" >}} ## Change alert rules list view diff --git a/docs/sources/as-code/observability-as-code/schema-v2/_index.md b/docs/sources/as-code/observability-as-code/schema-v2/_index.md index 9be869a8391..65c73a49cbe 100644 --- a/docs/sources/as-code/observability-as-code/schema-v2/_index.md +++ b/docs/sources/as-code/observability-as-code/schema-v2/_index.md @@ -186,7 +186,7 @@ For the JSON and field usage notes, refer to the [links schema documentation](ht ### `tags` -The tags associated with the dashboard: +Tags associated with the dashboard. Each tag can be up to 50 characters long. ` [...string]` diff --git a/docs/sources/datasources/aws-cloudwatch/_index.md b/docs/sources/datasources/aws-cloudwatch/_index.md index bf3a14c590f..9cd5ed87a09 100644 --- a/docs/sources/datasources/aws-cloudwatch/_index.md +++ b/docs/sources/datasources/aws-cloudwatch/_index.md @@ -105,6 +105,11 @@ refs: destination: /docs/grafana//panels-visualizations/visualizations/ - pattern: /docs/grafana-cloud/ destination: /docs/grafana-cloud/visualizations/panels-visualizations/visualizations/ + cloudwatch-troubleshooting: + - pattern: /docs/grafana/ + destination: /docs/grafana//datasources/aws-cloudwatch/troubleshooting/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana//datasources/aws-cloudwatch/troubleshooting/ --- # Amazon CloudWatch data source @@ -119,6 +124,7 @@ The following documents will help you get started working with the CloudWatch da - [CloudWatch query editor](ref:cloudwatch-query-editor) - [Templates and variables](ref:cloudwatch-template-variables) - [Configure AWS authentication](ref:cloudwatch-aws-authentication) +- [Troubleshoot CloudWatch issues](ref:cloudwatch-troubleshooting) ## Import pre-configured dashboards diff --git a/docs/sources/datasources/aws-cloudwatch/configure/index.md b/docs/sources/datasources/aws-cloudwatch/configure/index.md index 7e80433756b..242b3513d47 100644 --- a/docs/sources/datasources/aws-cloudwatch/configure/index.md +++ b/docs/sources/datasources/aws-cloudwatch/configure/index.md @@ -1,11 +1,12 @@ --- aliases: - - ../data-sources/aws-CloudWatch/ - - ../data-sources/aws-CloudWatch/preconfig-CloudWatch-dashboards/ - - ../data-sources/aws-CloudWatch/provision-CloudWatch/ - - CloudWatch/ - - preconfig-CloudWatch-dashboards/ - - provision-CloudWatch/ + - ../../data-sources/aws-cloudwatch/configure/ + - ../../data-sources/aws-cloudwatch/ + - ../../data-sources/aws-cloudwatch/preconfig-cloudwatch-dashboards/ + - ../../data-sources/aws-cloudwatch/provision-cloudwatch/ + - ../cloudwatch/ + - ../preconfig-cloudwatch-dashboards/ + - ../provision-cloudwatch/ description: This document provides configuration instructions for the CloudWatch data source. keywords: - grafana @@ -25,11 +26,6 @@ refs: destination: /docs/grafana//panels-visualizations/visualizations/logs/ - pattern: /docs/grafana-cloud/ destination: /docs/grafana//panels-visualizations/visualizations/logs/ - explore: - - pattern: /docs/grafana/ - destination: /docs/grafana//explore/ - - pattern: /docs/grafana-cloud/ - destination: /docs/grafana//explore/ provisioning-data-sources: - pattern: /docs/grafana/ destination: /docs/grafana//administration/provisioning/#data-sources @@ -40,26 +36,16 @@ refs: destination: /docs/grafana//setup-grafana/configure-grafana/#aws - pattern: /docs/grafana-cloud/ destination: /docs/grafana//setup-grafana/configure-grafana/#aws - alerting: - - pattern: /docs/grafana/ - destination: /docs/grafana//alerting/ - - pattern: /docs/grafana-cloud/ - destination: /docs/grafana-cloud/alerting-and-irm/alerting/ - build-dashboards: - - pattern: /docs/grafana/ - destination: /docs/grafana//dashboards/build-dashboards/ - - pattern: /docs/grafana-cloud/ - destination: /docs/grafana//dashboards/build-dashboards/ data-source-management: - pattern: /docs/grafana/ destination: /docs/grafana//administration/data-source-management/ - pattern: /docs/grafana-cloud/ destination: /docs/grafana//administration/data-source-management/ - CloudWatch-aws-authentication: + cloudwatch-aws-authentication: - pattern: /docs/grafana/ - destination: /docs/grafana//datasources/aws-CloudWatch/aws-authentication/ + destination: /docs/grafana//datasources/aws-cloudwatch/aws-authentication/ - pattern: /docs/grafana-cloud/ - destination: /docs/grafana//datasources/aws-CloudWatch/aws-authentication/ + destination: /docs/grafana//datasources/aws-cloudwatch/aws-authentication/ private-data-source-connect: - pattern: /docs/grafana/ destination: /docs/grafana-cloud/connect-externally-hosted/private-data-source-connect/ @@ -108,7 +94,7 @@ The following are configuration options for the CloudWatch data source. Grafana plugin requests to AWS are made on behalf of an AWS Identity and Access Management (IAM) role or IAM user. The IAM user or IAM role must have the associated policies to perform certain API actions. -For authentication options and configuration details, refer to [AWS authentication](aws-authentication/). +For authentication options and configuration details, refer to [AWS authentication](ref:cloudwatch-aws-authentication). | Setting | Description | | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -153,7 +139,7 @@ You must use both an access key ID and a secret access key to authenticate. Grafana automatically creates a link to a trace in X-Ray data source if logs contain the `@xrayTraceId` field. To use this feature, you must already have an X-Ray data source configured. For details, see the [X-Ray data source docs](/grafana/plugins/grafana-X-Ray-datasource/). To view the X-Ray link, select the log row in either the Explore view or dashboard [Logs panel](ref:logs) to view the log details section. -To log the `@xrayTraceId`, refer to the [AWS X-Ray documentation](https://docs.amazonaws.cn/en_us/xray/latest/devguide/xray-services.html). To provide the field to Grafana, your log queries must also contain the `@xrayTraceId` field, for example by using the query `fields @message, @xrayTraceId`. +To log the `@xrayTraceId`, refer to the [AWS X-Ray documentation](https://docs.aws.amazon.com/xray/latest/devguide/xray-services.html). To provide the field to Grafana, your log queries must also contain the `@xrayTraceId` field, for example by using the query `fields @message, @xrayTraceId`. **Private data source connect** - _Only for Grafana Cloud users._ @@ -172,7 +158,7 @@ To troubleshoot issues while setting up the CloudWatch data source, check the `/ ### IAM policy examples To read CloudWatch metrics and EC2 tags, instances, regions, and alarms, you must grant Grafana permissions via IAM. -You can attach these permissions to the IAM role or IAM user you configured in [AWS authentication](aws-authentication/). +You can attach these permissions to the IAM role or IAM user you configured in [AWS authentication](ref:cloudwatch-aws-authentication). **Metrics-only permissions:** @@ -323,7 +309,7 @@ You can attach these permissions to the IAM role or IAM user you configured in [ Cross-account observability lets you retrieve metrics and logs across different accounts in a single region, but you can't query EC2 Instance Attributes across accounts because those come from the EC2 API and not the CloudWatch API. {{< /admonition >}} -For more information on configuring authentication, refer to [Configure AWS authentication](ref:CloudWatch-aws-authentication). +For more information on configuring authentication, refer to [Configure AWS authentication](ref:cloudwatch-aws-authentication). ### CloudWatch Logs data protection diff --git a/docs/sources/datasources/aws-cloudwatch/query-editor/index.md b/docs/sources/datasources/aws-cloudwatch/query-editor/index.md index 9bc7ab64047..9288a750742 100644 --- a/docs/sources/datasources/aws-cloudwatch/query-editor/index.md +++ b/docs/sources/datasources/aws-cloudwatch/query-editor/index.md @@ -34,11 +34,6 @@ refs: destination: /docs/grafana//panels-visualizations/query-transform-data/#navigate-the-query-tab - pattern: /docs/grafana-cloud/ destination: /docs/grafana//panels-visualizations/query-transform-data/#navigate-the-query-tab - explore: - - pattern: /docs/grafana/ - destination: /docs/grafana//explore/ - - pattern: /docs/grafana-cloud/ - destination: /docs/grafana//explore/ alerting: - pattern: /docs/grafana/ destination: /docs/grafana//alerting/ @@ -183,7 +178,7 @@ If you use the expression field to reference another query, such as `queryA * 2` When you select `Builder` mode within the Metric search editor, a new Account field is displayed. Use the `Account` field to specify which of the linked monitoring accounts to target for the given query. By default, the `All` option is specified, which will target all linked accounts. While in `Code` mode, you can specify any math expression. If the Monitoring account badge displays in the query editor header, all `SEARCH` expressions entered in this field will be cross-account by default and can query metrics from linked accounts. Note that while queries run cross-account, the autocomplete feature currently doesn't fetch cross-account resources, so you'll need to manually specify resource names when writing cross-account queries. -You can limit the search to one or a set of accounts, as documented in the [AWS documentation](http://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Unified-Cross-Account.html). +You can limit the search to one or a set of accounts, as documented in the [AWS documentation](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Unified-Cross-Account.html). ### Period macro @@ -198,7 +193,7 @@ The link provided is valid for any account but displays the expected metrics onl {{< figure src="/media/docs/cloudwatch/cloudwatch-deep-link-v12.1.png" caption="CloudWatch deep linking" >}} -This feature is not available for metrics based on [metric math expressions](#metric-math-expressions). +This feature is not available for metrics based on [metric math expressions](#use-metric-math-expressions). ### Use Metric Insights syntax @@ -319,9 +314,9 @@ The CloudWatch plugin monitors and troubleshoots applications that span multiple To enable cross-account observability, complete the following steps: -1. Go to the [Amazon CloudWatch documentation](http://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Unified-Cross-Account.html) and follow the instructions for enabling cross-account observability. +1. Go to the [Amazon CloudWatch documentation](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Unified-Cross-Account.html) and follow the instructions for enabling cross-account observability. -1. Add [two API actions](https://grafana.com//docs/grafana/latest/datasources/aws-cloudwatch/configure/#cross-account-observability-permissions) to the IAM policy attached to the role/user running the plugin. +1. Add [two API actions](https://grafana.com/docs/grafana/latest/datasources/aws-cloudwatch/configure/#cross-account-observability-permissions) to the IAM policy attached to the role/user running the plugin. Cross-account querying is available in the plugin through the **Logs**, **Metric search**, and **Metric Insights** modes. After you have configured it, you'll see a **Monitoring account** badge in the query editor header. diff --git a/docs/sources/datasources/aws-cloudwatch/troubleshooting/index.md b/docs/sources/datasources/aws-cloudwatch/troubleshooting/index.md new file mode 100644 index 00000000000..77ce4106bf8 --- /dev/null +++ b/docs/sources/datasources/aws-cloudwatch/troubleshooting/index.md @@ -0,0 +1,519 @@ +--- +aliases: + - ../../data-sources/aws-cloudwatch/troubleshooting/ +description: Troubleshooting guide for the Amazon CloudWatch data source in Grafana +keywords: + - grafana + - cloudwatch + - aws + - troubleshooting + - errors + - authentication + - query +labels: + products: + - cloud + - enterprise + - oss +menuTitle: Troubleshooting +title: Troubleshoot Amazon CloudWatch data source issues +weight: 500 +refs: + configure-cloudwatch: + - pattern: /docs/grafana/ + destination: /docs/grafana//datasources/aws-cloudwatch/configure/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana//datasources/aws-cloudwatch/configure/ + cloudwatch-aws-authentication: + - pattern: /docs/grafana/ + destination: /docs/grafana//datasources/aws-cloudwatch/aws-authentication/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana//datasources/aws-cloudwatch/aws-authentication/ + cloudwatch-template-variables: + - pattern: /docs/grafana/ + destination: /docs/grafana//datasources/aws-cloudwatch/template-variables/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana//datasources/aws-cloudwatch/template-variables/ + cloudwatch-query-editor: + - pattern: /docs/grafana/ + destination: /docs/grafana//datasources/aws-cloudwatch/query-editor/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana//datasources/aws-cloudwatch/query-editor/ + private-data-source-connect: + - pattern: /docs/grafana/ + destination: /docs/grafana-cloud/connect-externally-hosted/private-data-source-connect/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana-cloud/connect-externally-hosted/private-data-source-connect/ +--- + +# Troubleshoot Amazon CloudWatch data source issues + +This document provides solutions to common issues you may encounter when configuring or using the Amazon CloudWatch data source. For configuration instructions, refer to [Configure CloudWatch](ref:configure-cloudwatch). + +{{< admonition type="note" >}} +The data source health check validates both metrics and logs permissions. If your IAM policy only grants access to one of these (for example, metrics-only or logs-only), the health check displays a red status. However, the service you have permissions for is still usable—you can query metrics or logs based on whichever permissions are configured. +{{< /admonition >}} + +## Authentication errors + +These errors occur when AWS credentials are invalid, missing, or don't have the required permissions. + +### "Access Denied" or "Not authorized to perform this operation" + +**Symptoms:** + +- Save & test fails with "Access Denied" +- Queries return authorization errors +- Namespaces, metrics, or dimensions don't load + +**Possible causes and solutions:** + +| Cause | Solution | +| --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| IAM policy missing required permissions | Attach the appropriate IAM policy to your user or role. For metrics, you need `cloudwatch:ListMetrics`, `cloudwatch:GetMetricData`, and related permissions. For logs, you need `logs:DescribeLogGroups`, `logs:StartQuery`, `logs:GetQueryResults`, and related permissions. Refer to [Configure CloudWatch](ref:configure-cloudwatch) for complete policy examples. | +| Incorrect access key or secret key | Verify the credentials in the AWS Console under **IAM** > **Users** > your user > **Security credentials**. Generate new credentials if necessary. | +| Credentials have expired | For temporary credentials, generate new ones. For access keys, verify they haven't been deactivated or deleted. | +| Wrong AWS region | Verify the default region in the data source configuration matches where your resources are located. | +| Assume Role ARN is incorrect | Verify the role ARN format: `arn:aws:iam:::role/`. Check that the role exists in the AWS Console. | + +### "Unable to assume role" + +**Symptoms:** + +- Authentication fails when using Assume Role ARN +- Error message references STS or AssumeRole + +**Solutions:** + +1. Verify the trust relationship on the IAM role allows the Grafana credentials to assume it. +1. Check the trust policy includes the correct principal (the user or role running Grafana). +1. If using an external ID, ensure it matches exactly in both the role's trust policy and the Grafana data source configuration. +1. Verify the base credentials have the `sts:AssumeRole` permission. +1. Check that the role ARN is correct and the role exists. + +**Example trust policy:** + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "AWS": "arn:aws:iam:::user/" + }, + "Action": "sts:AssumeRole", + "Condition": { + "StringEquals": { + "sts:ExternalId": "" + } + } + } + ] +} +``` + +### AWS SDK Default authentication not working + +**Symptoms:** + +- Data source test fails when using AWS SDK Default +- Works locally but fails in production + +**Solutions:** + +1. Verify AWS credentials are configured in the environment where Grafana runs. +1. Check for credentials in the default locations: + - Environment variables (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`) + - Shared credentials file (`~/.aws/credentials`) + - EC2 instance metadata (if running on EC2) + - ECS task role (if running in ECS) + - EKS service account (if running in EKS) +1. Ensure the Grafana process has permission to read the credentials file. +1. For EKS with IRSA, set the pod's security context to allow user 472 (grafana) to access the projected token. Refer to [AWS authentication](ref:cloudwatch-aws-authentication) for details. + +### Credentials file not found + +**Symptoms:** + +- Error indicates credentials file cannot be read +- Authentication fails with "Credentials file" option + +**Solutions:** + +1. Create the credentials file at `~/.aws/credentials` for the user running the `grafana-server` service. +1. Verify the file has correct permissions (`0644`). +1. If the file exists but isn't working, move it to `/usr/share/grafana/` and set permissions to `0644`. +1. Ensure the profile name in the data source configuration matches a profile in the credentials file. + +## Connection errors + +These errors occur when Grafana cannot reach AWS CloudWatch endpoints. + +### "Request timed out" or connection failures + +**Symptoms:** + +- Data source test times out +- Queries fail with timeout errors +- Intermittent connection issues + +**Solutions:** + +1. Verify network connectivity from the Grafana server to AWS endpoints. +1. Check firewall rules allow outbound HTTPS (port 443) to AWS services. +1. If using a VPC, ensure proper NAT gateway or VPC endpoint configuration. +1. For Grafana Cloud connecting to private resources, configure [Private data source connect](ref:private-data-source-connect). +1. Check if the default region is correct—incorrect regions may cause longer timeouts. +1. Increase the timeout settings if queries involve large data volumes. + +### Custom endpoint configuration issues + +**Symptoms:** + +- Connection fails when using a custom endpoint +- Endpoint URL rejected + +**Solutions:** + +1. Verify the endpoint URL format is correct. +1. Ensure the endpoint is accessible from the Grafana server. +1. Check that the endpoint supports the required AWS APIs. +1. For VPC endpoints, verify the endpoint policy allows the required actions. + +## CloudWatch Metrics query errors + +These errors occur when querying CloudWatch Metrics. + +### "No data" or empty results + +**Symptoms:** + +- Query executes without error but returns no data +- Charts show "No data" message + +**Possible causes and solutions:** + +| Cause | Solution | +| ------------------------------- | ---------------------------------------------------------------------------------------------------------- | +| Time range doesn't contain data | Expand the dashboard time range. CloudWatch metrics have different retention periods based on resolution. | +| Wrong namespace or metric name | Verify the namespace (for example, `AWS/EC2`) and metric name (for example, `CPUUtilization`) are correct. | +| Incorrect dimensions | Ensure dimension names and values match your AWS resources exactly. | +| Match Exact enabled incorrectly | When Match Exact is enabled, all dimensions must be specified. Try disabling it to see if metrics appear. | +| Period too large | Reduce the period setting or set it to "auto" to ensure data points are returned for your time range. | +| Custom metrics not configured | Add custom metric namespaces in the data source configuration under **Namespaces of Custom Metrics**. | + +### "Metric not found" or metrics don't appear in drop-down + +**Symptoms:** + +- Expected metrics don't appear in the query editor +- Metric drop-down is empty for a namespace + +**Solutions:** + +1. Verify the metric exists in the selected region. +1. For custom metrics, add the namespace to **Namespaces of Custom Metrics** in the data source configuration. +1. Check that the IAM policy includes `cloudwatch:ListMetrics` permission. +1. CloudWatch limits `ListMetrics` to 500 results per page. To retrieve more metrics, increase the `list_metrics_page_limit` setting in the [Grafana configuration file](https://grafana.com/docs/grafana/latest/datasources/aws-cloudwatch/configure/#configure-the-data-source-with-grafanaini). +1. Use the Query Inspector to verify the API request and response. + +### Dimension values not loading + +**Symptoms:** + +- Dimension value drop-down doesn't populate +- Wildcard searches return no results + +**Solutions:** + +1. Verify the IAM policy includes `cloudwatch:ListMetrics` permission. +1. Check that the namespace and metric are selected before dimension values can load. +1. For EC2 dimensions, ensure `ec2:DescribeTags` and `ec2:DescribeInstances` permissions are granted. +1. Dimension values require existing metrics—if no metrics match, no values appear. + +### "Too many data points" or API throttling + +**Symptoms:** + +- Queries fail with throttling errors +- Performance degrades with multiple panels + +**Solutions:** + +1. Increase the period setting to reduce the number of data points. +1. Reduce the time range of your queries. +1. Use fewer dimensions or wildcard queries per panel. +1. Request a quota increase for `GetMetricData` requests per second in the [AWS Service Quotas console](https://console.aws.amazon.com/servicequotas/). +1. Enable query caching in Grafana to reduce API calls. + +### Metric math expression errors + +**Symptoms:** + +- Expression returns errors +- Referenced metrics not found + +**Solutions:** + +1. Verify each referenced metric has a unique ID set. +1. Check that metric IDs start with a lowercase letter and contain only letters, numbers, and underscores. +1. Ensure all referenced metrics are in the same query. +1. Verify the expression syntax follows [AWS Metric Math](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/using-metric-math.html) documentation. +1. Metric math expressions can't be used with Grafana alerting if they reference other query rows. + +## CloudWatch Logs query errors + +These errors occur when querying CloudWatch Logs. + +### "Query failed" or logs don't appear + +**Symptoms:** + +- Log queries return errors +- No log data is displayed + +**Solutions:** + +1. Verify log group names are correct and exist in the selected region. +1. Check the IAM policy includes `logs:StartQuery`, `logs:GetQueryResults`, and `logs:DescribeLogGroups` permissions. +1. Ensure the time range contains log data. +1. Verify the query syntax is valid. For CloudWatch Logs Insights QL, test the query in the AWS Console. +1. Select the correct query language (Logs Insights QL, OpenSearch PPL, or OpenSearch SQL) based on your query syntax. + +### Log query timeout + +**Symptoms:** + +- Query runs for a long time then fails +- Error mentions timeout + +**Solutions:** + +1. Increase the **Query timeout result** setting in the data source configuration (default is 30 minutes). +1. Narrow the time range to reduce the amount of data scanned. +1. Add filters to your query to limit results. +1. Break complex queries into smaller, more focused queries. +1. For alerting, the timeout defined in the [Grafana configuration file](https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/#unified_alerting) takes precedence. + +### Log groups not appearing in selector + +**Symptoms:** + +- Log group selector is empty +- Can't find expected log groups + +**Solutions:** + +1. Verify the IAM policy includes `logs:DescribeLogGroups` permission. +1. Check that log groups exist in the selected region. +1. For cross-account observability, ensure proper IAM permissions for `oam:ListSinks` and `oam:ListAttachedLinks`. +1. Use prefix search to filter log groups if you have many groups. +1. Verify the selected account (for cross-account) contains the expected log groups. + +### OpenSearch SQL query errors + +**Symptoms:** + +- OpenSearch SQL queries fail +- Syntax errors with SQL queries + +**Solutions:** + +1. Specify the log group identifier or ARN in the `FROM` clause: + + ```sql + SELECT * FROM `log_group_name` WHERE `@message` LIKE '%error%' + ``` + +1. For multiple log groups, use the `logGroups` function: + + ```sql + SELECT * FROM `logGroups(logGroupIdentifier: ['LogGroup1', 'LogGroup2'])` + ``` + +1. Amazon CloudWatch supports only a subset of OpenSearch SQL commands. Refer to the [CloudWatch Logs documentation](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL_AnalyzeLogData_Languages.html) for supported syntax. + +## Template variable errors + +These errors occur when using template variables with the CloudWatch data source. + +### Variables return no values + +**Symptoms:** + +- Variable drop-down is empty +- Dashboard fails to load with variable errors + +**Solutions:** + +1. Verify the data source connection is working. +1. Check that the IAM policy includes permissions for the variable query type: + - **Regions:** No additional permissions needed. + - **Namespaces:** No additional permissions needed. + - **Metrics:** Requires `cloudwatch:ListMetrics`. + - **Dimension Values:** Requires `cloudwatch:ListMetrics`. + - **EC2 Instance Attributes:** Requires `ec2:DescribeInstances`. + - **EBS Volume IDs:** Requires `ec2:DescribeVolumes`. + - **Resource ARNs:** Requires `tag:GetResources`. + - **Log Groups:** Requires `logs:DescribeLogGroups`. +1. For dependent variables, ensure parent variables have valid selections. +1. Verify the region is set correctly (use "default" for the data source's default region). + +For more information on template variables, refer to [CloudWatch template variables](ref:cloudwatch-template-variables). + +### Multi-value template variables cause query failures + +**Symptoms:** + +- Queries fail when selecting multiple dimension values +- Error about search expression limits + +**Solutions:** + +1. Search expressions are limited to 1,024 characters. Reduce the number of selected values. +1. Use the asterisk (`*`) wildcard instead of selecting "All" to query all metrics for a dimension. +1. Multi-valued template variables are only supported for dimension values—not for Region, Namespace, or Metric Name. + +## Cross-account observability errors + +These errors occur when using CloudWatch cross-account observability features. + +### Cross-account queries fail + +**Symptoms:** + +- Can't query metrics or logs from linked accounts +- Monitoring account badge doesn't appear + +**Solutions:** + +1. Verify cross-account observability is configured in the AWS CloudWatch console. +1. Add the required IAM permissions: + + ```json + { + "Version": "2012-10-17", + "Statement": [ + { + "Action": ["oam:ListSinks", "oam:ListAttachedLinks"], + "Effect": "Allow", + "Resource": "*" + } + ] + } + ``` + +1. Check that the monitoring account and source accounts are properly linked in AWS. +1. Cross-account observability works within a single region—verify all accounts are in the same region. +1. EC2 Instance Attributes can't be queried across accounts because they use the EC2 API, not the CloudWatch API. + +## Quota and pricing issues + +These issues relate to AWS service quotas and cost management. + +### API throttling errors + +**Symptoms:** + +- "Rate exceeded" errors +- Dashboard panels intermittently fail to load + +**Solutions:** + +1. Reduce the frequency of dashboard refreshes. +1. Increase the period setting to reduce `GetMetricData` requests. +1. Enable query caching in Grafana (available in Grafana Enterprise and Grafana Cloud). +1. Request a quota increase in the [AWS Service Quotas console](https://console.aws.amazon.com/servicequotas/). +1. Consider consolidating similar queries using metric math. + +### Unexpectedly high CloudWatch costs + +**Symptoms:** + +- AWS CloudWatch costs are higher than expected +- Frequent API calls from Grafana + +**Solutions:** + +1. The `GetMetricData` API doesn't qualify for the CloudWatch API free tier. +1. Reduce dashboard auto-refresh frequency. +1. Increase the period setting to reduce data points returned. +1. Use query caching to reduce repeated API calls. +1. Review variable query settings—set variable refresh to "On dashboard load" instead of "On time range change." +1. Avoid using wildcards in dimensions when possible, as they generate search expressions with multiple API calls. + +## Other common issues + +These issues don't produce specific error messages but are commonly encountered. + +### Custom metrics don't appear + +**Symptoms:** + +- Custom metrics from applications or agents don't show in the namespace drop-down +- Only standard AWS namespaces are visible + +**Solutions:** + +1. Add your custom metric namespace to the **Namespaces of Custom Metrics** field in the data source configuration. +1. Separate multiple namespaces with commas (for example, `CWAgent,CustomNamespace`). +1. Verify custom metrics have been published to CloudWatch in the selected region. + +### Pre-configured dashboards not working + +**Symptoms:** + +- Imported dashboards show no data +- Dashboard variables don't load + +**Solutions:** + +1. Verify the data source name in the dashboard matches your CloudWatch data source. +1. Check that the dashboard's AWS region setting matches where your resources are located. +1. Ensure the IAM policy grants access to the required services (EC2, Lambda, RDS, etc.). +1. Verify resources exist and are emitting metrics in the selected region. + +### X-Ray trace links not appearing + +**Symptoms:** + +- Log entries don't show X-Ray trace links +- `@xrayTraceId` field not appearing + +**Solutions:** + +1. Verify an X-Ray data source is configured and linked in the CloudWatch data source settings. +1. Ensure your logs contain the `@xrayTraceId` field. +1. Update log queries to include `@xrayTraceId` in the fields, for example: `fields @message, @xrayTraceId`. +1. Configure your application to log X-Ray trace IDs. Refer to the [AWS X-Ray documentation](https://docs.aws.amazon.com/xray/latest/devguide/xray-services.html). + +## Enable debug logging + +To capture detailed error information for troubleshooting: + +1. Set the Grafana log level to `debug` in the configuration file: + + ```ini + [log] + level = debug + ``` + +1. Review logs in `/var/log/grafana/grafana.log` (or your configured log location). +1. Look for CloudWatch-specific entries that include request and response details. +1. Reset the log level to `info` after troubleshooting to avoid excessive log volume. + +## Get additional help + +If you've tried the solutions above and still encounter issues: + +1. Check the [Grafana community forums](https://community.grafana.com/) for similar issues. +1. Review the [CloudWatch plugin GitHub issues](https://github.com/grafana/grafana/issues) for known bugs. +1. Consult the [AWS CloudWatch documentation](https://docs.aws.amazon.com/cloudwatch/) for service-specific guidance. +1. Contact Grafana Support if you're an Enterprise, Cloud Pro, or Cloud Contracted user. +1. When reporting issues, include: + - Grafana version + - AWS region + - Error messages (redact sensitive information) + - Steps to reproduce + - Query configuration (redact credentials and account IDs) diff --git a/docs/sources/datasources/graphite/_index.md b/docs/sources/datasources/graphite/_index.md index fba9d616f38..78972af5781 100644 --- a/docs/sources/datasources/graphite/_index.md +++ b/docs/sources/datasources/graphite/_index.md @@ -111,3 +111,4 @@ After installing and configuring the Graphite data source you can: - Add [transformations](ref:transformations) - Add [annotations](ref:annotate-visualizations) - Set up [alerting](ref:alerting) +- [Troubleshoot](troubleshooting/) common issues with the Graphite data source diff --git a/docs/sources/datasources/graphite/troubleshooting/index.md b/docs/sources/datasources/graphite/troubleshooting/index.md new file mode 100644 index 00000000000..41702c6b975 --- /dev/null +++ b/docs/sources/datasources/graphite/troubleshooting/index.md @@ -0,0 +1,174 @@ +--- +description: Troubleshoot common issues with the Graphite data source. +keywords: + - grafana + - graphite + - troubleshooting + - guide +labels: + products: + - cloud + - enterprise + - oss +menuTitle: Troubleshooting +title: Troubleshoot Graphite data source issues +weight: 400 +refs: + configure-graphite: + - pattern: /docs/grafana/ + destination: /docs/grafana//datasources/graphite/configure/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana//datasources/graphite/configure/ + query-editor: + - pattern: /docs/grafana/ + destination: /docs/grafana//datasources/graphite/query-editor/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana//datasources/graphite/query-editor/ +--- + +# Troubleshoot Graphite data source issues + +This document provides solutions for common issues you might encounter when using the Graphite data source. + +## Connection issues + +Use the following troubleshooting steps to resolve connection problems between Grafana and your Graphite server. + +**Data source test fails with "Unable to connect":** + +If the data source test fails, verify the following: + +- The URL in your data source configuration is correct and accessible from the Grafana server. +- The Graphite server is running and accepting connections. +- Any firewall rules or network policies allow traffic between Grafana and the Graphite server. +- If using TLS, ensure your certificates are valid and properly configured. + +To test connectivity, run the following command from the Grafana server: + +```sh +curl -v /render +``` + +Replace _``_ with your Graphite server URL. A successful connection returns a response from the Graphite server. + +**Authentication errors:** + +If you receive 401 or 403 errors: + +- Verify your Basic Auth username and password are correct. +- Ensure the **With Credentials** toggle is enabled if your Graphite server requires cookies for authentication. +- Check that your TLS client certificates are valid and match what the server expects. + +For detailed authentication configuration, refer to [Configure the Graphite data source](ref:configure-graphite). + +## Query issues + +Use the following troubleshooting steps to resolve problems with Graphite queries. + +**No data returned:** + +If your query returns no data: + +- Verify the metric path exists in your Graphite server by testing directly in the Graphite web interface. +- Check that the time range in Grafana matches when data was collected. +- Ensure wildcards in your query match existing metrics. +- Confirm your query syntax is correct for your Graphite version. + +**HTTP 500 errors with HTML content:** + +Graphite-web versions before 1.6 return HTTP 500 errors with full HTML stack traces when a query fails. If you see error messages containing HTML tags: + +- Check the Graphite server logs for the full error details. +- Verify your query syntax is valid. +- Ensure the requested time range doesn't exceed your Graphite server's capabilities. +- Check that all functions used in your query are supported by your Graphite version. + +**Parser errors in the query editor:** + +If the query editor displays parser errors: + +- Check for unbalanced parentheses in function calls. +- Verify that function arguments are in the correct format. +- Ensure metric paths don't contain unsupported characters. + +For query syntax help, refer to [Graphite query editor](ref:query-editor). + +## Version and feature issues + +Use the following troubleshooting steps to resolve problems related to Graphite versions and features. + +**Functions missing from the query editor:** + +If expected functions don't appear in the query editor: + +- Verify the correct Graphite version is selected in the data source configuration. +- The available functions depend on the configured version. For example, tag-based functions require Graphite 1.1 or later. +- If using a custom Graphite installation with additional functions, ensure the version setting matches your server. + +**Tag-based queries not working:** + +If `seriesByTag()` or other tag functions fail: + +- Confirm your Graphite server is version 1.1 or later. +- Verify the Graphite version setting in your data source configuration matches your actual server version. +- Check that tags are properly configured in your Graphite server. + +## Performance issues + +Use the following troubleshooting steps to address slow queries or timeouts. + +**Queries timing out:** + +If queries consistently time out: + +- Increase the **Timeout** setting in the data source configuration. +- Reduce the time range of your query. +- Use more specific metric paths instead of broad wildcards. +- Consider using `summarize()` or `consolidateBy()` functions to reduce the amount of data returned. +- Check your Graphite server's performance and resource utilization. + +**Slow autocomplete in the query editor:** + +If metric path autocomplete is slow: + +- This often indicates a large number of metrics in your Graphite server. +- Use more specific path prefixes to narrow the search scope. +- Check your Graphite server's index performance. + +## MetricTank-specific issues + +If you're using MetricTank as your Graphite backend, use the following troubleshooting steps. + +**Rollup indicator not appearing:** + +If the rollup indicator doesn't display when expected: + +- Verify **Metrictank** is selected as the Graphite backend type in the data source configuration. +- Ensure the **Rollup indicator** toggle is enabled. +- The indicator only appears when data aggregation actually occurs. + +**Unexpected data aggregation:** + +If you see unexpected aggregation in your data: + +- Check the rollup configuration in your MetricTank instance. +- Adjust the time range or use `consolidateBy()` to control aggregation behavior. +- Review the query processing metadata in the panel inspector for details on how data was processed. + +## Get additional help + +If you continue to experience issues: + +- Check the [Grafana community forums](https://community.grafana.com/) for similar issues and solutions. +- Review the [Graphite documentation](https://graphite.readthedocs.io/) for additional configuration options. +- Contact [Grafana Support](https://grafana.com/support/) if you're an Enterprise, Cloud Pro, or Cloud Advanced customer. + +When reporting issues, include the following information: + +- Grafana version +- Graphite version (for example, 1.1.x) and backend type (Default or MetricTank) +- Authentication method (Basic Auth, TLS, or none) +- Error messages (redact sensitive information) +- Steps to reproduce the issue +- Relevant configuration such as data source settings, timeout values, and Graphite version setting (redact passwords and other credentials) +- Sample query (if applicable, with sensitive data redacted) diff --git a/docs/sources/datasources/mssql/_index.md b/docs/sources/datasources/mssql/_index.md index a5e00da6dcb..b7ea159e972 100644 --- a/docs/sources/datasources/mssql/_index.md +++ b/docs/sources/datasources/mssql/_index.md @@ -99,12 +99,27 @@ refs: destination: /docs/grafana//administration/data-source-management/#query-and-resource-caching - pattern: /docs/grafana-cloud/ destination: /docs/grafana//administration/data-source-management/#query-and-resource-caching + mssql-troubleshoot: + - pattern: /docs/grafana/ + destination: /docs/grafana//datasources/mssql/troubleshooting/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana//datasources/mssql/troubleshooting/ + postgres: + - pattern: /docs/grafana/ + destination: /docs/grafana//datasources/postgres/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana//datasources/postgres/ + mysql: + - pattern: /docs/grafana/ + destination: /docs/grafana//datasources/mysql/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana//datasources/mysql/ --- # Microsoft SQL Server (MSSQL) data source Grafana ships with built-in support for Microsoft SQL Server (MSSQL). -You can query and visualize data from any Microsoft SQL Server 2005 or newer, including the Microsoft Azure SQL Database. +You can query and visualize data from any Microsoft SQL Server 2005 or newer, including Microsoft Azure SQL Database. Use this data source to create dashboards, explore SQL data, and monitor MSSQL-based workloads in real time. @@ -113,10 +128,33 @@ The following documentation helps you get started working with the Microsoft SQL - [Configure the Microsoft SQL Server data source](ref:configure-mssql-data-source) - [Microsoft SQL Server query editor](ref:mssql-query-editor) - [Microsoft SQL Server template variables](ref:mssql-template-variables) +- [Troubleshoot Microsoft SQL Server data source issues](ref:mssql-troubleshoot) -## Get the most out of the data source +## Supported versions -After installing and configuring the Microsoft SQL Server data source, you can: +This data source supports the following Microsoft SQL Server versions: + +- Microsoft SQL Server 2005 and newer +- Microsoft Azure SQL Database +- Azure SQL Managed Instance + +Grafana recommends using the latest available service pack for your SQL Server version for optimal compatibility. + +## Key capabilities + +The Microsoft SQL Server data source supports: + +- **Time series queries:** Visualize metrics over time using the built-in time grouping macros. +- **Table queries:** Display query results in table format for any valid SQL query. +- **Template variables:** Create dynamic dashboards with variable-driven queries. +- **Annotations:** Overlay events from SQL Server on your dashboard graphs. +- **Alerting:** Create alerts based on SQL Server query results. +- **Stored procedures:** Execute stored procedures and visualize results. +- **Macros:** Simplify queries with built-in macros for time filtering and grouping. + +## Additional resources + +After configuring the Microsoft SQL Server data source, you can: - Create a wide variety of [visualizations](ref:visualizations) - Configure and use [templates and variables](ref:variables) @@ -124,3 +162,8 @@ After installing and configuring the Microsoft SQL Server data source, you can: - Add [annotations](ref:annotate-visualizations) - Set up [alerting](ref:alerting) - Optimize performance with [query caching](ref:query-caching) + +## Related data sources + +- [PostgreSQL](ref:postgres) - For PostgreSQL databases. +- [MySQL](ref:mysql) - For MySQL and MariaDB databases. diff --git a/docs/sources/datasources/mssql/configure/index.md b/docs/sources/datasources/mssql/configure/index.md index 7ce6398f1cc..f41deeb51dd 100644 --- a/docs/sources/datasources/mssql/configure/index.md +++ b/docs/sources/datasources/mssql/configure/index.md @@ -89,6 +89,26 @@ refs: destination: /docs/grafana//setup-grafana/configure-access/configure-authentication/azuread/#enable-azure-ad-oauth-in-grafana - pattern: /docs/grafana-cloud/ destination: /docs/grafana//setup-grafana/configure-access/configure-authentication/azuread/#enable-azure-ad-oauth-in-grafana + mssql-query-editor: + - pattern: /docs/grafana/ + destination: /docs/grafana//datasources/mssql/query-editor/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana//datasources/mssql/query-editor/ + mssql-template-variables: + - pattern: /docs/grafana/ + destination: /docs/grafana//datasources/mssql/template-variables/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana//datasources/mssql/template-variables/ + alerting: + - pattern: /docs/grafana/ + destination: /docs/grafana//alerting/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana-cloud/alerting-and-irm/alerting/ + mssql-troubleshoot: + - pattern: /docs/grafana/ + destination: /docs/grafana//datasources/mssql/troubleshooting/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana//datasources/mssql/troubleshooting/ --- # Configure the Microsoft SQL Server data source @@ -97,13 +117,28 @@ This document provides instructions for configuring the Microsoft SQL Server dat ## Before you begin -- Grafana comes with a built-in MSSQL data source plugin, eliminating the need to install a plugin. +Before configuring the Microsoft SQL Server data source, ensure you have the following: -- You must have the `Organization administrator` role to configure the MSSQL data source. Organization administrators can also [configure the data source via YAML](#provision-the-data-source) with the Grafana provisioning system. +- **Grafana permissions:** You must have the `Organization administrator` role to configure data sources. Organization administrators can also [configure the data source via YAML](#provision-the-data-source) with the Grafana provisioning system. -- Familiarize yourself with your MSSQL security configuration and gather any necessary security certificates and client keys. +- **A running SQL Server instance:** Microsoft SQL Server 2005 or newer, Azure SQL Database, or Azure SQL Managed Instance. -- Verify that data from MSSQL is being written to your Grafana instance. +- **Network access:** Grafana must be able to reach your SQL Server. The default port is `1433`. + +- **Authentication credentials:** Depending on your authentication method, you need one of: + - SQL Server login credentials (username and password). + - Windows/Kerberos credentials and configuration (not supported in Grafana Cloud). + - Azure Entra ID app registration or managed identity. + +- **Security certificates:** If using encrypted connections, gather any necessary TLS/SSL certificates. + +{{< admonition type="note" >}} +Grafana ships with a built-in Microsoft SQL Server data source plugin. No additional installation is required. +{{< /admonition >}} + +{{< admonition type="tip" >}} +**Grafana Cloud users:** If your SQL Server is in a private network, you can configure [Private data source connect](ref:private-data-source-connect) to establish connectivity. +{{< /admonition >}} ## Add the MSSQL data source @@ -382,3 +417,48 @@ datasources: secureJsonData: password: 'Password!' ``` + +### Configure with Terraform + +You can configure the Microsoft SQL Server data source using [Terraform](https://www.terraform.io/) with the [Grafana Terraform provider](https://registry.terraform.io/providers/grafana/grafana/latest/docs). + +For more information about provisioning resources with Terraform, refer to the [Grafana as code using Terraform](https://grafana.com/docs/grafana-cloud/developer-resources/infrastructure-as-code/terraform/) documentation. + +#### Terraform example + +The following example creates a basic Microsoft SQL Server data source: + +```hcl +resource "grafana_data_source" "mssql" { + name = "MSSQL" + type = "mssql" + url = "localhost:1433" + user = "grafana" + + json_data_encoded = jsonencode({ + database = "grafana" + maxOpenConns = 100 + maxIdleConns = 100 + maxIdleConnsAuto = true + connMaxLifetime = 14400 + connectionTimeout = 0 + encrypt = "false" + }) + + secure_json_data_encoded = jsonencode({ + password = "Password!" + }) +} +``` + +For all available configuration options, refer to the [Grafana provider data source resource documentation](https://registry.terraform.io/providers/grafana/grafana/latest/docs/resources/data_source). + +## Next steps + +After configuring your Microsoft SQL Server data source, you can: + +- [Write queries](ref:mssql-query-editor) using the query editor to explore and visualize your data +- [Create template variables](ref:mssql-template-variables) to build dynamic, reusable dashboards +- [Add annotations](ref:annotate-visualizations) to overlay SQL Server events on your graphs +- [Set up alerting](ref:alerting) to create alert rules based on your SQL Server data +- [Troubleshoot issues](ref:mssql-troubleshoot) if you encounter problems with your data source diff --git a/docs/sources/datasources/mssql/troubleshooting/index.md b/docs/sources/datasources/mssql/troubleshooting/index.md new file mode 100644 index 00000000000..a62f3eb59e1 --- /dev/null +++ b/docs/sources/datasources/mssql/troubleshooting/index.md @@ -0,0 +1,333 @@ +--- +description: Troubleshoot common problems with the Microsoft SQL Server data source in Grafana +keywords: + - grafana + - MSSQL + - Microsoft + - SQL + - troubleshooting + - errors +labels: + products: + - cloud + - enterprise + - oss +menuTitle: Troubleshooting +title: Troubleshoot Microsoft SQL Server data source issues +weight: 400 +refs: + configure-mssql-data-source: + - pattern: /docs/grafana/ + destination: /docs/grafana//datasources/mssql/configure/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana//datasources/mssql/configure/ + mssql-query-editor: + - pattern: /docs/grafana/ + destination: /docs/grafana//datasources/mssql/query-editor/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana//datasources/mssql/query-editor/ + private-data-source-connect: + - pattern: /docs/grafana/ + destination: /docs/grafana-cloud/connect-externally-hosted/private-data-source-connect/ + - pattern: /docs/grafana-cloud/ + destination: /docs/grafana-cloud/connect-externally-hosted/private-data-source-connect/ +--- + +# Troubleshoot Microsoft SQL Server data source issues + +This document provides solutions to common issues you may encounter when configuring or using the Microsoft SQL Server (MSSQL) data source in Grafana. + +## Connection errors + +These errors occur when Grafana cannot establish or maintain a connection to the Microsoft SQL Server. + +### Unable to connect to the server + +**Error message:** "Unable to open tcp connection" or "dial tcp: connection refused" + +**Cause:** Grafana cannot establish a network connection to the SQL Server. + +**Solution:** + +1. Verify that the SQL Server is running and accessible. +1. Check that the host and port are correct in the data source configuration. The default SQL Server port is `1433`. +1. Ensure there are no firewall rules blocking the connection between Grafana and SQL Server. +1. Verify that SQL Server is configured to allow remote connections. +1. For Grafana Cloud, ensure you have configured [Private data source connect](ref:private-data-source-connect) if your SQL Server instance is not publicly accessible. + +### Connection timeout + +**Error message:** "Connection timed out" or "I/O timeout" + +**Cause:** The connection to SQL Server timed out before receiving a response. + +**Solution:** + +1. Check the network latency between Grafana and SQL Server. +1. Verify that SQL Server is not overloaded or experiencing performance issues. +1. Increase the **Connection timeout** setting in the data source configuration under **Additional settings**. +1. Check if any network devices (load balancers, proxies) are timing out the connection. + +### Encryption-related connection failures + +**Error message:** "TLS handshake failed" or "certificate verify failed" + +**Cause:** There is a mismatch between the encryption settings in Grafana and what the SQL Server supports or requires. + +**Solution:** + +1. For older versions of SQL Server (2008, 2008R2), set the **Encrypt** option to **Disable** or **False** in the data source configuration. +1. Verify that the SQL Server has a valid SSL certificate if encryption is enabled. +1. Check that the certificate is trusted by the Grafana server. +1. Ensure you're using the latest available service pack for your SQL Server version for optimal compatibility. + +### Named instance connection issues + +**Error message:** "Cannot connect to named instance" or connection fails when using instance name + +**Cause:** Grafana cannot resolve the SQL Server named instance. + +**Solution:** + +1. Use the format `hostname\instancename` or `hostname\instancename,port` in the **Host** field. +1. Verify that the SQL Server Browser service is running on the SQL Server machine. +1. If the Browser service is unavailable, specify the port number directly: `hostname,port`. +1. Check that UDP port 1434 is open if using the SQL Server Browser service. + +## Authentication errors + +These errors occur when there are issues with authentication credentials or permissions. + +### Login failed for user + +**Error message:** "Login failed for user 'username'" or "Authentication failed" + +**Cause:** The authentication credentials are invalid or the user doesn't have permission to access the database. + +**Solution:** + +1. Verify that the username and password are correct. +1. Check that the user exists in SQL Server and is enabled. +1. Ensure the user has access to the specified database. +1. For Windows Authentication, verify that the credentials are in the correct format (`DOMAIN\User`). +1. Check that the SQL Server authentication mode allows the type of login you're using (SQL Server Authentication, Windows Authentication, or Mixed Mode). + +### Access denied to database + +**Error message:** "Cannot open database 'dbname' requested by the login" + +**Cause:** The authenticated user doesn't have permission to access the specified database. + +**Solution:** + +1. Verify that the database name is correct in the data source configuration. +1. Ensure the user is mapped to the database with appropriate permissions. +1. Grant at least `SELECT` permission on the required tables: + + ```sql + USE [your_database] + GRANT SELECT ON dbo.YourTable TO [your_user] + ``` + +1. Check that the user doesn't have any conflicting permissions from the public role. + +### Windows Authentication (Kerberos) issues + +**Error message:** "Kerberos authentication failed" or "Cannot initialize Kerberos" + +**Cause:** Kerberos configuration is incorrect or incomplete. + +**Solution:** + +1. Verify that the Kerberos configuration file (`krb5.conf`) path is correct in the data source settings. +1. For keytab authentication, ensure the keytab file exists and is readable by Grafana. +1. Check that the realm and KDC settings are correct in the Kerberos configuration. +1. Verify DNS is correctly resolving the KDC servers. +1. Ensure the service principal name (SPN) is registered for the SQL Server instance. + +{{< admonition type="note" >}} +Kerberos authentication is not supported in Grafana Cloud. +{{< /admonition >}} + +### Azure Entra ID authentication errors + +**Error message:** "AADSTS error codes" or "Azure AD authentication failed" + +**Cause:** Azure Entra ID (formerly Azure AD) authentication is misconfigured. + +**Solution:** + +1. For **App Registration** authentication: + - Verify the tenant ID, client ID, and client secret are correct. + - Ensure the app registration has been added as a user in the Azure SQL database. + - Check that the client secret hasn't expired. + +1. For **Managed Identity** authentication: + - Verify `managed_identity_enabled = true` is set in the Grafana server configuration. + - Ensure the managed identity has been added to the Azure SQL database. + - Confirm the Azure resource hosting Grafana has managed identity enabled. + +1. For **Current User** authentication: + - Ensure `user_identity_enabled = true` is set in the Grafana server configuration. + - Verify the app registration is configured to issue both Access Tokens and ID Tokens. + - Check that the required API permissions are configured (`user_impersonation` for Azure SQL). + +For detailed Azure authentication configuration, refer to [Configure the Microsoft SQL Server data source](ref:configure-mssql-data-source). + +## Query errors + +These errors occur when there are issues with query syntax or configuration. + +### Time column not found or invalid + +**Error message:** "Could not find time column" or time series visualization shows no data + +**Cause:** The query doesn't return a properly formatted `time` column for time series visualization. + +**Solution:** + +1. Ensure your query includes a column named `time` when using the **Time series** format. +1. Use the `$__time()` macro to rename your date column: `$__time(your_date_column)`. +1. Verify the time column is of a valid SQL date/time type (`datetime`, `datetime2`, `date`) or contains Unix epoch values. +1. Ensure the result set is sorted by the time column using `ORDER BY`. + +### Macro expansion errors + +**Error message:** "Error parsing query" or macros appear unexpanded in the query + +**Cause:** Grafana macros are being used incorrectly. + +**Solution:** + +1. Verify macro syntax: use `$__timeFilter(column)` not `$_timeFilter(column)`. +1. Macros don't work inside stored procedures—use explicit date parameters instead. +1. Check that the column name passed to macros exists in your table. +1. View the expanded query by clicking **Generated SQL** after running the query to debug macro expansion. + +### Timezone and time shift issues + +**Cause:** Time series data appears shifted or doesn't align with expected times. + +**Solution:** + +1. Store timestamps in UTC in your database to avoid timezone issues. +1. Time macros (`$__time`, `$__timeFilter`, etc.) always expand to UTC values. +1. If your timestamps are stored in local time, convert them to UTC in your query: + + ```sql + SELECT + your_datetime_column AT TIME ZONE 'Your Local Timezone' AT TIME ZONE 'UTC' AS time, + value + FROM your_table + ``` + +1. Don't pass timezone parameters to time macros—they're not supported. + +### Query returns too many rows + +**Error message:** "Result set too large" or browser becomes unresponsive + +**Cause:** The query returns more data than can be efficiently processed. + +**Solution:** + +1. Add time filters using `$__timeFilter(column)` to limit data to the dashboard time range. +1. Use aggregations (`AVG`, `SUM`, `COUNT`) with `GROUP BY` instead of returning raw rows. +1. Add a `TOP` clause to limit results: `SELECT TOP 1000 ...`. +1. Use the `$__timeGroup()` macro to aggregate data into time intervals. + +### Stored procedure returns no data + +**Cause:** Stored procedure output isn't being captured correctly. + +**Solution:** + +1. Ensure the stored procedure uses `SELECT` statements, not just variable assignments. +1. Remove `SET NOCOUNT ON` if present, or ensure it's followed by a `SELECT` statement. +1. Verify the stored procedure parameters are being passed correctly. +1. Test the stored procedure directly in SQL Server Management Studio with the same parameters. + +For more information on using stored procedures, refer to the [query editor documentation](ref:mssql-query-editor). + +## Performance issues + +These issues relate to slow queries or high resource usage. + +### Slow query execution + +**Cause:** Queries take a long time to execute. + +**Solution:** + +1. Reduce the dashboard time range to limit data volume. +1. Add indexes to columns used in `WHERE` clauses and time filters. +1. Use aggregations instead of returning individual rows. +1. Increase the **Min time interval** setting to reduce the number of data points. +1. Review the query execution plan in SQL Server Management Studio to identify bottlenecks. + +### Connection pool exhaustion + +**Error message:** "Too many connections" or "Connection pool exhausted" + +**Cause:** Too many concurrent connections to the database. + +**Solution:** + +1. Increase the **Max open** connection limit in the data source configuration. +1. Enable **Auto max idle** to automatically manage idle connections. +1. Reduce the number of panels querying the same data source simultaneously. +1. Check for long-running queries that might be holding connections. + +## Other common issues + +The following issues don't produce specific error messages but are commonly encountered. + +### System databases appear in queries + +**Cause:** Queries accidentally access system databases. + +**Solution:** + +1. The query editor automatically excludes `tempdb`, `model`, `msdb`, and `master` from the database dropdown. +1. Always specify the database in your data source configuration to restrict access. +1. Ensure the database user only has permissions on the intended database. + +### Template variable queries fail + +**Cause:** Variable queries return unexpected results or errors. + +**Solution:** + +1. Verify the variable query syntax is valid SQL that returns a single column. +1. Check that the data source connection is working. +1. Ensure the user has permission to access the tables referenced in the variable query. +1. Test the query in the query editor before using it as a variable query. + +### Data appears incorrect or misaligned + +**Cause:** Data formatting or type conversion issues. + +**Solution:** + +1. Use explicit column aliases to ensure consistent naming: `SELECT value AS metric`. +1. Verify numeric columns are actually numeric types, not strings. +1. Check for `NULL` values that might affect aggregations. +1. Use the `FILL` option in `$__timeGroup()` macro to handle missing data points. + +## Get additional help + +If you continue to experience issues after following this troubleshooting guide: + +1. Check the [Grafana community forums](https://community.grafana.com/) for similar issues. +1. Review the [Grafana GitHub issues](https://github.com/grafana/grafana/issues) for known bugs. +1. Enable debug logging in Grafana to capture detailed error information. +1. Check SQL Server logs for additional error details. +1. Contact Grafana Support if you're an Enterprise or Cloud customer. + +When reporting issues, include: + +- Grafana version +- SQL Server version +- Error messages (redact sensitive information) +- Steps to reproduce +- Relevant query examples (redact sensitive data) diff --git a/docs/sources/developer-resources/api-reference/http-api/dashboard.md b/docs/sources/developer-resources/api-reference/http-api/dashboard.md index abef6a8f5e6..1b5d32bb9f4 100644 --- a/docs/sources/developer-resources/api-reference/http-api/dashboard.md +++ b/docs/sources/developer-resources/api-reference/http-api/dashboard.md @@ -231,6 +231,10 @@ JSON Body schema: - **metadata.annotations.grafana.app/folder** - Optional field, the unique identifier of the folder under which the dashboard should be created. - **spec** – The dashboard json. +{{< admonition type="note" >}} +Custom labels and annotations in the metadata field are supported on some instances, with full support planned for all instances when these APIs reach general availability. If they are not yet supported on your instance, they will be ignored. +{{< /admonition >}} + **Example Response**: ```http @@ -521,6 +525,10 @@ JSON Body schema: - **metadata.annotations.grafana.app/message** - Optional field, to set a commit message for the version history. - **spec** – The dashboard json. +{{< admonition type="note" >}} +Custom labels and annotations in the metadata field are supported on some instances, with full support planned for all instances when these APIs reach general availability. If they are not yet supported on your instance, they will be ignored. +{{< /admonition >}} + **Example Response**: ```http diff --git a/docs/sources/developer-resources/api-reference/http-api/folder.md b/docs/sources/developer-resources/api-reference/http-api/folder.md index f042a3a5a3e..6a6b18abeba 100644 --- a/docs/sources/developer-resources/api-reference/http-api/folder.md +++ b/docs/sources/developer-resources/api-reference/http-api/folder.md @@ -259,6 +259,10 @@ JSON Body schema: - **metadata.annotations.grafana.app/folder** - Optional field, the unique identifier of the parent folder under which the folder should be created. Requires nested folders to be enabled. - **spec.title** – The title of the folder. +{{< admonition type="note" >}} +Custom labels and annotations in the metadata field are supported on some instances, with full support planned for all instances when these APIs reach general availability. If they are not yet supported on your instance, they will be ignored. +{{< /admonition >}} + **Example Response**: ```http @@ -337,6 +341,10 @@ JSON Body schema: - **metadata.annotations.grafana.app/folder** - Optional field, the unique identifier of the parent folder under which the folder should be - update this to move the folder under a different parent folder. Requires nested folders to be enabled. - **spec.title** – The title of the folder. +{{< admonition type="note" >}} +Custom labels and annotations in the metadata field are supported on some instances, with full support planned for all instances when these APIs reach general availability. If they are not yet supported on your instance, they will be ignored. +{{< /admonition >}} + **Example Response**: ```http diff --git a/docs/sources/developer-resources/api-reference/http-api/library_element.md b/docs/sources/developer-resources/api-reference/http-api/library_element.md index ea241c220e1..ce367c485ef 100644 --- a/docs/sources/developer-resources/api-reference/http-api/library_element.md +++ b/docs/sources/developer-resources/api-reference/http-api/library_element.md @@ -41,7 +41,8 @@ Query parameters: - `sortDirection`: Sort order of elements. Use `alpha-asc` for ascending and `alpha-desc` for descending sort order. - `typeFilter`: A comma separated list of types to filter the elements by. - `excludeUid`: Element UID to exclude from search results. -- `folderFilter`: A comma separated list of folder IDs to filter the elements by. +- `folderFilter`: **Deprecated.** A comma separated list of folder IDs to filter the elements by. Use `folderFilterUIDs` instead. +- `folderFilterUIDs`: A comma separated list of folder UIDs to filter the elements by. - `perPage`: The number of results per page; default is 100. - `page`: The page for a set of records, given that only `perPage` records are returned at a time. Numbering starts at `1`. diff --git a/docs/sources/developer-resources/api-reference/http-api/preferences.md b/docs/sources/developer-resources/api-reference/http-api/preferences.md index 1cd350ee059..079fa1ebce9 100644 --- a/docs/sources/developer-resources/api-reference/http-api/preferences.md +++ b/docs/sources/developer-resources/api-reference/http-api/preferences.md @@ -25,7 +25,7 @@ Keys: - **theme** - One of: `light`, `dark`, or an empty string for the default theme - **homeDashboardId** - Deprecated. Use `homeDashboardUID` instead. - **homeDashboardUID**: The `:uid` of a dashboard -- **timezone** - One of: `utc`, `browser`, or an empty string for the default +- **timezone** - Any valid IANA timezone string (e.g., `America/New_York`, `Europe/London`), `utc`, `browser`, or an empty string for the default. Omitting a key will cause the current value to be replaced with the system default value. diff --git a/docs/sources/developers/plugins/plugin.schema.json b/docs/sources/developers/plugins/plugin.schema.json index 1898cd46b94..cae948ce4f3 100644 --- a/docs/sources/developers/plugins/plugin.schema.json +++ b/docs/sources/developers/plugins/plugin.schema.json @@ -369,7 +369,7 @@ "description": "For data source plugins. Proxy routes used for plugin authentication and adding headers to HTTP requests made by the plugin. For more information, refer to [Authentication for data source plugins](https://grafana.com/developers/plugin-tools/how-to-guides/data-source-plugins/add-authentication-for-data-source-plugins).", "items": { "type": "object", - "description": "", + "description": "For data source plugins. Proxy routes used for plugin authentication and adding headers to HTTP requests made by the plugin. For more information, refer to [Authentication for data source plugins](https://grafana.com/developers/plugin-tools/how-to-guides/data-source-plugins/add-authentication-for-data-source-plugins).", "additionalProperties": false, "properties": { "path": { diff --git a/docs/sources/setup-grafana/configure-access/configure-authentication/anonymous-auth/index.md b/docs/sources/setup-grafana/configure-access/configure-authentication/anonymous-auth/index.md index 77df611f904..27c65e7bd02 100644 --- a/docs/sources/setup-grafana/configure-access/configure-authentication/anonymous-auth/index.md +++ b/docs/sources/setup-grafana/configure-access/configure-authentication/anonymous-auth/index.md @@ -38,13 +38,6 @@ Users can now view anonymous usage statistics, including the count of devices an The number of anonymous devices is not limited by default. The configuration option `device_limit` allows you to enforce a limit on the number of anonymous devices. This enables you to have greater control over the usage within your Grafana instance and keep the usage within the limits of your environment. Once the limit is reached, any new devices that try to access Grafana will be denied access. -To display anonymous users and devices for versions 10.2, 10.3, 10.4, you need to enable the feature toggle `displayAnonymousStats` - -```bash -[feature_toggles] -enable = displayAnonymousStats -``` - ## Configuration Example: @@ -67,3 +60,15 @@ device_limit = ``` If you change your organization name in the Grafana UI this setting needs to be updated to match the new name. + +## Licensing for anonymous access + +Grafana Enterprise (self-managed) licenses anonymous access as active users. + +Anonymous access lets people use Grafana without login credentials. It was an early way to share dashboards, but Public dashboards gives you a more secure way to share dashboards. + +### How anonymous usage is counted + +Grafana estimates anonymous active users from anonymous devices: + +- **Counting rule**: Grafana counts 1 anonymous user for every 3 anonymous devices detected. diff --git a/docs/sources/setup-grafana/configure-grafana/_index.md b/docs/sources/setup-grafana/configure-grafana/_index.md index 67c361b2bdc..d9125991c12 100644 --- a/docs/sources/setup-grafana/configure-grafana/_index.md +++ b/docs/sources/setup-grafana/configure-grafana/_index.md @@ -2836,9 +2836,11 @@ For more information about Grafana Enterprise, refer to [Grafana Enterprise](../ Keys of features to enable, separated by space. -#### `FEATURE_TOGGLE_NAME = false` +#### `FEATURE_NAME = ` -Some feature toggles for stable features are on by default. Use this setting to disable an on-by-default feature toggle with the name FEATURE_TOGGLE_NAME, for example, `exploreMixedDatasource = false`. +Use a key-value pair to set feature flag values explicitly, overriding any default values. A few different types are supported, following the OpenFeature specification. See the defaults.ini file for more details. + +For example, to disable an on-by-default feature toggle named `exploreMixedDatasource`, specify `exploreMixedDatasource = false`.
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 16c97f6d10a..b7f55555e07 100644 --- a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md +++ b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md @@ -66,7 +66,6 @@ Most [generally available](https://grafana.com/docs/release-life-cycle/#general- | `sharingDashboardImage` | Enables image sharing functionality for dashboards | Yes | | `tabularNumbers` | Use fixed-width numbers globally in the UI | | | `azureResourcePickerUpdates` | Enables the updated Azure Monitor resource picker | Yes | -| `tempoSearchBackendMigration` | Run search queries through the tempo backend | | | `opentsdbBackendMigration` | Run queries through the data source backend | | ## Public preview feature toggles diff --git a/docs/sources/shared/datasources/tempo-editor-traceql.md b/docs/sources/shared/datasources/tempo-editor-traceql.md index 54496c339e3..003a449fd96 100644 --- a/docs/sources/shared/datasources/tempo-editor-traceql.md +++ b/docs/sources/shared/datasources/tempo-editor-traceql.md @@ -135,9 +135,12 @@ You can use the **Span Limit** field in **Options** section of the TraceQL query This field sets the maximum number of spans to return for each span set. By default, the maximum value that you can set for the **Span Limit** value (or the spss query) is 100. In Tempo configuration, this value is controlled by the `max_spans_per_span_set` parameter and can be modified by your Tempo administrator. -Grafana Cloud users can contact Grafana Support to request a change. Entering a value higher than the default results in an error. +{{< admonition type="note" >}} +Changing the value of `max_spans_per_span_set` isn't supported in Grafana Cloud. +{{< /admonition >}} + ### Focus on traces or spans Under **Options**, you can choose to display the table as **Traces** or **Spans** focused. diff --git a/docs/sources/tutorials/alerting-get-started-pt6/index.md b/docs/sources/tutorials/alerting-get-started-pt6/index.md index 470330237e2..edf5e61e178 100644 --- a/docs/sources/tutorials/alerting-get-started-pt6/index.md +++ b/docs/sources/tutorials/alerting-get-started-pt6/index.md @@ -23,6 +23,8 @@ killercoda: This tutorial is a continuation of the [Get started with Grafana Alerting - Route alerts using dynamic labels](http://www.grafana.com/tutorials/alerting-get-started-pt5/) tutorial. +{{< youtube id="mqj_hN24zLU" >}} + In this tutorial you will learn how to: diff --git a/docs/sources/visualizations/dashboards/manage-dashboards/index.md b/docs/sources/visualizations/dashboards/manage-dashboards/index.md index f42892d4f39..b65fcecd758 100644 --- a/docs/sources/visualizations/dashboards/manage-dashboards/index.md +++ b/docs/sources/visualizations/dashboards/manage-dashboards/index.md @@ -124,6 +124,8 @@ For more information about dashboard permissions, refer to [Dashboard permission ## Restore deleted dashboards {{% admonition type="caution" %}} +Restoring deleted dashboards is currently in private preview. Grafana Labs offers support on a best-effort basis, and breaking changes might occur prior to the feature being made generally available. + The feature is only available in Grafana Cloud. {{% /admonition %}} diff --git a/docs/sources/visualizations/dashboards/share-dashboards-panels/_index.md b/docs/sources/visualizations/dashboards/share-dashboards-panels/_index.md index 5fcd2344fe2..e7749ba5b88 100644 --- a/docs/sources/visualizations/dashboards/share-dashboards-panels/_index.md +++ b/docs/sources/visualizations/dashboards/share-dashboards-panels/_index.md @@ -98,7 +98,7 @@ You can share dashboards in the following ways: - [As a report](#schedule-a-report) - [As a snapshot](#share-a-snapshot) - [As a PDF export](#export-a-dashboard-as-pdf) -- [As a JSON file export](#export-a-dashboard-as-json) +- [As a JSON file export](#export-a-dashboard-as-code) - [As an image export](#export-a-dashboard-as-an-image) When you share a dashboard externally as a link or by email, those dashboards are included in a list of your shared dashboards. To view the list and manage these dashboards, navigate to **Dashboards > Shared dashboards**. diff --git a/e2e-playwright/dashboard-cujs/adhoc-filters-cujs.spec.ts b/e2e-playwright/dashboard-cujs/adhoc-filters-cujs.spec.ts index 038fe099eeb..2a0f6932141 100644 --- a/e2e-playwright/dashboard-cujs/adhoc-filters-cujs.spec.ts +++ b/e2e-playwright/dashboard-cujs/adhoc-filters-cujs.spec.ts @@ -1,6 +1,7 @@ import { test, expect } from '@grafana/plugin-e2e'; -import { setScopes } from '../utils/scope-helpers'; +import { setScopes, setupScopeRoutes } from '../utils/scope-helpers'; +import { testScopes } from '../utils/scopes'; import { getAdHocFilterOptionValues, @@ -13,6 +14,7 @@ import { } from './cuj-selectors'; import { prepareAPIMocks } from './utils'; +const USE_LIVE_DATA = Boolean(process.env.API_CONFIG_PATH); const DASHBOARD_UNDER_TEST = 'cuj-dashboard-1'; test.use({ @@ -34,6 +36,11 @@ test.describe( const adHocFilterPills = getAdHocFilterPills(page); const scopesSelectorInput = getScopesSelectorInput(page); + // Set up routes before any navigation (only for mocked mode) + if (!USE_LIVE_DATA) { + await setupScopeRoutes(page, testScopes()); + } + await test.step('1.Apply filtering to a whole dashboard', async () => { const dashboardPage = await gotoDashboardPage({ uid: DASHBOARD_UNDER_TEST }); diff --git a/e2e-playwright/dashboard-cujs/cuj-selectors.ts b/e2e-playwright/dashboard-cujs/cuj-selectors.ts index f2366fd2ef1..548c183ef3f 100644 --- a/e2e-playwright/dashboard-cujs/cuj-selectors.ts +++ b/e2e-playwright/dashboard-cujs/cuj-selectors.ts @@ -66,6 +66,17 @@ export function getScopesDashboards(page: Page) { return page.locator('[data-testid^="scopes-dashboards-"][role="treeitem"]'); } +/** + * Clicks the first available dashboard in the scopes dashboard list. + */ +export async function clickFirstScopesDashboard(page: Page) { + const dashboards = getScopesDashboards(page); + // Wait for at least one dashboard to be visible + await expect(dashboards.first()).toBeVisible({ timeout: 10000 }); + // Click - Playwright will automatically wait for the element to be actionable + await dashboards.first().click(); +} + export function getScopesDashboardsSearchInput(page: Page) { return page.getByTestId('scopes-dashboards-search'); } diff --git a/e2e-playwright/dashboard-cujs/dashboard-navigation.spec.ts b/e2e-playwright/dashboard-cujs/dashboard-navigation.spec.ts index 008e1e5538c..c941c40f6ef 100644 --- a/e2e-playwright/dashboard-cujs/dashboard-navigation.spec.ts +++ b/e2e-playwright/dashboard-cujs/dashboard-navigation.spec.ts @@ -1,8 +1,10 @@ import { test, expect } from '@grafana/plugin-e2e'; -import { setScopes } from '../utils/scope-helpers'; +import { setScopes, setupScopeRoutes } from '../utils/scope-helpers'; +import { testScopes } from '../utils/scopes'; import { + clickFirstScopesDashboard, getAdHocFilterPills, getGroupByInput, getGroupByValues, @@ -21,6 +23,7 @@ test.use({ }, }); +const USE_LIVE_DATA = Boolean(process.env.API_CONFIG_PATH); const DASHBOARD_UNDER_TEST = 'cuj-dashboard-1'; const DASHBOARD_UNDER_TEST_2 = 'cuj-dashboard-2'; const NAVIGATE_TO = 'cuj-dashboard-3'; @@ -38,6 +41,11 @@ test.describe( const adhocFilterPills = getAdHocFilterPills(page); const groupByValues = getGroupByValues(page); + // Set up routes before any navigation (only for mocked mode) + if (!USE_LIVE_DATA) { + await setupScopeRoutes(page, testScopes()); + } + await test.step('1.Search dashboard', async () => { await gotoDashboardPage({ uid: DASHBOARD_UNDER_TEST }); @@ -74,7 +82,7 @@ test.describe( await expect(markdownContent).toContainText(`now-12h`); - await scopesDashboards.first().click(); + await clickFirstScopesDashboard(page); await page.waitForURL('**/d/**'); await expect(markdownContent).toBeVisible(); @@ -117,10 +125,10 @@ test.describe( await groupByVariable.press('Enter'); await groupByVariable.press('Escape'); - await expect(scopesDashboards.first()).toBeVisible(); - const { getRequests, waitForExpectedRequests } = await trackDashboardReloadRequests(page); - await scopesDashboards.first().click(); + + await clickFirstScopesDashboard(page); + await page.waitForURL('**/d/**'); await waitForExpectedRequests(); await page.waitForLoadState('networkidle'); @@ -158,8 +166,7 @@ test.describe( const oldFilters = `GroupByVar: ${selectedValues}\n\nAdHocVar: ${processedPills}`; await expect(markdownContent).toContainText(oldFilters); - await expect(scopesDashboards.first()).toBeVisible(); - await scopesDashboards.first().click(); + await clickFirstScopesDashboard(page); await page.waitForURL('**/d/**'); const newPillCount = await adhocFilterPills.count(); diff --git a/e2e-playwright/dashboard-cujs/dashboard-view.spec.ts b/e2e-playwright/dashboard-cujs/dashboard-view.spec.ts index 53dd02a0314..e9c1370bbc6 100644 --- a/e2e-playwright/dashboard-cujs/dashboard-view.spec.ts +++ b/e2e-playwright/dashboard-cujs/dashboard-view.spec.ts @@ -165,9 +165,8 @@ test.describe( await refreshBtn.click(); - await page.waitForLoadState('networkidle'); - - expect(await panelContent.textContent()).not.toBe(panelContents); + // Wait for the panel content to change (not just for network to complete) + await expect(panelContent).not.toHaveText(panelContents!, { timeout: 10000 }); }); await test.step('6.Turn off refresh', async () => { diff --git a/e2e-playwright/dashboard-cujs/scope-cujs.spec.ts b/e2e-playwright/dashboard-cujs/scope-cujs.spec.ts index 54ec3ca7a8b..dd1cd50c35f 100644 --- a/e2e-playwright/dashboard-cujs/scope-cujs.spec.ts +++ b/e2e-playwright/dashboard-cujs/scope-cujs.spec.ts @@ -9,6 +9,7 @@ import { openScopesSelector, searchScopes, selectScope, + setupScopeRoutes, } from '../utils/scope-helpers'; import { testScopes } from '../utils/scopes'; @@ -36,32 +37,37 @@ test.describe( const scopesSelector = getScopesSelectorInput(page); const recentScopesSelector = getRecentScopesSelector(page); const scopeTreeCheckboxes = getScopeTreeCheckboxes(page); + const scopes = testScopes(); + + // Set up routes once before any navigation (only for mocked mode) + if (!USE_LIVE_DATA) { + await setupScopeRoutes(page, scopes); + } await test.step('1.View and select any scope', async () => { await gotoDashboardPage({ uid: DASHBOARD_UNDER_TEST }); expect.soft(scopesSelector).toHaveAttribute('data-value', ''); - const scopes = testScopes(); - await openScopesSelector(page, USE_LIVE_DATA ? undefined : scopes); //used only in mocked scopes version + await openScopesSelector(page, USE_LIVE_DATA ? undefined : scopes); let scopeName = await getScopeTreeName(page, 0); - const firstLevelScopes = scopes[0].children!; //used only in mocked scopes version + const firstLevelScopes = scopes[0].children!; await expandScopesSelection(page, scopeName, USE_LIVE_DATA ? undefined : firstLevelScopes); scopeName = await getScopeTreeName(page, 1); - const secondLevelScopes = firstLevelScopes[0].children!; //used only in mocked scopes version + const secondLevelScopes = firstLevelScopes[0].children!; await expandScopesSelection(page, scopeName, USE_LIVE_DATA ? undefined : secondLevelScopes); - const selectedScopes = [secondLevelScopes[0]]; //used only in mocked scopes version + const selectedScopes = [secondLevelScopes[0]]; scopeName = await getScopeLeafName(page, 0); let scopeTitle = await getScopeLeafTitle(page, 0); await selectScope(page, scopeName, USE_LIVE_DATA ? undefined : selectedScopes[0]); - await applyScopes(page, USE_LIVE_DATA ? undefined : selectedScopes); //used only in mocked scopes version + await applyScopes(page, USE_LIVE_DATA ? undefined : selectedScopes); expect.soft(scopesSelector).toHaveAttribute('data-value', scopeTitle); }); @@ -70,28 +76,27 @@ test.describe( await gotoDashboardPage({ uid: DASHBOARD_UNDER_TEST }); expect.soft(scopesSelector).toHaveAttribute('data-value', ''); - const scopes = testScopes(); - await openScopesSelector(page, USE_LIVE_DATA ? undefined : scopes); //used only in mocked scopes version + await openScopesSelector(page, USE_LIVE_DATA ? undefined : scopes); let scopeName = await getScopeTreeName(page, 0); - const firstLevelScopes = scopes[0].children!; //used only in mocked scopes version + const firstLevelScopes = scopes[0].children!; await expandScopesSelection(page, scopeName, USE_LIVE_DATA ? undefined : firstLevelScopes); scopeName = await getScopeTreeName(page, 1); - const secondLevelScopes = firstLevelScopes[0].children!; //used only in mocked scopes version + const secondLevelScopes = firstLevelScopes[0].children!; await expandScopesSelection(page, scopeName, USE_LIVE_DATA ? undefined : secondLevelScopes); const scopeTitles: string[] = []; - const selectedScopes = [secondLevelScopes[0], secondLevelScopes[1]]; //used only in mocked scopes version + const selectedScopes = [secondLevelScopes[0], secondLevelScopes[1]]; for (let i = 0; i < selectedScopes.length; i++) { scopeName = await getScopeLeafName(page, i); scopeTitles.push(await getScopeLeafTitle(page, i)); - await selectScope(page, scopeName, USE_LIVE_DATA ? undefined : selectedScopes[i]); //used only in mocked scopes version + await selectScope(page, scopeName, USE_LIVE_DATA ? undefined : selectedScopes[i]); } - await applyScopes(page, USE_LIVE_DATA ? undefined : selectedScopes); //used only in mocked scopes version + await applyScopes(page, USE_LIVE_DATA ? undefined : selectedScopes); await expect.soft(scopesSelector).toHaveAttribute('data-value', scopeTitles.join(' + ')); }); @@ -102,8 +107,7 @@ test.describe( expect.soft(scopesSelector).toHaveAttribute('data-value', ''); - const scopes = testScopes(); - await openScopesSelector(page, USE_LIVE_DATA ? undefined : scopes); //used only in mocked scopes version + await openScopesSelector(page, USE_LIVE_DATA ? undefined : scopes); await recentScopesSelector.click(); @@ -121,26 +125,25 @@ test.describe( expect.soft(scopesSelector).toHaveAttribute('data-value', ''); - const scopes = testScopes(); await openScopesSelector(page, USE_LIVE_DATA ? undefined : scopes); let scopeName = await getScopeTreeName(page, 1); - const firstLevelScopes = scopes[2].children!; //used only in mocked scopes version + const firstLevelScopes = scopes[2].children!; await expandScopesSelection(page, scopeName, USE_LIVE_DATA ? undefined : firstLevelScopes); scopeName = await getScopeTreeName(page, 1); - const secondLevelScopes = firstLevelScopes[0].children!; //used only in mocked scopes version + const secondLevelScopes = firstLevelScopes[0].children!; await expandScopesSelection(page, scopeName, USE_LIVE_DATA ? undefined : secondLevelScopes); - const selectedScopes = [secondLevelScopes[0]]; //used only in mocked scopes version + const selectedScopes = [secondLevelScopes[0]]; scopeName = await getScopeLeafName(page, 0); let scopeTitle = await getScopeLeafTitle(page, 0); await selectScope(page, scopeName, USE_LIVE_DATA ? undefined : selectedScopes[0]); - await applyScopes(page, USE_LIVE_DATA ? undefined : []); //used only in mocked scopes version + await applyScopes(page, USE_LIVE_DATA ? undefined : []); expect.soft(scopesSelector).toHaveAttribute('data-value', new RegExp(`^${scopeTitle}`)); }); @@ -148,17 +151,16 @@ test.describe( await test.step('5.View pre-completed production entity values as I type', async () => { await gotoDashboardPage({ uid: DASHBOARD_UNDER_TEST }); - const scopes = testScopes(); - await openScopesSelector(page, USE_LIVE_DATA ? undefined : scopes); //used only in mocked scopes version + await openScopesSelector(page, USE_LIVE_DATA ? undefined : scopes); let scopeName = await getScopeTreeName(page, 0); - const firstLevelScopes = scopes[0].children!; //used only in mocked scopes version + const firstLevelScopes = scopes[0].children!; await expandScopesSelection(page, scopeName, USE_LIVE_DATA ? undefined : firstLevelScopes); scopeName = await getScopeTreeName(page, 1); - const secondLevelScopes = firstLevelScopes[0].children!; //used only in mocked scopes version + const secondLevelScopes = firstLevelScopes[0].children!; await expandScopesSelection(page, scopeName, USE_LIVE_DATA ? undefined : secondLevelScopes); const scopeSearchOne = await getScopeLeafTitle(page, 0); diff --git a/e2e-playwright/dashboard-cujs/scope-redirect.spec.ts b/e2e-playwright/dashboard-cujs/scope-redirect.spec.ts index 952e8a3da63..b140e7a9838 100644 --- a/e2e-playwright/dashboard-cujs/scope-redirect.spec.ts +++ b/e2e-playwright/dashboard-cujs/scope-redirect.spec.ts @@ -1,6 +1,6 @@ import { test, expect } from '@grafana/plugin-e2e'; -import { applyScopes, openScopesSelector, selectScope } from '../utils/scope-helpers'; +import { applyScopes, openScopesSelector, selectScope, setupScopeRoutes } from '../utils/scope-helpers'; import { testScopesWithRedirect } from '../utils/scopes'; test.use({ @@ -16,8 +16,13 @@ test.describe('Scope Redirect Functionality', () => { test('should redirect to custom URL when scope has redirectUrl', async ({ page, gotoDashboardPage }) => { const scopes = testScopesWithRedirect(); - await test.step('Navigate to dashboard and open scopes selector', async () => { + await test.step('Set up routes and navigate to dashboard', async () => { + // Set up routes BEFORE navigation to ensure all requests are mocked + await setupScopeRoutes(page, scopes); await gotoDashboardPage({ uid: 'cuj-dashboard-1' }); + }); + + await test.step('Open scopes selector', async () => { await openScopesSelector(page, scopes); }); @@ -40,8 +45,12 @@ test.describe('Scope Redirect Functionality', () => { test('should prioritize redirectUrl over scope navigation fallback', async ({ page, gotoDashboardPage }) => { const scopes = testScopesWithRedirect(); - await test.step('Navigate to dashboard and open scopes selector', async () => { + await test.step('Set up routes and navigate to dashboard', async () => { + await setupScopeRoutes(page, scopes); await gotoDashboardPage({ uid: 'cuj-dashboard-1' }); + }); + + await test.step('Open scopes selector', async () => { await openScopesSelector(page, scopes); }); @@ -68,8 +77,12 @@ test.describe('Scope Redirect Functionality', () => { }) => { const scopes = testScopesWithRedirect(); - await test.step('Navigate to dashboard and select scope', async () => { + await test.step('Set up routes and navigate to dashboard', async () => { + await setupScopeRoutes(page, scopes); await gotoDashboardPage({ uid: 'cuj-dashboard-1' }); + }); + + await test.step('Select and apply scope', async () => { await openScopesSelector(page, scopes); await selectScope(page, 'sn-redirect-fallback', scopes[1]); await applyScopes(page, [scopes[1]]); @@ -112,8 +125,12 @@ test.describe('Scope Redirect Functionality', () => { }) => { const scopes = testScopesWithRedirect(); - await test.step('Navigate to dashboard and select scope', async () => { + await test.step('Set up routes and navigate to dashboard', async () => { + await setupScopeRoutes(page, scopes); await gotoDashboardPage({ uid: 'cuj-dashboard-1' }); + }); + + await test.step('Select and apply scope', async () => { await openScopesSelector(page, scopes); await selectScope(page, 'sn-redirect-fallback', scopes[1]); await applyScopes(page, [scopes[1]]); @@ -151,9 +168,13 @@ test.describe('Scope Redirect Functionality', () => { test('should not redirect to redirectPath when on active scope navigation', async ({ page, gotoDashboardPage }) => { const scopes = testScopesWithRedirect(); + await test.step('Set up routes and navigate to dashboard', async () => { + await setupScopeRoutes(page, scopes); + await gotoDashboardPage({ uid: 'cuj-dashboard-1' }); + }); + await test.step('Set up scope navigation to dashboard-1', async () => { // First, apply a scope that creates scope navigation to dashboard-1 (without redirectPath) - await gotoDashboardPage({ uid: 'cuj-dashboard-1' }); await openScopesSelector(page, scopes); await selectScope(page, 'sn-redirect-setup', scopes[2]); await applyScopes(page, [scopes[2]]); diff --git a/e2e-playwright/dashboard-new-layouts/dashboard-keybindings.spec.ts b/e2e-playwright/dashboard-new-layouts/dashboard-keybindings.spec.ts index 19ad38f16d5..867337ba088 100644 --- a/e2e-playwright/dashboard-new-layouts/dashboard-keybindings.spec.ts +++ b/e2e-playwright/dashboard-new-layouts/dashboard-keybindings.spec.ts @@ -51,6 +51,8 @@ test.describe('Dashboard keybindings with new layouts', { tag: ['@dashboards'] } await expect(dashboardPage.getByGrafanaSelector(selectors.components.PanelInspector.Json.content)).toBeVisible(); + // Press Escape to close tooltip on the close button + await page.keyboard.press('Escape'); // Press Escape to close inspector await page.keyboard.press('Escape'); diff --git a/e2e-playwright/dashboard-new-layouts/dashboards-edit-variables.spec.ts b/e2e-playwright/dashboard-new-layouts/dashboards-edit-variables.spec.ts index 4b5ea9574f8..15a41047fe6 100644 --- a/e2e-playwright/dashboard-new-layouts/dashboards-edit-variables.spec.ts +++ b/e2e-playwright/dashboard-new-layouts/dashboards-edit-variables.spec.ts @@ -1,6 +1,6 @@ import { test, expect } from '@grafana/plugin-e2e'; -import { flows, type Variable } from './utils'; +import { flows, saveDashboard, type Variable } from './utils'; test.use({ featureToggles: { @@ -64,20 +64,7 @@ test.describe( label: 'VariableUnderTest', }; - // common steps to add a new variable - await flows.newEditPaneVariableClick(dashboardPage, selectors); - await flows.newEditPanelCommonVariableInputs(dashboardPage, selectors, variable); - - // set the textbox variable value - const type = 'variable-type Value'; - const fieldLabel = dashboardPage.getByGrafanaSelector( - selectors.components.PanelEditor.OptionsPane.fieldLabel(type) - ); - await expect(fieldLabel).toBeVisible(); - const inputField = fieldLabel.locator('input'); - await expect(inputField).toBeVisible(); - await inputField.fill(variable.value); - await inputField.blur(); + await flows.addNewTextBoxVariable(dashboardPage, variable); // select the variable in the dashboard and confirm the variable value is set await dashboardPage.getByGrafanaSelector(selectors.pages.Dashboard.SubMenu.submenuItem).click(); @@ -140,5 +127,94 @@ test.describe( await expect(panelContent).toBeVisible(); await expect(markdownContent).toContainText('VariableUnderTest: 10m'); }); + test('can hide a variable', async ({ dashboardPage, selectors, page }) => { + const variable: Variable = { + type: 'textbox', + name: 'VariableUnderTest', + value: 'foo', + label: 'VariableUnderTest', + }; + + await saveDashboard(dashboardPage, page, selectors, 'can hide a variable'); + await flows.addNewTextBoxVariable(dashboardPage, variable); + + // check the variable is visible in the dashboard + const variableLabel = dashboardPage.getByGrafanaSelector( + selectors.pages.Dashboard.SubMenu.submenuItemLabels(variable.label) + ); + await expect(variableLabel).toBeVisible(); + // hide the variable + await dashboardPage + .getByGrafanaSelector(selectors.pages.Dashboard.Settings.Variables.Edit.General.generalDisplaySelect) + .click(); + await page.getByText('Hidden', { exact: true }).click(); + + // check that the variable is still visible + await expect( + dashboardPage.getByGrafanaSelector(selectors.pages.Dashboard.SubMenu.submenuItemLabels(variable.label!)) + ).toBeVisible(); + + // save dashboard and exit edit mode and check variable is not visible + await saveDashboard(dashboardPage, page, selectors); + await dashboardPage.getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.editButton).click(); + await expect( + dashboardPage.getByGrafanaSelector(selectors.pages.Dashboard.SubMenu.submenuItemLabels(variable.label!)) + ).toBeHidden(); + // refresh and check that variable isn't visible + await page.reload(); + await expect( + dashboardPage.getByGrafanaSelector(selectors.pages.Dashboard.SubMenu.submenuItemLabels(variable.label!)) + ).toBeHidden(); + // check that the variable is visible in edit mode + await dashboardPage.getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.editButton).click(); + await expect( + dashboardPage.getByGrafanaSelector(selectors.pages.Dashboard.SubMenu.submenuItemLabels(variable.label!)) + ).toBeVisible(); + }); + + test('can hide variable under the controls menu', async ({ dashboardPage, selectors, page }) => { + const variable: Variable = { + type: 'textbox', + name: 'VariableUnderTest', + value: 'foo', + label: 'VariableUnderTest', + }; + await saveDashboard(dashboardPage, page, selectors, 'can hide a variable in controls menu'); + + await flows.addNewTextBoxVariable(dashboardPage, variable); + + // check the variable is visible in the dashboard + const variableLabel = dashboardPage.getByGrafanaSelector( + selectors.pages.Dashboard.SubMenu.submenuItemLabels(variable.label) + ); + await expect(variableLabel).toBeVisible(); + // hide the variable + await dashboardPage + .getByGrafanaSelector(selectors.pages.Dashboard.Settings.Variables.Edit.General.generalDisplaySelect) + .click(); + await page.getByText('Controls menu', { exact: true }).click(); + + // check that the variable is hidden under the controls menu + await expect( + dashboardPage.getByGrafanaSelector(selectors.pages.Dashboard.SubMenu.submenuItemLabels(variable.label!)) + ).toBeHidden(); + await dashboardPage.getByGrafanaSelector(selectors.pages.Dashboard.ControlsButton).click(); + await expect( + dashboardPage.getByGrafanaSelector(selectors.pages.Dashboard.SubMenu.submenuItemLabels(variable.label!)) + ).toBeVisible(); + + // save dashboard and refresh + await saveDashboard(dashboardPage, page, selectors); + await page.reload(); + + //check that the variable is hidden under the controls menu + await expect( + dashboardPage.getByGrafanaSelector(selectors.pages.Dashboard.SubMenu.submenuItemLabels(variable.label!)) + ).toBeHidden(); + await dashboardPage.getByGrafanaSelector(selectors.pages.Dashboard.ControlsButton).click(); + await expect( + dashboardPage.getByGrafanaSelector(selectors.pages.Dashboard.SubMenu.submenuItemLabels(variable.label!)) + ).toBeVisible(); + }); } ); diff --git a/e2e-playwright/dashboard-new-layouts/dashboards-repeats-custom-grid.spec.ts b/e2e-playwright/dashboard-new-layouts/dashboards-repeats-custom-grid.spec.ts index 8cc1f552377..e60b722c46e 100644 --- a/e2e-playwright/dashboard-new-layouts/dashboards-repeats-custom-grid.spec.ts +++ b/e2e-playwright/dashboard-new-layouts/dashboards-repeats-custom-grid.spec.ts @@ -1,6 +1,7 @@ import { test, expect } from '@grafana/plugin-e2e'; import testV2DashWithRepeats from '../dashboards/V2DashWithRepeats.json'; +import testV2DashWithRowRepeats from '../dashboards/V2DashWithRowRepeats.json'; import { checkRepeatedPanelTitles, @@ -10,11 +11,14 @@ import { saveDashboard, importTestDashboard, goToEmbeddedPanel, + goToPanelSnapshot, } from './utils'; const repeatTitleBase = 'repeat - '; const newTitleBase = 'edited rep - '; const repeatOptions = [1, 2, 3, 4]; +const getTitleInRepeatRow = (rowIndex: number, panelIndex: number) => + `repeated-row-${rowIndex}-repeated-panel-${panelIndex}`; test.use({ featureToggles: { @@ -165,9 +169,7 @@ test.describe( ) ).toBeVisible(); - await dashboardPage - .getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.backToDashboardButton) - .click(); + await page.keyboard.press('Escape'); await expect( dashboardPage.getByGrafanaSelector(selectors.components.DashboardEditPaneSplitter.primaryBody) @@ -217,9 +219,7 @@ test.describe( ) ).toBeVisible(); - await dashboardPage - .getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.backToDashboardButton) - .click(); + await page.keyboard.press('Escape'); await expect( dashboardPage.getByGrafanaSelector(selectors.components.DashboardEditPaneSplitter.primaryBody) @@ -405,5 +405,143 @@ test.describe( await dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.headerContainer).all() ).toHaveLength(3); }); + + test('can view repeated panel in a repeated row', async ({ dashboardPage, selectors, page }) => { + await importTestDashboard( + page, + selectors, + 'Custom grid repeats - view repeated panel in a repeated row', + JSON.stringify(testV2DashWithRowRepeats) + ); + + // make sure the repeated panel is present in multiple rows + await expect( + dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title(getTitleInRepeatRow(1, 1))) + ).toBeVisible(); + await expect( + dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title(getTitleInRepeatRow(2, 2))) + ).toBeVisible(); + + await dashboardPage + .getByGrafanaSelector(selectors.components.Panels.Panel.title(getTitleInRepeatRow(1, 1))) + .hover(); + + await page.keyboard.press('v'); + + await expect( + dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title(getTitleInRepeatRow(2, 2))) + ).not.toBeVisible(); + + await expect( + dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title(getTitleInRepeatRow(1, 1))) + ).toBeVisible(); + + const repeatedPanelUrl = page.url(); + + await page.keyboard.press('Escape'); + + // load view panel directly + await page.goto(repeatedPanelUrl); + + await expect( + dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title(getTitleInRepeatRow(1, 1))) + ).toBeVisible(); + + await expect( + dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title(getTitleInRepeatRow(2, 2))) + ).not.toBeVisible(); + }); + + test('can view embedded panel in a repeated row', async ({ dashboardPage, selectors, page }) => { + const embedPanelTitle = 'embedded-panel'; + await importTestDashboard( + page, + selectors, + 'Custom grid repeats - view embedded repeated panel in a repeated row', + JSON.stringify(testV2DashWithRowRepeats) + ); + + await dashboardPage + .getByGrafanaSelector(selectors.components.Panels.Panel.title(getTitleInRepeatRow(1, 1))) + .hover(); + await page.keyboard.press('p+e'); + + await goToEmbeddedPanel(page); + + await expect( + dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title(getTitleInRepeatRow(1, 1))) + ).toBeVisible(); + + await expect( + dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title(getTitleInRepeatRow(2, 2))) + ).not.toBeVisible(); + }); + + // there is a bug in the Snapshot feature that prevents the next two tests from passing + // tracking issue: https://github.com/grafana/grafana/issues/114509 + test.skip('can view repeated panel inside snapshot', async ({ dashboardPage, selectors, page }) => { + await importTestDashboard( + page, + selectors, + 'Custom grid repeats - view repeated panel inside snapshot', + JSON.stringify(testV2DashWithRowRepeats) + ); + + await dashboardPage + .getByGrafanaSelector(selectors.components.Panels.Panel.title(getTitleInRepeatRow(1, 1))) + .hover(); + await page.keyboard.press('p+s'); + + // click "Publish snapshot" + await dashboardPage + .getByGrafanaSelector(selectors.pages.ShareDashboardDrawer.ShareSnapshot.publishSnapshot) + .click(); + + // click "Copy link" button in the snapshot drawer + await dashboardPage + .getByGrafanaSelector(selectors.pages.ShareDashboardDrawer.ShareSnapshot.copyUrlButton) + .click(); + + await goToPanelSnapshot(page); + + await expect( + dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title(getTitleInRepeatRow(1, 1))) + ).toBeVisible(); + + await expect( + dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title(getTitleInRepeatRow(2, 2))) + ).not.toBeVisible(); + }); + test.skip('can view single panel in a repeated row inside snapshot', async ({ dashboardPage, selectors, page }) => { + await importTestDashboard( + page, + selectors, + 'Custom grid repeats - view single panel inside snapshot', + JSON.stringify(testV2DashWithRowRepeats) + ); + + await dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('single panel row 1')).hover(); + // open panel snapshot + await page.keyboard.press('p+s'); + + // click "Publish snapshot" + await dashboardPage + .getByGrafanaSelector(selectors.pages.ShareDashboardDrawer.ShareSnapshot.publishSnapshot) + .click(); + + // click "Copy link" button + await dashboardPage + .getByGrafanaSelector(selectors.pages.ShareDashboardDrawer.ShareSnapshot.copyUrlButton) + .click(); + + await goToPanelSnapshot(page); + + await expect( + dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('single panel row 1')) + ).toBeVisible(); + await expect( + dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title(getTitleInRepeatRow(1, 1))) + ).toBeHidden(); + }); } ); diff --git a/e2e-playwright/dashboard-new-layouts/utils.ts b/e2e-playwright/dashboard-new-layouts/utils.ts index 6bc6f033c6e..70fd2255c36 100644 --- a/e2e-playwright/dashboard-new-layouts/utils.ts +++ b/e2e-playwright/dashboard-new-layouts/utils.ts @@ -79,6 +79,20 @@ export const flows = { await variableLabelInput.blur(); } }, + async addNewTextBoxVariable(dashboardPage: DashboardPage, variable: Variable) { + await flows.newEditPaneVariableClick(dashboardPage, selectors); + await flows.newEditPanelCommonVariableInputs(dashboardPage, selectors, variable); + // set the textbox variable value + const type = 'variable-type Value'; + const fieldLabel = dashboardPage.getByGrafanaSelector( + selectors.components.PanelEditor.OptionsPane.fieldLabel(type) + ); + await expect(fieldLabel).toBeVisible(); + const inputField = fieldLabel.locator('input'); + await expect(inputField).toBeVisible(); + await inputField.fill(variable.value); + await inputField.blur(); + }, }; export type Variable = { @@ -89,8 +103,16 @@ export type Variable = { value: string; }; -export async function saveDashboard(dashboardPage: DashboardPage, page: Page, selectors: E2ESelectorGroups) { +export async function saveDashboard( + dashboardPage: DashboardPage, + page: Page, + selectors: E2ESelectorGroups, + title?: string +) { await dashboardPage.getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.saveButton).click(); + if (title) { + await page.getByTestId(selectors.components.Drawer.DashboardSaveDrawer.saveAsTitleInput).fill(title); + } await dashboardPage.getByGrafanaSelector(selectors.components.Drawer.DashboardSaveDrawer.saveButton).click(); await expect(page.getByText('Dashboard saved')).toBeVisible(); } @@ -196,6 +218,15 @@ export async function goToEmbeddedPanel(page: Page) { await page.goto(soloPanelUrl!); } +export async function goToPanelSnapshot(page: Page) { + // extracting snapshot url from clipboard + const snapshotUrl = await page.evaluate(() => navigator.clipboard.readText()); + + expect(snapshotUrl).toBeDefined(); + + await page.goto(snapshotUrl); +} + export async function moveTab( dashboardPage: DashboardPage, page: Page, diff --git a/e2e-playwright/dashboards-suite/dashboard-browse-nested.spec.ts b/e2e-playwright/dashboards-suite/dashboard-browse-nested.spec.ts index 6765d299e53..caa83bfdb90 100644 --- a/e2e-playwright/dashboards-suite/dashboard-browse-nested.spec.ts +++ b/e2e-playwright/dashboards-suite/dashboard-browse-nested.spec.ts @@ -10,7 +10,7 @@ const NUM_NESTED_DASHBOARDS = 60; test.use({ featureToggles: { kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); diff --git a/e2e-playwright/dashboards-suite/dashboard-browse.spec.ts b/e2e-playwright/dashboards-suite/dashboard-browse.spec.ts index 8ae318bcefa..6949eca4555 100644 --- a/e2e-playwright/dashboards-suite/dashboard-browse.spec.ts +++ b/e2e-playwright/dashboards-suite/dashboard-browse.spec.ts @@ -5,7 +5,7 @@ import testDashboard from '../dashboards/TestDashboard.json'; test.use({ featureToggles: { kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); diff --git a/e2e-playwright/dashboards-suite/dashboard-export-image.spec.ts b/e2e-playwright/dashboards-suite/dashboard-export-image.spec.ts index a97a04a14b8..e15991514a2 100644 --- a/e2e-playwright/dashboards-suite/dashboard-export-image.spec.ts +++ b/e2e-playwright/dashboards-suite/dashboard-export-image.spec.ts @@ -7,7 +7,7 @@ test.use({ scenes: true, sharingDashboardImage: true, // Enable the export image feature kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); diff --git a/e2e-playwright/dashboards-suite/dashboard-export-json.spec.ts b/e2e-playwright/dashboards-suite/dashboard-export-json.spec.ts index 428193ab5fa..26a8fb61dc8 100644 --- a/e2e-playwright/dashboards-suite/dashboard-export-json.spec.ts +++ b/e2e-playwright/dashboards-suite/dashboard-export-json.spec.ts @@ -3,7 +3,7 @@ import { test, expect } from '@grafana/plugin-e2e'; test.use({ featureToggles: { kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); diff --git a/e2e-playwright/dashboards-suite/dashboard-keybindings.spec.ts b/e2e-playwright/dashboards-suite/dashboard-keybindings.spec.ts index b0ecf44f9f1..dd83b3a0cfd 100644 --- a/e2e-playwright/dashboards-suite/dashboard-keybindings.spec.ts +++ b/e2e-playwright/dashboards-suite/dashboard-keybindings.spec.ts @@ -3,7 +3,7 @@ import { test, expect } from '@grafana/plugin-e2e'; test.use({ featureToggles: { kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); @@ -58,6 +58,8 @@ test.describe( await expect(dashboardPage.getByGrafanaSelector(selectors.components.PanelInspector.Json.content)).toBeVisible(); + // Press Escape to close tooltip on the close button + await page.keyboard.press('Escape'); // Press Escape to close inspector await page.keyboard.press('Escape'); diff --git a/e2e-playwright/dashboards-suite/dashboard-links-without-slug.spec.ts b/e2e-playwright/dashboards-suite/dashboard-links-without-slug.spec.ts index 0a982e148b5..ca05fd24160 100644 --- a/e2e-playwright/dashboards-suite/dashboard-links-without-slug.spec.ts +++ b/e2e-playwright/dashboards-suite/dashboard-links-without-slug.spec.ts @@ -5,7 +5,7 @@ import testDashboard from '../dashboards/DataLinkWithoutSlugTest.json'; test.use({ featureToggles: { kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); diff --git a/e2e-playwright/dashboards-suite/dashboard-live-streaming.spec.ts b/e2e-playwright/dashboards-suite/dashboard-live-streaming.spec.ts index 20f455ea3a8..b7e18e56b45 100644 --- a/e2e-playwright/dashboards-suite/dashboard-live-streaming.spec.ts +++ b/e2e-playwright/dashboards-suite/dashboard-live-streaming.spec.ts @@ -5,7 +5,7 @@ import testDashboard from '../dashboards/DashboardLiveTest.json'; test.use({ featureToggles: { kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); diff --git a/e2e-playwright/dashboards-suite/dashboard-public-create.spec.ts b/e2e-playwright/dashboards-suite/dashboard-public-create.spec.ts index fd5dc979d81..9653218f5ff 100644 --- a/e2e-playwright/dashboards-suite/dashboard-public-create.spec.ts +++ b/e2e-playwright/dashboards-suite/dashboard-public-create.spec.ts @@ -3,7 +3,7 @@ import { test, expect } from '@grafana/plugin-e2e'; test.use({ featureToggles: { kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', dashboardScene: false, // this test is for the old sharing modal only used when scenes is turned off }, }); diff --git a/e2e-playwright/dashboards-suite/dashboard-public-templating.spec.ts b/e2e-playwright/dashboards-suite/dashboard-public-templating.spec.ts index c59e323076d..9f15a740fcf 100644 --- a/e2e-playwright/dashboards-suite/dashboard-public-templating.spec.ts +++ b/e2e-playwright/dashboards-suite/dashboard-public-templating.spec.ts @@ -3,7 +3,7 @@ import { test, expect } from '@grafana/plugin-e2e'; test.use({ featureToggles: { kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', dashboardScene: false, // this test is for the old sharing modal only used when scenes is turned off }, }); diff --git a/e2e-playwright/dashboards-suite/dashboard-share-externally-create.spec.ts b/e2e-playwright/dashboards-suite/dashboard-share-externally-create.spec.ts index 3398e9aaa35..3827872c199 100644 --- a/e2e-playwright/dashboards-suite/dashboard-share-externally-create.spec.ts +++ b/e2e-playwright/dashboards-suite/dashboard-share-externally-create.spec.ts @@ -4,7 +4,7 @@ test.use({ featureToggles: { scenes: true, kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); diff --git a/e2e-playwright/dashboards-suite/dashboard-share-internally.spec.ts b/e2e-playwright/dashboards-suite/dashboard-share-internally.spec.ts index 26f8b85d13e..6ff1825f9cd 100644 --- a/e2e-playwright/dashboards-suite/dashboard-share-internally.spec.ts +++ b/e2e-playwright/dashboards-suite/dashboard-share-internally.spec.ts @@ -4,7 +4,7 @@ test.use({ featureToggles: { scenes: true, kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); diff --git a/e2e-playwright/dashboards-suite/dashboard-share-snapshot-create.spec.ts b/e2e-playwright/dashboards-suite/dashboard-share-snapshot-create.spec.ts index 1a7e03d6243..b5c77458121 100644 --- a/e2e-playwright/dashboards-suite/dashboard-share-snapshot-create.spec.ts +++ b/e2e-playwright/dashboards-suite/dashboard-share-snapshot-create.spec.ts @@ -6,7 +6,7 @@ test.use({ featureToggles: { scenes: true, kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); diff --git a/e2e-playwright/dashboards-suite/dashboard-templating.spec.ts b/e2e-playwright/dashboards-suite/dashboard-templating.spec.ts index 78c35dc5de7..0a4eb5d3a9a 100644 --- a/e2e-playwright/dashboards-suite/dashboard-templating.spec.ts +++ b/e2e-playwright/dashboards-suite/dashboard-templating.spec.ts @@ -6,7 +6,7 @@ test.use({ timezoneId: 'Pacific/Easter', featureToggles: { kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); diff --git a/e2e-playwright/dashboards-suite/dashboard-time-zone.spec.ts b/e2e-playwright/dashboards-suite/dashboard-time-zone.spec.ts index 937224290b0..ee3de574512 100644 --- a/e2e-playwright/dashboards-suite/dashboard-time-zone.spec.ts +++ b/e2e-playwright/dashboards-suite/dashboard-time-zone.spec.ts @@ -8,7 +8,7 @@ const TIMEZONE_DASHBOARD_UID = 'd41dbaa2-a39e-4536-ab2b-caca52f1a9c8'; test.use({ featureToggles: { kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); diff --git a/e2e-playwright/dashboards-suite/dashboard-timepicker.spec.ts b/e2e-playwright/dashboards-suite/dashboard-timepicker.spec.ts index 4ffd65b83a3..ae2f08b230f 100644 --- a/e2e-playwright/dashboards-suite/dashboard-timepicker.spec.ts +++ b/e2e-playwright/dashboards-suite/dashboard-timepicker.spec.ts @@ -17,7 +17,7 @@ test.use({ }, featureToggles: { kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); diff --git a/e2e-playwright/dashboards-suite/embedded-dashboard.spec.ts b/e2e-playwright/dashboards-suite/embedded-dashboard.spec.ts index f457eddf19e..aad8ed3367a 100644 --- a/e2e-playwright/dashboards-suite/embedded-dashboard.spec.ts +++ b/e2e-playwright/dashboards-suite/embedded-dashboard.spec.ts @@ -3,7 +3,7 @@ import { test, expect } from '@grafana/plugin-e2e'; test.use({ featureToggles: { kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); diff --git a/e2e-playwright/dashboards-suite/general-dashboards.spec.ts b/e2e-playwright/dashboards-suite/general-dashboards.spec.ts index 99f84cb6d9f..d3ba9d9046e 100644 --- a/e2e-playwright/dashboards-suite/general-dashboards.spec.ts +++ b/e2e-playwright/dashboards-suite/general-dashboards.spec.ts @@ -5,7 +5,7 @@ const PAGE_UNDER_TEST = 'edediimbjhdz4b/a-tall-dashboard'; test.use({ featureToggles: { kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); diff --git a/e2e-playwright/dashboards-suite/import-dashboard.spec.ts b/e2e-playwright/dashboards-suite/import-dashboard.spec.ts index 5fdca6954aa..f489f576887 100644 --- a/e2e-playwright/dashboards-suite/import-dashboard.spec.ts +++ b/e2e-playwright/dashboards-suite/import-dashboard.spec.ts @@ -5,7 +5,7 @@ import testDashboard from '../dashboards/TestDashboard.json'; test.use({ featureToggles: { kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); diff --git a/e2e-playwright/dashboards-suite/load-options-from-url.spec.ts b/e2e-playwright/dashboards-suite/load-options-from-url.spec.ts index ca06e31528a..08847be8d8e 100644 --- a/e2e-playwright/dashboards-suite/load-options-from-url.spec.ts +++ b/e2e-playwright/dashboards-suite/load-options-from-url.spec.ts @@ -5,7 +5,7 @@ const PAGE_UNDER_TEST = '-Y-tnEDWk/templating-nested-template-variables'; test.use({ featureToggles: { kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); diff --git a/e2e-playwright/dashboards-suite/new-constant-variable.spec.ts b/e2e-playwright/dashboards-suite/new-constant-variable.spec.ts index fa0b5fc1bfd..0abd9d248f1 100644 --- a/e2e-playwright/dashboards-suite/new-constant-variable.spec.ts +++ b/e2e-playwright/dashboards-suite/new-constant-variable.spec.ts @@ -6,7 +6,7 @@ const DASHBOARD_NAME = 'Test variable output'; test.use({ featureToggles: { kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); diff --git a/e2e-playwright/dashboards-suite/new-custom-variable.spec.ts b/e2e-playwright/dashboards-suite/new-custom-variable.spec.ts index c14a952e1d9..79e545c9a41 100644 --- a/e2e-playwright/dashboards-suite/new-custom-variable.spec.ts +++ b/e2e-playwright/dashboards-suite/new-custom-variable.spec.ts @@ -53,7 +53,7 @@ async function assertPreviewValues( test.use({ featureToggles: { kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); diff --git a/e2e-playwright/dashboards-suite/new-datasource-variable.spec.ts b/e2e-playwright/dashboards-suite/new-datasource-variable.spec.ts index cc19e67cda4..03859ccc5ea 100644 --- a/e2e-playwright/dashboards-suite/new-datasource-variable.spec.ts +++ b/e2e-playwright/dashboards-suite/new-datasource-variable.spec.ts @@ -6,7 +6,7 @@ const DASHBOARD_NAME = 'Test variable output'; test.use({ featureToggles: { kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); diff --git a/e2e-playwright/dashboards-suite/new-interval-variable.spec.ts b/e2e-playwright/dashboards-suite/new-interval-variable.spec.ts index d76b5291c42..9c5cc8cc60f 100644 --- a/e2e-playwright/dashboards-suite/new-interval-variable.spec.ts +++ b/e2e-playwright/dashboards-suite/new-interval-variable.spec.ts @@ -19,7 +19,7 @@ async function assertPreviewValues( test.use({ featureToggles: { kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); diff --git a/e2e-playwright/dashboards-suite/new-query-variable.spec.ts b/e2e-playwright/dashboards-suite/new-query-variable.spec.ts index 852261dbaf5..96375f3fb97 100644 --- a/e2e-playwright/dashboards-suite/new-query-variable.spec.ts +++ b/e2e-playwright/dashboards-suite/new-query-variable.spec.ts @@ -6,7 +6,7 @@ const DASHBOARD_NAME = 'Templating - Nested Template Variables'; test.use({ featureToggles: { kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); diff --git a/e2e-playwright/dashboards-suite/new-text-box-variable.spec.ts b/e2e-playwright/dashboards-suite/new-text-box-variable.spec.ts index c669dc563c4..ba3b9466e7d 100644 --- a/e2e-playwright/dashboards-suite/new-text-box-variable.spec.ts +++ b/e2e-playwright/dashboards-suite/new-text-box-variable.spec.ts @@ -6,7 +6,7 @@ const DASHBOARD_NAME = 'Test variable output'; test.use({ featureToggles: { kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); diff --git a/e2e-playwright/dashboards-suite/repeating-a-panel-horizontally.spec.ts b/e2e-playwright/dashboards-suite/repeating-a-panel-horizontally.spec.ts index a55f14b8643..413466972e1 100644 --- a/e2e-playwright/dashboards-suite/repeating-a-panel-horizontally.spec.ts +++ b/e2e-playwright/dashboards-suite/repeating-a-panel-horizontally.spec.ts @@ -5,7 +5,7 @@ const PAGE_UNDER_TEST = 'WVpf2jp7z/repeating-a-panel-horizontally'; test.use({ featureToggles: { kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); diff --git a/e2e-playwright/dashboards-suite/repeating-a-panel-vertically.spec.ts b/e2e-playwright/dashboards-suite/repeating-a-panel-vertically.spec.ts index bb188c87e8d..53966eadf05 100644 --- a/e2e-playwright/dashboards-suite/repeating-a-panel-vertically.spec.ts +++ b/e2e-playwright/dashboards-suite/repeating-a-panel-vertically.spec.ts @@ -5,7 +5,7 @@ const PAGE_UNDER_TEST = 'OY8Ghjt7k/repeating-a-panel-vertically'; test.use({ featureToggles: { kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); diff --git a/e2e-playwright/dashboards-suite/repeating-an-empty-row.spec.ts b/e2e-playwright/dashboards-suite/repeating-an-empty-row.spec.ts index e31c5792062..06c0e77989b 100644 --- a/e2e-playwright/dashboards-suite/repeating-an-empty-row.spec.ts +++ b/e2e-playwright/dashboards-suite/repeating-an-empty-row.spec.ts @@ -5,7 +5,7 @@ const PAGE_UNDER_TEST = 'dtpl2Ctnk/repeating-an-empty-row'; test.use({ featureToggles: { kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); diff --git a/e2e-playwright/dashboards-suite/set-options-from-ui.spec.ts b/e2e-playwright/dashboards-suite/set-options-from-ui.spec.ts index 53290345e73..629abda2ce3 100644 --- a/e2e-playwright/dashboards-suite/set-options-from-ui.spec.ts +++ b/e2e-playwright/dashboards-suite/set-options-from-ui.spec.ts @@ -5,7 +5,7 @@ const PAGE_UNDER_TEST = '-Y-tnEDWk/templating-nested-template-variables'; test.use({ featureToggles: { kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); diff --git a/e2e-playwright/dashboards-suite/snapshot-create.spec.ts b/e2e-playwright/dashboards-suite/snapshot-create.spec.ts index 123aa7f3279..50febc211b8 100644 --- a/e2e-playwright/dashboards-suite/snapshot-create.spec.ts +++ b/e2e-playwright/dashboards-suite/snapshot-create.spec.ts @@ -5,7 +5,7 @@ const DASHBOARD_UID = 'ZqZnVvFZz'; test.use({ featureToggles: { kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', dashboardScene: false, // this test is for the old sharing modal only used when scenes is turned off }, }); diff --git a/e2e-playwright/dashboards-suite/templating-dashboard-links-and-variables.spec.ts b/e2e-playwright/dashboards-suite/templating-dashboard-links-and-variables.spec.ts index 1d8fd32ff06..1806aca24bf 100644 --- a/e2e-playwright/dashboards-suite/templating-dashboard-links-and-variables.spec.ts +++ b/e2e-playwright/dashboards-suite/templating-dashboard-links-and-variables.spec.ts @@ -5,7 +5,7 @@ const DASHBOARD_UID = 'yBCC3aKGk'; test.use({ featureToggles: { kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); diff --git a/e2e-playwright/dashboards-suite/textbox-variables.spec.ts b/e2e-playwright/dashboards-suite/textbox-variables.spec.ts index 4fb56ef8b8e..b78e781dad1 100644 --- a/e2e-playwright/dashboards-suite/textbox-variables.spec.ts +++ b/e2e-playwright/dashboards-suite/textbox-variables.spec.ts @@ -7,7 +7,7 @@ const PAGE_UNDER_TEST = 'AejrN1AMz'; test.use({ featureToggles: { kubernetesDashboards: process.env.FORCE_V2_DASHBOARDS_API === 'true', - kubernetesDashboardsV2: process.env.FORCE_V2_DASHBOARDS_API === 'true', + dashboardNewLayouts: process.env.FORCE_V2_DASHBOARDS_API === 'true', }, }); diff --git a/e2e-playwright/panels-suite/canvas-icon-mappings.spec.ts b/e2e-playwright/panels-suite/canvas-icon-mappings.spec.ts new file mode 100644 index 00000000000..72de7a6c62c --- /dev/null +++ b/e2e-playwright/panels-suite/canvas-icon-mappings.spec.ts @@ -0,0 +1,99 @@ +import { test, expect } from '@grafana/plugin-e2e'; + +const DASHBOARD_UID = 'canvas-icon-fix-test-v2'; +const PANEL_TITLE = 'Various SVG icons'; + +test.describe('Canvas Panel - Icon Mappings', () => { + test('should render field-based icons from value mappings correctly', async ({ gotoDashboardPage, page }) => { + await test.step('Navigate to dashboard and wait for panel to load', async () => { + await gotoDashboardPage({ uid: DASHBOARD_UID }); + await page.waitForSelector('svg', { timeout: 10000 }); + }); + + await test.step('Verify value mapping text values are displayed', async () => { + await expect(page.getByText('Success')).toBeVisible(); + await expect(page.getByText('Warning')).toBeVisible(); + await expect(page.getByText('Error')).toBeVisible(); + }); + + await test.step('Verify SVG icons rendered for mapped values', async () => { + const svgCount = await page.locator('svg').count(); + expect(svgCount).toBeGreaterThanOrEqual(3); + }); + }); + + test('should render fixed path icons correctly', async ({ gotoDashboardPage, page }) => { + await test.step('Set up network interception for absolute URL icon', async () => { + await page.route('https://grafana.com/static/assets/img/grafana_icon.svg', async (route) => { + const dummySvg = ` + + TEST + `; + await route.fulfill({ + status: 200, + contentType: 'image/svg+xml', + body: dummySvg, + }); + }); + }); + + await test.step('Navigate to dashboard and wait for SVGs to load', async () => { + await gotoDashboardPage({ uid: DASHBOARD_UID }); + await page.waitForSelector('svg:not([aria-hidden="true"])', { timeout: 10000 }); + await page.waitForLoadState('networkidle', { timeout: 10000 }); + }); + + await test.step('Verify at least 5 visible SVG icons are rendered (3 mapped + 2 fixed)', async () => { + const visibleSvgs = page.locator('svg:not([aria-hidden="true"])'); + const svgCount = await visibleSvgs.count(); + expect(svgCount).toBeGreaterThanOrEqual(5); + }); + + await test.step('Verify visible SVG icons have content', async () => { + const visibleSvgs = page.locator('svg:not([aria-hidden="true"])'); + const count = await visibleSvgs.count(); + + for (let i = 0; i < Math.min(count, 5); i++) { + const svg = visibleSvgs.nth(i); + await expect(svg).toBeAttached(); + const svgContent = await svg.innerHTML(); + expect(svgContent.length).toBeGreaterThan(0); + } + }); + }); + + test('should not make invalid requests for unmapped numeric values', async ({ gotoDashboardPage, page }) => { + const failedRequests: string[] = []; + + await test.step('Set up network request monitoring', async () => { + page.on('requestfailed', (request) => { + const url = request.url(); + if (url.match(/\/build\/\d+$/)) { + failedRequests.push(url); + } + }); + }); + + await test.step('Navigate to dashboard and wait for loading', async () => { + await gotoDashboardPage({ uid: DASHBOARD_UID }); + await page.waitForTimeout(2000); + }); + + await test.step('Verify no invalid numeric path requests were made', async () => { + expect(failedRequests).toHaveLength(0); + }); + }); + + test('should display text values from value mappings correctly', async ({ gotoDashboardPage, page }) => { + await test.step('Navigate to dashboard', async () => { + await gotoDashboardPage({ uid: DASHBOARD_UID }); + }); + + await test.step('Verify mapped text values are displayed', async () => { + await expect(page.getByText('Success')).toBeVisible(); + await expect(page.getByText('Warning')).toBeVisible(); + await expect(page.getByText('Error')).toBeVisible(); + await expect(page.getByText('No mapping (14)')).toBeVisible(); + }); + }); +}); diff --git a/e2e-playwright/panels-suite/canvas-scene.spec.ts b/e2e-playwright/panels-suite/canvas-scene.spec.ts index b1fc028f3ae..c0b392d544b 100644 --- a/e2e-playwright/panels-suite/canvas-scene.spec.ts +++ b/e2e-playwright/panels-suite/canvas-scene.spec.ts @@ -2,18 +2,16 @@ import { Locator } from '@playwright/test'; import { test, expect } from '@grafana/plugin-e2e'; -import { setVisualization } from './vizpicker-utils'; - test.use({ featureToggles: { canvasPanelPanZoom: true, }, }); test.describe('Canvas Panel - Scene Tests', () => { - test.beforeEach(async ({ page, gotoDashboardPage, selectors }) => { + test.beforeEach(async ({ page, gotoDashboardPage }) => { const dashboardPage = await gotoDashboardPage({}); const panelEditPage = await dashboardPage.addPanel(); - await setVisualization(panelEditPage, 'Canvas', selectors); + await panelEditPage.setVisualization('Canvas'); // Wait for canvas panel to load await page.waitForSelector('[data-testid="canvas-scene-pan-zoom"]', { timeout: 10000 }); diff --git a/e2e-playwright/panels-suite/gauge.spec.ts b/e2e-playwright/panels-suite/gauge.spec.ts new file mode 100644 index 00000000000..cb4b26e9850 --- /dev/null +++ b/e2e-playwright/panels-suite/gauge.spec.ts @@ -0,0 +1,101 @@ +import { test, expect } from '@grafana/plugin-e2e'; + +// this test requires a larger viewport so all gauge panels load properly +test.use({ + featureToggles: { newGauge: true }, + viewport: { width: 1280, height: 3000 }, +}); + +const OLD_GAUGES_DASHBOARD_UID = '_5rDmaQiz'; +const NEW_GAUGES_DASHBOARD_UID = 'panel-tests-gauge-new'; + +test.describe( + 'Gauge Panel', + { + tag: ['@panels', '@gauge'], + }, + () => { + test('successfully migrates all gauge panels', async ({ gotoDashboardPage, selectors }) => { + const dashboardPage = await gotoDashboardPage({ uid: OLD_GAUGES_DASHBOARD_UID }); + + // check that gauges are rendered + const gaugeElements = dashboardPage.getByGrafanaSelector( + selectors.components.Panels.Visualization.Gauge.Container + ); + await expect(gaugeElements).toHaveCount(16); + + // check that no panel errors exist + const errorInfo = dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.headerCornerInfo('error')); + await expect(errorInfo).toBeHidden(); + }); + + test('renders new gauge panels', async ({ gotoDashboardPage, selectors }) => { + // open Panel Tests - Gauge + const dashboardPage = await gotoDashboardPage({ uid: NEW_GAUGES_DASHBOARD_UID }); + + // check that gauges are rendered + const gaugeElements = dashboardPage.getByGrafanaSelector( + selectors.components.Panels.Visualization.Gauge.Container + ); + await expect(gaugeElements).toHaveCount(32); + + // check that no panel errors exist + const errorInfo = dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.headerCornerInfo('error')); + await expect(errorInfo).toBeHidden(); + }); + + test('renders sparklines in gauge panels', async ({ gotoDashboardPage, page }) => { + await gotoDashboardPage({ + uid: NEW_GAUGES_DASHBOARD_UID, + queryParams: new URLSearchParams({ editPanel: '11' }), + }); + + await expect(page.locator('.uplot')).toHaveCount(5); + }); + + test('"no data"', async ({ gotoDashboardPage, selectors }) => { + const dashboardPage = await gotoDashboardPage({ + uid: NEW_GAUGES_DASHBOARD_UID, + queryParams: new URLSearchParams({ editPanel: '36' }), + }); + + await expect( + dashboardPage.getByGrafanaSelector(selectors.components.Panels.Visualization.Gauge.Container), + 'that the gauge does not appear' + ).toBeHidden(); + + await expect( + dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.PanelDataErrorMessage), + 'that the empty text appears' + ).toHaveText('No data'); + + // update the "No value" option and see if the panel updates + const noValueOption = dashboardPage + .getByGrafanaSelector(selectors.components.PanelEditor.OptionsPane.fieldLabel('Standard options No value')) + .locator('input'); + + await noValueOption.fill('My empty value'); + await noValueOption.blur(); + await expect( + dashboardPage.getByGrafanaSelector(selectors.components.Panels.Visualization.Gauge.Container), + 'that the empty text shows up in an empty gauge' + ).toHaveText('My empty value'); + + // test the "no numeric fields" message on the next panel + const dashboardPage2 = await gotoDashboardPage({ + uid: NEW_GAUGES_DASHBOARD_UID, + queryParams: new URLSearchParams({ editPanel: '37' }), + }); + + await expect( + dashboardPage2.getByGrafanaSelector(selectors.components.Panels.Visualization.Gauge.Container), + 'that the gauge does not appear' + ).toBeHidden(); + + await expect( + dashboardPage2.getByGrafanaSelector(selectors.components.Panels.Panel.PanelDataErrorMessage), + 'that the empty text appears' + ).toHaveText('Data is missing a number field'); + }); + } +); diff --git a/e2e-playwright/panels-suite/state-timeline.spec.ts b/e2e-playwright/panels-suite/state-timeline.spec.ts index ebdeb8d5398..d851a25f8af 100644 --- a/e2e-playwright/panels-suite/state-timeline.spec.ts +++ b/e2e-playwright/panels-suite/state-timeline.spec.ts @@ -78,6 +78,16 @@ test.describe('Panels test: StateTimeine', { tag: ['@panels', '@state-timeline'] await dashboardPage.getByGrafanaSelector(selectors.components.Portal.container).getByLabel('Close').click(); await expect(tooltip, 'tooltip closed on "x" click').toBeHidden(); + // test that CMD/CTRL+C doesn't dismiss the tooltip + await stateTimelineUplot.click({ position: { x: 100, y: 50 } }); + await expect(tooltip, 'tooltip appears on click').toBeVisible(); + await page.keyboard.press('Meta+C'); + await expect(tooltip, 'tooltip persists after CMD/CTRL+C').toBeVisible(); + + // test that Escape key dismisses the tooltip + await page.keyboard.press('Escape'); + await expect(tooltip, 'tooltip closed on Escape key').toBeHidden(); + // disable tooltips await dashboardPage .getByGrafanaSelector(selectors.components.PanelEditor.OptionsPane.fieldLabel('Tooltip Tooltip mode')) diff --git a/e2e-playwright/panels-suite/status-history.spec.ts b/e2e-playwright/panels-suite/status-history.spec.ts index bece3aa47c7..b2e628c0795 100644 --- a/e2e-playwright/panels-suite/status-history.spec.ts +++ b/e2e-playwright/panels-suite/status-history.spec.ts @@ -76,6 +76,16 @@ test.describe('Panels test: StatusHistory', { tag: ['@panels', '@status-history' await dashboardPage.getByGrafanaSelector(selectors.components.Portal.container).getByLabel('Close').click(); await expect(tooltip, 'tooltip closed on "x" click').toBeHidden(); + // test that CMD/CTRL+C doesn't dismiss the tooltip + await statusHistoryUplot.click({ position: { x: 100, y: 50 } }); + await expect(tooltip, 'tooltip appears on click').toBeVisible(); + await page.keyboard.press('Meta+C'); + await expect(tooltip, 'tooltip persists after CMD/CTRL+C').toBeVisible(); + + // test that Escape key dismisses the tooltip + await page.keyboard.press('Escape'); + await expect(tooltip, 'tooltip closed on Escape key').toBeHidden(); + // disable tooltips await dashboardPage .getByGrafanaSelector(selectors.components.PanelEditor.OptionsPane.fieldLabel('Tooltip Tooltip mode')) diff --git a/e2e-playwright/panels-suite/table-kitchenSink.spec.ts b/e2e-playwright/panels-suite/table-kitchenSink.spec.ts index 6dddba81820..ac10cb2b735 100644 --- a/e2e-playwright/panels-suite/table-kitchenSink.spec.ts +++ b/e2e-playwright/panels-suite/table-kitchenSink.spec.ts @@ -82,9 +82,9 @@ test.describe('Panels test: Table - Kitchen Sink', { tag: ['@panels', '@table'] await expect(getCellHeight(page, 1, longTextColIdx)).resolves.toBeLessThan(100); // click cell inspect, check that cell inspection pops open in the side as we'd expect. - await loremIpsumCell.getByLabel('Inspect value').click(); const loremIpsumText = await loremIpsumCell.textContent(); expect(loremIpsumText).toBeDefined(); + await loremIpsumCell.getByLabel('Inspect value').click(); await expect(page.getByRole('dialog').getByText(loremIpsumText!)).toBeVisible(); }); diff --git a/e2e-playwright/panels-suite/vizpicker-utils.ts b/e2e-playwright/panels-suite/vizpicker-utils.ts deleted file mode 100644 index 1785dd7e04a..00000000000 --- a/e2e-playwright/panels-suite/vizpicker-utils.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { expect, E2ESelectorGroups, PanelEditPage } from '@grafana/plugin-e2e'; - -// this replaces the panelEditPage.setVisualization method used previously in tests, since it -// does not know how to use the updated 12.4 viz picker UI to set the visualization -export const setVisualization = async (panelEditPage: PanelEditPage, vizName: string, selectors: E2ESelectorGroups) => { - const vizPicker = panelEditPage.getByGrafanaSelector(selectors.components.PanelEditor.toggleVizPicker); - await expect(vizPicker, '"Change" button should be visible').toBeVisible(); - await vizPicker.click(); - - const allVizTabBtn = panelEditPage.getByGrafanaSelector(selectors.components.Tab.title('All visualizations')); - await expect(allVizTabBtn, '"All visualiations" button should be visible').toBeVisible(); - await allVizTabBtn.click(); - - const vizItem = panelEditPage.getByGrafanaSelector(selectors.components.PluginVisualization.item(vizName)); - await expect(vizItem, `"${vizName}" item should be visible`).toBeVisible(); - await vizItem.scrollIntoViewIfNeeded(); - await vizItem.click(); - - await expect(vizPicker, '"Change" button should be visible again').toBeVisible(); - await expect( - panelEditPage.getByGrafanaSelector(selectors.components.PanelEditor.OptionsPane.header), - 'Panel header should have the new viz type name' - ).toHaveText(vizName); -}; diff --git a/e2e-playwright/plugin-e2e/plugin-e2e-api-tests/as-admin-user/panelDataAssertion.spec.ts b/e2e-playwright/plugin-e2e/plugin-e2e-api-tests/as-admin-user/panelDataAssertion.spec.ts index 336dbef0a29..0133a3e3712 100644 --- a/e2e-playwright/plugin-e2e/plugin-e2e-api-tests/as-admin-user/panelDataAssertion.spec.ts +++ b/e2e-playwright/plugin-e2e/plugin-e2e-api-tests/as-admin-user/panelDataAssertion.spec.ts @@ -1,6 +1,5 @@ import { expect, test } from '@grafana/plugin-e2e'; -import { setVisualization } from '../../../panels-suite/vizpicker-utils'; import { formatExpectError } from '../errors'; import { successfulDataQuery } from '../mocks/queries'; @@ -25,10 +24,10 @@ test.describe( ).toContainText(['Field', 'Max', 'Mean', 'Last']); }); - test('table panel data assertions', async ({ panelEditPage, selectors }) => { + test('table panel data assertions', async ({ panelEditPage }) => { await panelEditPage.mockQueryDataResponse(successfulDataQuery, 200); await panelEditPage.datasource.set('gdev-testdata'); - await setVisualization(panelEditPage, 'Table', selectors); + await panelEditPage.setVisualization('Table'); await panelEditPage.refreshPanel(); await expect( panelEditPage.panel.locator, @@ -44,10 +43,10 @@ test.describe( ).toContainText(['val1', 'val2', 'val3', 'val4']); }); - test('timeseries panel - table view assertions', async ({ panelEditPage, selectors }) => { + test('timeseries panel - table view assertions', async ({ panelEditPage }) => { await panelEditPage.mockQueryDataResponse(successfulDataQuery, 200); await panelEditPage.datasource.set('gdev-testdata'); - await setVisualization(panelEditPage, 'Time series', selectors); + await panelEditPage.setVisualization('Time series'); await panelEditPage.refreshPanel(); await panelEditPage.toggleTableView(); await expect( diff --git a/e2e-playwright/plugin-e2e/plugin-e2e-api-tests/as-admin-user/panelEditPage.spec.ts b/e2e-playwright/plugin-e2e/plugin-e2e-api-tests/as-admin-user/panelEditPage.spec.ts index 93e0525ab0e..46c36277848 100644 --- a/e2e-playwright/plugin-e2e/plugin-e2e-api-tests/as-admin-user/panelEditPage.spec.ts +++ b/e2e-playwright/plugin-e2e/plugin-e2e-api-tests/as-admin-user/panelEditPage.spec.ts @@ -1,6 +1,5 @@ import { expect, test } from '@grafana/plugin-e2e'; -import { setVisualization } from '../../../panels-suite/vizpicker-utils'; import { formatExpectError } from '../errors'; import { successfulDataQuery } from '../mocks/queries'; import { scenarios } from '../mocks/resources'; @@ -54,10 +53,10 @@ test.describe( ).toHaveText(scenarios.map((s) => s.name)); }); - test('mocked query data response', async ({ panelEditPage, page, selectors }) => { + test('mocked query data response', async ({ panelEditPage, page }) => { await panelEditPage.mockQueryDataResponse(successfulDataQuery, 200); await panelEditPage.datasource.set('gdev-testdata'); - await setVisualization(panelEditPage, TABLE_VIZ_NAME, selectors); + await panelEditPage.setVisualization(TABLE_VIZ_NAME); await panelEditPage.refreshPanel(); await expect( panelEditPage.panel.getErrorIcon(), @@ -76,7 +75,7 @@ test.describe( selectors, page, }) => { - await setVisualization(panelEditPage, TABLE_VIZ_NAME, selectors); + await panelEditPage.setVisualization(TABLE_VIZ_NAME); await expect( panelEditPage.getByGrafanaSelector(selectors.components.PanelEditor.OptionsPane.header), formatExpectError('Expected panel visualization to be set to table') @@ -93,8 +92,8 @@ test.describe( ).toBeVisible(); }); - test('Select time zone in timezone picker', async ({ panelEditPage, selectors }) => { - await setVisualization(panelEditPage, TIME_SERIES_VIZ_NAME, selectors); + test('Select time zone in timezone picker', async ({ panelEditPage }) => { + await panelEditPage.setVisualization(TIME_SERIES_VIZ_NAME); const axisOptions = await panelEditPage.getCustomOptions('Axis'); const timeZonePicker = axisOptions.getSelect('Time zone'); @@ -102,8 +101,8 @@ test.describe( await expect(timeZonePicker).toHaveSelected('Europe/Stockholm'); }); - test('select unit in unit picker', async ({ panelEditPage, selectors }) => { - await setVisualization(panelEditPage, TIME_SERIES_VIZ_NAME, selectors); + test('select unit in unit picker', async ({ panelEditPage }) => { + await panelEditPage.setVisualization(TIME_SERIES_VIZ_NAME); const standardOptions = panelEditPage.getStandardOptions(); const unitPicker = standardOptions.getUnitPicker('Unit'); @@ -112,8 +111,8 @@ test.describe( await expect(unitPicker).toHaveSelected('Pixels'); }); - test('enter value in number input', async ({ panelEditPage, selectors }) => { - await setVisualization(panelEditPage, TIME_SERIES_VIZ_NAME, selectors); + test('enter value in number input', async ({ panelEditPage }) => { + await panelEditPage.setVisualization(TIME_SERIES_VIZ_NAME); const axisOptions = panelEditPage.getCustomOptions('Axis'); const lineWith = axisOptions.getNumberInput('Soft min'); @@ -122,8 +121,8 @@ test.describe( await expect(lineWith).toHaveValue('10'); }); - test('enter value in slider', async ({ panelEditPage, selectors }) => { - await setVisualization(panelEditPage, TIME_SERIES_VIZ_NAME, selectors); + test('enter value in slider', async ({ panelEditPage }) => { + await panelEditPage.setVisualization(TIME_SERIES_VIZ_NAME); const graphOptions = panelEditPage.getCustomOptions('Graph styles'); const lineWidth = graphOptions.getSliderInput('Line width'); @@ -132,8 +131,8 @@ test.describe( await expect(lineWidth).toHaveValue('10'); }); - test('select value in single value select', async ({ panelEditPage, selectors }) => { - await setVisualization(panelEditPage, TIME_SERIES_VIZ_NAME, selectors); + test('select value in single value select', async ({ panelEditPage }) => { + await panelEditPage.setVisualization(TIME_SERIES_VIZ_NAME); const standardOptions = panelEditPage.getStandardOptions(); const colorSchemeSelect = standardOptions.getSelect('Color scheme'); @@ -141,8 +140,8 @@ test.describe( await expect(colorSchemeSelect).toHaveSelected('Classic palette'); }); - test('clear input', async ({ panelEditPage, selectors }) => { - await setVisualization(panelEditPage, TIME_SERIES_VIZ_NAME, selectors); + test('clear input', async ({ panelEditPage }) => { + await panelEditPage.setVisualization(TIME_SERIES_VIZ_NAME); const panelOptions = panelEditPage.getPanelOptions(); const title = panelOptions.getTextInput('Title'); @@ -151,8 +150,8 @@ test.describe( await expect(title).toHaveValue(''); }); - test('enter value in input', async ({ panelEditPage, selectors }) => { - await setVisualization(panelEditPage, TIME_SERIES_VIZ_NAME, selectors); + test('enter value in input', async ({ panelEditPage }) => { + await panelEditPage.setVisualization(TIME_SERIES_VIZ_NAME); const panelOptions = panelEditPage.getPanelOptions(); const description = panelOptions.getTextInput('Description'); @@ -161,8 +160,8 @@ test.describe( await expect(description).toHaveValue('This is a panel'); }); - test('unchecking switch', async ({ panelEditPage, selectors }) => { - await setVisualization(panelEditPage, TIME_SERIES_VIZ_NAME, selectors); + test('unchecking switch', async ({ panelEditPage }) => { + await panelEditPage.setVisualization(TIME_SERIES_VIZ_NAME); const axisOptions = panelEditPage.getCustomOptions('Axis'); const showBorder = axisOptions.getSwitch('Show border'); @@ -174,8 +173,8 @@ test.describe( await expect(showBorder).toBeChecked({ checked: false }); }); - test('checking switch', async ({ panelEditPage, selectors }) => { - await setVisualization(panelEditPage, TIME_SERIES_VIZ_NAME, selectors); + test('checking switch', async ({ panelEditPage }) => { + await panelEditPage.setVisualization(TIME_SERIES_VIZ_NAME); const axisOptions = panelEditPage.getCustomOptions('Axis'); const showBorder = axisOptions.getSwitch('Show border'); @@ -184,8 +183,8 @@ test.describe( await expect(showBorder).toBeChecked(); }); - test('re-selecting value in radio button group', async ({ panelEditPage, selectors }) => { - await setVisualization(panelEditPage, TIME_SERIES_VIZ_NAME, selectors); + test('re-selecting value in radio button group', async ({ panelEditPage }) => { + await panelEditPage.setVisualization(TIME_SERIES_VIZ_NAME); const axisOptions = panelEditPage.getCustomOptions('Axis'); const placement = axisOptions.getRadioGroup('Placement'); @@ -196,8 +195,8 @@ test.describe( await expect(placement).toHaveChecked('Auto'); }); - test('selecting value in radio button group', async ({ panelEditPage, selectors }) => { - await setVisualization(panelEditPage, TIME_SERIES_VIZ_NAME, selectors); + test('selecting value in radio button group', async ({ panelEditPage }) => { + await panelEditPage.setVisualization(TIME_SERIES_VIZ_NAME); const axisOptions = panelEditPage.getCustomOptions('Axis'); const placement = axisOptions.getRadioGroup('Placement'); diff --git a/e2e-playwright/smoke-tests-suite/panels.spec.ts b/e2e-playwright/smoke-tests-suite/panels.spec.ts index 22f6088d99d..0ad50a1aed7 100644 --- a/e2e-playwright/smoke-tests-suite/panels.spec.ts +++ b/e2e-playwright/smoke-tests-suite/panels.spec.ts @@ -1,4 +1,4 @@ -import { BootData } from '@grafana/data'; +import { BootData, PanelPluginMeta } from '@grafana/data'; import { test, expect } from '@grafana/plugin-e2e'; test.describe( @@ -22,7 +22,7 @@ test.describe( await dashboardPage.addPanel(); // Get panel types from window object - const panelTypes = await page.evaluate(() => { + const panelTypes: PanelPluginMeta[] = await page.evaluate(() => { // @grafana/plugin-e2e doesn't export the full bootdata config // eslint-disable-next-line @typescript-eslint/consistent-type-assertions const win = window as typeof window & { grafanaBootData: BootData }; diff --git a/e2e-playwright/utils/scope-helpers.ts b/e2e-playwright/utils/scope-helpers.ts index fc88a79d8fa..df11644a396 100644 --- a/e2e-playwright/utils/scope-helpers.ts +++ b/e2e-playwright/utils/scope-helpers.ts @@ -6,7 +6,150 @@ import { Resource } from '../../public/app/features/apiserver/types'; import { testScopes } from './scopes'; -const USE_LIVE_DATA = Boolean(process.env.API_CALLS_CONFIG_PATH); +const USE_LIVE_DATA = Boolean(process.env.API_CONFIG_PATH); + +/** + * Sets up all scope-related API routes before navigation. + * This ensures that ALL scope API requests (including those made during initial page load) + * are intercepted by the mocks, preventing RTK Query from caching real API responses. + * + * Call this BEFORE navigating to a page (e.g., before gotoDashboardPage). + */ +export async function setupScopeRoutes(page: Page, scopes: TestScope[]): Promise { + // Route for scope node children (tree structure) + await page.route(`**/apis/scope.grafana.app/v0alpha1/namespaces/*/find/scope_node_children*`, async (route) => { + const url = new URL(route.request().url()); + const parentParam = url.searchParams.get('parent'); + const queryParam = url.searchParams.get('query'); + + // Find the appropriate scopes based on parent + let scopesToReturn = scopes; + if (parentParam) { + // Find nested scopes based on parent name + const findChildren = (items: TestScope[]): TestScope[] => { + for (const item of items) { + if (item.name === parentParam && item.children) { + return item.children; + } + if (item.children) { + const found = findChildren(item.children); + if (found.length > 0) { + return found; + } + } + } + return []; + }; + scopesToReturn = findChildren(scopes); + if (scopesToReturn.length === 0) { + scopesToReturn = scopes; // Fallback to root scopes + } + } + + // Filter by search query if provided + if (queryParam) { + const query = queryParam.toLowerCase(); + const filterByQuery = (items: TestScope[]): TestScope[] => { + const results: TestScope[] = []; + for (const item of items) { + // Exact match on name or title containing the query + if (item.name.toLowerCase() === query || item.title.toLowerCase() === query) { + results.push(item); + } else if (item.name.toLowerCase().includes(query) || item.title.toLowerCase().includes(query)) { + results.push(item); + } + // Also search in children + if (item.children) { + results.push(...filterByQuery(item.children)); + } + } + return results; + }; + scopesToReturn = filterByQuery(scopesToReturn); + } + + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ + apiVersion: 'scope.grafana.app/v0alpha1', + kind: 'FindScopeNodeChildrenResults', + metadata: {}, + items: scopesToReturn.map((scope) => ({ + kind: 'ScopeNode', + apiVersion: 'scope.grafana.app/v0alpha1', + metadata: { + name: scope.name, + namespace: 'default', + }, + spec: { + title: scope.title, + description: scope.title, + disableMultiSelect: scope.disableMultiSelect ?? false, + nodeType: scope.children ? 'container' : 'leaf', + ...(parentParam && { parentName: parentParam }), + ...((scope.addLinks || scope.children) && { + linkType: 'scope', + linkId: `scope-${scope.name}`, + }), + ...(scope.redirectPath && { redirectPath: scope.redirectPath }), + }, + })), + }), + }); + }); + + // Route for individual scope fetching + await page.route(`**/apis/scope.grafana.app/v0alpha1/namespaces/*/scopes/*`, async (route) => { + const url = route.request().url(); + const scopeName = url.split('/scopes/')[1]?.split('?')[0]; + + // Find the scope in the test data + const findScope = (items: TestScope[]): TestScope | undefined => { + for (const item of items) { + if (`scope-${item.name}` === scopeName) { + return item; + } + if (item.children) { + const found = findScope(item.children); + if (found) { + return found; + } + } + } + return undefined; + }; + + const scope = findScope(scopes); + + if (scope) { + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ + kind: 'Scope', + apiVersion: 'scope.grafana.app/v0alpha1', + metadata: { + name: `scope-${scope.name}`, + namespace: 'default', + }, + spec: { + title: scope.title, + description: '', + filters: scope.filters, + category: scope.category, + type: scope.type, + }, + }), + }); + } else { + await route.fulfill({ status: 404 }); + } + }); + + // Note: Dashboard bindings and navigations routes are set up dynamically in applyScopes() + // with scope-specific URL patterns to avoid cache issues. They are not set up here. +} export type TestScope = { name: string; @@ -24,6 +167,9 @@ export type TestScope = { type ScopeDashboardBinding = Resource; +/** + * Sets up a route for scope node children requests and waits for the response. + */ export async function scopeNodeChildrenRequest( page: Page, scopes: TestScope[], @@ -68,10 +214,13 @@ export async function scopeNodeChildrenRequest( return page.waitForResponse((response) => response.url().includes(`/find/scope_node_children`)); } +/** + * Opens the scopes selector dropdown and waits for the tree to load. + */ export async function openScopesSelector(page: Page, scopes?: TestScope[]) { const click = async () => await page.getByTestId('scopes-selector-input').click(); - if (!scopes) { + if (!scopes || USE_LIVE_DATA) { await click(); return; } @@ -82,10 +231,13 @@ export async function openScopesSelector(page: Page, scopes?: TestScope[]) { await responsePromise; } +/** + * Expands a scope tree node and waits for children to load. + */ export async function expandScopesSelection(page: Page, parentScope: string, scopes?: TestScope[]) { const click = async () => await page.getByTestId(`scopes-tree-${parentScope}-expand`).click(); - if (!scopes) { + if (!scopes || USE_LIVE_DATA) { await click(); return; } @@ -96,6 +248,9 @@ export async function expandScopesSelection(page: Page, parentScope: string, sco await responsePromise; } +/** + * Sets up a route for individual scope requests and waits for the response. + */ export async function scopeSelectRequest(page: Page, selectedScope: TestScope): Promise { await page.route( `**/apis/scope.grafana.app/v0alpha1/namespaces/*/scopes/scope-${selectedScope.name}`, @@ -125,6 +280,9 @@ export async function scopeSelectRequest(page: Page, selectedScope: TestScope): return page.waitForResponse((response) => response.url().includes(`/scopes/scope-${selectedScope.name}`)); } +/** + * Selects a scope in the tree. + */ export async function selectScope(page: Page, scopeName: string, selectedScope?: TestScope) { const click = async () => { const element = page.locator( @@ -134,7 +292,7 @@ export async function selectScope(page: Page, scopeName: string, selectedScope?: await element.click({ force: true }); }; - if (!selectedScope) { + if (!selectedScope || USE_LIVE_DATA) { await click(); return; } @@ -145,14 +303,22 @@ export async function selectScope(page: Page, scopeName: string, selectedScope?: await responsePromise; } +/** + * Applies the selected scopes and waits for the selector to close and page to settle. + * Sets up routes dynamically with scope-specific URL patterns to avoid cache issues. + */ export async function applyScopes(page: Page, scopes?: TestScope[]) { const click = async () => { await page.getByTestId('scopes-selector-apply').scrollIntoViewIfNeeded(); await page.getByTestId('scopes-selector-apply').click({ force: true }); }; - if (!scopes) { + if (!scopes || USE_LIVE_DATA) { await click(); + // Wait for the apply button to disappear (selector closed) + await page.waitForSelector('[data-testid="scopes-selector-apply"]', { state: 'hidden', timeout: 5000 }); + // Wait for any resulting API calls (dashboard bindings, etc.) to complete + await page.waitForLoadState('networkidle'); return; } @@ -166,7 +332,7 @@ export async function applyScopes(page: Page, scopes?: TestScope[]) { const groups: string[] = ['Most relevant', 'Dashboards', 'Something else', '']; - // Mock scope_dashboard_bindings endpoint + // Mock scope_dashboard_bindings endpoint with scope-specific URL pattern await page.route(dashboardBindingsUrl, async (route) => { await route.fulfill({ status: 200, @@ -220,7 +386,7 @@ export async function applyScopes(page: Page, scopes?: TestScope[]) { }); }); - // Mock scope_navigations endpoint + // Mock scope_navigations endpoint with scope-specific URL pattern await page.route(scopeNavigationsUrl, async (route) => { await route.fulfill({ status: 200, @@ -266,21 +432,23 @@ export async function applyScopes(page: Page, scopes?: TestScope[]) { (response) => response.url().includes(`/find/scope_dashboard_bindings`) || response.url().includes(`/find/scope_navigations`) ); - const scopeRequestPromises: Array> = []; - - for (const scope of scopes) { - scopeRequestPromises.push(scopeSelectRequest(page, scope)); - } await click(); await responsePromise; - await Promise.all(scopeRequestPromises); + // Wait for the apply button to disappear (selector closed) + await page.waitForSelector('[data-testid="scopes-selector-apply"]', { state: 'hidden', timeout: 5000 }); + // Wait for any resulting API calls to complete + await page.waitForLoadState('networkidle'); } -export async function searchScopes(page: Page, value: string, resultScopes: TestScope[]) { +/** + * Searches for scopes in the tree and waits for results. + * Sets up a route dynamically with filtered results to return only matching scopes. + */ +export async function searchScopes(page: Page, value: string, resultScopes?: TestScope[]) { const click = async () => await page.getByTestId('scopes-tree-search').fill(value); - if (!resultScopes) { + if (!resultScopes || USE_LIVE_DATA) { await click(); return; } diff --git a/e2e-playwright/various-suite/gauge.spec.ts b/e2e-playwright/various-suite/gauge.spec.ts deleted file mode 100644 index 3e2d6023c95..00000000000 --- a/e2e-playwright/various-suite/gauge.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { test, expect } from '@grafana/plugin-e2e'; - -// this test requires a larger viewport so all gauge panels load properly -test.use({ - viewport: { width: 1280, height: 1080 }, -}); - -test.describe( - 'Gauge Panel', - { - tag: ['@various'], - }, - () => { - test('Gauge rendering e2e tests', async ({ gotoDashboardPage, selectors, page }) => { - // open Panel Tests - Gauge - const dashboardPage = await gotoDashboardPage({ uid: '_5rDmaQiz' }); - - // check that gauges are rendered - const gaugeElements = page.locator('.flot-base'); - await expect(gaugeElements).toHaveCount(16); - - // check that no panel errors exist - const errorInfo = dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.headerCornerInfo('error')); - await expect(errorInfo).toBeHidden(); - }); - } -); diff --git a/e2e-playwright/various-suite/visualization-suggestions-v2.spec.ts b/e2e-playwright/various-suite/visualization-suggestions-v2.spec.ts new file mode 100644 index 00000000000..282ec1314cc --- /dev/null +++ b/e2e-playwright/various-suite/visualization-suggestions-v2.spec.ts @@ -0,0 +1,178 @@ +import { test, expect } from '@grafana/plugin-e2e'; + +test.use({ + featureToggles: { + newVizSuggestions: true, + externalVizSuggestions: false, + }, + viewport: { + width: 800, + height: 1500, + }, +}); + +test.describe( + 'Visualization suggestions v2', + { + tag: ['@various', '@suggestions'], + }, + () => { + test('Should be shown and clickable', async ({ selectors, gotoPanelEditPage }) => { + // Open dashboard with edit panel + const panelEditPage = await gotoPanelEditPage({ + dashboard: { + uid: 'aBXrJ0R7z', + }, + id: '9', + }); + + await expect( + panelEditPage.getByGrafanaSelector(selectors.components.Panels.Panel.content).locator('.uplot'), + 'time series to be rendered inside panel' + ).toBeVisible(); + + // Try visualization suggestions + await panelEditPage.getByGrafanaSelector(selectors.components.PanelEditor.toggleVizPicker).click(); + await panelEditPage.getByGrafanaSelector(selectors.components.Tab.title('Suggestions')).click(); + + // Verify we see suggestions + await expect( + panelEditPage.getByGrafanaSelector(selectors.components.VisualizationPreview.card('Line chart')), + 'line chart suggestion to be rendered' + ).toBeVisible(); + + // TODO: in this part of the test, we will change the query and the transforms and observe suggestions being updated. + + // Select a visualization and verify table header is visible from preview + await panelEditPage.getByGrafanaSelector(selectors.components.VisualizationPreview.card('Table')).click(); + await expect( + panelEditPage + .getByGrafanaSelector(selectors.components.Panels.Panel.content) + .getByRole('grid') + .getByRole('row') + .first(), + 'table to be rendered inside panel' + ).toBeVisible(); + await expect( + panelEditPage.getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.discardChangesButton), + 'discard changes button disabled since panel has not yet changed' + ).toBeDisabled(); + + // apply the suggestion and verify panel options are visible + await panelEditPage.getByGrafanaSelector(selectors.components.VisualizationPreview.confirm('Table')).click(); + await expect( + panelEditPage + .getByGrafanaSelector(selectors.components.Panels.Panel.content) + .getByRole('grid') + .getByRole('row') + .first(), + 'table to be rendered inside panel' + ).toBeVisible(); + await expect( + panelEditPage.getByGrafanaSelector(selectors.components.PanelEditor.OptionsPane.header), + 'options pane to be rendered' + ).toBeVisible(); + await expect( + panelEditPage.getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.discardChangesButton), + 'discard changes button enabled now that panel is dirty' + ).toBeEnabled(); + }); + + test('should not apply suggestion if you navigate toggle the viz picker back off', async ({ + selectors, + gotoPanelEditPage, + }) => { + // Open dashboard with edit panel + const panelEditPage = await gotoPanelEditPage({ + dashboard: { + uid: 'aBXrJ0R7z', + }, + id: '9', + }); + + await expect( + panelEditPage.getByGrafanaSelector(selectors.components.Panels.Panel.content).locator('.uplot'), + 'time series to be rendered inside panel;' + ).toBeVisible(); + + // Try visualization suggestions + await panelEditPage.getByGrafanaSelector(selectors.components.PanelEditor.toggleVizPicker).click(); + await panelEditPage.getByGrafanaSelector(selectors.components.Tab.title('Suggestions')).click(); + + // Verify we see suggestions + await expect( + panelEditPage.getByGrafanaSelector(selectors.components.VisualizationPreview.card('Line chart')), + 'line chart suggestion to be rendered' + ).toBeVisible(); + + // Select a visualization + await panelEditPage.getByGrafanaSelector(selectors.components.VisualizationPreview.card('Table')).click(); + await expect( + panelEditPage + .getByGrafanaSelector(selectors.components.Panels.Panel.content) + .getByRole('grid') + .getByRole('row') + .first(), + 'table to be rendered inside panel' + ).toBeVisible(); + await expect( + panelEditPage.getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.discardChangesButton) + ).toBeDisabled(); + + // Verify that toggling the viz picker back cancels the suggestion, restores the line chart, shows panel options + await panelEditPage.getByGrafanaSelector(selectors.components.PanelEditor.toggleVizPicker).click(); + await expect( + panelEditPage.getByGrafanaSelector(selectors.components.Panels.Panel.content).locator('.uplot'), + 'time series to be rendered inside panel' + ).toBeVisible(); + await expect( + panelEditPage.getByGrafanaSelector(selectors.components.PanelEditor.OptionsPane.header), + 'options pane to be rendered' + ).toBeVisible(); + await expect( + panelEditPage.getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.discardChangesButton), + 'discard changes button is still disabled since no changes were applied' + ).toBeDisabled(); + }); + + test('should not apply suggestion if you navigate back to the dashboard', async ({ + page, + selectors, + gotoPanelEditPage, + }) => { + // Open dashboard with edit panel + const panelEditPage = await gotoPanelEditPage({ + dashboard: { + uid: 'aBXrJ0R7z', + }, + id: '9', + }); + + // Try visualization suggestions + await panelEditPage.getByGrafanaSelector(selectors.components.PanelEditor.toggleVizPicker).click(); + await panelEditPage.getByGrafanaSelector(selectors.components.Tab.title('Suggestions')).click(); + + // Verify we see suggestions + await expect( + panelEditPage.getByGrafanaSelector(selectors.components.VisualizationPreview.card('Line chart')), + 'line chart suggestion to be rendered' + ).toBeVisible(); + + // Select a visualization + await panelEditPage.getByGrafanaSelector(selectors.components.VisualizationPreview.card('Table')).click(); + await expect(page.getByRole('grid').getByRole('row').first(), 'table row to be rendered').toBeVisible(); + await expect( + panelEditPage.getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.discardChangesButton) + ).toBeDisabled(); + + // Verify that navigating back to the dashboard cancels the suggestion and restores the line chart. + await panelEditPage + .getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.backToDashboardButton) + .click(); + await expect( + page.locator('[data-viz-panel-key="panel-9"]').locator('.uplot'), + 'time series to be rendered inside the panel' + ).toBeVisible(); + }); + } +); diff --git a/e2e-playwright/various-suite/visualization-suggestions.spec.ts b/e2e-playwright/various-suite/visualization-suggestions.spec.ts index d01447b7eb7..7872e5a69d0 100644 --- a/e2e-playwright/various-suite/visualization-suggestions.spec.ts +++ b/e2e-playwright/various-suite/visualization-suggestions.spec.ts @@ -3,7 +3,7 @@ import { test, expect } from '@grafana/plugin-e2e'; test.describe( 'Visualization suggestions', { - tag: ['@various'], + tag: ['@various', '@suggestions'], }, () => { test('Should be shown and clickable', async ({ page, selectors, gotoPanelEditPage }) => { diff --git a/e2e/dashboards-search-suite/mode0.ini b/e2e/dashboards-search-suite/mode0.ini index 7248a2f81a2..2b38cd62c9b 100644 --- a/e2e/dashboards-search-suite/mode0.ini +++ b/e2e/dashboards-search-suite/mode0.ini @@ -3,7 +3,6 @@ [feature_toggles] unifiedStorageSearchUI = true grafanaAPIServerWithExperimentalAPIs = true -unifiedStorageSearchSprinkles = true [unified_storage] enable_search = true diff --git a/e2e/dashboards-search-suite/mode1.ini b/e2e/dashboards-search-suite/mode1.ini index 9875afbec80..b2e9da27c3d 100644 --- a/e2e/dashboards-search-suite/mode1.ini +++ b/e2e/dashboards-search-suite/mode1.ini @@ -3,7 +3,6 @@ [feature_toggles] unifiedStorageSearchUI = true grafanaAPIServerWithExperimentalAPIs = true -unifiedStorageSearchSprinkles = true [unified_storage] enable_search = true diff --git a/e2e/dashboards-search-suite/mode2-legacy-search-api.ini b/e2e/dashboards-search-suite/mode2-legacy-search-api.ini index 18bd29127a0..9517e105306 100644 --- a/e2e/dashboards-search-suite/mode2-legacy-search-api.ini +++ b/e2e/dashboards-search-suite/mode2-legacy-search-api.ini @@ -3,7 +3,6 @@ [feature_toggles] unifiedStorageSearchUI = false grafanaAPIServerWithExperimentalAPIs = true -unifiedStorageSearchSprinkles = true [unified_storage] enable_search = true diff --git a/e2e/dashboards-search-suite/mode2.ini b/e2e/dashboards-search-suite/mode2.ini index d255663299e..138e4960cef 100644 --- a/e2e/dashboards-search-suite/mode2.ini +++ b/e2e/dashboards-search-suite/mode2.ini @@ -3,7 +3,6 @@ [feature_toggles] unifiedStorageSearchUI = true grafanaAPIServerWithExperimentalAPIs = true -unifiedStorageSearchSprinkles = true [unified_storage] enable_search = true diff --git a/e2e/dashboards-search-suite/mode3.ini b/e2e/dashboards-search-suite/mode3.ini index dfc75a310b0..0835dcb3aaa 100644 --- a/e2e/dashboards-search-suite/mode3.ini +++ b/e2e/dashboards-search-suite/mode3.ini @@ -3,7 +3,6 @@ [feature_toggles] unifiedStorageSearchUI = true grafanaAPIServerWithExperimentalAPIs = true -unifiedStorageSearchSprinkles = true [unified_storage] enable_search = true diff --git a/e2e/dashboards-search-suite/mode4.ini b/e2e/dashboards-search-suite/mode4.ini index a73a0502353..675cc237298 100644 --- a/e2e/dashboards-search-suite/mode4.ini +++ b/e2e/dashboards-search-suite/mode4.ini @@ -3,7 +3,6 @@ [feature_toggles] unifiedStorageSearchUI = true grafanaAPIServerWithExperimentalAPIs = true -unifiedStorageSearchSprinkles = true [unified_storage] enable_search = true diff --git a/e2e/dashboards-search-suite/mode5.ini b/e2e/dashboards-search-suite/mode5.ini index a79ab97e792..78b43ee681e 100644 --- a/e2e/dashboards-search-suite/mode5.ini +++ b/e2e/dashboards-search-suite/mode5.ini @@ -3,7 +3,6 @@ [feature_toggles] unifiedStorageSearchUI = true grafanaAPIServerWithExperimentalAPIs = true -unifiedStorageSearchSprinkles = true [unified_storage] enable_search = true diff --git a/eslint-suppressions.json b/eslint-suppressions.json index 597f2b94a1a..f633ed5b4eb 100644 --- a/eslint-suppressions.json +++ b/eslint-suppressions.json @@ -1021,11 +1021,6 @@ "count": 2 } }, - "public/app/core/actions/index.ts": { - "no-barrel-files/no-barrel-files": { - "count": 4 - } - }, "public/app/core/components/AccessControl/PermissionList.tsx": { "no-restricted-syntax": { "count": 1 @@ -1161,11 +1156,6 @@ "count": 2 } }, - "public/app/core/config.ts": { - "no-barrel-files/no-barrel-files": { - "count": 2 - } - }, "public/app/core/navigation/types.ts": { "@typescript-eslint/no-explicit-any": { "count": 1 @@ -2610,11 +2600,6 @@ "count": 2 } }, - "public/app/features/explore/hooks/useStateSync/index.ts": { - "no-barrel-files/no-barrel-files": { - "count": 1 - } - }, "public/app/features/explore/spec/helper/setup.tsx": { "@typescript-eslint/no-explicit-any": { "count": 1 @@ -4030,11 +4015,6 @@ "count": 1 } }, - "public/app/plugins/datasource/parca/webpack.config.ts": { - "no-barrel-files/no-barrel-files": { - "count": 1 - } - }, "public/app/plugins/datasource/prometheus/configuration/AzureAuthSettings.tsx": { "no-restricted-syntax": { "count": 1 @@ -4103,7 +4083,7 @@ "count": 1 }, "@typescript-eslint/no-explicit-any": { - "count": 2 + "count": 1 } }, "public/app/plugins/datasource/tempo/resultTransformer.ts": { diff --git a/eslint.config.js b/eslint.config.js index bd1be26465a..5e44ffebaf4 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -585,6 +585,8 @@ module.exports = [ // FIXME: Remove once all enterprise issues are fixed - // we don't have a suppressions file/approach for enterprise code yet ...enterpriseIgnores, + // Ignore decoupled plugin webpack configs + 'public/app/**/webpack.config.ts', ], rules: { 'no-barrel-files/no-barrel-files': 'error', diff --git a/go.mod b/go.mod index fb1ab1ce189..fe3e62e3fde 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( buf.build/gen/go/parca-dev/parca/protocolbuffers/go v1.36.2-20250703125925-3f0fcf4bff96.1 // @grafana/observability-traces-and-profiling cloud.google.com/go/kms v1.22.0 // @grafana/grafana-backend-group cloud.google.com/go/storage v1.55.0 // @grafana/grafana-backend-group - connectrpc.com/connect v1.18.1 // @grafana/observability-traces-and-profiling + connectrpc.com/connect v1.19.1 // @grafana/observability-traces-and-profiling cuelang.org/go v0.11.1 // @grafana/grafana-as-code dario.cat/mergo v1.0.2 // @grafana/grafana-app-platform-squad filippo.io/age v1.2.1 // @grafana/identity-access-team @@ -25,20 +25,22 @@ require ( github.com/Masterminds/semver v1.5.0 // @grafana/grafana-backend-group github.com/Masterminds/semver/v3 v3.4.0 // @grafana/grafana-developer-enablement-squad github.com/Masterminds/sprig/v3 v3.3.0 // @grafana/grafana-backend-group - github.com/ProtonMail/go-crypto v1.1.6 // @grafana/plugins-platform-backend github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f // @grafana/grafana-backend-group github.com/alicebob/miniredis/v2 v2.34.0 // @grafana/alerting-backend github.com/andybalholm/brotli v1.2.0 // @grafana/partner-datasources github.com/apache/arrow-go/v18 v18.4.1 // @grafana/plugins-platform-backend github.com/armon/go-radix v1.0.0 // @grafana/grafana-app-platform-squad github.com/aws/aws-sdk-go v1.55.7 // @grafana/aws-datasources - github.com/aws/aws-sdk-go-v2 v1.39.1 // @grafana/aws-datasources + github.com/aws/aws-sdk-go-v2 v1.40.0 // @grafana/aws-datasources + github.com/aws/aws-sdk-go-v2/credentials v1.18.21 // indirect; @grafana/grafana-operator-experience-squad github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.45.3 // @grafana/aws-datasources github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.51.0 // @grafana/aws-datasources github.com/aws/aws-sdk-go-v2/service/ec2 v1.225.2 // @grafana/aws-datasources github.com/aws/aws-sdk-go-v2/service/oam v1.18.3 // @grafana/aws-datasources github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.26.6 // @grafana/aws-datasources - github.com/aws/smithy-go v1.23.1 // @grafana/aws-datasources + github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.40.1 // @grafana/grafana-operator-experience-squad + github.com/aws/aws-sdk-go-v2/service/sts v1.39.1 // indirect; @grafana/grafana-operator-experience-squad + github.com/aws/smithy-go v1.23.2 // @grafana/aws-datasources github.com/beevik/etree v1.4.1 // @grafana/grafana-backend-group github.com/benbjohnson/clock v1.3.5 // @grafana/alerting-backend github.com/blang/semver/v4 v4.0.0 // indirect; @grafana/grafana-developer-enablement-squad @@ -80,14 +82,14 @@ require ( github.com/golang/protobuf v1.5.4 // @grafana/grafana-backend-group github.com/golang/snappy v1.0.0 // @grafana/alerting-backend github.com/google/go-cmp v0.7.0 // @grafana/grafana-backend-group - github.com/google/go-github/v70 v70.0.0 // indirect; @grafana/grafana-git-ui-sync-team + github.com/google/go-github/v70 v70.0.0 // @grafana/grafana-git-ui-sync-team github.com/google/go-querystring v1.1.0 // indirect; @grafana/oss-big-tent github.com/google/uuid v1.6.0 // @grafana/grafana-backend-group github.com/google/wire v0.7.0 // @grafana/grafana-backend-group github.com/googleapis/gax-go/v2 v2.15.0 // @grafana/grafana-backend-group github.com/gorilla/mux v1.8.1 // @grafana/grafana-backend-group github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // @grafana/grafana-app-platform-squad - github.com/grafana/alerting v0.0.0-20251212143239-491433b332b7 // @grafana/alerting-backend + github.com/grafana/alerting v0.0.0-20260112172717-98a49ed9557f // @grafana/alerting-backend github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f // @grafana/identity-access-team github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4 // @grafana/identity-access-team github.com/grafana/dataplane/examples v0.0.1 // @grafana/observability-metrics @@ -99,7 +101,7 @@ require ( github.com/grafana/grafana-api-golang-client v0.27.0 // @grafana/alerting-backend 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-aws-sdk v1.4.2 // @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 github.com/grafana/grafana-google-sdk-go v0.4.2 // @grafana/partner-datasources @@ -110,15 +112,15 @@ require ( github.com/grafana/nanogit v0.3.0 // indirect; @grafana/grafana-git-ui-sync-team github.com/grafana/otel-profiling-go v0.5.1 // @grafana/grafana-backend-group github.com/grafana/pyroscope-go/godeltaprof v0.1.9 // @grafana/observability-traces-and-profiling - github.com/grafana/pyroscope/api v1.2.1-0.20250415190842-3ff7247547ae // @grafana/observability-traces-and-profiling + github.com/grafana/pyroscope/api v1.2.1-0.20251118081820-ace37f973a0f // @grafana/observability-traces-and-profiling + github.com/grafana/tempo v1.5.1-0.20250529124718-87c2dc380cec // @grafana/observability-traces-and-profiling github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // @grafana/grafana-search-and-storage github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 // @grafana/plugins-platform-backend github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 // @grafana/grafana-backend-group github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // @grafana/identity-access-team github.com/hashicorp/go-hclog v1.6.3 // @grafana/plugins-platform-backend github.com/hashicorp/go-multierror v1.1.1 // @grafana/alerting-squad - github.com/hashicorp/go-plugin v1.7.0 // @grafana/plugins-platform-backend - github.com/hashicorp/go-secure-stdlib/plugincontainer v0.4.2 // @grafana/plugins-platform-backend + github.com/hashicorp/go-plugin v1.7.0 // indirect; @grafana/plugins-platform-backend github.com/hashicorp/go-version v1.7.0 // @grafana/grafana-backend-group github.com/hashicorp/golang-lru/v2 v2.0.7 // @grafana/alerting-backend github.com/hashicorp/hcl/v2 v2.24.0 // @grafana/alerting-backend @@ -146,6 +148,7 @@ require ( github.com/olekukonko/tablewriter v0.0.5 // @grafana/grafana-backend-group github.com/open-feature/go-sdk v1.16.0 // @grafana/grafana-backend-group github.com/open-feature/go-sdk-contrib/providers/go-feature-flag v0.2.6 // @grafana/grafana-backend-group + github.com/open-feature/go-sdk-contrib/providers/ofrep v0.1.6 // @grafana/grafana-backend-group github.com/openfga/api/proto v0.0.0-20250909172242-b4b2a12f5c67 // @grafana/identity-access-team github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20251027165255-0f8f255e5f6c // @grafana/identity-access-team github.com/openfga/openfga v1.11.1 // @grafana/identity-access-team @@ -154,6 +157,7 @@ require ( github.com/openzipkin/zipkin-go v0.4.3 // @grafana/oss-big-tent github.com/patrickmn/go-cache v2.1.0+incompatible // @grafana/alerting-backend github.com/phpdave11/gofpdi v1.0.14 // @grafana/sharing-squad + github.com/pressly/goose/v3 v3.26.0 // @grafana/identity-access-team 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 @@ -181,6 +185,7 @@ require ( github.com/xlab/treeprint v1.2.0 // @grafana/observability-traces-and-profiling github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // @grafana/grafana-operator-experience-squad github.com/yudai/gojsondiff v1.0.0 // @grafana/grafana-backend-group + go.etcd.io/bbolt v1.4.2 // @grafana/grafana-search-and-storage go.opentelemetry.io/collector/pdata v1.44.0 // @grafana/grafana-backend-group 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 @@ -244,7 +249,6 @@ require ( github.com/grafana/grafana/apps/example v0.0.0-20251027162426-edef69fdc82b // @grafana/grafana-app-platform-squad github.com/grafana/grafana/apps/folder v0.0.0 // @grafana/grafana-search-and-storage github.com/grafana/grafana/apps/iam v0.0.0 // @grafana/identity-access-team - github.com/grafana/grafana/apps/investigations v0.0.0 // @fcjack @matryer github.com/grafana/grafana/apps/logsdrilldown v0.0.0 // @grafana/observability-logs github.com/grafana/grafana/apps/playlist v0.0.0 // @grafana/grafana-app-platform-squad github.com/grafana/grafana/apps/plugins v0.0.0 // @grafana/plugins-platform-backend @@ -257,12 +261,13 @@ require ( github.com/grafana/grafana/pkg/aggregator v0.0.0 // @grafana/grafana-app-platform-squad github.com/grafana/grafana/pkg/apimachinery v0.0.0 // @grafana/grafana-app-platform-squad github.com/grafana/grafana/pkg/apiserver v0.0.0 // @grafana/grafana-app-platform-squad + github.com/grafana/grafana/pkg/plugins v0.0.0 // @grafana/plugins-platform-backend // This needs to be here for other projects that import grafana/grafana // For local development grafana/grafana will always use the local files // Check go.work file for details github.com/grafana/grafana/pkg/promlib v0.0.8 // @grafana/oss-big-tent - github.com/grafana/grafana/pkg/semconv v0.0.0-20250804150913-990f1c69ecc2 // @grafana/grafana-app-platform-squad + github.com/grafana/grafana/pkg/semconv v0.0.0 // @grafana/grafana-app-platform-squad ) // Replace the workspace versions @@ -278,7 +283,6 @@ replace ( github.com/grafana/grafana/apps/dashboard => ./apps/dashboard github.com/grafana/grafana/apps/folder => ./apps/folder github.com/grafana/grafana/apps/iam => ./apps/iam - github.com/grafana/grafana/apps/investigations => ./apps/investigations github.com/grafana/grafana/apps/logsdrilldown => ./apps/logsdrilldown github.com/grafana/grafana/apps/playlist => ./apps/playlist github.com/grafana/grafana/apps/plugins => ./apps/plugins @@ -292,6 +296,8 @@ replace ( github.com/grafana/grafana/pkg/aggregator => ./pkg/aggregator github.com/grafana/grafana/pkg/apimachinery => ./pkg/apimachinery github.com/grafana/grafana/pkg/apiserver => ./pkg/apiserver + github.com/grafana/grafana/pkg/plugins => ./pkg/plugins + github.com/grafana/grafana/pkg/semconv => ./pkg/semconv ) require ( @@ -338,23 +344,21 @@ require ( github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/at-wat/mqtt-go v0.19.6 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.11 // indirect - github.com/aws/aws-sdk-go-v2/config v1.31.10 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.18.14 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.8 // indirect + github.com/aws/aws-sdk-go-v2/config v1.31.17 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13 // indirect github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.84 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.8 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.8 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.36 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.8 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.17 // indirect github.com/aws/aws-sdk-go-v2/service/kms v1.41.2 // indirect github.com/aws/aws-sdk-go-v2/service/s3 v1.84.0 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.29.4 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.0 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.38.5 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.30.1 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.5 // indirect github.com/axiomhq/hyperloglog v0.0.0-20240507144631-af9851f82b27 // indirect github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df // indirect @@ -391,7 +395,6 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cheekybits/genny v1.0.0 // indirect github.com/chromedp/cdproto v0.0.0-20250803210736-d308e07a266d // indirect - github.com/cloudflare/circl v1.6.1 // indirect github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f // indirect github.com/cockroachdb/apd/v3 v3.2.1 // indirect github.com/containerd/errdefs v1.0.0 // indirect @@ -452,7 +455,6 @@ require ( github.com/gopherjs/gopherjs v1.17.2 // indirect github.com/grafana/jsonparser v0.0.0-20240425183733-ea80629e1a32 // indirect github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect - github.com/grafana/sqlds/v4 v4.2.7 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect github.com/hashicorp/consul/api v1.31.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect @@ -489,7 +491,6 @@ require ( github.com/jhump/protoreflect v1.17.0 // indirect github.com/jonboulle/clockwork v0.5.0 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/joshlf/go-acl v0.0.0-20200411065538-eae00ae38531 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6 // indirect github.com/jtolds/gls v4.20.0+incompatible // indirect @@ -541,7 +542,6 @@ require ( github.com/oklog/run v1.1.0 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/oklog/ulid/v2 v2.1.1 // indirect - github.com/open-feature/go-sdk-contrib/providers/ofrep v0.1.6 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal v0.124.1 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/pkg/core/xidutils v0.124.1 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/jaeger v0.124.1 // indirect @@ -556,7 +556,6 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - 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.19.2 // indirect @@ -603,7 +602,6 @@ require ( github.com/yuin/gopher-lua v1.1.1 // indirect 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.6 // indirect go.etcd.io/etcd/client/pkg/v3 v3.6.6 // indirect go.etcd.io/etcd/client/v3 v3.6.6 // indirect @@ -658,11 +656,12 @@ require ( sigs.k8s.io/yaml v1.6.0 // indirect ) -require github.com/grafana/tempo v1.5.1-0.20250529124718-87c2dc380cec // @grafana/observability-traces-and-profiling - require ( - github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect + github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/IBM/pgxpoolprometheus v1.1.2 // indirect + github.com/Machiel/slugify v1.0.1 // indirect + github.com/ProtonMail/go-crypto v1.3.0 // indirect + github.com/cloudflare/circl v1.6.1 // indirect github.com/containerd/log v0.1.0 // indirect github.com/containerd/platforms v0.2.1 // indirect github.com/cpuguy83/dockercfg v0.3.2 // indirect @@ -679,6 +678,11 @@ require ( 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/google/gnostic v0.7.1 // indirect + github.com/gophercloud/gophercloud/v2 v2.9.0 // indirect + github.com/grafana/sqlds/v5 v5.0.3 // indirect + github.com/hashicorp/go-secure-stdlib/plugincontainer v0.4.2 // indirect + github.com/joshlf/go-acl v0.0.0-20200411065538-eae00ae38531 // 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 @@ -700,7 +704,7 @@ require ( replace github.com/crewjam/saml => github.com/grafana/saml v0.4.15-0.20240917091248-ae3bbdad8a56 // Use our fork of the upstream Alertmanager. -replace github.com/prometheus/alertmanager => github.com/grafana/prometheus-alertmanager v0.25.1-0.20250911094103-5456b6e45604 +replace github.com/prometheus/alertmanager => github.com/grafana/prometheus-alertmanager v0.25.1-0.20260112162805-d29cc9cf7f0f exclude github.com/mattn/go-sqlite3 v2.0.3+incompatible diff --git a/go.sum b/go.sum index c1a8d8ad808..67d95c625b6 100644 --- a/go.sum +++ b/go.sum @@ -627,8 +627,8 @@ cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoIS cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= -connectrpc.com/connect v1.18.1 h1:PAg7CjSAGvscaf6YZKUefjoih5Z/qYkyaTrBW8xvYPw= -connectrpc.com/connect v1.18.1/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8= +connectrpc.com/connect v1.19.1 h1:R5M57z05+90EfEvCY1b7hBxDVOUl45PrtXtAV2fOC14= +connectrpc.com/connect v1.19.1/go.mod h1:tN20fjdGlewnSFeZxLKb0xwIZ6ozc3OQs2hTXy4du9w= contrib.go.opencensus.io/exporter/ocagent v0.6.0/go.mod h1:zmKjrJcdo0aYcVS7bmEeSEBLPA9YJp5bjrofdU3pIXs= 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= @@ -679,8 +679,8 @@ github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1/go.mod h1:8cl44BDmi+ github.com/Azure/azure-storage-blob-go v0.15.0 h1:rXtgp8tN1p29GvpGgfJetavIG0V7OgcSXPpwp3tx6qk= github.com/Azure/azure-storage-blob-go v0.15.0/go.mod h1:vbjsVbX0dlxnRc4FFMPsS9BsJWPcne7GB7onqlPvz58= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v11.2.8+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= @@ -738,6 +738,8 @@ github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXY github.com/IBM/pgxpoolprometheus v1.1.2 h1:sHJwxoL5Lw4R79Zt+H4Uj1zZ4iqXJLdk7XDE7TPs97U= github.com/IBM/pgxpoolprometheus v1.1.2/go.mod h1:+vWzISN6S9ssgurhUNmm6AlXL9XLah3TdWJktquKTR8= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= +github.com/Machiel/slugify v1.0.1 h1:EfWSlRWstMadsgzmiV7d0yVd2IFlagWH68Q+DcYCm4E= +github.com/Machiel/slugify v1.0.1/go.mod h1:fTFGn5uWEynW4CUMG7sWkYXOf1UgDxyTM3DbR6Qfg3k= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= @@ -760,8 +762,8 @@ github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.5 h1:zl/OfRA6nftbBK9qTohYBJ5xvw6C/oNKizR7cZGl3cI= github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= -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/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw= +github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= @@ -848,24 +850,24 @@ github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2z github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= github.com/aws/aws-sdk-go v1.55.7 h1:UJrkFq7es5CShfBwlWAC8DA077vp8PyVbQd3lqLiztE= github.com/aws/aws-sdk-go v1.55.7/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= -github.com/aws/aws-sdk-go-v2 v1.39.1 h1:fWZhGAwVRK/fAN2tmt7ilH4PPAE11rDj7HytrmbZ2FE= -github.com/aws/aws-sdk-go-v2 v1.39.1/go.mod h1:sDioUELIUO9Znk23YVmIk86/9DOpkbyyVb1i/gUNFXY= +github.com/aws/aws-sdk-go-v2 v1.40.0 h1:/WMUA0kjhZExjOQN2z3oLALDREea1A7TobfuiBrKlwc= +github.com/aws/aws-sdk-go-v2 v1.40.0/go.mod h1:c9pm7VwuW0UPxAEYGyTmyurVcNrbF6Rt/wixFqDhcjE= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.11 h1:12SpdwU8Djs+YGklkinSSlcrPyj3H4VifVsKf78KbwA= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.11/go.mod h1:dd+Lkp6YmMryke+qxW/VnKyhMBDTYP41Q2Bb+6gNZgY= -github.com/aws/aws-sdk-go-v2/config v1.31.10 h1:7LllDZAegXU3yk41mwM6KcPu0wmjKGQB1bg99bNdQm4= -github.com/aws/aws-sdk-go-v2/config v1.31.10/go.mod h1:Ge6gzXPjqu4v0oHvgAwvGzYcK921GU0hQM25WF/Kl+8= -github.com/aws/aws-sdk-go-v2/credentials v1.18.14 h1:TxkI7QI+sFkTItN/6cJuMZEIVMFXeu2dI1ZffkXngKI= -github.com/aws/aws-sdk-go-v2/credentials v1.18.14/go.mod h1:12x4Uw/vijC11XkctTjy92TNCQ+UnNJkT7fzX0Yd93E= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.8 h1:gLD09eaJUdiszm7vd1btiQUYE0Hj+0I2b8AS+75z9AY= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.8/go.mod h1:4RW3oMPt1POR74qVOC4SbubxAwdP4pCT0nSw3jycOU4= +github.com/aws/aws-sdk-go-v2/config v1.31.17 h1:QFl8lL6RgakNK86vusim14P2k8BFSxjvUkcWLDjgz9Y= +github.com/aws/aws-sdk-go-v2/config v1.31.17/go.mod h1:V8P7ILjp/Uef/aX8TjGk6OHZN6IKPM5YW6S78QnRD5c= +github.com/aws/aws-sdk-go-v2/credentials v1.18.21 h1:56HGpsgnmD+2/KpG0ikvvR8+3v3COCwaF4r+oWwOeNA= +github.com/aws/aws-sdk-go-v2/credentials v1.18.21/go.mod h1:3YELwedmQbw7cXNaII2Wywd+YY58AmLPwX4LzARgmmA= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13 h1:T1brd5dR3/fzNFAQch/iBKeX07/ffu/cLu+q+RuzEWk= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13/go.mod h1:Peg/GBAQ6JDt+RoBf4meB1wylmAipb7Kg2ZFakZTlwk= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.84 h1:cTXRdLkpBanlDwISl+5chq5ui1d1YWg4PWMR9c3kXyw= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.84/go.mod h1:kwSy5X7tfIHN39uucmjQVs2LvDdXEjQucgQQEqCggEo= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.8 h1:6bgAZgRyT4RoFWhxS+aoGMFyE0cD1bSzFnEEi4bFPGI= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.8/go.mod h1:KcGkXFVU8U28qS4KvLEcPxytPZPBcRawaH2Pf/0jptE= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.8 h1:HhJYoES3zOz34yWEpGENqJvRVPqpmJyR3+AFg9ybhdY= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.8/go.mod h1:JnA+hPWeYAVbDssp83tv+ysAG8lTfLVXvSsyKg/7xNA= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14 h1:PZHqQACxYb8mYgms4RZbhZG0a7dPW06xOjmaH0EJC/I= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14/go.mod h1:VymhrMJUWs69D8u0/lZ7jSB6WgaG/NqHi3gX0aYf6U0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14 h1:bOS19y6zlJwagBfHxs0ESzr1XCOU2KXJCWcq3E2vfjY= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14/go.mod h1:1ipeGBMAxZ0xcTm6y6paC2C/J6f6OO7LBODV9afuAyM= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.36 h1:GMYy2EOWfzdP3wfVAGXBNKY5vK4K8vMET4sYOYltmqs= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.36/go.mod h1:gDhdAV6wL3PmPqBhiPbnlS447GoWs8HTTOYef9/9Inw= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.45.3 h1:Nn3qce+OHZuMj/edx4its32uxedAmquCDxtZkrdeiD4= @@ -874,12 +876,12 @@ github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.51.0 h1:e5cbPZYTIY2nUEFie github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.51.0/go.mod h1:UseIHRfrm7PqeZo6fcTb6FUCXzCnh1KJbQbmOfxArGM= github.com/aws/aws-sdk-go-v2/service/ec2 v1.225.2 h1:IfMb3Ar8xEaWjgH/zeVHYD8izwJdQgRP5mKCTDt4GNk= github.com/aws/aws-sdk-go-v2/service/ec2 v1.225.2/go.mod h1:35jGWx7ECvCwTsApqicFYzZ7JFEnBc6oHUuOQ3xIS54= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1 h1:oegbebPEMA/1Jny7kvwejowCaHz1FWZAQ94WXFNCyTM= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1/go.mod h1:kemo5Myr9ac0U9JfSjMo9yHLtw+pECEHsFtJ9tqCEI8= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 h1:x2Ibm/Af8Fi+BH+Hsn9TXGdT+hKbDd5XOTZxTMxDk7o= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3/go.mod h1:IW1jwyrQgMdhisceG8fQLmQIydcT/jWY21rFhzgaKwo= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.4 h1:nAP2GYbfh8dd2zGZqFRSMlq+/F6cMPBUuCsGAMkN074= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.4/go.mod h1:LT10DsiGjLWh4GbjInf9LQejkYEhBgBCjLG5+lvk4EE= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.8 h1:M6JI2aGFEzYxsF6CXIuRBnkge9Wf9a2xU39rNeXgu10= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.8/go.mod h1:Fw+MyTwlwjFsSTE31mH211Np+CUslml8mzc0AFEG09s= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13 h1:kDqdFvMY4AtKoACfzIGD8A0+hbT41KTKF//gq7jITfM= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13/go.mod h1:lmKuogqSU3HzQCwZ9ZtcqOc5XGMqtDK7OIc2+DxiUEg= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.17 h1:qcLWgdhq45sDM9na4cvXax9dyLitn8EYBRl8Ak4XtG4= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.17/go.mod h1:M+jkjBFZ2J6DJrjMv2+vkBbuht6kxJYtJiwoVgX4p4U= github.com/aws/aws-sdk-go-v2/service/kms v1.41.2 h1:zJeUxFP7+XP52u23vrp4zMcVhShTWbNO8dHV6xCSvFo= @@ -890,14 +892,16 @@ github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.26.6 h1:Pwbxovp github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.26.6/go.mod h1:Z4xLt5mXspLKjBV92i165wAJ/3T6TIv4n7RtIS8pWV0= github.com/aws/aws-sdk-go-v2/service/s3 v1.84.0 h1:0reDqfEN+tB+sozj2r92Bep8MEwBZgtAXTND1Kk9OXg= github.com/aws/aws-sdk-go-v2/service/s3 v1.84.0/go.mod h1:kUklwasNoCn5YpyAqC/97r6dzTA1SRKJfKq16SXeoDU= -github.com/aws/aws-sdk-go-v2/service/sso v1.29.4 h1:FTdEN9dtWPB0EOURNtDPmwGp6GGvMqRJCAihkSl/1No= -github.com/aws/aws-sdk-go-v2/service/sso v1.29.4/go.mod h1:mYubxV9Ff42fZH4kexj43gFPhgc/LyC7KqvUKt1watc= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.0 h1:I7ghctfGXrscr7r1Ga/mDqSJKm7Fkpl5Mwq79Z+rZqU= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.0/go.mod h1:Zo9id81XP6jbayIFWNuDpA6lMBWhsVy+3ou2jLa4JnA= -github.com/aws/aws-sdk-go-v2/service/sts v1.38.5 h1:+LVB0xBqEgjQoqr9bGZbRzvg212B0f17JdflleJRNR4= -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/aws/aws-sdk-go-v2/service/secretsmanager v1.40.1 h1:w6a0H79HrHf3lr+zrw+pSzR5B+caiQFAKiNHlrUcnoc= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.40.1/go.mod h1:c6Vg0BRiU7v0MVhHupw90RyL120QBwAMLbDCzptGeMk= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.1 h1:0JPwLz1J+5lEOfy/g0SURC9cxhbQ1lIMHMa+AHZSzz0= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.1/go.mod h1:fKvyjJcz63iL/ftA6RaM8sRCtN4r4zl4tjL3qw5ec7k= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.5 h1:OWs0/j2UYR5LOGi88sD5/lhN6TDLG6SfA7CqsQO9zF0= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.5/go.mod h1:klO+ejMvYsB4QATfEOIXk8WAEwN4N0aBfJpvC+5SZBo= +github.com/aws/aws-sdk-go-v2/service/sts v1.39.1 h1:mLlUgHn02ue8whiR4BmxxGJLR2gwU6s6ZzJ5wDamBUs= +github.com/aws/aws-sdk-go-v2/service/sts v1.39.1/go.mod h1:E19xDjpzPZC7LS2knI9E6BaRFDK43Eul7vd6rSq2HWk= +github.com/aws/smithy-go v1.23.2 h1:Crv0eatJUQhaManss33hS5r40CG3ZFH+21XSkqMrIUM= +github.com/aws/smithy-go v1.23.2/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= github.com/axiomhq/hyperloglog v0.0.0-20191112132149-a4c4c47bc57f/go.mod h1:2stgcRjl6QmW+gU2h5E7BQXg4HU0gzxKWDuT5HviN9s= github.com/axiomhq/hyperloglog v0.0.0-20240507144631-af9851f82b27 h1:60m4tnanN1ctzIu4V3bfCNJ39BiOPSm1gHFlFjTkRE0= github.com/axiomhq/hyperloglog v0.0.0-20240507144631-af9851f82b27/go.mod h1:k08r+Yj1PRAmuayFiRK6MYuR5Ve4IuZtTfxErMIh0+c= @@ -1499,6 +1503,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 v0.7.1 h1:t5Kc7j/8kYr8t2u11rykRrPPovlEMG4+xdc/SpekATs= +github.com/google/gnostic v0.7.1/go.mod h1:KSw6sxnxEBFM8jLPfJd46xZP+yQcfE8XkiqfZx5zR28= 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= @@ -1605,9 +1611,8 @@ github.com/googleapis/gnostic v0.3.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTV github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gophercloud/gophercloud v0.3.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= -github.com/gophercloud/gophercloud v1.13.0 h1:8iY9d1DAbzMW6Vok1AxbbK5ZaUjzMp0tdyt4fX9IeJ0= -github.com/gophercloud/gophercloud/v2 v2.6.0 h1:XJKQ0in3iHOZHVAFMXq/OhjCuvvG+BKR0unOqRfG1EI= -github.com/gophercloud/gophercloud/v2 v2.6.0/go.mod h1:Ki/ILhYZr/5EPebrPL9Ej+tUg4lqx71/YH2JWVeU+Qk= +github.com/gophercloud/gophercloud/v2 v2.9.0 h1:Y9OMrwKF9EDERcHFSOTpf/6XGoAI0yOxmsLmQki4LPM= +github.com/gophercloud/gophercloud/v2 v2.9.0/go.mod h1:Ki/ILhYZr/5EPebrPL9Ej+tUg4lqx71/YH2JWVeU+Qk= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= @@ -1622,8 +1627,8 @@ github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7Fsg github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= 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/alerting v0.0.0-20251212143239-491433b332b7 h1:ZzG/gCclEit9w0QUfQt9GURcOycAIGcsQAhY1u0AEX0= -github.com/grafana/alerting v0.0.0-20251212143239-491433b332b7/go.mod h1:l7v67cgP7x72ajB9UPZlumdrHqNztpKoqQ52cU8T3LU= +github.com/grafana/alerting v0.0.0-20260112172717-98a49ed9557f h1:3bXOyht68qkfvD6Y8z8XoenFbytSSOIkr/s+AqRzj0o= +github.com/grafana/alerting v0.0.0-20260112172717-98a49ed9557f/go.mod h1:Ji0SfJChcwjgq8ljy6Y5CcYfHfAYKXjKYeysOoDS/6s= github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f h1:Cbm6OKkOcJ+7CSZsGsEJzktC/SIa5bxVeYKQLuYK86o= github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f/go.mod h1:axY0cdOg3q0TZHwpHnIz5x16xZ8ZBxJHShsSHHXcHQg= github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4 h1:Muoy+FMGrHj3GdFbvsMzUT7eusgii9PKf9L1ZaXDDbY= @@ -1648,8 +1653,8 @@ github.com/grafana/grafana-app-sdk v0.48.7 h1:9mF7nqkqP0QUYYDlznoOt+GIyjzj45wGfU 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-aws-sdk v1.4.2 h1:GrUEoLbs46r8rG/GZL4L2b63Bo+rkIYKdtCT7kT5KkM= +github.com/grafana/grafana-aws-sdk v1.4.2/go.mod h1:1qnZdYs6gQzxxF0dDodaE7Rn9fiMzuhwvtaAZ7ySnhY= 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-cloud-migration-snapshot v1.9.0 h1:JOzchPgptwJdruYoed7x28lFDwhzs7kssResYsnC0iI= @@ -1666,8 +1671,6 @@ github.com/grafana/grafana/apps/quotas v0.0.0-20251209183543-1013d74f13f2 h1:rDP github.com/grafana/grafana/apps/quotas v0.0.0-20251209183543-1013d74f13f2/go.mod h1:M7bV60iRB61y0ISPG1HX/oNLZtlh0ZF22rUYwNkAKjo= github.com/grafana/grafana/pkg/promlib v0.0.8 h1:VUWsqttdf0wMI4j9OX9oNrykguQpZcruudDAFpJJVw0= github.com/grafana/grafana/pkg/promlib v0.0.8/go.mod h1:U1ezG/MGaEPoThqsr3lymMPN5yIPdVTJnDZ+wcXT+ao= -github.com/grafana/grafana/pkg/semconv v0.0.0-20250804150913-990f1c69ecc2 h1:A65jWgLk4Re28gIuZcpC0aTh71JZ0ey89hKGE9h543s= -github.com/grafana/grafana/pkg/semconv v0.0.0-20250804150913-990f1c69ecc2/go.mod h1:2HRzUK/xQEYc+8d5If/XSusMcaYq9IptnBSHACiQcOQ= github.com/grafana/jsonparser v0.0.0-20240425183733-ea80629e1a32 h1:NznuPwItog+rwdVg8hAuGKP29ndRSzJAwhxKldkP8oQ= github.com/grafana/jsonparser v0.0.0-20240425183733-ea80629e1a32/go.mod h1:796sq+UcONnSlzA3RtlBZ+b/hrerkZXiEmO8oMjyRwY= github.com/grafana/loki/pkg/push v0.0.0-20250823105456-332df2b20000 h1:/5LKSYgLmAhwA4m6iGUD4w1YkydEWWjazn9qxCFT8W0= @@ -1678,18 +1681,18 @@ 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/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= -github.com/grafana/prometheus-alertmanager v0.25.1-0.20250911094103-5456b6e45604/go.mod h1:O/QP1BCm0HHIzbKvgMzqb5sSyH88rzkFk84F4TfJjBU= +github.com/grafana/prometheus-alertmanager v0.25.1-0.20260112162805-d29cc9cf7f0f h1:9tRhudagkQO2s61SLFLSziIdCm7XlkfypVKDxpcHokg= +github.com/grafana/prometheus-alertmanager v0.25.1-0.20260112162805-d29cc9cf7f0f/go.mod h1:AsVdCBeDFN9QbgpJg+8voDAcgsW0RmNvBd70ecMMdC0= github.com/grafana/pyroscope-go/godeltaprof v0.1.9 h1:c1Us8i6eSmkW+Ez05d3co8kasnuOY813tbMN8i/a3Og= github.com/grafana/pyroscope-go/godeltaprof v0.1.9/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU= -github.com/grafana/pyroscope/api v1.2.1-0.20250415190842-3ff7247547ae h1:35W3Wjp9KWnSoV/DuymmyIj5aHE0CYlDQ5m2KeXUPAc= -github.com/grafana/pyroscope/api v1.2.1-0.20250415190842-3ff7247547ae/go.mod h1:6CJ1uXmLZ13ufpO9xE4pST+DyaBt0uszzrV0YnoaVLQ= +github.com/grafana/pyroscope/api v1.2.1-0.20251118081820-ace37f973a0f h1:fTlIj5n4x5dU63XHItug7GLjtnaeJdPqBlqg4zlABq0= +github.com/grafana/pyroscope/api v1.2.1-0.20251118081820-ace37f973a0f/go.mod h1:VBNcIhunCZsJ3/mcYx+j7uFf0P/108eiWa+8+Z9ll3o= github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248= github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk= github.com/grafana/saml v0.4.15-0.20240917091248-ae3bbdad8a56 h1:SDGrP81Vcd102L3UJEryRd1eestRw73wt+b8vnVEFe0= github.com/grafana/saml v0.4.15-0.20240917091248-ae3bbdad8a56/go.mod h1:S4+611dxnKt8z/ulbvaJzcgSHsuhjVc1QHNTcr1R7Fw= -github.com/grafana/sqlds/v4 v4.2.7 h1:sFQhsS7DBakNMdxa++yOfJ9BVvkZwFJ0B95o57K0/XA= -github.com/grafana/sqlds/v4 v4.2.7/go.mod h1:BQRjUG8rOqrBI4NAaeoWrIMuoNgfi8bdhCJ+5cgEfLU= +github.com/grafana/sqlds/v5 v5.0.3 h1:+yUMUxfa0WANQsmS9xtTFSRX1Q55Iv1B9EjlrW4VlBU= +github.com/grafana/sqlds/v5 v5.0.3/go.mod h1:GKeTTiC+GeR1X0z3f0Iee+hZnNgN62uQpj5XVMx5Uew= github.com/grafana/tempo v1.5.1-0.20250529124718-87c2dc380cec h1:wnzJov9RhSHGaTYGzTygL4qq986fLen8xSqnQgaMd28= github.com/grafana/tempo v1.5.1-0.20250529124718-87c2dc380cec/go.mod h1:j1IY7J2rUz7TcTjFVVx6HCpyTlYOJPtXuGRZ7sI+vSo= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= diff --git a/go.work b/go.work index 884f393673e..462bbb36a04 100644 --- a/go.work +++ b/go.work @@ -17,7 +17,6 @@ use ( ./apps/example ./apps/folder ./apps/iam - ./apps/investigations ./apps/logsdrilldown ./apps/playlist ./apps/plugins @@ -33,11 +32,12 @@ use ( ./pkg/build ./pkg/build/wire // skip:golangci-lint ./pkg/codegen + ./pkg/plugins ./pkg/plugins/codegen ./pkg/promlib ./pkg/semconv ) -replace github.com/prometheus/alertmanager => github.com/grafana/prometheus-alertmanager v0.25.1-0.20250911094103-5456b6e45604 +replace github.com/prometheus/alertmanager => github.com/grafana/prometheus-alertmanager v0.25.1-0.20260112162805-d29cc9cf7f0f replace github.com/crewjam/saml => github.com/grafana/saml v0.4.15-0.20240917091248-ae3bbdad8a56 diff --git a/go.work.sum b/go.work.sum index 73813d12650..d064248a16a 100644 --- a/go.work.sum +++ b/go.work.sum @@ -259,6 +259,7 @@ codeberg.org/go-latex/latex v0.1.0 h1:hoGO86rIbWVyjtlDLzCqZPjNykpWQ9YuTZqAzPcfL3 codeberg.org/go-latex/latex v0.1.0/go.mod h1:LA0q/AyWIYrqVd+A9Upkgsb+IqPcmSTKc9Dny04MHMw= codeberg.org/go-pdf/fpdf v0.10.0 h1:u+w669foDDx5Ds43mpiiayp40Ov6sZalgcPMDBcZRd4= codeberg.org/go-pdf/fpdf v0.10.0/go.mod h1:Y0DGRAdZ0OmnZPvjbMp/1bYxmIPxm0ws4tfoPOc4LjU= +connectrpc.com/connect v1.18.1/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8= contrib.go.opencensus.io/exporter/ocagent v0.6.0 h1:Z1n6UAyr0QwM284yUuh5Zd8JlvxUGAhFZcgMJkMPrGM= contrib.go.opencensus.io/exporter/prometheus v0.4.0/go.mod h1:o7cosnyfuPVK0tB8q0QmaQNhGnptITnPQB+z1+qeFB0= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= @@ -423,21 +424,31 @@ github.com/aws/aws-msk-iam-sasl-signer-go v1.0.1 h1:nMp7diZObd4XEVUR0pEvn7/E13JI github.com/aws/aws-msk-iam-sasl-signer-go v1.0.1/go.mod h1:MVYeeOhILFFemC/XlYTClvBjYZrg/EPd3ts885KrNTI= github.com/aws/aws-sdk-go-v2 v1.36.5/go.mod h1:EYrzvCCN9CMUTa5+6lf6MM4tq3Zjp8UhSGR/cBsjai0= github.com/aws/aws-sdk-go-v2 v1.38.1/go.mod h1:9Q0OoGQoboYIAJyslFyF1f5K1Ryddop8gqMhWx/n4Wg= +github.com/aws/aws-sdk-go-v2 v1.39.1/go.mod h1:sDioUELIUO9Znk23YVmIk86/9DOpkbyyVb1i/gUNFXY= +github.com/aws/aws-sdk-go-v2 v1.39.6/go.mod h1:c9pm7VwuW0UPxAEYGyTmyurVcNrbF6Rt/wixFqDhcjE= github.com/aws/aws-sdk-go-v2/config v1.29.17/go.mod h1:9P4wwACpbeXs9Pm9w1QTh6BwWwJjwYvJ1iCt5QbCXh8= github.com/aws/aws-sdk-go-v2/config v1.31.2/go.mod h1:17ft42Yb2lF6OigqSYiDAiUcX4RIkEMY6XxEMJsrAes= +github.com/aws/aws-sdk-go-v2/config v1.31.10/go.mod h1:Ge6gzXPjqu4v0oHvgAwvGzYcK921GU0hQM25WF/Kl+8= github.com/aws/aws-sdk-go-v2/credentials v1.17.70/go.mod h1:M+lWhhmomVGgtuPOhO85u4pEa3SmssPTdcYpP/5J/xc= github.com/aws/aws-sdk-go-v2/credentials v1.18.6/go.mod h1:/jdQkh1iVPa01xndfECInp1v1Wnp70v3K4MvtlLGVEc= +github.com/aws/aws-sdk-go-v2/credentials v1.18.14/go.mod h1:12x4Uw/vijC11XkctTjy92TNCQ+UnNJkT7fzX0Yd93E= github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.19.5 h1:oUEqVqonG3xuarrsze1KVJ30KagNYDemikTbdu8KlN8= github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.19.5/go.mod h1:VNM08cHlOsIbSHRqb6D/M2L4kKXfJv3A2/f0GNbOQSc= github.com/aws/aws-sdk-go-v2/feature/dynamodb/expression v1.7.87 h1:oDPArGgCrG/4aTi86ij3S2PB59XXkTSKYVNQlmqRHXQ= github.com/aws/aws-sdk-go-v2/feature/dynamodb/expression v1.7.87/go.mod h1:ZeQC4gVarhdcWeM1c90DyBLaBCNhEeAbKUXwVI/byvw= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32/go.mod h1:h4Sg6FQdexC1yYG9RDnOvLbW1a/P986++/Y/a+GyEM8= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.4/go.mod h1:9xzb8/SV62W6gHQGC/8rrvgNXU6ZoYM3sAIJCIrXJxY= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.8/go.mod h1:4RW3oMPt1POR74qVOC4SbubxAwdP4pCT0nSw3jycOU4= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.69/go.mod h1:GJj8mmO6YT6EqgduWocwhMoxTLFitkhIrK+owzrYL2I= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36/go.mod h1:Q1lnJArKRXkenyog6+Y+zr7WDpk4e6XlR6gs20bbeNo= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.4/go.mod h1:l4bdfCD7XyyZA9BolKBo1eLqgaJxl0/x91PL4Yqe0ao= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.8/go.mod h1:KcGkXFVU8U28qS4KvLEcPxytPZPBcRawaH2Pf/0jptE= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.13/go.mod h1:oGnKwIYZ4XttyU2JWxFrwvhF6YKiK/9/wmE3v3Iu9K8= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36/go.mod h1:UdyGa7Q91id/sdyHPwth+043HhmP6yP9MBHgbZM0xo8= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.4/go.mod h1:yDmJgqOiH4EA8Hndnv4KwAo8jCGTSnM5ASG1nBI+toA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.8/go.mod h1:JnA+hPWeYAVbDssp83tv+ysAG8lTfLVXvSsyKg/7xNA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.13/go.mod h1:YE94ZoDArI7awZqJzBAZ3PDD2zSfuP7w6P2knOzIn8M= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34/go.mod h1:zf7Vcd1ViW7cPqYWEHLHJkS50X0JS2IKz9Cgaj6ugrs= github.com/aws/aws-sdk-go-v2/service/dynamodb v1.44.0 h1:A99gjqZDbdhjtjJVZrmVzVKO2+p3MSg35bDWtbMQVxw= github.com/aws/aws-sdk-go-v2/service/dynamodb v1.44.0/go.mod h1:mWB0GE1bqcVSvpW7OtFA0sKuHk52+IqtnsYU2jUfYAs= @@ -445,11 +456,13 @@ github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.26.0 h1:0wOCTKrmwkyC8Bk7 github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.26.0/go.mod h1:He/RikglWUczbkV+fkdpcV/3GdL/rTRNVy7VaUiezMo= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4/go.mod h1:/xFi9KtvBXP97ppCz1TAEvU1Uf66qvid89rbem3wCzQ= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0/go.mod h1:eb3gfbVIxIoGgJsi9pGne19dhCBpK6opTYpQqAmdy44= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.1/go.mod h1:kemo5Myr9ac0U9JfSjMo9yHLtw+pECEHsFtJ9tqCEI8= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.0/go.mod h1:iu6FSzgt+M2/x3Dk8zhycdIcHjEFb36IS8HVUVFoMg0= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.17 h1:x187MqiHwBGjMGAed8Y8K1VGuCtFvQvXb24r+bwmSdo= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.17/go.mod h1:mC9qMbA6e1pwEq6X3zDGtZRXMG2YaElJkbJlMVHLs5I= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17/go.mod h1:ygpklyoaypuyDvOM5ujWGrYWpAK3h7ugnmKCU/76Ys4= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.4/go.mod h1:nLEfLnVMmLvyIG58/6gsSA03F1voKGaCfHV7+lR8S7s= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.8/go.mod h1:Fw+MyTwlwjFsSTE31mH211Np+CUslml8mzc0AFEG09s= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15/go.mod h1:ZH34PJUc8ApjBIfgQCFvkWcUDBtl/WTD+uiYHjd8igA= github.com/aws/aws-sdk-go-v2/service/kinesis v1.33.0 h1:JPXkrQk5OS/+Q81fKH97Ll/Vmmy0p9vwHhxw+V+tVjg= github.com/aws/aws-sdk-go-v2/service/kinesis v1.33.0/go.mod h1:dJngkoVMrq0K7QvRkdRZYM4NUp6cdWa2GBdpm8zoY8U= @@ -483,14 +496,18 @@ github.com/aws/aws-sdk-go-v2/service/ssm v1.60.1 h1:OwMzNDe5VVTXD4kGmeK/FtqAITiV github.com/aws/aws-sdk-go-v2/service/ssm v1.60.1/go.mod h1:IyVabkWrs8SNdOEZLyFFcW9bUltV4G6OQS0s6H20PHg= github.com/aws/aws-sdk-go-v2/service/sso v1.25.5/go.mod h1:b7SiVprpU+iGazDUqvRSLf5XmCdn+JtT1on7uNL6Ipc= github.com/aws/aws-sdk-go-v2/service/sso v1.28.2/go.mod h1:n9bTZFZcBa9hGGqVz3i/a6+NG0zmZgtkB9qVVFDqPA8= +github.com/aws/aws-sdk-go-v2/service/sso v1.29.4/go.mod h1:mYubxV9Ff42fZH4kexj43gFPhgc/LyC7KqvUKt1watc= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3/go.mod h1:vq/GQR1gOFLquZMSrxUK/cpvKCNVYibNyJ1m7JrU88E= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.33.2/go.mod h1:eknndR9rU8UpE/OmFpqU78V1EcXPKFTTm5l/buZYgvM= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.0/go.mod h1:Zo9id81XP6jbayIFWNuDpA6lMBWhsVy+3ou2jLa4JnA= github.com/aws/aws-sdk-go-v2/service/sts v1.34.0/go.mod h1:7ph2tGpfQvwzgistp2+zga9f+bCjlQJPkPUmMgDSD7w= github.com/aws/aws-sdk-go-v2/service/sts v1.38.0/go.mod h1:bEPcjW7IbolPfK67G1nilqWyoxYMSPrDiIQ3RdIdKgo= +github.com/aws/aws-sdk-go-v2/service/sts v1.38.5/go.mod h1:xoaxeqnnUaZjPjaICgIy5B+MHCSb/ZSOn4MvkFNOUA0= github.com/aws/smithy-go v1.22.4/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= github.com/aws/smithy-go v1.22.5 h1:P9ATCXPMb2mPjYBgueqJNCA5S9UfktsW0tTxi+a7eqw= github.com/aws/smithy-go v1.22.5/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= github.com/aws/smithy-go v1.23.0/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= +github.com/aws/smithy-go v1.23.1/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= 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= @@ -533,12 +550,12 @@ 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/centrifugal/centrifuge v0.37.2/go.mod h1:aj4iRJGhzi3SlL8iUtVezxway1Xf8g+hmNQkLLO7sS8= +github.com/centrifugal/protocol v0.16.2/go.mod h1:Q7OpS/8HMXDnL7f9DpNx24IhG96MP88WPpVTTCdrokI= 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= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo= @@ -558,6 +575,7 @@ github.com/cilium/ebpf v0.9.1/go.mod h1:+OhNOIXx/Fnu1IE8bJz2dzOA+VSfyTfdNUVdlQnx github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible h1:C29Ae4G5GtYyYMm1aztcyj/J5ckgJm2zwdDajFbx1NY= github.com/circonus-labs/circonusllhist v0.1.3 h1:TJH+oke8D16535+jHExHj4nQvzlZrj7ug5D7I/orNUA= github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= +github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk= github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= @@ -739,6 +757,8 @@ github.com/felixge/fgprof v0.9.4/go.mod h1:yKl+ERSa++RYOs32d8K6WEXCB4uXdLls4ZaZP github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/flosch/pongo2/v4 v4.0.2 h1:gv+5Pe3vaSVmiJvh/BZa82b7/00YUGm0PIyVVLop0Hw= github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8= +github.com/flowstack/go-jsonschema v0.1.1 h1:dCrjGJRXIlbDsLAgTJZTjhwUJnnxVWl1OgNyYh5nyDc= +github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= github.com/fluent/fluent-bit-go v0.0.0-20230731091245-a7a013e2473c h1:yKN46XJHYC/gvgH2UsisJ31+n4K3S7QYZSfU2uAWjuI= github.com/fluent/fluent-bit-go v0.0.0-20230731091245-a7a013e2473c/go.mod h1:L92h+dgwElEyUuShEwjbiHjseW410WIcNz+Bjutc8YQ= github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8= @@ -793,7 +813,15 @@ 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/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= +github.com/go-openapi/swag/conv v0.25.1/go.mod h1:Z1mFEGPfyIKPu0806khI3zF+/EUXde+fdeksUl2NiDs= +github.com/go-openapi/swag/fileutils v0.25.1/go.mod h1:+NXtt5xNZZqmpIpjqcujqojGFek9/w55b3ecmOdtg8M= +github.com/go-openapi/swag/jsonutils v0.25.1/go.mod h1:JpEkAjxQXpiaHmRO04N1zE4qbUEg3b7Udll7AMGTNOo= +github.com/go-openapi/swag/loading v0.25.1/go.mod h1:xoIe2EG32NOYYbqxvXgPzne989bWvSNoWoyQVWEZicc= +github.com/go-openapi/swag/mangling v0.25.1/go.mod h1:CdiMQ6pnfAgyQGSOIYnZkXvqhnnwOn997uXZMAd/7mQ= +github.com/go-openapi/swag/stringutils v0.25.1/go.mod h1:JLdSAq5169HaiDUbTvArA2yQxmgn4D6h4A+4HqVvAYg= +github.com/go-openapi/swag/typeutils v0.25.1/go.mod h1:9McMC/oCdS4BKwk2shEB7x17P6HmMmA6dQRtAkSnNb8= +github.com/go-openapi/swag/yamlutils v0.25.1/go.mod h1:cm9ywbzncy3y6uPm/97ysW8+wZ09qsks+9RS8fLWKqg= 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= @@ -867,6 +895,7 @@ github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQ github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= +github.com/gophercloud/gophercloud v1.13.0 h1:8iY9d1DAbzMW6Vok1AxbbK5ZaUjzMp0tdyt4fX9IeJ0= github.com/gophercloud/gophercloud v1.13.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= @@ -877,6 +906,8 @@ github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7 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/alerting v0.0.0-20260112110054-6c6f13659ad3 h1:KVncUdAc5YwY/OQmw6HgzJmbRKn6IwrhvtcBAd1yDHo= +github.com/grafana/alerting v0.0.0-20260112110054-6c6f13659ad3/go.mod h1:Oy4MthJqfErlieO14ryZXdukDrUACy8Lg56P3zP7S1k= 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= @@ -921,6 +952,7 @@ github.com/grafana/grafana-aws-sdk v1.0.2 h1:98eBuHYFmgvH0xO9kKf4RBsEsgQRp8EOA/9 github.com/grafana/grafana-aws-sdk v1.0.2/go.mod h1:hO7q7yWV+t6dmiyJjMa3IbuYnYkBua+G/IAlOPVIYKE= github.com/grafana/grafana-aws-sdk v1.1.0/go.mod h1:7e+47EdHynteYWGoT5Ere9KeOXQObsk8F0vkOLQ1tz8= github.com/grafana/grafana-aws-sdk v1.2.0/go.mod h1:bBo7qOmM3f61vO+2JxTolNUph1l2TmtzmWcU9/Im+8A= +github.com/grafana/grafana-aws-sdk v1.3.0/go.mod h1:VGycF0JkCGKND2O5je1ucOqPJ0ZNhZYzV3c2bNBAaGk= github.com/grafana/grafana-azure-sdk-go/v2 v2.1.6/go.mod h1:V7y2BmsWxS3A9Ohebwn4OiSfJJqi//4JQydQ8fHTduo= github.com/grafana/grafana-azure-sdk-go/v2 v2.2.0/go.mod h1:H9sVh9A4yg5egMGZeh0mifxT1Q/uqwKe1LBjBJU6pN8= github.com/grafana/grafana-plugin-sdk-go v0.263.0/go.mod h1:U43Cnrj/9DNYyvFcNdeUWNjMXTKNB0jcTcQGpWKd2gw= @@ -966,8 +998,12 @@ github.com/grafana/prometheus-alertmanager v0.25.1-0.20250331083058-4563aec7a975 github.com/grafana/prometheus-alertmanager v0.25.1-0.20250331083058-4563aec7a975/go.mod h1:FGdGvhI40Dq+CTQaSzK9evuve774cgOUdGfVO04OXkw= github.com/grafana/prometheus-alertmanager v0.25.1-0.20250604130045-92c8f6389b36 h1:AjZ58JRw1ZieFH/SdsddF5BXtsDKt5kSrKNPWrzYz3Y= github.com/grafana/prometheus-alertmanager v0.25.1-0.20250604130045-92c8f6389b36/go.mod h1:O/QP1BCm0HHIzbKvgMzqb5sSyH88rzkFk84F4TfJjBU= +github.com/grafana/prometheus-alertmanager v0.25.1-0.20260112162805-d29cc9cf7f0f h1:9tRhudagkQO2s61SLFLSziIdCm7XlkfypVKDxpcHokg= +github.com/grafana/prometheus-alertmanager v0.25.1-0.20260112162805-d29cc9cf7f0f/go.mod h1:AsVdCBeDFN9QbgpJg+8voDAcgsW0RmNvBd70ecMMdC0= github.com/grafana/pyroscope-go/godeltaprof v0.1.8/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU= +github.com/grafana/pyroscope/api v1.2.1-0.20250415190842-3ff7247547ae/go.mod h1:6CJ1uXmLZ13ufpO9xE4pST+DyaBt0uszzrV0YnoaVLQ= github.com/grafana/sqlds/v4 v4.2.4/go.mod h1:BQRjUG8rOqrBI4NAaeoWrIMuoNgfi8bdhCJ+5cgEfLU= +github.com/grafana/sqlds/v4 v4.2.7/go.mod h1:BQRjUG8rOqrBI4NAaeoWrIMuoNgfi8bdhCJ+5cgEfLU= github.com/grafana/tail v0.0.0-20230510142333-77b18831edf0 h1:bjh0PVYSVVFxzINqPFYJmAmJNrWPgnVjuSdYJGHmtFU= github.com/grafana/tail v0.0.0-20230510142333-77b18831edf0/go.mod h1:7t5XR+2IA8P2qggOAHTj/GCZfoLBle3OvNSYh1VkRBU= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= @@ -982,7 +1018,6 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9K 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= @@ -1321,6 +1356,7 @@ github.com/open-telemetry/opentelemetry-collector-contrib/receiver/opencensusrec github.com/open-telemetry/opentelemetry-collector-contrib/receiver/zipkinreceiver v0.121.0/go.mod h1:3axnebi8xUm9ifbs1myzehw2nODtIMrQlL566sJ4bYw= github.com/open-telemetry/opentelemetry-collector-contrib/receiver/zipkinreceiver v0.124.1 h1:XkxqUEoukMWXF+EpEWeM9itXKt62yKi13Lzd8ZEASP4= github.com/open-telemetry/opentelemetry-collector-contrib/receiver/zipkinreceiver v0.124.1/go.mod h1:CuCZVPz+yn88b5vhZPAlxaMrVuhAVexUV6f8b07lpUc= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/runc v1.1.5/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= github.com/opencontainers/runtime-spec v1.0.3-0.20220825212826-86290f6a00fb/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= @@ -1404,7 +1440,6 @@ 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= @@ -1623,7 +1658,6 @@ 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= @@ -1830,6 +1864,7 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.4 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0/go.mod h1:ru6KHrNtNHxM4nD/vd6QrLVWgKhxPYgblq4VAtNawTQ= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.60.0/go.mod h1:CosX/aS4eHnG9D7nESYpV753l4j9q5j3SL/PUYd2lR8= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.61.0/go.mod h1:HfvuU0kW9HewH14VCOLImqKvUgONodURG7Alj/IrnGI= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.62.0/go.mod h1:WfEApdZDMlLUAev/0QQpr8EJ/z0VWDKYZ5tF5RH5T1U= @@ -1839,6 +1874,7 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1: go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg= go.opentelemetry.io/contrib/otelconf v0.15.0 h1:BLNiIUsrNcqhSKpsa6CnhE6LdrpY1A8X0szMVsu99eo= go.opentelemetry.io/contrib/otelconf v0.15.0/go.mod h1:OPH1seO5z9dp1P26gnLtoM9ht7JDvh3Ws6XRHuXqImY= go.opentelemetry.io/contrib/propagators/aws v1.37.0 h1:cp8AFiM/qjBm10C/ATIRnEDXpD5MBknrA0ANw4T2/ss= @@ -1910,7 +1946,6 @@ 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= @@ -1925,10 +1960,12 @@ gocloud.dev/secrets/hashivault v0.42.0/go.mod h1:LXprr1XLEAT7BVZ+Y66dJEHQMzDsowI golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc= golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.11.1-0.20230711161743-2e82bdd1719d/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= @@ -1936,6 +1973,7 @@ golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632 golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= +golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc= golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= @@ -1949,6 +1987,7 @@ golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5N golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ= golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= golang.org/x/exp v0.0.0-20250811191247-51f88131bc50/go.mod h1:rT6SFzZ7oxADUDx58pcaKFTcZ+inxAa9fTrYx/uVYwg= +golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk= golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e h1:qyrTQ++p1afMkO4DPEeLGq/3oTsdlvdH4vqZUBWzUKM= golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ= @@ -2034,6 +2073,7 @@ golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053/go.mod h1:+nZKN+XVh4LCiA9DV3ywrzN4gumyCnKjau3NGb9SGoE= +golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= @@ -2042,6 +2082,7 @@ golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= @@ -2057,7 +2098,6 @@ golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= @@ -2118,8 +2158,8 @@ 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-20251111163417-95abcf5c77ba/go.mod h1:G5IanEx8/PgI9w6CFcYQf7jMtHQhZruvfM1i3qOqk5U= 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= @@ -2150,10 +2190,9 @@ 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-20251111163417-95abcf5c77ba/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= @@ -2177,7 +2216,6 @@ 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= @@ -2209,7 +2247,6 @@ gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzE gopkg.in/vmihailenco/msgpack.v2 v2.9.2 h1:gjPqo9orRVlSAH/065qw3MsFCDpH7fa1KpiizXyllY4= gopkg.in/vmihailenco/msgpack.v2 v2.9.2/go.mod h1:/3Dn1Npt9+MYyLpYYXjInO/5jvMLamn+AEGwNEOatn8= gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= -gotest.tools/v3 v3.5.0/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= honnef.co/go/tools v0.3.2 h1:ytYb4rOqyp1TSa2EPvNVwtPQJctSELKaMyLfqNP4+34= honnef.co/go/tools v0.3.2/go.mod h1:jzwdWgg7Jdq75wlfblQxO4neNaFFSvgc1tD5Wv8U0Yw= @@ -2299,7 +2336,6 @@ 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/kinds/dashboard/dashboard_kind.cue b/kinds/dashboard/dashboard_kind.cue index 08b7a1b2b6e..f17aa67f209 100644 --- a/kinds/dashboard/dashboard_kind.cue +++ b/kinds/dashboard/dashboard_kind.cue @@ -218,8 +218,10 @@ lineage: schemas: [{ // Optional field, if you want to extract part of a series name or metric node segment. // Named capture groups can be used to separate the display text and value. regex?: string - // Determine whether regex applies to variable value or display text - regexApplyTo?: #VariableRegexApplyTo + // Optional, indicates whether a custom type variable uses CSV or JSON to define its values + valuesFormat?: "csv" | "json" | *"csv" + // Determine whether regex applies to variable value or display text + regexApplyTo?: #VariableRegexApplyTo // Additional static options for query variable staticOptions?: [...#VariableOption] // Ordering of static options in relation to options returned from data source for query variable diff --git a/package.json b/package.json index 73dec9dbc90..a6887b216e4 100644 --- a/package.json +++ b/package.json @@ -62,8 +62,7 @@ "stats": "webpack --mode production --config scripts/webpack/webpack.prod.js --profile --json > compilation-stats.json", "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 --conditions=@grafana-app/source --platform=node --tsconfig=./scripts/cli/tsconfig.json | node", + "themes-generate": "yarn workspace @grafana/data 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'", @@ -254,7 +253,6 @@ "ts-jest": "29.4.0", "ts-node": "10.9.2", "typescript": "5.9.2", - "typescript-json-schema": "^0.65.1", "webpack": "5.101.0", "webpack-assets-manifest": "^5.1.0", "webpack-cli": "6.0.1", @@ -265,7 +263,7 @@ "webpackbar": "^7.0.0", "yaml": "^2.0.0", "yargs": "^18.0.0", - "zod": "^4.0.0" + "zod": "^4.3.0" }, "dependencies": { "@bsull/augurs": "^0.10.0", @@ -295,8 +293,8 @@ "@grafana/plugin-ui": "^0.11.1", "@grafana/prometheus": "workspace:*", "@grafana/runtime": "workspace:*", - "@grafana/scenes": "6.52.0", - "@grafana/scenes-react": "6.52.0", + "@grafana/scenes": "v6.52.1", + "@grafana/scenes-react": "v6.52.1", "@grafana/schema": "workspace:*", "@grafana/sql": "workspace:*", "@grafana/ui": "workspace:*", @@ -347,6 +345,7 @@ "date-fns": "4.1.0", "debounce-promise": "3.1.2", "diff": "^8.0.0", + "downsample": "1.4.0", "fast-deep-equal": "^3.1.3", "fast-json-patch": "3.1.1", "file-saver": "2.0.5", @@ -460,8 +459,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", - "@storybook/core@npm:8.6.2": "patch:@storybook/core@npm%3A8.6.2#~/.yarn/patches/@storybook-core-npm-8.6.2-8c752112c0.patch" + "nodemailer": "7.0.11", + "@storybook/core@npm:8.6.15": "patch:@storybook/core@npm%3A8.6.15#~/.yarn/patches/@storybook-core-npm-8.6.15-a468a35170.patch" }, "workspaces": { "packages": [ diff --git a/packages/grafana-alerting/package.json b/packages/grafana-alerting/package.json index d64f1c01893..fa0ee6e5168 100644 --- a/packages/grafana-alerting/package.json +++ b/packages/grafana-alerting/package.json @@ -58,14 +58,12 @@ "bundle": "rollup -c rollup.config.ts --configPlugin esbuild", "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 && node ../../scripts/prepare-npm-package.js", "postpack": "mv package.json.bak package.json", "i18n-extract": "i18next-cli extract --sync-primary" }, "devDependencies": { "@grafana/test-utils": "workspace:*", - "@rtk-query/codegen-openapi": "^2.0.0", "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", @@ -96,8 +94,9 @@ "dependencies": { "@emotion/css": "11.13.5", "@faker-js/faker": "^9.8.0", + "@grafana/api-clients": "12.4.0-pre", "@grafana/i18n": "12.4.0-pre", - "@reduxjs/toolkit": "^2.9.0", + "@reduxjs/toolkit": "2.10.1", "fishery": "^2.3.1", "lodash": "^4.17.21", "tinycolor2": "^1.6.0" diff --git a/packages/grafana-alerting/scripts/README.md b/packages/grafana-alerting/scripts/README.md deleted file mode 100644 index 32730a22a13..00000000000 --- a/packages/grafana-alerting/scripts/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# Re-generate the clients - -⚠️ This guide assumes the Backend definitions have been updated in `apps/alerting`. - -## Re-create OpenAPI specification - -Start with re-generating the OpenAPI snapshots by running the test in `pkg/tests/apis/openapi_test.go`. - -This will output the OpenAPI JSON spec file(s) in `pkg/tests/apis/openapi_snapshots`. - -## Process OpenAPI specifications - -Next up run the post-processing of the snapshots with `yarn run process-specs`, this will copy processed specifications to `./data/openapi/`. - -## Generate RTKQ files - -These files are built using the `yarn run codegen` command, make sure to run that in the Grafana Alerting package working directory. - -`yarn --cwd ./packages/grafana-alerting run codegen`. - -API clients will be written to `src/grafana/api//api.gen.ts`. - -Make sure to create a versioned API client for each API version – see `src/grafana/api/v0alpha1/api.ts` as an example. diff --git a/packages/grafana-alerting/scripts/codegen.ts b/packages/grafana-alerting/scripts/codegen.ts deleted file mode 100644 index 59c9a7e5cb8..00000000000 --- a/packages/grafana-alerting/scripts/codegen.ts +++ /dev/null @@ -1,55 +0,0 @@ -/** - * This script will generate TypeScript type definitions and a RTKQ clients for the alerting k8s APIs. - * - * Run `yarn run codegen` from the "grafana-alerting" package to invoke this script. - * - * API clients will be placed in "src/grafana/api//api.gen.ts" - */ -import type { ConfigFile } from '@rtk-query/codegen-openapi'; - -// ℹ️ append API groups and versions here to generate additional API clients -const SPECS = [ - ['notifications.alerting.grafana.app', ['v0alpha1']], - ['rules.alerting.grafana.app', ['v0alpha1']], - // keep this in Grafana Enterprise - // ['alertenrichment.grafana.app', ['v1beta1']], -] as const; - -type OutputFile = Omit; -type OutputFiles = Record; - -const outputFiles = SPECS.reduce((groupAcc, [group, versions]) => { - return versions.reduce((versionAcc, version) => { - // Create a unique export name based on the group - const groupName = group.split('.')[0]; // e.g., 'notifications', 'rules', 'alertenrichment' - const exportName = `${groupName}API`; - - // ℹ️ these snapshots are generated by running "go test pkg/tests/apis/openapi_test.go" and "scripts/process-specs.ts", - // see the README in the "openapi_snapshots" directory - const schemaFile = `../../../data/openapi/${group}-${version}.json`; - - // ℹ️ make sure there is a API file in each versioned directory - const apiFile = `../src/grafana/api/${groupName}/${version}/api.ts`; - - // output each api client into a versioned directory with group-specific naming - const outputPath = `../src/grafana/api/${groupName}/${version}/${groupName}.api.gen.ts`; - - versionAcc[outputPath] = { - exportName, - schemaFile, - apiFile, - tag: true, // generate tags for cache invalidation - } satisfies OutputFile; - - return versionAcc; - }, groupAcc); -}, {}); - -export default { - // these are intentionally empty but will be set for each versioned config file - exportName: '', - schemaFile: '', - apiFile: '', - - outputFiles, -} satisfies ConfigFile; diff --git a/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/api.ts b/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/api.ts deleted file mode 100644 index 5b45157954f..00000000000 --- a/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/api.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; - -import { getAPIBaseURL, getAPIReducerPath } from '../../util'; - -import { GROUP, VERSION } from './const'; - -const baseUrl = getAPIBaseURL(GROUP, VERSION); -const reducerPath = getAPIReducerPath(GROUP, VERSION); - -export const api = createApi({ - reducerPath, - baseQuery: fetchBaseQuery({ - // Set URL correctly so MSW can intercept requests - // https://mswjs.io/docs/runbook#rtk-query-requests-are-not-intercepted - baseUrl: new URL(baseUrl, globalThis.location.origin).href, - }), - endpoints: () => ({}), -}); diff --git a/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/const.ts b/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/const.ts deleted file mode 100644 index a196bb9516e..00000000000 --- a/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/const.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const VERSION = 'v0alpha1' as const; -export const GROUP = 'notifications.alerting.grafana.app' as const; diff --git a/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/fakes/Receivers.ts b/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/fakes/Receivers.ts index fbd88a5972d..693e2a05f30 100644 --- a/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/fakes/Receivers.ts +++ b/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/fakes/Receivers.ts @@ -1,8 +1,9 @@ import { faker } from '@faker-js/faker'; import { Factory } from 'fishery'; +import { API_GROUP, API_VERSION } from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1'; + import { DEFAULT_NAMESPACE, generateResourceVersion, generateTitle, generateUID } from '../../../../../mocks/util'; -import { GROUP, VERSION } from '../../const'; import { ContactPoint, ContactPointMetadataAnnotations, @@ -14,7 +15,7 @@ import { AlertingEntityMetadataAnnotationsFactory } from './common'; export const ListReceiverApiResponseFactory = Factory.define(() => ({ kind: 'ReceiverList', - apiVersion: `${GROUP}/${VERSION}`, + apiVersion: `${API_GROUP}/${API_VERSION}`, metadata: { resourceVersion: generateResourceVersion(), }, @@ -26,7 +27,7 @@ export const ContactPointFactory = Factory.define(() => { return { kind: 'Receiver', - apiVersion: `${GROUP}/${VERSION}`, + apiVersion: `${API_GROUP}/${API_VERSION}`, metadata: { name: btoa(title), namespace: DEFAULT_NAMESPACE, diff --git a/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers/ReceiverHandlers/createReceiverHandler.ts b/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers/ReceiverHandlers/createReceiverHandler.ts index 2c21893b6d3..7502d4da000 100644 --- a/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers/ReceiverHandlers/createReceiverHandler.ts +++ b/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers/ReceiverHandlers/createReceiverHandler.ts @@ -1,13 +1,17 @@ import { HttpResponse, http } from 'msw'; +import { + API_GROUP, + API_VERSION, + CreateReceiverApiResponse, +} from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1'; + import { getAPIBaseURLForMocks } from '../../../../../../mocks/util'; -import { CreateReceiverApiResponse } from '../../../../v0alpha1/notifications.api.gen'; -import { GROUP, VERSION } from '../../../const'; export function createReceiverHandler( data: CreateReceiverApiResponse | ((info: Parameters[1]>[0]) => Response) ) { - return http.post(getAPIBaseURLForMocks(GROUP, VERSION, '/receivers'), function handler(info) { + return http.post(getAPIBaseURLForMocks(API_GROUP, API_VERSION, '/receivers'), function handler(info) { if (typeof data === 'function') { return data(info); } diff --git a/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers/ReceiverHandlers/deleteReceiverHandler.ts b/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers/ReceiverHandlers/deleteReceiverHandler.ts index d3ff5c660f8..fc859d30043 100644 --- a/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers/ReceiverHandlers/deleteReceiverHandler.ts +++ b/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers/ReceiverHandlers/deleteReceiverHandler.ts @@ -1,13 +1,17 @@ import { HttpResponse, http } from 'msw'; +import { + API_GROUP, + API_VERSION, + DeleteReceiverApiResponse, +} from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1'; + import { getAPIBaseURLForMocks } from '../../../../../../mocks/util'; -import { DeleteReceiverApiResponse } from '../../../../v0alpha1/notifications.api.gen'; -import { GROUP, VERSION } from '../../../const'; export function deleteReceiverHandler( data: DeleteReceiverApiResponse | ((info: Parameters[1]>[0]) => Response) ) { - return http.delete(getAPIBaseURLForMocks(GROUP, VERSION, '/receivers/:name'), function handler(info) { + return http.delete(getAPIBaseURLForMocks(API_GROUP, API_VERSION, '/receivers/:name'), function handler(info) { if (typeof data === 'function') { return data(info); } diff --git a/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers/ReceiverHandlers/deletecollectionReceiverHandler.ts b/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers/ReceiverHandlers/deletecollectionReceiverHandler.ts index f3871112e66..27f68e67834 100644 --- a/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers/ReceiverHandlers/deletecollectionReceiverHandler.ts +++ b/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers/ReceiverHandlers/deletecollectionReceiverHandler.ts @@ -1,13 +1,17 @@ import { HttpResponse, http } from 'msw'; +import { + API_GROUP, + API_VERSION, + DeletecollectionReceiverApiResponse, +} from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1'; + import { getAPIBaseURLForMocks } from '../../../../../../mocks/util'; -import { DeletecollectionReceiverApiResponse } from '../../../../v0alpha1/notifications.api.gen'; -import { GROUP, VERSION } from '../../../const'; export function deletecollectionReceiverHandler( data: DeletecollectionReceiverApiResponse | ((info: Parameters[1]>[0]) => Response) ) { - return http.delete(getAPIBaseURLForMocks(GROUP, VERSION, '/receivers'), function handler(info) { + return http.delete(getAPIBaseURLForMocks(API_GROUP, API_VERSION, '/receivers'), function handler(info) { if (typeof data === 'function') { return data(info); } diff --git a/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers/ReceiverHandlers/getReceiverHandler.ts b/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers/ReceiverHandlers/getReceiverHandler.ts index d90d1fbecba..c7e533d47dc 100644 --- a/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers/ReceiverHandlers/getReceiverHandler.ts +++ b/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers/ReceiverHandlers/getReceiverHandler.ts @@ -1,13 +1,17 @@ import { HttpResponse, http } from 'msw'; +import { + API_GROUP, + API_VERSION, + GetReceiverApiResponse, +} from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1'; + import { getAPIBaseURLForMocks } from '../../../../../../mocks/util'; -import { GetReceiverApiResponse } from '../../../../v0alpha1/notifications.api.gen'; -import { GROUP, VERSION } from '../../../const'; export function getReceiverHandler( data: GetReceiverApiResponse | ((info: Parameters[1]>[0]) => Response) ) { - return http.get(getAPIBaseURLForMocks(GROUP, VERSION, '/receivers/:name'), function handler(info) { + return http.get(getAPIBaseURLForMocks(API_GROUP, API_VERSION, '/receivers/:name'), function handler(info) { if (typeof data === 'function') { return data(info); } diff --git a/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers/ReceiverHandlers/listReceiverHandler.ts b/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers/ReceiverHandlers/listReceiverHandler.ts index fde49565388..b6f577bcca5 100644 --- a/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers/ReceiverHandlers/listReceiverHandler.ts +++ b/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers/ReceiverHandlers/listReceiverHandler.ts @@ -1,13 +1,14 @@ import { HttpResponse, http } from 'msw'; +import { API_GROUP, API_VERSION } from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1'; + import { getAPIBaseURLForMocks } from '../../../../../../mocks/util'; -import { GROUP, VERSION } from '../../../const'; import { EnhancedListReceiverApiResponse } from '../../../types'; export function listReceiverHandler( data: EnhancedListReceiverApiResponse | ((info: Parameters[1]>[0]) => Response) ) { - return http.get(getAPIBaseURLForMocks(GROUP, VERSION, '/receivers'), function handler(info) { + return http.get(getAPIBaseURLForMocks(API_GROUP, API_VERSION, '/receivers'), function handler(info) { if (typeof data === 'function') { return data(info); } diff --git a/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers/ReceiverHandlers/replaceReceiverHandler.ts b/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers/ReceiverHandlers/replaceReceiverHandler.ts index c054de71882..1ed5bb7b50b 100644 --- a/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers/ReceiverHandlers/replaceReceiverHandler.ts +++ b/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers/ReceiverHandlers/replaceReceiverHandler.ts @@ -1,13 +1,17 @@ import { HttpResponse, http } from 'msw'; +import { + API_GROUP, + API_VERSION, + ReplaceReceiverApiResponse, +} from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1'; + import { getAPIBaseURLForMocks } from '../../../../../../mocks/util'; -import { ReplaceReceiverApiResponse } from '../../../../v0alpha1/notifications.api.gen'; -import { GROUP, VERSION } from '../../../const'; export function replaceReceiverHandler( data: ReplaceReceiverApiResponse | ((info: Parameters[1]>[0]) => Response) ) { - return http.put(getAPIBaseURLForMocks(GROUP, VERSION, '/receivers/:name'), function handler(info) { + return http.put(getAPIBaseURLForMocks(API_GROUP, API_VERSION, '/receivers/:name'), function handler(info) { if (typeof data === 'function') { return data(info); } diff --git a/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers/ReceiverHandlers/updateReceiverHandler.ts b/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers/ReceiverHandlers/updateReceiverHandler.ts index ce8498331cd..3b2c7536ec2 100644 --- a/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers/ReceiverHandlers/updateReceiverHandler.ts +++ b/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/mocks/handlers/ReceiverHandlers/updateReceiverHandler.ts @@ -1,13 +1,17 @@ import { HttpResponse, http } from 'msw'; +import { + API_GROUP, + API_VERSION, + UpdateReceiverApiResponse, +} from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1'; + import { getAPIBaseURLForMocks } from '../../../../../../mocks/util'; -import { UpdateReceiverApiResponse } from '../../../../v0alpha1/notifications.api.gen'; -import { GROUP, VERSION } from '../../../const'; export function updateReceiverHandler( data: UpdateReceiverApiResponse | ((info: Parameters[1]>[0]) => Response) ) { - return http.patch(getAPIBaseURLForMocks(GROUP, VERSION, '/receivers/:name'), function handler(info) { + return http.patch(getAPIBaseURLForMocks(API_GROUP, API_VERSION, '/receivers/:name'), function handler(info) { if (typeof data === 'function') { return data(info); } diff --git a/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/types.ts b/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/types.ts index 1212fc74b92..b5913c3ab38 100644 --- a/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/types.ts +++ b/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/types.ts @@ -3,7 +3,11 @@ */ import { MergeDeep, MergeExclusive, OverrideProperties } from 'type-fest'; -import type { ListReceiverApiResponse, Receiver, ReceiverIntegration } from './notifications.api.gen'; +import type { + ListReceiverApiResponse, + Receiver, + ReceiverIntegration, +} from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1'; type GenericIntegration = OverrideProperties< ReceiverIntegration, diff --git a/packages/grafana-alerting/src/grafana/api/rules/v0alpha1/api.ts b/packages/grafana-alerting/src/grafana/api/rules/v0alpha1/api.ts deleted file mode 100644 index 5b45157954f..00000000000 --- a/packages/grafana-alerting/src/grafana/api/rules/v0alpha1/api.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; - -import { getAPIBaseURL, getAPIReducerPath } from '../../util'; - -import { GROUP, VERSION } from './const'; - -const baseUrl = getAPIBaseURL(GROUP, VERSION); -const reducerPath = getAPIReducerPath(GROUP, VERSION); - -export const api = createApi({ - reducerPath, - baseQuery: fetchBaseQuery({ - // Set URL correctly so MSW can intercept requests - // https://mswjs.io/docs/runbook#rtk-query-requests-are-not-intercepted - baseUrl: new URL(baseUrl, globalThis.location.origin).href, - }), - endpoints: () => ({}), -}); diff --git a/packages/grafana-alerting/src/grafana/api/rules/v0alpha1/const.ts b/packages/grafana-alerting/src/grafana/api/rules/v0alpha1/const.ts deleted file mode 100644 index 823560db3fb..00000000000 --- a/packages/grafana-alerting/src/grafana/api/rules/v0alpha1/const.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const VERSION = 'v0alpha1' as const; -export const GROUP = 'rules.alerting.grafana.app' as const; diff --git a/packages/grafana-alerting/src/grafana/contactPoints/hooks/v0alpha1/useContactPoints.tsx b/packages/grafana-alerting/src/grafana/contactPoints/hooks/v0alpha1/useContactPoints.tsx index 7b6ec11f2b2..60a661ac749 100644 --- a/packages/grafana-alerting/src/grafana/contactPoints/hooks/v0alpha1/useContactPoints.tsx +++ b/packages/grafana-alerting/src/grafana/contactPoints/hooks/v0alpha1/useContactPoints.tsx @@ -7,9 +7,10 @@ import { OverrideProperties } from 'type-fest'; import { CreateReceiverApiArg, - type ListReceiverApiArg, - notificationsAPI, -} from '../../../api/notifications/v0alpha1/notifications.api.gen'; + ListReceiverApiArg, + generatedAPI as notificationsAPIv0alpha1, +} from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1'; + import type { ContactPoint, EnhancedListReceiverApiResponse } from '../../../api/notifications/v0alpha1/types'; // this is a workaround for the fact that the generated types are not narrow enough @@ -22,17 +23,17 @@ type ListContactPointsHookResult = TypedUseQueryHookResult< // Type for the options that can be passed to the hook // Based on the pattern used for mutation options in this file type ListContactPointsQueryArgs = Parameters< - typeof notificationsAPI.endpoints.listReceiver.useQuery + typeof notificationsAPIv0alpha1.endpoints.listReceiver.useQuery >[0]; type ListContactPointsQueryOptions = Parameters< - typeof notificationsAPI.endpoints.listReceiver.useQuery + typeof notificationsAPIv0alpha1.endpoints.listReceiver.useQuery >[1]; /** * useListContactPoints is a hook that fetches a list of contact points * - * This function wraps the notificationsAPI.useListReceiverQuery with proper typing + * This function wraps the notificationsAPIv0alpha1.useListReceiverQuery with proper typing * to ensure that the returned ContactPoints are correctly typed in the data.items array. * * It automatically uses the configured namespace for the query. @@ -43,8 +44,8 @@ type ListContactPointsQueryOptions = Parameters< export function useListContactPoints( queryArgs: ListContactPointsQueryArgs = {}, queryOptions: ListContactPointsQueryOptions = {} -) { - return notificationsAPI.useListReceiverQuery(queryArgs, queryOptions); +): ListContactPointsHookResult { + return notificationsAPIv0alpha1.useListReceiverQuery(queryArgs, queryOptions); } // type narrowing mutations requires us to define a few helper types @@ -60,7 +61,7 @@ type CreateContactPointMutation = TypedUseMutationResult< >; type UseCreateContactPointOptions = Parameters< - typeof notificationsAPI.endpoints.createReceiver.useMutation + typeof notificationsAPIv0alpha1.endpoints.createReceiver.useMutation >[0]; /** @@ -69,8 +70,16 @@ type UseCreateContactPointOptions = Parameters< * This function wraps the notificationsAPI.useCreateReceiverMutation with proper typing * to ensure that the payload supports type narrowing. */ -export function useCreateContactPoint(options?: UseCreateContactPointOptions) { - const [updateFn, result] = notificationsAPI.endpoints.createReceiver.useMutation(options); +export function useCreateContactPoint( + options?: UseCreateContactPointOptions +): readonly [ + ( + args: CreateContactPointArgs + ) => ReturnType[0]>, + ReturnType>[1], +] { + const [updateFn, result] = + notificationsAPIv0alpha1.endpoints.createReceiver.useMutation(options); const typedUpdateFn = (args: CreateContactPointArgs) => { // @ts-expect-error this one is just impossible for me to figure out diff --git a/packages/grafana-alerting/src/grafana/contactPoints/utils.ts b/packages/grafana-alerting/src/grafana/contactPoints/utils.ts index ac4242bd1b1..e6748c657ff 100644 --- a/packages/grafana-alerting/src/grafana/contactPoints/utils.ts +++ b/packages/grafana-alerting/src/grafana/contactPoints/utils.ts @@ -1,6 +1,7 @@ import { countBy, isEmpty } from 'lodash'; -import { Receiver } from '../api/notifications/v0alpha1/notifications.api.gen'; +import { Receiver } from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1'; + import { ContactPoint } from '../api/notifications/v0alpha1/types'; /** diff --git a/packages/grafana-alerting/src/grafana/matchers/types.ts b/packages/grafana-alerting/src/grafana/matchers/types.ts index 3cf3103fd1c..f2d20ace7e9 100644 --- a/packages/grafana-alerting/src/grafana/matchers/types.ts +++ b/packages/grafana-alerting/src/grafana/matchers/types.ts @@ -1,4 +1,4 @@ -import { RoutingTreeMatcher } from '../api/notifications/v0alpha1/notifications.api.gen'; +import { RoutingTreeMatcher } from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1'; export type Label = [string, string]; diff --git a/packages/grafana-alerting/src/grafana/notificationPolicies/hooks/useMatchPolicies.test.ts b/packages/grafana-alerting/src/grafana/notificationPolicies/hooks/useMatchPolicies.test.ts index dc650db546b..655b4571309 100644 --- a/packages/grafana-alerting/src/grafana/notificationPolicies/hooks/useMatchPolicies.test.ts +++ b/packages/grafana-alerting/src/grafana/notificationPolicies/hooks/useMatchPolicies.test.ts @@ -1,6 +1,6 @@ -import { VERSION } from '../../api/notifications/v0alpha1/const'; +import { API_VERSION, RoutingTree } from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1'; + import { LabelMatcherFactory, RouteFactory } from '../../api/notifications/v0alpha1/mocks/fakes/Routes'; -import { RoutingTree } from '../../api/notifications/v0alpha1/notifications.api.gen'; import { Label } from '../../matchers/types'; import { matchInstancesToRouteTrees } from './useMatchPolicies'; @@ -16,7 +16,7 @@ describe('matchInstancesToRouteTrees', () => { const trees: RoutingTree[] = [ { kind: 'RoutingTree', - apiVersion: VERSION, + apiVersion: API_VERSION, metadata: { name: treeName }, spec: { defaults: { @@ -24,7 +24,6 @@ describe('matchInstancesToRouteTrees', () => { }, routes: [route], }, - status: {}, }, ]; @@ -51,7 +50,7 @@ describe('matchInstancesToRouteTrees', () => { const trees: RoutingTree[] = [ { kind: 'RoutingTree', - apiVersion: VERSION, + apiVersion: API_VERSION, metadata: { name: treeName }, spec: { defaults: { @@ -59,7 +58,6 @@ describe('matchInstancesToRouteTrees', () => { }, routes: [route], }, - status: {}, }, ]; diff --git a/packages/grafana-alerting/src/grafana/notificationPolicies/hooks/useMatchPolicies.ts b/packages/grafana-alerting/src/grafana/notificationPolicies/hooks/useMatchPolicies.ts index d23efaae967..305671601f7 100644 --- a/packages/grafana-alerting/src/grafana/notificationPolicies/hooks/useMatchPolicies.ts +++ b/packages/grafana-alerting/src/grafana/notificationPolicies/hooks/useMatchPolicies.ts @@ -1,6 +1,10 @@ import { useCallback } from 'react'; -import { RoutingTree, notificationsAPI } from '../../api/notifications/v0alpha1/notifications.api.gen'; +import { + RoutingTree, + generatedAPI as notificationsAPIv0alpha1, +} from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1'; + import { Label } from '../../matchers/types'; import { USER_DEFINED_TREE_NAME } from '../consts'; import { Route, RouteWithID } from '../types'; @@ -24,6 +28,11 @@ export type InstanceMatchResult = { matchedRoutes: RouteMatch[]; }; +interface UseMatchInstancesToRouteTreesReturnType + extends ReturnType { + matchInstancesToRouteTrees: (instances: Label[][]) => InstanceMatchResult[]; +} + /** * React hook that finds notification policy routes in all routing trees that match the provided set of alert instances. * @@ -35,8 +44,8 @@ export type InstanceMatchResult = { * @returns An object containing a `matchInstancesToRoutingTrees` function that takes alert instances * and returns an array of InstanceMatchResult objects, each containing the matched routes and matching details */ -export function useMatchInstancesToRouteTrees() { - const { data, ...rest } = notificationsAPI.endpoints.listRoutingTree.useQuery( +export function useMatchInstancesToRouteTrees(): UseMatchInstancesToRouteTreesReturnType { + const { data, ...rest } = notificationsAPIv0alpha1.endpoints.listRoutingTree.useQuery( {}, { refetchOnFocus: true, diff --git a/packages/grafana-alerting/src/grafana/notificationPolicies/types.ts b/packages/grafana-alerting/src/grafana/notificationPolicies/types.ts index 56465daf613..84f0e07d3b7 100644 --- a/packages/grafana-alerting/src/grafana/notificationPolicies/types.ts +++ b/packages/grafana-alerting/src/grafana/notificationPolicies/types.ts @@ -1,6 +1,7 @@ import { OverrideProperties } from 'type-fest'; -import { RoutingTreeRoute } from '../api/notifications/v0alpha1/notifications.api.gen'; +import { RoutingTreeRoute } from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1'; + import { LabelMatcher } from '../matchers/types'; // type-narrow the route tree diff --git a/packages/grafana-alerting/src/grafana/notificationPolicies/utils.ts b/packages/grafana-alerting/src/grafana/notificationPolicies/utils.ts index 1fc7608a76f..6f7fb7d2ade 100644 --- a/packages/grafana-alerting/src/grafana/notificationPolicies/utils.ts +++ b/packages/grafana-alerting/src/grafana/notificationPolicies/utils.ts @@ -1,6 +1,7 @@ import { groupBy, isArray, pick, reduce, uniqueId } from 'lodash'; -import { RoutingTree, RoutingTreeRoute } from '../api/notifications/v0alpha1/notifications.api.gen'; +import { RoutingTree, RoutingTreeRoute } from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1'; + import { Label } from '../matchers/types'; import { LabelMatchDetails, matchLabels } from '../matchers/utils'; diff --git a/packages/grafana-alerting/src/unstable.ts b/packages/grafana-alerting/src/unstable.ts index e033b55437c..15bce11bebf 100644 --- a/packages/grafana-alerting/src/unstable.ts +++ b/packages/grafana-alerting/src/unstable.ts @@ -19,5 +19,5 @@ export { type LabelMatcher, type Label } from './grafana/matchers/types'; export { matchLabelsSet, matchLabels, isLabelMatch, type LabelMatchDetails } from './grafana/matchers/utils'; // API endpoints -export { notificationsAPI as notificationsAPIv0alpha1 } from './grafana/api/notifications/v0alpha1/notifications.api.gen'; -export { rulesAPI as rulesAPIv0alpha1 } from './grafana/api/rules/v0alpha1/rules.api.gen'; +export { generatedAPI as notificationsAPIv0alpha1 } from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1'; +export { generatedAPI as rulesAPIv0alpha1 } from '@grafana/api-clients/rtkq/rules.alerting/v0alpha1'; diff --git a/packages/grafana-alerting/tests/provider.tsx b/packages/grafana-alerting/tests/provider.tsx index b3caa8679b2..7a3ac8bc241 100644 --- a/packages/grafana-alerting/tests/provider.tsx +++ b/packages/grafana-alerting/tests/provider.tsx @@ -2,13 +2,25 @@ import { configureStore } from '@reduxjs/toolkit'; import { useEffect } from 'react'; import { Provider } from 'react-redux'; -import { notificationsAPIv0alpha1 } from '../src/unstable'; +import { MockBackendSrv } from '@grafana/api-clients'; +import { generatedAPI as notificationsAPIv0alpha1 } from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1'; +import { generatedAPI as rulesAPIv0alpha1 } from '@grafana/api-clients/rtkq/rules.alerting/v0alpha1'; +import { setBackendSrv } from '@grafana/runtime'; + +// Initialize BackendSrv for tests - this allows RTKQ to make HTTP requests +// The actual HTTP requests will be intercepted by MSW (setupMockServer) +// We only need to implement fetch() which is what RTKQ uses +// we could remove this once @grafana/api-client no longer uses the BackendSrv +// @ts-ignore +setBackendSrv(new MockBackendSrv()); // create an empty store -export const store = configureStore({ - middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(notificationsAPIv0alpha1.middleware), +export const store: ReturnType = configureStore({ + middleware: (getDefaultMiddleware) => + getDefaultMiddleware().concat(notificationsAPIv0alpha1.middleware).concat(rulesAPIv0alpha1.middleware), reducer: { [notificationsAPIv0alpha1.reducerPath]: notificationsAPIv0alpha1.reducer, + [rulesAPIv0alpha1.reducerPath]: rulesAPIv0alpha1.reducer, }, }); diff --git a/packages/grafana-alerting/tests/test-utils.tsx b/packages/grafana-alerting/tests/test-utils.tsx index e0f0e12ac9c..5c7de34c9c3 100644 --- a/packages/grafana-alerting/tests/test-utils.tsx +++ b/packages/grafana-alerting/tests/test-utils.tsx @@ -13,7 +13,14 @@ import '@testing-library/jest-dom'; * method which wraps the passed element in all of the necessary Providers, * so it can render correctly in the context of the application */ -const customRender = (ui: React.ReactNode, renderOptions: RenderOptions = {}) => { +const customRender = ( + ui: React.ReactNode, + renderOptions: RenderOptions = {} +): { + renderResult: ReturnType; + user: ReturnType; + store: typeof store; +} => { const user = userEvent.setup(); const Providers = renderOptions.wrapper || getDefaultWrapper(); diff --git a/packages/grafana-api-clients/package.json b/packages/grafana-api-clients/package.json index 39accb04535..f72eab55212 100644 --- a/packages/grafana-api-clients/package.json +++ b/packages/grafana-api-clients/package.json @@ -116,6 +116,18 @@ "import": "./dist/esm/clients/rtkq/shorturl/v1beta1/index.mjs", "require": "./dist/cjs/clients/rtkq/shorturl/v1beta1/index.cjs" }, + "./rtkq/notifications.alerting/v0alpha1": { + "@grafana-app/source": "./src/clients/rtkq/notifications.alerting/v0alpha1/index.ts", + "types": "./dist/types/clients/rtkq/notifications.alerting/v0alpha1/index.d.ts", + "import": "./dist/esm/clients/rtkq/notifications.alerting/v0alpha1/index.mjs", + "require": "./dist/cjs/clients/rtkq/notifications.alerting/v0alpha1/index.cjs" + }, + "./rtkq/rules.alerting/v0alpha1": { + "@grafana-app/source": "./src/clients/rtkq/rules.alerting/v0alpha1/index.ts", + "types": "./dist/types/clients/rtkq/rules.alerting/v0alpha1/index.d.ts", + "import": "./dist/esm/clients/rtkq/rules.alerting/v0alpha1/index.mjs", + "require": "./dist/cjs/clients/rtkq/rules.alerting/v0alpha1/index.cjs" + }, "./rtkq/historian.alerting/v0alpha1": { "@grafana-app/source": "./src/clients/rtkq/historian.alerting/v0alpha1/index.ts", "types": "./dist/types/clients/rtkq/historian.alerting/v0alpha1/index.d.ts", @@ -127,6 +139,12 @@ "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" + }, + "./rtkq/logsdrilldown/v1beta1": { + "@grafana-app/source": "./src/clients/rtkq/logsdrilldown/v1beta1/index.ts", + "types": "./dist/types/clients/rtkq/logsdrilldown/v1beta1/index.d.ts", + "import": "./dist/esm/clients/rtkq/logsdrilldown/v1beta1/index.mjs", + "require": "./dist/cjs/clients/rtkq/logsdrilldown/v1beta1/index.cjs" } }, "publishConfig": { @@ -158,7 +176,7 @@ }, "peerDependencies": { "@grafana/runtime": ">=11.6 <= 12.x", - "@reduxjs/toolkit": "^2.8.0", + "@reduxjs/toolkit": "^2.10.0", "rxjs": "7.8.2" } } diff --git a/packages/grafana-api-clients/src/clients/rtkq/createBaseQuery.ts b/packages/grafana-api-clients/src/clients/rtkq/createBaseQuery.ts index 477e139faac..c6216cc13b5 100644 --- a/packages/grafana-api-clients/src/clients/rtkq/createBaseQuery.ts +++ b/packages/grafana-api-clients/src/clients/rtkq/createBaseQuery.ts @@ -34,6 +34,8 @@ export function createBaseQuery({ baseURL }: CreateBaseQueryOptions): BaseQueryF getBackendSrv().fetch({ ...requestOptions, url: baseURL + requestOptions.url, + // Default to GET so backend_srv correctly skips success alerts for queries + method: requestOptions.method ?? 'GET', showErrorAlert: requestOptions.showErrorAlert ?? false, data: requestOptions.body, headers, diff --git a/packages/grafana-api-clients/src/clients/rtkq/dashboard/v0alpha1/endpoints.gen.ts b/packages/grafana-api-clients/src/clients/rtkq/dashboard/v0alpha1/endpoints.gen.ts index 5d3e72b13aa..9605b8e9355 100644 --- a/packages/grafana-api-clients/src/clients/rtkq/dashboard/v0alpha1/endpoints.gen.ts +++ b/packages/grafana-api-clients/src/clients/rtkq/dashboard/v0alpha1/endpoints.gen.ts @@ -243,8 +243,11 @@ const injectedRtkApi = api type: queryArg['type'], folder: queryArg.folder, facet: queryArg.facet, + facetLimit: queryArg.facetLimit, tags: queryArg.tags, libraryPanel: queryArg.libraryPanel, + panelType: queryArg.panelType, + dataSourceType: queryArg.dataSourceType, permission: queryArg.permission, sort: queryArg.sort, limit: queryArg.limit, @@ -284,6 +287,10 @@ const injectedRtkApi = api query: (queryArg) => ({ url: `/snapshots/delete/${queryArg.deleteKey}`, method: 'DELETE' }), invalidatesTags: ['Snapshot'], }), + getSnapshotSettings: build.query({ + query: () => ({ url: `/snapshots/settings` }), + providesTags: ['Snapshot'], + }), getSnapshot: build.query({ query: (queryArg) => ({ url: `/snapshots/${queryArg.name}`, @@ -663,10 +670,16 @@ export type SearchDashboardsAndFoldersApiArg = { folder?: string; /** count distinct terms for selected fields */ facet?: string[]; + /** maximum number of terms to return per facet (default 50, max 1000) */ + facetLimit?: number; /** tag query filter */ tags?: string[]; /** find dashboards that reference a given libraryPanel */ libraryPanel?: string; + /** find dashboards using panels of a given plugin type */ + panelType?: string; + /** find dashboards using datasources of a given plugin type */ + dataSourceType?: string; /** permission needed for the resource (view, edit, admin) */ permission?: 'view' | 'edit' | 'admin'; /** sortable field */ @@ -739,6 +752,8 @@ export type DeleteWithKeyApiArg = { /** unique key returned in create */ deleteKey: string; }; +export type GetSnapshotSettingsApiResponse = /** status 200 undefined */ any; +export type GetSnapshotSettingsApiArg = void; export type GetSnapshotApiResponse = /** status 200 OK */ Snapshot; export type GetSnapshotApiArg = { /** name of the Snapshot */ @@ -1270,6 +1285,8 @@ export const { useLazyListSnapshotQuery, useCreateSnapshotMutation, useDeleteWithKeyMutation, + useGetSnapshotSettingsQuery, + useLazyGetSnapshotSettingsQuery, useGetSnapshotQuery, useLazyGetSnapshotQuery, useDeleteSnapshotMutation, diff --git a/packages/grafana-api-clients/src/clients/rtkq/index.ts b/packages/grafana-api-clients/src/clients/rtkq/index.ts index 17a471862f8..708a7b04d5b 100644 --- a/packages/grafana-api-clients/src/clients/rtkq/index.ts +++ b/packages/grafana-api-clients/src/clients/rtkq/index.ts @@ -9,11 +9,14 @@ import { generatedAPI as folderAPIv1beta1 } from './folder/v1beta1'; import { generatedAPI as historianAlertingAPIv0alpha1 } from './historian.alerting/v0alpha1'; import { generatedAPI as iamAPIv0alpha1 } from './iam/v0alpha1'; import { generatedAPI as logsdrilldownAPIv1alpha1 } from './logsdrilldown/v1alpha1'; +import { generatedAPI as logsdrilldownAPIv1beta1 } from './logsdrilldown/v1beta1'; import { generatedAPI as migrateToCloudAPI } from './migrate-to-cloud'; +import { generatedAPI as notificationsAlertingAPIv0alpha1 } from './notifications.alerting/v0alpha1'; import { generatedAPI as playlistAPIv0alpha1 } from './playlist/v0alpha1'; import { generatedAPI as preferencesUserAPI } from './preferences/user'; import { generatedAPI as preferencesAPIv1alpha1 } from './preferences/v1alpha1'; import { generatedAPI as provisioningAPIv0alpha1 } from './provisioning/v0alpha1'; +import { generatedAPI as rulesAlertingAPIv0alpha1 } from './rules.alerting/v0alpha1'; import { generatedAPI as shortURLAPIv1beta1 } from './shorturl/v1beta1'; import { generatedAPI as legacyUserAPI } from './user'; // PLOP_INJECT_IMPORT @@ -33,7 +36,10 @@ export const allMiddleware = [ shortURLAPIv1beta1.middleware, correlationsAPIv0alpha1.middleware, legacyUserAPI.middleware, + notificationsAlertingAPIv0alpha1.middleware, + rulesAlertingAPIv0alpha1.middleware, historianAlertingAPIv0alpha1.middleware, + logsdrilldownAPIv1beta1.middleware, logsdrilldownAPIv1alpha1.middleware, // PLOP_INJECT_MIDDLEWARE ] as const; @@ -53,8 +59,11 @@ export const allReducers = { [shortURLAPIv1beta1.reducerPath]: shortURLAPIv1beta1.reducer, [correlationsAPIv0alpha1.reducerPath]: correlationsAPIv0alpha1.reducer, [legacyUserAPI.reducerPath]: legacyUserAPI.reducer, + [notificationsAlertingAPIv0alpha1.reducerPath]: notificationsAlertingAPIv0alpha1.reducer, + [rulesAlertingAPIv0alpha1.reducerPath]: rulesAlertingAPIv0alpha1.reducer, [historianAlertingAPIv0alpha1.reducerPath]: historianAlertingAPIv0alpha1.reducer, [logsdrilldownAPIv1alpha1.reducerPath]: logsdrilldownAPIv1alpha1.reducer, + [logsdrilldownAPIv1beta1.reducerPath]: logsdrilldownAPIv1beta1.reducer, // PLOP_INJECT_REDUCER }; 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 4f17bb46ecf..4ceed793cad 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 @@ -1021,6 +1021,7 @@ const injectedRtkApi = api typeFilter: queryArg.typeFilter, excludeUid: queryArg.excludeUid, folderFilter: queryArg.folderFilter, + folderFilterUIDs: queryArg.folderFilterUiDs, perPage: queryArg.perPage, page: queryArg.page, }, @@ -2915,8 +2916,11 @@ export type GetLibraryElementsApiArg = { typeFilter?: string; /** Element UID to exclude from search results. */ excludeUid?: string; - /** A comma separated list of folder ID(s) to filter the elements by. */ + /** A comma separated list of folder ID(s) to filter the elements by. + Deprecated: Use FolderFilterUIDs instead. */ folderFilter?: string; + /** A comma separated list of folder UID(s) to filter the elements by. */ + folderFilterUiDs?: string; /** The number of results per page. */ perPage?: number; /** The page for a set of records, given that only perPage records are returned at a time. Numbering starts at 1. */ @@ -5312,7 +5316,8 @@ export type PatchPrefsCmd = { queryHistory?: QueryHistoryPreference; regionalFormat?: string; theme?: 'light' | 'dark'; - timezone?: 'utc' | 'browser'; + /** Any IANA timezone string (e.g. America/New_York), 'utc', 'browser', or empty string */ + timezone?: string; weekStart?: string; }; export type UpdatePrefsCmd = { @@ -5325,7 +5330,8 @@ export type UpdatePrefsCmd = { queryHistory?: QueryHistoryPreference; regionalFormat?: string; theme?: 'light' | 'dark' | 'system'; - timezone?: 'utc' | 'browser'; + /** Any IANA timezone string (e.g. America/New_York), 'utc', 'browser', or empty string */ + timezone?: string; weekStart?: string; }; export type OrgUserDto = { @@ -5334,6 +5340,7 @@ export type OrgUserDto = { }; authLabels?: string[]; avatarUrl?: string; + created?: string; email?: string; isDisabled?: boolean; isExternallySynced?: boolean; @@ -5554,6 +5561,7 @@ export type ReportDashboard = { }; export type Type = string; export type ReportOptions = { + csvEncoding?: string; layout?: string; orientation?: string; pdfCombineOneFile?: boolean; @@ -6111,6 +6119,7 @@ export type ChangeUserPasswordCommand = { export type UserSearchHitDto = { authLabels?: string[]; avatarUrl?: string; + created?: string; email?: string; id?: number; isAdmin?: boolean; diff --git a/packages/grafana-api-clients/src/clients/rtkq/logsdrilldown/v1beta1/baseAPI.ts b/packages/grafana-api-clients/src/clients/rtkq/logsdrilldown/v1beta1/baseAPI.ts new file mode 100644 index 00000000000..484d5084e89 --- /dev/null +++ b/packages/grafana-api-clients/src/clients/rtkq/logsdrilldown/v1beta1/baseAPI.ts @@ -0,0 +1,16 @@ +import { createApi } from '@reduxjs/toolkit/query/react'; + +import { getAPIBaseURL } from '../../../../utils/utils'; +import { createBaseQuery } from '../../createBaseQuery'; + +export const API_GROUP = 'logsdrilldown.grafana.app' as const; +export const API_VERSION = 'v1beta1' as const; +export const BASE_URL = getAPIBaseURL(API_GROUP, API_VERSION); + +export const api = createApi({ + reducerPath: 'logsdrilldownAPIv1beta1', + baseQuery: createBaseQuery({ + baseURL: BASE_URL, + }), + endpoints: () => ({}), +}); diff --git a/packages/grafana-api-clients/src/clients/rtkq/logsdrilldown/v1beta1/endpoints.gen.ts b/packages/grafana-api-clients/src/clients/rtkq/logsdrilldown/v1beta1/endpoints.gen.ts new file mode 100644 index 00000000000..65395d2279d --- /dev/null +++ b/packages/grafana-api-clients/src/clients/rtkq/logsdrilldown/v1beta1/endpoints.gen.ts @@ -0,0 +1,652 @@ +import { api } from './baseAPI'; +export const addTagTypes = ['API Discovery', 'LogsDrilldownDefaultColumns'] as const; +const injectedRtkApi = api + .enhanceEndpoints({ + addTagTypes, + }) + .injectEndpoints({ + endpoints: (build) => ({ + getApiResources: build.query({ + query: () => ({ url: `/` }), + providesTags: ['API Discovery'], + }), + listLogsDrilldownDefaultColumns: build.query< + ListLogsDrilldownDefaultColumnsApiResponse, + ListLogsDrilldownDefaultColumnsApiArg + >({ + query: (queryArg) => ({ + url: `/logsdrilldowndefaultcolumns`, + params: { + pretty: queryArg.pretty, + allowWatchBookmarks: queryArg.allowWatchBookmarks, + continue: queryArg['continue'], + fieldSelector: queryArg.fieldSelector, + labelSelector: queryArg.labelSelector, + limit: queryArg.limit, + resourceVersion: queryArg.resourceVersion, + resourceVersionMatch: queryArg.resourceVersionMatch, + sendInitialEvents: queryArg.sendInitialEvents, + timeoutSeconds: queryArg.timeoutSeconds, + watch: queryArg.watch, + }, + }), + providesTags: ['LogsDrilldownDefaultColumns'], + }), + createLogsDrilldownDefaultColumns: build.mutation< + CreateLogsDrilldownDefaultColumnsApiResponse, + CreateLogsDrilldownDefaultColumnsApiArg + >({ + query: (queryArg) => ({ + url: `/logsdrilldowndefaultcolumns`, + method: 'POST', + body: queryArg.logsDrilldownDefaultColumns, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + }, + }), + invalidatesTags: ['LogsDrilldownDefaultColumns'], + }), + deletecollectionLogsDrilldownDefaultColumns: build.mutation< + DeletecollectionLogsDrilldownDefaultColumnsApiResponse, + DeletecollectionLogsDrilldownDefaultColumnsApiArg + >({ + query: (queryArg) => ({ + url: `/logsdrilldowndefaultcolumns`, + method: 'DELETE', + params: { + pretty: queryArg.pretty, + continue: queryArg['continue'], + dryRun: queryArg.dryRun, + fieldSelector: queryArg.fieldSelector, + gracePeriodSeconds: queryArg.gracePeriodSeconds, + ignoreStoreReadErrorWithClusterBreakingPotential: queryArg.ignoreStoreReadErrorWithClusterBreakingPotential, + labelSelector: queryArg.labelSelector, + limit: queryArg.limit, + orphanDependents: queryArg.orphanDependents, + propagationPolicy: queryArg.propagationPolicy, + resourceVersion: queryArg.resourceVersion, + resourceVersionMatch: queryArg.resourceVersionMatch, + sendInitialEvents: queryArg.sendInitialEvents, + timeoutSeconds: queryArg.timeoutSeconds, + }, + }), + invalidatesTags: ['LogsDrilldownDefaultColumns'], + }), + getLogsDrilldownDefaultColumns: build.query< + GetLogsDrilldownDefaultColumnsApiResponse, + GetLogsDrilldownDefaultColumnsApiArg + >({ + query: (queryArg) => ({ + url: `/logsdrilldowndefaultcolumns/${queryArg.name}`, + params: { + pretty: queryArg.pretty, + }, + }), + providesTags: ['LogsDrilldownDefaultColumns'], + }), + replaceLogsDrilldownDefaultColumns: build.mutation< + ReplaceLogsDrilldownDefaultColumnsApiResponse, + ReplaceLogsDrilldownDefaultColumnsApiArg + >({ + query: (queryArg) => ({ + url: `/logsdrilldowndefaultcolumns/${queryArg.name}`, + method: 'PUT', + body: queryArg.logsDrilldownDefaultColumns, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + }, + }), + invalidatesTags: ['LogsDrilldownDefaultColumns'], + }), + deleteLogsDrilldownDefaultColumns: build.mutation< + DeleteLogsDrilldownDefaultColumnsApiResponse, + DeleteLogsDrilldownDefaultColumnsApiArg + >({ + query: (queryArg) => ({ + url: `/logsdrilldowndefaultcolumns/${queryArg.name}`, + method: 'DELETE', + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + gracePeriodSeconds: queryArg.gracePeriodSeconds, + ignoreStoreReadErrorWithClusterBreakingPotential: queryArg.ignoreStoreReadErrorWithClusterBreakingPotential, + orphanDependents: queryArg.orphanDependents, + propagationPolicy: queryArg.propagationPolicy, + }, + }), + invalidatesTags: ['LogsDrilldownDefaultColumns'], + }), + updateLogsDrilldownDefaultColumns: build.mutation< + UpdateLogsDrilldownDefaultColumnsApiResponse, + UpdateLogsDrilldownDefaultColumnsApiArg + >({ + query: (queryArg) => ({ + url: `/logsdrilldowndefaultcolumns/${queryArg.name}`, + method: 'PATCH', + body: queryArg.patch, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + force: queryArg.force, + }, + }), + invalidatesTags: ['LogsDrilldownDefaultColumns'], + }), + getLogsDrilldownDefaultColumnsStatus: build.query< + GetLogsDrilldownDefaultColumnsStatusApiResponse, + GetLogsDrilldownDefaultColumnsStatusApiArg + >({ + query: (queryArg) => ({ + url: `/logsdrilldowndefaultcolumns/${queryArg.name}/status`, + params: { + pretty: queryArg.pretty, + }, + }), + providesTags: ['LogsDrilldownDefaultColumns'], + }), + replaceLogsDrilldownDefaultColumnsStatus: build.mutation< + ReplaceLogsDrilldownDefaultColumnsStatusApiResponse, + ReplaceLogsDrilldownDefaultColumnsStatusApiArg + >({ + query: (queryArg) => ({ + url: `/logsdrilldowndefaultcolumns/${queryArg.name}/status`, + method: 'PUT', + body: queryArg.logsDrilldownDefaultColumns, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + }, + }), + invalidatesTags: ['LogsDrilldownDefaultColumns'], + }), + updateLogsDrilldownDefaultColumnsStatus: build.mutation< + UpdateLogsDrilldownDefaultColumnsStatusApiResponse, + UpdateLogsDrilldownDefaultColumnsStatusApiArg + >({ + query: (queryArg) => ({ + url: `/logsdrilldowndefaultcolumns/${queryArg.name}/status`, + method: 'PATCH', + body: queryArg.patch, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + force: queryArg.force, + }, + }), + invalidatesTags: ['LogsDrilldownDefaultColumns'], + }), + }), + overrideExisting: false, + }); +export { injectedRtkApi as generatedAPI }; +export type GetApiResourcesApiResponse = /** status 200 OK */ ApiResourceList; +export type GetApiResourcesApiArg = void; +export type ListLogsDrilldownDefaultColumnsApiResponse = /** status 200 OK */ LogsDrilldownDefaultColumnsList; +export type ListLogsDrilldownDefaultColumnsApiArg = { + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** allowWatchBookmarks requests watch events with type "BOOKMARK". Servers that do not implement bookmarks may ignore this flag and bookmarks are sent at the server's discretion. Clients should not assume bookmarks are returned at any specific interval, nor may they assume the server will send any BOOKMARK event during a session. If this is not a watch, this field is ignored. */ + allowWatchBookmarks?: boolean; + /** The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the "next key". + + This field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications. */ + continue?: string; + /** A selector to restrict the list of returned objects by their fields. Defaults to everything. */ + fieldSelector?: string; + /** A selector to restrict the list of returned objects by their labels. Defaults to everything. */ + labelSelector?: string; + /** limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true. + + The server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned. */ + limit?: number; + /** resourceVersion sets a constraint on what resource versions a request may be served from. See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersion?: string; + /** resourceVersionMatch determines how resourceVersion is applied to list calls. It is highly recommended that resourceVersionMatch be set for list calls where resourceVersion is set See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersionMatch?: string; + /** `sendInitialEvents=true` may be set together with `watch=true`. In that case, the watch stream will begin with synthetic events to produce the current state of objects in the collection. Once all such events have been sent, a synthetic "Bookmark" event will be sent. The bookmark will report the ResourceVersion (RV) corresponding to the set of objects, and be marked with `"k8s.io/initial-events-end": "true"` annotation. Afterwards, the watch stream will proceed as usual, sending watch events corresponding to changes (subsequent to the RV) to objects watched. + + When `sendInitialEvents` option is set, we require `resourceVersionMatch` option to also be set. The semantic of the watch request is as following: - `resourceVersionMatch` = NotOlderThan + is interpreted as "data at least as new as the provided `resourceVersion`" + and the bookmark event is send when the state is synced + to a `resourceVersion` at least as fresh as the one provided by the ListOptions. + If `resourceVersion` is unset, this is interpreted as "consistent read" and the + bookmark event is send when the state is synced at least to the moment + when request started being processed. + - `resourceVersionMatch` set to any other value or unset + Invalid error is returned. + + Defaults to true if `resourceVersion=""` or `resourceVersion="0"` (for backward compatibility reasons) and to false otherwise. */ + sendInitialEvents?: boolean; + /** Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity. */ + timeoutSeconds?: number; + /** Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion. */ + watch?: boolean; +}; +export type CreateLogsDrilldownDefaultColumnsApiResponse = /** status 200 OK */ + | LogsDrilldownDefaultColumns + | /** status 201 Created */ LogsDrilldownDefaultColumns + | /** status 202 Accepted */ LogsDrilldownDefaultColumns; +export type CreateLogsDrilldownDefaultColumnsApiArg = { + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + logsDrilldownDefaultColumns: LogsDrilldownDefaultColumns; +}; +export type DeletecollectionLogsDrilldownDefaultColumnsApiResponse = /** status 200 OK */ Status; +export type DeletecollectionLogsDrilldownDefaultColumnsApiArg = { + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the "next key". + + This field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications. */ + continue?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** A selector to restrict the list of returned objects by their fields. Defaults to everything. */ + fieldSelector?: string; + /** The duration in seconds before the object should be deleted. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately. */ + gracePeriodSeconds?: number; + /** if set to true, it will trigger an unsafe deletion of the resource in case the normal deletion flow fails with a corrupt object error. A resource is considered corrupt if it can not be retrieved from the underlying storage successfully because of a) its data can not be transformed e.g. decryption failure, or b) it fails to decode into an object. NOTE: unsafe deletion ignores finalizer constraints, skips precondition checks, and removes the object from the storage. WARNING: This may potentially break the cluster if the workload associated with the resource being unsafe-deleted relies on normal deletion flow. Use only if you REALLY know what you are doing. The default value is false, and the user must opt in to enable it */ + ignoreStoreReadErrorWithClusterBreakingPotential?: boolean; + /** A selector to restrict the list of returned objects by their labels. Defaults to everything. */ + labelSelector?: string; + /** limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true. + + The server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned. */ + limit?: number; + /** Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. Should the dependent objects be orphaned. If true/false, the "orphan" finalizer will be added to/removed from the object's finalizers list. Either this field or PropagationPolicy may be set, but not both. */ + orphanDependents?: boolean; + /** Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground. */ + propagationPolicy?: string; + /** resourceVersion sets a constraint on what resource versions a request may be served from. See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersion?: string; + /** resourceVersionMatch determines how resourceVersion is applied to list calls. It is highly recommended that resourceVersionMatch be set for list calls where resourceVersion is set See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersionMatch?: string; + /** `sendInitialEvents=true` may be set together with `watch=true`. In that case, the watch stream will begin with synthetic events to produce the current state of objects in the collection. Once all such events have been sent, a synthetic "Bookmark" event will be sent. The bookmark will report the ResourceVersion (RV) corresponding to the set of objects, and be marked with `"k8s.io/initial-events-end": "true"` annotation. Afterwards, the watch stream will proceed as usual, sending watch events corresponding to changes (subsequent to the RV) to objects watched. + + When `sendInitialEvents` option is set, we require `resourceVersionMatch` option to also be set. The semantic of the watch request is as following: - `resourceVersionMatch` = NotOlderThan + is interpreted as "data at least as new as the provided `resourceVersion`" + and the bookmark event is send when the state is synced + to a `resourceVersion` at least as fresh as the one provided by the ListOptions. + If `resourceVersion` is unset, this is interpreted as "consistent read" and the + bookmark event is send when the state is synced at least to the moment + when request started being processed. + - `resourceVersionMatch` set to any other value or unset + Invalid error is returned. + + Defaults to true if `resourceVersion=""` or `resourceVersion="0"` (for backward compatibility reasons) and to false otherwise. */ + sendInitialEvents?: boolean; + /** Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity. */ + timeoutSeconds?: number; +}; +export type GetLogsDrilldownDefaultColumnsApiResponse = /** status 200 OK */ LogsDrilldownDefaultColumns; +export type GetLogsDrilldownDefaultColumnsApiArg = { + /** name of the LogsDrilldownDefaultColumns */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; +}; +export type ReplaceLogsDrilldownDefaultColumnsApiResponse = /** status 200 OK */ + | LogsDrilldownDefaultColumns + | /** status 201 Created */ LogsDrilldownDefaultColumns; +export type ReplaceLogsDrilldownDefaultColumnsApiArg = { + /** name of the LogsDrilldownDefaultColumns */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + logsDrilldownDefaultColumns: LogsDrilldownDefaultColumns; +}; +export type DeleteLogsDrilldownDefaultColumnsApiResponse = /** status 200 OK */ + | Status + | /** status 202 Accepted */ Status; +export type DeleteLogsDrilldownDefaultColumnsApiArg = { + /** name of the LogsDrilldownDefaultColumns */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** The duration in seconds before the object should be deleted. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately. */ + gracePeriodSeconds?: number; + /** if set to true, it will trigger an unsafe deletion of the resource in case the normal deletion flow fails with a corrupt object error. A resource is considered corrupt if it can not be retrieved from the underlying storage successfully because of a) its data can not be transformed e.g. decryption failure, or b) it fails to decode into an object. NOTE: unsafe deletion ignores finalizer constraints, skips precondition checks, and removes the object from the storage. WARNING: This may potentially break the cluster if the workload associated with the resource being unsafe-deleted relies on normal deletion flow. Use only if you REALLY know what you are doing. The default value is false, and the user must opt in to enable it */ + ignoreStoreReadErrorWithClusterBreakingPotential?: boolean; + /** Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. Should the dependent objects be orphaned. If true/false, the "orphan" finalizer will be added to/removed from the object's finalizers list. Either this field or PropagationPolicy may be set, but not both. */ + orphanDependents?: boolean; + /** Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground. */ + propagationPolicy?: string; +}; +export type UpdateLogsDrilldownDefaultColumnsApiResponse = /** status 200 OK */ + | LogsDrilldownDefaultColumns + | /** status 201 Created */ LogsDrilldownDefaultColumns; +export type UpdateLogsDrilldownDefaultColumnsApiArg = { + /** name of the LogsDrilldownDefaultColumns */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch). */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + /** Force is going to "force" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests. */ + force?: boolean; + patch: Patch; +}; +export type GetLogsDrilldownDefaultColumnsStatusApiResponse = /** status 200 OK */ LogsDrilldownDefaultColumns; +export type GetLogsDrilldownDefaultColumnsStatusApiArg = { + /** name of the LogsDrilldownDefaultColumns */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; +}; +export type ReplaceLogsDrilldownDefaultColumnsStatusApiResponse = /** status 200 OK */ + | LogsDrilldownDefaultColumns + | /** status 201 Created */ LogsDrilldownDefaultColumns; +export type ReplaceLogsDrilldownDefaultColumnsStatusApiArg = { + /** name of the LogsDrilldownDefaultColumns */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + logsDrilldownDefaultColumns: LogsDrilldownDefaultColumns; +}; +export type UpdateLogsDrilldownDefaultColumnsStatusApiResponse = /** status 200 OK */ + | LogsDrilldownDefaultColumns + | /** status 201 Created */ LogsDrilldownDefaultColumns; +export type UpdateLogsDrilldownDefaultColumnsStatusApiArg = { + /** name of the LogsDrilldownDefaultColumns */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch). */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + /** Force is going to "force" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests. */ + force?: boolean; + patch: Patch; +}; +export type ApiResource = { + /** categories is a list of the grouped resources this resource belongs to (e.g. 'all') */ + categories?: string[]; + /** group is the preferred group of the resource. Empty implies the group of the containing resource list. For subresources, this may have a different value, for example: Scale". */ + group?: string; + /** kind is the kind for the resource (e.g. 'Foo' is the kind for a resource 'foo') */ + kind: string; + /** name is the plural name of the resource. */ + name: string; + /** namespaced indicates if a resource is namespaced or not. */ + namespaced: boolean; + /** shortNames is a list of suggested short names of the resource. */ + shortNames?: string[]; + /** singularName is the singular name of the resource. This allows clients to handle plural and singular opaquely. The singularName is more correct for reporting status on a single item and both singular and plural are allowed from the kubectl CLI interface. */ + singularName: string; + /** The hash value of the storage version, the version this resource is converted to when written to the data store. Value must be treated as opaque by clients. Only equality comparison on the value is valid. This is an alpha feature and may change or be removed in the future. The field is populated by the apiserver only if the StorageVersionHash feature gate is enabled. This field will remain optional even if it graduates. */ + storageVersionHash?: string; + /** verbs is a list of supported kube verbs (this includes get, list, watch, create, update, patch, delete, deletecollection, and proxy) */ + verbs: string[]; + /** version is the preferred version of the resource. Empty implies the version of the containing resource list For subresources, this may have a different value, for example: v1 (while inside a v1beta1 version of the core resource's group)". */ + version?: string; +}; +export type ApiResourceList = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + /** groupVersion is the group and version this APIResourceList is for. */ + groupVersion: string; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + /** resources contains the name of the resources and if they are namespaced. */ + resources: ApiResource[]; +}; +export type Time = string; +export type FieldsV1 = object; +export type ManagedFieldsEntry = { + /** APIVersion defines the version of this resource that this field set applies to. The format is "group/version" just like the top-level APIVersion field. It is necessary to track the version of a field set because it cannot be automatically converted. */ + apiVersion?: string; + /** FieldsType is the discriminator for the different fields format and version. There is currently only one possible value: "FieldsV1" */ + fieldsType?: string; + /** FieldsV1 holds the first JSON version format as described in the "FieldsV1" type. */ + fieldsV1?: FieldsV1; + /** Manager is an identifier of the workflow managing these fields. */ + manager?: string; + /** Operation is the type of operation which lead to this ManagedFieldsEntry being created. The only valid values for this field are 'Apply' and 'Update'. */ + operation?: string; + /** Subresource is the name of the subresource used to update that object, or empty string if the object was updated through the main resource. The value of this field is used to distinguish between managers, even if they share the same name. For example, a status update will be distinct from a regular update using the same manager name. Note that the APIVersion field is not related to the Subresource field and it always corresponds to the version of the main resource. */ + subresource?: string; + /** Time is the timestamp of when the ManagedFields entry was added. The timestamp will also be updated if a field is added, the manager changes any of the owned fields value or removes a field. The timestamp does not update when a field is removed from the entry because another manager took it over. */ + time?: Time; +}; +export type OwnerReference = { + /** API version of the referent. */ + apiVersion: string; + /** If true, AND if the owner has the "foregroundDeletion" finalizer, then the owner cannot be deleted from the key-value store until this reference is removed. See https://kubernetes.io/docs/concepts/architecture/garbage-collection/#foreground-deletion for how the garbage collector interacts with this field and enforces the foreground deletion. Defaults to false. To set this field, a user needs "delete" permission of the owner, otherwise 422 (Unprocessable Entity) will be returned. */ + blockOwnerDeletion?: boolean; + /** If true, this reference points to the managing controller. */ + controller?: boolean; + /** Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind: string; + /** Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names */ + name: string; + /** UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids */ + uid: string; +}; +export type ObjectMeta = { + /** Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations */ + annotations?: { + [key: string]: string; + }; + /** CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata */ + creationTimestamp?: Time; + /** Number of seconds allowed for this object to gracefully terminate before it will be removed from the system. Only set when deletionTimestamp is also set. May only be shortened. Read-only. */ + deletionGracePeriodSeconds?: number; + /** DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This field is set by the server when a graceful deletion is requested by the user, and is not directly settable by a client. The resource is expected to be deleted (no longer visible from resource lists, and not reachable by name) after the time in this field, once the finalizers list is empty. As long as the finalizers list contains items, deletion is blocked. Once the deletionTimestamp is set, this value may not be unset or be set further into the future, although it may be shortened or the resource may be deleted prior to this time. For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react by sending a graceful termination signal to the containers in the pod. After that 30 seconds, the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup, remove the pod from the API. In the presence of network partitions, this object may still exist after this timestamp, until an administrator or automated process can determine the resource is fully terminated. If not set, graceful deletion of the object has not been requested. + + Populated by the system when a graceful deletion is requested. Read-only. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata */ + deletionTimestamp?: Time; + /** Must be empty before the object is deleted from the registry. Each entry is an identifier for the responsible component that will remove the entry from the list. If the deletionTimestamp of the object is non-nil, entries in this list can only be removed. Finalizers may be processed and removed in any order. Order is NOT enforced because it introduces significant risk of stuck finalizers. finalizers is a shared field, any actor with permission can reorder it. If the finalizer list is processed in order, then this can lead to a situation in which the component responsible for the first finalizer in the list is waiting for a signal (field value, external system, or other) produced by a component responsible for a finalizer later in the list, resulting in a deadlock. Without enforced ordering finalizers are free to order amongst themselves and are not vulnerable to ordering changes in the list. */ + finalizers?: string[]; + /** GenerateName is an optional prefix, used by the server, to generate a unique name ONLY IF the Name field has not been provided. If this field is used, the name returned to the client will be different than the name passed. This value will also be combined with a unique suffix. The provided value has the same validation rules as the Name field, and may be truncated by the length of the suffix required to make the value unique on the server. + + If this field is specified and the generated name exists, the server will return a 409. + + Applied only if Name is not specified. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency */ + generateName?: string; + /** A sequence number representing a specific generation of the desired state. Populated by the system. Read-only. */ + generation?: number; + /** Map of string keys and values that can be used to organize and categorize (scope and select) objects. May match selectors of replication controllers and services. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels */ + labels?: { + [key: string]: string; + }; + /** ManagedFields maps workflow-id and version to the set of fields that are managed by that workflow. This is mostly for internal housekeeping, and users typically shouldn't need to set or understand this field. A workflow can be the user's name, a controller's name, or the name of a specific apply path like "ci-cd". The set of fields is always in the version that the workflow used when modifying the object. */ + managedFields?: ManagedFieldsEntry[]; + /** Name must be unique within a namespace. Is required when creating resources, although some resources may allow a client to request the generation of an appropriate name automatically. Name is primarily intended for creation idempotence and configuration definition. Cannot be updated. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names */ + name?: string; + /** Namespace defines the space within which each name must be unique. An empty namespace is equivalent to the "default" namespace, but "default" is the canonical representation. Not all objects are required to be scoped to a namespace - the value of this field for those objects will be empty. + + Must be a DNS_LABEL. Cannot be updated. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces */ + namespace?: string; + /** List of objects depended by this object. If ALL objects in the list have been deleted, this object will be garbage collected. If this object is managed by a controller, then an entry in this list will point to this controller, with the controller field set to true. There cannot be more than one managing controller. */ + ownerReferences?: OwnerReference[]; + /** An opaque value that represents the internal version of this object that can be used by clients to determine when objects have changed. May be used for optimistic concurrency, change detection, and the watch operation on a resource or set of resources. Clients must treat these values as opaque and passed unmodified back to the server. They may only be valid for a particular resource or set of resources. + + Populated by the system. Read-only. Value must be treated as opaque by clients and . More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency */ + resourceVersion?: string; + /** Deprecated: selfLink is a legacy read-only field that is no longer populated by the system. */ + selfLink?: string; + /** UID is the unique in time and space value for this object. It is typically generated by the server on successful creation of a resource and is not allowed to change on PUT operations. + + Populated by the system. Read-only. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids */ + uid?: string; +}; +export type LogsDrilldownDefaultColumnsLogsDefaultColumnsLabel = { + key: string; + value: string; +}; +export type LogsDrilldownDefaultColumnsLogsDefaultColumnsLabels = LogsDrilldownDefaultColumnsLogsDefaultColumnsLabel[]; +export type LogsDrilldownDefaultColumnsLogsDefaultColumnsRecord = { + columns: string[]; + labels: LogsDrilldownDefaultColumnsLogsDefaultColumnsLabels; +}; +export type LogsDrilldownDefaultColumnsLogsDefaultColumnsRecords = + LogsDrilldownDefaultColumnsLogsDefaultColumnsRecord[]; +export type LogsDrilldownDefaultColumnsSpec = { + records: LogsDrilldownDefaultColumnsLogsDefaultColumnsRecords; +}; +export type LogsDrilldownDefaultColumnsOperatorState = { + /** descriptiveState is an optional more descriptive state field which has no requirements on format */ + descriptiveState?: string; + /** details contains any extra information that is operator-specific */ + details?: { + [key: string]: { + [key: string]: any; + }; + }; + /** lastEvaluation is the ResourceVersion last evaluated */ + lastEvaluation: string; + /** state describes the state of the lastEvaluation. + It is limited to three possible states for machine evaluation. */ + state: 'success' | 'in_progress' | 'failed'; +}; +export type LogsDrilldownDefaultColumnsStatus = { + /** additionalFields is reserved for future use */ + additionalFields?: { + [key: string]: { + [key: string]: any; + }; + }; + /** operatorStates is a map of operator ID to operator state evaluations. + Any operator which consumes this kind SHOULD add its state evaluation information to this field. */ + operatorStates?: { + [key: string]: LogsDrilldownDefaultColumnsOperatorState; + }; +}; +export type LogsDrilldownDefaultColumns = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion: string; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind: string; + metadata: ObjectMeta; + spec: LogsDrilldownDefaultColumnsSpec; + status?: LogsDrilldownDefaultColumnsStatus; +}; +export type ListMeta = { + /** continue may be set if the user set a limit on the number of items returned, and indicates that the server has more data available. The value is opaque and may be used to issue another request to the endpoint that served this list to retrieve the next set of available objects. Continuing a consistent list may not be possible if the server configuration has changed or more than a few minutes have passed. The resourceVersion field returned when using this continue value will be identical to the value in the first response, unless you have received this token from an error message. */ + continue?: string; + /** remainingItemCount is the number of subsequent items in the list which are not included in this list response. If the list request contained label or field selectors, then the number of remaining items is unknown and the field will be left unset and omitted during serialization. If the list is complete (either because it is not chunking or because this is the last chunk), then there are no more remaining items and this field will be left unset and omitted during serialization. Servers older than v1.15 do not set this field. The intended use of the remainingItemCount is *estimating* the size of a collection. Clients should not rely on the remainingItemCount to be set or to be exact. */ + remainingItemCount?: number; + /** String that identifies the server's internal version of this object that can be used by clients to determine when objects have changed. Value must be treated as opaque by clients and passed unmodified back to the server. Populated by the system. Read-only. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency */ + resourceVersion?: string; + /** Deprecated: selfLink is a legacy read-only field that is no longer populated by the system. */ + selfLink?: string; +}; +export type LogsDrilldownDefaultColumnsList = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + items: LogsDrilldownDefaultColumns[]; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + metadata: ListMeta; +}; +export type StatusCause = { + /** The field of the resource that has caused this error, as named by its JSON serialization. May include dot and postfix notation for nested attributes. Arrays are zero-indexed. Fields may appear more than once in an array of causes due to fields having multiple errors. Optional. + + Examples: + "name" - the field "name" on the current resource + "items[0].name" - the field "name" on the first array entry in "items" */ + field?: string; + /** A human-readable description of the cause of the error. This field may be presented as-is to a reader. */ + message?: string; + /** A machine-readable description of the cause of the error. If this value is empty there is no information available. */ + reason?: string; +}; +export type StatusDetails = { + /** The Causes array includes more details associated with the StatusReason failure. Not all StatusReasons may provide detailed causes. */ + causes?: StatusCause[]; + /** The group attribute of the resource associated with the status StatusReason. */ + group?: string; + /** The kind attribute of the resource associated with the status StatusReason. On some operations may differ from the requested resource Kind. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + /** The name attribute of the resource associated with the status StatusReason (when there is a single name which can be described). */ + name?: string; + /** If specified, the time in seconds before the operation should be retried. Some errors may indicate the client must take an alternate action - for those errors this field may indicate how long to wait before taking the alternate action. */ + retryAfterSeconds?: number; + /** UID of the resource. (when there is a single resource which can be described). More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids */ + uid?: string; +}; +export type Status = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + /** Suggested HTTP return code for this status, 0 if not set. */ + code?: number; + /** Extended data associated with the reason. Each reason may define its own extended details. This field is optional and the data returned is not guaranteed to conform to any schema except that defined by the reason type. */ + details?: StatusDetails; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + /** A human-readable description of the status of this operation. */ + message?: string; + /** Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + metadata?: ListMeta; + /** A machine-readable description of why this operation is in the "Failure" status. If this value is empty there is no information available. A Reason clarifies an HTTP status code but does not override it. */ + reason?: string; + /** Status of the operation. One of: "Success" or "Failure". More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status */ + status?: string; +}; +export type Patch = object; +export const { + useGetApiResourcesQuery, + useLazyGetApiResourcesQuery, + useListLogsDrilldownDefaultColumnsQuery, + useLazyListLogsDrilldownDefaultColumnsQuery, + useCreateLogsDrilldownDefaultColumnsMutation, + useDeletecollectionLogsDrilldownDefaultColumnsMutation, + useGetLogsDrilldownDefaultColumnsQuery, + useLazyGetLogsDrilldownDefaultColumnsQuery, + useReplaceLogsDrilldownDefaultColumnsMutation, + useDeleteLogsDrilldownDefaultColumnsMutation, + useUpdateLogsDrilldownDefaultColumnsMutation, + useGetLogsDrilldownDefaultColumnsStatusQuery, + useLazyGetLogsDrilldownDefaultColumnsStatusQuery, + useReplaceLogsDrilldownDefaultColumnsStatusMutation, + useUpdateLogsDrilldownDefaultColumnsStatusMutation, +} = injectedRtkApi; diff --git a/packages/grafana-api-clients/src/clients/rtkq/logsdrilldown/v1beta1/index.ts b/packages/grafana-api-clients/src/clients/rtkq/logsdrilldown/v1beta1/index.ts new file mode 100644 index 00000000000..d80fd6d553a --- /dev/null +++ b/packages/grafana-api-clients/src/clients/rtkq/logsdrilldown/v1beta1/index.ts @@ -0,0 +1,5 @@ +export { BASE_URL, API_GROUP, API_VERSION } from './baseAPI'; +import { generatedAPI as rawAPI } from './endpoints.gen'; + +export * from './endpoints.gen'; +export const generatedAPI = rawAPI.enhanceEndpoints({}); diff --git a/packages/grafana-api-clients/src/clients/rtkq/notifications.alerting/v0alpha1/baseAPI.ts b/packages/grafana-api-clients/src/clients/rtkq/notifications.alerting/v0alpha1/baseAPI.ts new file mode 100644 index 00000000000..f302218e275 --- /dev/null +++ b/packages/grafana-api-clients/src/clients/rtkq/notifications.alerting/v0alpha1/baseAPI.ts @@ -0,0 +1,16 @@ +import { createApi } from '@reduxjs/toolkit/query/react'; + +import { getAPIBaseURL } from '../../../../utils/utils'; +import { createBaseQuery } from '../../createBaseQuery'; + +export const API_GROUP = 'notifications.alerting.grafana.app' as const; +export const API_VERSION = 'v0alpha1' as const; +export const BASE_URL = getAPIBaseURL(API_GROUP, API_VERSION); + +export const api = createApi({ + reducerPath: 'notificationsAlertingAPIv0alpha1', + baseQuery: createBaseQuery({ + baseURL: BASE_URL, + }), + endpoints: () => ({}), +}); diff --git a/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/notifications.api.gen.ts b/packages/grafana-api-clients/src/clients/rtkq/notifications.alerting/v0alpha1/endpoints.gen.ts similarity index 82% rename from packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/notifications.api.gen.ts rename to packages/grafana-api-clients/src/clients/rtkq/notifications.alerting/v0alpha1/endpoints.gen.ts index 66b145753a6..35301a132fc 100644 --- a/packages/grafana-alerting/src/grafana/api/notifications/v0alpha1/notifications.api.gen.ts +++ b/packages/grafana-api-clients/src/clients/rtkq/notifications.alerting/v0alpha1/endpoints.gen.ts @@ -1,4 +1,4 @@ -import { api } from './api'; +import { api } from './baseAPI'; export const addTagTypes = ['API Discovery', 'Receiver', 'RoutingTree', 'TemplateGroup', 'TimeInterval'] as const; const injectedRtkApi = api .enhanceEndpoints({ @@ -7,7 +7,7 @@ const injectedRtkApi = api .injectEndpoints({ endpoints: (build) => ({ getApiResources: build.query({ - query: () => ({ url: `/apis/notifications.alerting.grafana.app/v0alpha1/` }), + query: () => ({ url: `/` }), providesTags: ['API Discovery'], }), listReceiver: build.query({ @@ -119,44 +119,6 @@ const injectedRtkApi = api }), invalidatesTags: ['Receiver'], }), - getReceiverStatus: build.query({ - query: (queryArg) => ({ - url: `/receivers/${queryArg.name}/status`, - params: { - pretty: queryArg.pretty, - }, - }), - providesTags: ['Receiver'], - }), - replaceReceiverStatus: build.mutation({ - query: (queryArg) => ({ - url: `/receivers/${queryArg.name}/status`, - method: 'PUT', - body: queryArg.receiver, - params: { - pretty: queryArg.pretty, - dryRun: queryArg.dryRun, - fieldManager: queryArg.fieldManager, - fieldValidation: queryArg.fieldValidation, - }, - }), - invalidatesTags: ['Receiver'], - }), - updateReceiverStatus: build.mutation({ - query: (queryArg) => ({ - url: `/receivers/${queryArg.name}/status`, - method: 'PATCH', - body: queryArg.patch, - params: { - pretty: queryArg.pretty, - dryRun: queryArg.dryRun, - fieldManager: queryArg.fieldManager, - fieldValidation: queryArg.fieldValidation, - force: queryArg.force, - }, - }), - invalidatesTags: ['Receiver'], - }), listRoutingTree: build.query({ query: (queryArg) => ({ url: `/routingtrees`, @@ -269,44 +231,6 @@ const injectedRtkApi = api }), invalidatesTags: ['RoutingTree'], }), - getRoutingTreeStatus: build.query({ - query: (queryArg) => ({ - url: `/routingtrees/${queryArg.name}/status`, - params: { - pretty: queryArg.pretty, - }, - }), - providesTags: ['RoutingTree'], - }), - replaceRoutingTreeStatus: build.mutation({ - query: (queryArg) => ({ - url: `/routingtrees/${queryArg.name}/status`, - method: 'PUT', - body: queryArg.routingTree, - params: { - pretty: queryArg.pretty, - dryRun: queryArg.dryRun, - fieldManager: queryArg.fieldManager, - fieldValidation: queryArg.fieldValidation, - }, - }), - invalidatesTags: ['RoutingTree'], - }), - updateRoutingTreeStatus: build.mutation({ - query: (queryArg) => ({ - url: `/routingtrees/${queryArg.name}/status`, - method: 'PATCH', - body: queryArg.patch, - params: { - pretty: queryArg.pretty, - dryRun: queryArg.dryRun, - fieldManager: queryArg.fieldManager, - fieldValidation: queryArg.fieldValidation, - force: queryArg.force, - }, - }), - invalidatesTags: ['RoutingTree'], - }), listTemplateGroup: build.query({ query: (queryArg) => ({ url: `/templategroups`, @@ -419,47 +343,6 @@ const injectedRtkApi = api }), invalidatesTags: ['TemplateGroup'], }), - getTemplateGroupStatus: build.query({ - query: (queryArg) => ({ - url: `/templategroups/${queryArg.name}/status`, - params: { - pretty: queryArg.pretty, - }, - }), - providesTags: ['TemplateGroup'], - }), - replaceTemplateGroupStatus: build.mutation< - ReplaceTemplateGroupStatusApiResponse, - ReplaceTemplateGroupStatusApiArg - >({ - query: (queryArg) => ({ - url: `/templategroups/${queryArg.name}/status`, - method: 'PUT', - body: queryArg.templateGroup, - params: { - pretty: queryArg.pretty, - dryRun: queryArg.dryRun, - fieldManager: queryArg.fieldManager, - fieldValidation: queryArg.fieldValidation, - }, - }), - invalidatesTags: ['TemplateGroup'], - }), - updateTemplateGroupStatus: build.mutation({ - query: (queryArg) => ({ - url: `/templategroups/${queryArg.name}/status`, - method: 'PATCH', - body: queryArg.patch, - params: { - pretty: queryArg.pretty, - dryRun: queryArg.dryRun, - fieldManager: queryArg.fieldManager, - fieldValidation: queryArg.fieldValidation, - force: queryArg.force, - }, - }), - invalidatesTags: ['TemplateGroup'], - }), listTimeInterval: build.query({ query: (queryArg) => ({ url: `/timeintervals`, @@ -572,48 +455,10 @@ const injectedRtkApi = api }), invalidatesTags: ['TimeInterval'], }), - getTimeIntervalStatus: build.query({ - query: (queryArg) => ({ - url: `/timeintervals/${queryArg.name}/status`, - params: { - pretty: queryArg.pretty, - }, - }), - providesTags: ['TimeInterval'], - }), - replaceTimeIntervalStatus: build.mutation({ - query: (queryArg) => ({ - url: `/timeintervals/${queryArg.name}/status`, - method: 'PUT', - body: queryArg.timeInterval, - params: { - pretty: queryArg.pretty, - dryRun: queryArg.dryRun, - fieldManager: queryArg.fieldManager, - fieldValidation: queryArg.fieldValidation, - }, - }), - invalidatesTags: ['TimeInterval'], - }), - updateTimeIntervalStatus: build.mutation({ - query: (queryArg) => ({ - url: `/timeintervals/${queryArg.name}/status`, - method: 'PATCH', - body: queryArg.patch, - params: { - pretty: queryArg.pretty, - dryRun: queryArg.dryRun, - fieldManager: queryArg.fieldManager, - fieldValidation: queryArg.fieldValidation, - force: queryArg.force, - }, - }), - invalidatesTags: ['TimeInterval'], - }), }), overrideExisting: false, }); -export { injectedRtkApi as notificationsAPI }; +export { injectedRtkApi as generatedAPI }; export type GetApiResourcesApiResponse = /** status 200 OK */ ApiResourceList; export type GetApiResourcesApiArg = void; export type ListReceiverApiResponse = /** status 200 OK */ ReceiverList; @@ -781,43 +626,6 @@ export type UpdateReceiverApiArg = { force?: boolean; patch: Patch; }; -export type GetReceiverStatusApiResponse = /** status 200 OK */ Receiver; -export type GetReceiverStatusApiArg = { - /** name of the Receiver */ - name: string; - /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ - pretty?: string; -}; -export type ReplaceReceiverStatusApiResponse = /** status 200 OK */ Receiver | /** status 201 Created */ Receiver; -export type ReplaceReceiverStatusApiArg = { - /** name of the Receiver */ - name: string; - /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ - pretty?: string; - /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ - dryRun?: string; - /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */ - fieldManager?: string; - /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ - fieldValidation?: string; - receiver: Receiver; -}; -export type UpdateReceiverStatusApiResponse = /** status 200 OK */ Receiver | /** status 201 Created */ Receiver; -export type UpdateReceiverStatusApiArg = { - /** name of the Receiver */ - name: string; - /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ - pretty?: string; - /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ - dryRun?: string; - /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch). */ - fieldManager?: string; - /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ - fieldValidation?: string; - /** Force is going to "force" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests. */ - force?: boolean; - patch: Patch; -}; export type ListRoutingTreeApiResponse = /** status 200 OK */ RoutingTreeList; export type ListRoutingTreeApiArg = { /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ @@ -983,47 +791,6 @@ export type UpdateRoutingTreeApiArg = { force?: boolean; patch: Patch; }; -export type GetRoutingTreeStatusApiResponse = /** status 200 OK */ RoutingTree; -export type GetRoutingTreeStatusApiArg = { - /** name of the RoutingTree */ - name: string; - /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ - pretty?: string; -}; -export type ReplaceRoutingTreeStatusApiResponse = /** status 200 OK */ - | RoutingTree - | /** status 201 Created */ RoutingTree; -export type ReplaceRoutingTreeStatusApiArg = { - /** name of the RoutingTree */ - name: string; - /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ - pretty?: string; - /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ - dryRun?: string; - /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */ - fieldManager?: string; - /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ - fieldValidation?: string; - routingTree: RoutingTree; -}; -export type UpdateRoutingTreeStatusApiResponse = /** status 200 OK */ - | RoutingTree - | /** status 201 Created */ RoutingTree; -export type UpdateRoutingTreeStatusApiArg = { - /** name of the RoutingTree */ - name: string; - /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ - pretty?: string; - /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ - dryRun?: string; - /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch). */ - fieldManager?: string; - /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ - fieldValidation?: string; - /** Force is going to "force" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests. */ - force?: boolean; - patch: Patch; -}; export type ListTemplateGroupApiResponse = /** status 200 OK */ TemplateGroupList; export type ListTemplateGroupApiArg = { /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ @@ -1193,47 +960,6 @@ export type UpdateTemplateGroupApiArg = { force?: boolean; patch: Patch; }; -export type GetTemplateGroupStatusApiResponse = /** status 200 OK */ TemplateGroup; -export type GetTemplateGroupStatusApiArg = { - /** name of the TemplateGroup */ - name: string; - /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ - pretty?: string; -}; -export type ReplaceTemplateGroupStatusApiResponse = /** status 200 OK */ - | TemplateGroup - | /** status 201 Created */ TemplateGroup; -export type ReplaceTemplateGroupStatusApiArg = { - /** name of the TemplateGroup */ - name: string; - /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ - pretty?: string; - /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ - dryRun?: string; - /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */ - fieldManager?: string; - /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ - fieldValidation?: string; - templateGroup: TemplateGroup; -}; -export type UpdateTemplateGroupStatusApiResponse = /** status 200 OK */ - | TemplateGroup - | /** status 201 Created */ TemplateGroup; -export type UpdateTemplateGroupStatusApiArg = { - /** name of the TemplateGroup */ - name: string; - /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ - pretty?: string; - /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ - dryRun?: string; - /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch). */ - fieldManager?: string; - /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ - fieldValidation?: string; - /** Force is going to "force" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests. */ - force?: boolean; - patch: Patch; -}; export type ListTimeIntervalApiResponse = /** status 200 OK */ TimeIntervalList; export type ListTimeIntervalApiArg = { /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ @@ -1399,47 +1125,6 @@ export type UpdateTimeIntervalApiArg = { force?: boolean; patch: Patch; }; -export type GetTimeIntervalStatusApiResponse = /** status 200 OK */ TimeInterval; -export type GetTimeIntervalStatusApiArg = { - /** name of the TimeInterval */ - name: string; - /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ - pretty?: string; -}; -export type ReplaceTimeIntervalStatusApiResponse = /** status 200 OK */ - | TimeInterval - | /** status 201 Created */ TimeInterval; -export type ReplaceTimeIntervalStatusApiArg = { - /** name of the TimeInterval */ - name: string; - /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ - pretty?: string; - /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ - dryRun?: string; - /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */ - fieldManager?: string; - /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ - fieldValidation?: string; - timeInterval: TimeInterval; -}; -export type UpdateTimeIntervalStatusApiResponse = /** status 200 OK */ - | TimeInterval - | /** status 201 Created */ TimeInterval; -export type UpdateTimeIntervalStatusApiArg = { - /** name of the TimeInterval */ - name: string; - /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ - pretty?: string; - /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ - dryRun?: string; - /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch). */ - fieldManager?: string; - /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ - fieldValidation?: string; - /** Force is going to "force" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests. */ - force?: boolean; - patch: Patch; -}; export type ApiResource = { /** categories is a list of the grouped resources this resource belongs to (e.g. 'all') */ categories?: string[]; @@ -1572,34 +1257,6 @@ export type ReceiverSpec = { integrations: ReceiverIntegration[]; title: string; }; -export type ReceiverOperatorState = { - /** descriptiveState is an optional more descriptive state field which has no requirements on format */ - descriptiveState?: string; - /** details contains any extra information that is operator-specific */ - details?: { - [key: string]: { - [key: string]: any; - }; - }; - /** lastEvaluation is the ResourceVersion last evaluated */ - lastEvaluation: string; - /** state describes the state of the lastEvaluation. - It is limited to three possible states for machine evaluation. */ - state: 'success' | 'in_progress' | 'failed'; -}; -export type ReceiverStatus = { - /** additionalFields is reserved for future use */ - additionalFields?: { - [key: string]: { - [key: string]: any; - }; - }; - /** operatorStates is a map of operator ID to operator state evaluations. - Any operator which consumes this kind SHOULD add its state evaluation information to this field. */ - operatorStates?: { - [key: string]: ReceiverOperatorState; - }; -}; export type Receiver = { /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ apiVersion: string; @@ -1607,7 +1264,6 @@ export type Receiver = { kind: string; metadata: ObjectMeta; spec: ReceiverSpec; - status?: ReceiverStatus; }; export type ListMeta = { /** continue may be set if the user set a limit on the number of items returned, and indicates that the server has more data available. The value is opaque and may be used to issue another request to the endpoint that served this list to retrieve the next set of available objects. Continuing a consistent list may not be possible if the server configuration has changed or more than a few minutes have passed. The resourceVersion field returned when using this continue value will be identical to the value in the first response, unless you have received this token from an error message. */ @@ -1700,34 +1356,6 @@ export type RoutingTreeSpec = { defaults: RoutingTreeRouteDefaults; routes: RoutingTreeRoute[]; }; -export type RoutingTreeOperatorState = { - /** descriptiveState is an optional more descriptive state field which has no requirements on format */ - descriptiveState?: string; - /** details contains any extra information that is operator-specific */ - details?: { - [key: string]: { - [key: string]: any; - }; - }; - /** lastEvaluation is the ResourceVersion last evaluated */ - lastEvaluation: string; - /** state describes the state of the lastEvaluation. - It is limited to three possible states for machine evaluation. */ - state: 'success' | 'in_progress' | 'failed'; -}; -export type RoutingTreeStatus = { - /** additionalFields is reserved for future use */ - additionalFields?: { - [key: string]: { - [key: string]: any; - }; - }; - /** operatorStates is a map of operator ID to operator state evaluations. - Any operator which consumes this kind SHOULD add its state evaluation information to this field. */ - operatorStates?: { - [key: string]: RoutingTreeOperatorState; - }; -}; export type RoutingTree = { /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ apiVersion: string; @@ -1735,7 +1363,6 @@ export type RoutingTree = { kind: string; metadata: ObjectMeta; spec: RoutingTreeSpec; - status?: RoutingTreeStatus; }; export type RoutingTreeList = { /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ @@ -1745,38 +1372,12 @@ export type RoutingTreeList = { kind?: string; metadata: ListMeta; }; +export type TemplateGroupTemplateKind = 'grafana' | 'mimir'; export type TemplateGroupSpec = { content: string; + kind: TemplateGroupTemplateKind; title: string; }; -export type TemplateGroupOperatorState = { - /** descriptiveState is an optional more descriptive state field which has no requirements on format */ - descriptiveState?: string; - /** details contains any extra information that is operator-specific */ - details?: { - [key: string]: { - [key: string]: any; - }; - }; - /** lastEvaluation is the ResourceVersion last evaluated */ - lastEvaluation: string; - /** state describes the state of the lastEvaluation. - It is limited to three possible states for machine evaluation. */ - state: 'success' | 'in_progress' | 'failed'; -}; -export type TemplateGroupStatus = { - /** additionalFields is reserved for future use */ - additionalFields?: { - [key: string]: { - [key: string]: any; - }; - }; - /** operatorStates is a map of operator ID to operator state evaluations. - Any operator which consumes this kind SHOULD add its state evaluation information to this field. */ - operatorStates?: { - [key: string]: TemplateGroupOperatorState; - }; -}; export type TemplateGroup = { /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ apiVersion: string; @@ -1784,7 +1385,6 @@ export type TemplateGroup = { kind: string; metadata: ObjectMeta; spec: TemplateGroupSpec; - status?: TemplateGroupStatus; }; export type TemplateGroupList = { /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ @@ -1810,34 +1410,6 @@ export type TimeIntervalSpec = { name: string; time_intervals: TimeIntervalInterval[]; }; -export type TimeIntervalOperatorState = { - /** descriptiveState is an optional more descriptive state field which has no requirements on format */ - descriptiveState?: string; - /** details contains any extra information that is operator-specific */ - details?: { - [key: string]: { - [key: string]: any; - }; - }; - /** lastEvaluation is the ResourceVersion last evaluated */ - lastEvaluation: string; - /** state describes the state of the lastEvaluation. - It is limited to three possible states for machine evaluation. */ - state: 'success' | 'in_progress' | 'failed'; -}; -export type TimeIntervalStatus = { - /** additionalFields is reserved for future use */ - additionalFields?: { - [key: string]: { - [key: string]: any; - }; - }; - /** operatorStates is a map of operator ID to operator state evaluations. - Any operator which consumes this kind SHOULD add its state evaluation information to this field. */ - operatorStates?: { - [key: string]: TimeIntervalOperatorState; - }; -}; export type TimeInterval = { /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ apiVersion: string; @@ -1845,7 +1417,6 @@ export type TimeInterval = { kind: string; metadata: ObjectMeta; spec: TimeIntervalSpec; - status?: TimeIntervalStatus; }; export type TimeIntervalList = { /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ @@ -1855,3 +1426,43 @@ export type TimeIntervalList = { kind?: string; metadata: ListMeta; }; +export const { + useGetApiResourcesQuery, + useLazyGetApiResourcesQuery, + useListReceiverQuery, + useLazyListReceiverQuery, + useCreateReceiverMutation, + useDeletecollectionReceiverMutation, + useGetReceiverQuery, + useLazyGetReceiverQuery, + useReplaceReceiverMutation, + useDeleteReceiverMutation, + useUpdateReceiverMutation, + useListRoutingTreeQuery, + useLazyListRoutingTreeQuery, + useCreateRoutingTreeMutation, + useDeletecollectionRoutingTreeMutation, + useGetRoutingTreeQuery, + useLazyGetRoutingTreeQuery, + useReplaceRoutingTreeMutation, + useDeleteRoutingTreeMutation, + useUpdateRoutingTreeMutation, + useListTemplateGroupQuery, + useLazyListTemplateGroupQuery, + useCreateTemplateGroupMutation, + useDeletecollectionTemplateGroupMutation, + useGetTemplateGroupQuery, + useLazyGetTemplateGroupQuery, + useReplaceTemplateGroupMutation, + useDeleteTemplateGroupMutation, + useUpdateTemplateGroupMutation, + useListTimeIntervalQuery, + useLazyListTimeIntervalQuery, + useCreateTimeIntervalMutation, + useDeletecollectionTimeIntervalMutation, + useGetTimeIntervalQuery, + useLazyGetTimeIntervalQuery, + useReplaceTimeIntervalMutation, + useDeleteTimeIntervalMutation, + useUpdateTimeIntervalMutation, +} = injectedRtkApi; diff --git a/packages/grafana-api-clients/src/clients/rtkq/notifications.alerting/v0alpha1/index.ts b/packages/grafana-api-clients/src/clients/rtkq/notifications.alerting/v0alpha1/index.ts new file mode 100644 index 00000000000..d80fd6d553a --- /dev/null +++ b/packages/grafana-api-clients/src/clients/rtkq/notifications.alerting/v0alpha1/index.ts @@ -0,0 +1,5 @@ +export { BASE_URL, API_GROUP, API_VERSION } from './baseAPI'; +import { generatedAPI as rawAPI } from './endpoints.gen'; + +export * from './endpoints.gen'; +export const generatedAPI = rawAPI.enhanceEndpoints({}); diff --git a/packages/grafana-api-clients/src/clients/rtkq/preferences/user/endpoints.gen.ts b/packages/grafana-api-clients/src/clients/rtkq/preferences/user/endpoints.gen.ts index 71107ce1072..93b5259f144 100644 --- a/packages/grafana-api-clients/src/clients/rtkq/preferences/user/endpoints.gen.ts +++ b/packages/grafana-api-clients/src/clients/rtkq/preferences/user/endpoints.gen.ts @@ -86,7 +86,8 @@ export type PatchPrefsCmd = { queryHistory?: QueryHistoryPreference; regionalFormat?: string; theme?: 'light' | 'dark'; - timezone?: 'utc' | 'browser'; + /** Any IANA timezone string (e.g. America/New_York), 'utc', 'browser', or empty string */ + timezone?: string; weekStart?: string; }; export type UpdatePrefsCmd = { @@ -99,7 +100,8 @@ export type UpdatePrefsCmd = { queryHistory?: QueryHistoryPreference; regionalFormat?: string; theme?: 'light' | 'dark' | 'system'; - timezone?: 'utc' | 'browser'; + /** Any IANA timezone string (e.g. America/New_York), 'utc', 'browser', or empty string */ + timezone?: string; weekStart?: string; }; export const { 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 be22503f3bf..40d4299a1a0 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 @@ -122,6 +122,10 @@ const injectedRtkApi = api }), invalidatesTags: ['Connection'], }), + getConnectionRepositories: build.query({ + query: (queryArg) => ({ url: `/connections/${queryArg.name}/repositories` }), + providesTags: ['Connection'], + }), getConnectionStatus: build.query({ query: (queryArg) => ({ url: `/connections/${queryArg.name}/status`, @@ -726,6 +730,18 @@ export type UpdateConnectionApiArg = { force?: boolean; patch: Patch; }; +export type GetConnectionRepositoriesApiResponse = /** status 200 OK */ { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + items: any[]; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + metadata?: any; +}; +export type GetConnectionRepositoriesApiArg = { + /** name of the ExternalRepositoryList */ + name: string; +}; export type GetConnectionStatusApiResponse = /** status 200 OK */ Connection; export type GetConnectionStatusApiArg = { /** name of the Connection */ @@ -1436,7 +1452,7 @@ export type ConnectionSecure = { /** PrivateKey is the reference to the private key used for GitHub App authentication. This value is stored securely and cannot be read back */ privateKey?: InlineSecureValue; /** Token is the reference of the token used to act as the Connection. This value is stored securely and cannot be read back */ - webhook?: InlineSecureValue; + token?: InlineSecureValue; }; export type BitbucketConnectionConfig = { /** App client ID */ @@ -2079,6 +2095,8 @@ export const { useReplaceConnectionMutation, useDeleteConnectionMutation, useUpdateConnectionMutation, + useGetConnectionRepositoriesQuery, + useLazyGetConnectionRepositoriesQuery, useGetConnectionStatusQuery, useLazyGetConnectionStatusQuery, useReplaceConnectionStatusMutation, diff --git a/packages/grafana-api-clients/src/clients/rtkq/rules.alerting/v0alpha1/baseAPI.ts b/packages/grafana-api-clients/src/clients/rtkq/rules.alerting/v0alpha1/baseAPI.ts new file mode 100644 index 00000000000..34762fa1b86 --- /dev/null +++ b/packages/grafana-api-clients/src/clients/rtkq/rules.alerting/v0alpha1/baseAPI.ts @@ -0,0 +1,16 @@ +import { createApi } from '@reduxjs/toolkit/query/react'; + +import { getAPIBaseURL } from '../../../../utils/utils'; +import { createBaseQuery } from '../../createBaseQuery'; + +export const API_GROUP = 'rules.alerting.grafana.app' as const; +export const API_VERSION = 'v0alpha1' as const; +export const BASE_URL = getAPIBaseURL(API_GROUP, API_VERSION); + +export const api = createApi({ + reducerPath: 'rulesAlertingAPIv0alpha1', + baseQuery: createBaseQuery({ + baseURL: BASE_URL, + }), + endpoints: () => ({}), +}); diff --git a/packages/grafana-alerting/src/grafana/api/rules/v0alpha1/rules.api.gen.ts b/packages/grafana-api-clients/src/clients/rtkq/rules.alerting/v0alpha1/endpoints.gen.ts similarity index 98% rename from packages/grafana-alerting/src/grafana/api/rules/v0alpha1/rules.api.gen.ts rename to packages/grafana-api-clients/src/clients/rtkq/rules.alerting/v0alpha1/endpoints.gen.ts index 361362d5699..cfd62d68def 100644 --- a/packages/grafana-alerting/src/grafana/api/rules/v0alpha1/rules.api.gen.ts +++ b/packages/grafana-api-clients/src/clients/rtkq/rules.alerting/v0alpha1/endpoints.gen.ts @@ -1,4 +1,4 @@ -import { api } from './api'; +import { api } from './baseAPI'; export const addTagTypes = ['API Discovery', 'AlertRule', 'RecordingRule'] as const; const injectedRtkApi = api .enhanceEndpoints({ @@ -7,7 +7,7 @@ const injectedRtkApi = api .injectEndpoints({ endpoints: (build) => ({ getApiResources: build.query({ - query: () => ({ url: `/apis/rules.alerting.grafana.app/v0alpha1/` }), + query: () => ({ url: `/` }), providesTags: ['API Discovery'], }), listAlertRule: build.query({ @@ -313,7 +313,7 @@ const injectedRtkApi = api }), overrideExisting: false, }); -export { injectedRtkApi as rulesAPI }; +export { injectedRtkApi as generatedAPI }; export type GetApiResourcesApiResponse = /** status 200 OK */ ApiResourceList; export type GetApiResourcesApiArg = void; export type ListAlertRuleApiResponse = /** status 200 OK */ AlertRuleList; @@ -1085,3 +1085,33 @@ export type RecordingRuleList = { kind?: string; metadata: ListMeta; }; +export const { + useGetApiResourcesQuery, + useLazyGetApiResourcesQuery, + useListAlertRuleQuery, + useLazyListAlertRuleQuery, + useCreateAlertRuleMutation, + useDeletecollectionAlertRuleMutation, + useGetAlertRuleQuery, + useLazyGetAlertRuleQuery, + useReplaceAlertRuleMutation, + useDeleteAlertRuleMutation, + useUpdateAlertRuleMutation, + useGetAlertRuleStatusQuery, + useLazyGetAlertRuleStatusQuery, + useReplaceAlertRuleStatusMutation, + useUpdateAlertRuleStatusMutation, + useListRecordingRuleQuery, + useLazyListRecordingRuleQuery, + useCreateRecordingRuleMutation, + useDeletecollectionRecordingRuleMutation, + useGetRecordingRuleQuery, + useLazyGetRecordingRuleQuery, + useReplaceRecordingRuleMutation, + useDeleteRecordingRuleMutation, + useUpdateRecordingRuleMutation, + useGetRecordingRuleStatusQuery, + useLazyGetRecordingRuleStatusQuery, + useReplaceRecordingRuleStatusMutation, + useUpdateRecordingRuleStatusMutation, +} = injectedRtkApi; diff --git a/packages/grafana-api-clients/src/clients/rtkq/rules.alerting/v0alpha1/index.ts b/packages/grafana-api-clients/src/clients/rtkq/rules.alerting/v0alpha1/index.ts new file mode 100644 index 00000000000..d80fd6d553a --- /dev/null +++ b/packages/grafana-api-clients/src/clients/rtkq/rules.alerting/v0alpha1/index.ts @@ -0,0 +1,5 @@ +export { BASE_URL, API_GROUP, API_VERSION } from './baseAPI'; +import { generatedAPI as rawAPI } from './endpoints.gen'; + +export * from './endpoints.gen'; +export const generatedAPI = rawAPI.enhanceEndpoints({}); diff --git a/packages/grafana-api-clients/src/index.ts b/packages/grafana-api-clients/src/index.ts index 96e34be4f87..3fb772884a1 100644 --- a/packages/grafana-api-clients/src/index.ts +++ b/packages/grafana-api-clients/src/index.ts @@ -1 +1,4 @@ export { getAPINamespace, getAPIBaseURL, normalizeError, handleRequestError } from './utils/utils'; + +/* @TODO figure out how to automatically set the MockBackendSrv when consumers of this package write tests using the exported clients */ +export { MockBackendSrv } from './utils/backendSrv.mock'; diff --git a/packages/grafana-api-clients/src/scripts/generate-rtk-apis.ts b/packages/grafana-api-clients/src/scripts/generate-rtk-apis.ts index a353b4e311f..8610da06920 100644 --- a/packages/grafana-api-clients/src/scripts/generate-rtk-apis.ts +++ b/packages/grafana-api-clients/src/scripts/generate-rtk-apis.ts @@ -108,7 +108,10 @@ const config: ConfigFile = { ...createAPIConfig('preferences', 'v1alpha1'), ...createAPIConfig('provisioning', 'v0alpha1'), ...createAPIConfig('shorturl', 'v1beta1'), + ...createAPIConfig('notifications.alerting', 'v0alpha1'), + ...createAPIConfig('rules.alerting', 'v0alpha1'), ...createAPIConfig('historian.alerting', 'v0alpha1'), + ...createAPIConfig('logsdrilldown', 'v1beta1'), ...createAPIConfig('logsdrilldown', 'v1alpha1'), // PLOP_INJECT_API_CLIENT - Used by the API client generator }, diff --git a/packages/grafana-api-clients/src/utils/backendSrv.mock.ts b/packages/grafana-api-clients/src/utils/backendSrv.mock.ts new file mode 100644 index 00000000000..ae7f1129913 --- /dev/null +++ b/packages/grafana-api-clients/src/utils/backendSrv.mock.ts @@ -0,0 +1,46 @@ +import { Observable } from 'rxjs'; +import { fromFetch } from 'rxjs/fetch'; + +import { BackendSrv, BackendSrvRequest, FetchResponse } from '@grafana/runtime'; + +/** + * Minimal mock implementation of BackendSrv for testing. + * Only implements the fetch() method which is used by RTKQ. + * HTTP requests are intercepted by MSW in tests. + */ +export class MockBackendSrv implements Partial { + fetch(options: BackendSrvRequest): Observable> { + const init: RequestInit = { + method: options.method || 'GET', + headers: options.headers, + body: options.data ? JSON.stringify(options.data) : undefined, + credentials: options.credentials, + signal: options.abortSignal, + }; + + return new Observable((observer) => { + fromFetch(options.url, init).subscribe({ + next: async (response) => { + try { + const data = await response.json(); + observer.next({ + data, + status: response.status, + statusText: response.statusText, + ok: response.ok, + headers: response.headers, + redirected: response.redirected, + type: response.type, + url: response.url, + config: options, + }); + observer.complete(); + } catch (error) { + observer.error(error); + } + }, + error: (error) => observer.error(error), + }); + }); + } +} diff --git a/packages/grafana-data/package.json b/packages/grafana-data/package.json index df595973cca..384666ea7f8 100644 --- a/packages/grafana-data/package.json +++ b/packages/grafana-data/package.json @@ -47,11 +47,12 @@ "LICENSE_APACHE2" ], "scripts": { - "build": "tsc -p ./tsconfig.build.json && rollup -c rollup.config.ts --configPlugin esbuild", + "build": "yarn themes-schema && 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 && node ../../scripts/prepare-npm-package.js", - "postpack": "mv package.json.bak package.json" + "postpack": "mv package.json.bak package.json", + "themes-schema": "tsx ./src/themes/scripts/generateSchema.ts" }, "dependencies": { "@braintree/sanitize-url": "7.0.1", @@ -81,10 +82,12 @@ "tinycolor2": "1.6.0", "tslib": "2.8.1", "uplot": "1.6.32", - "xss": "^1.0.14" + "xss": "^1.0.14", + "zod": "^4.3.0" }, "devDependencies": { "@grafana/scenes": "6.38.0", + "@rollup/plugin-json": "6.1.0", "@rollup/plugin-node-resolve": "16.0.1", "@testing-library/react": "16.3.0", "@types/history": "4.7.11", @@ -101,6 +104,7 @@ "rollup": "^4.22.4", "rollup-plugin-esbuild": "6.2.1", "rollup-plugin-node-externals": "^8.0.0", + "tsx": "^4.21.0", "typescript": "5.9.2" }, "peerDependencies": { diff --git a/packages/grafana-data/rollup.config.ts b/packages/grafana-data/rollup.config.ts index 87008ddc45f..0c40d731724 100644 --- a/packages/grafana-data/rollup.config.ts +++ b/packages/grafana-data/rollup.config.ts @@ -1,3 +1,4 @@ +import json from '@rollup/plugin-json'; import { createRequire } from 'node:module'; import { entryPoint, plugins, esmOutput, cjsOutput } from '../rollup.config.parts'; @@ -8,13 +9,13 @@ const pkg = rq('./package.json'); export default [ { input: entryPoint, - plugins, + plugins: [...plugins, json()], output: [cjsOutput(pkg, 'grafana-data'), esmOutput(pkg, 'grafana-data')], treeshake: false, }, { input: 'src/unstable.ts', - plugins, + plugins: [...plugins, json()], output: [cjsOutput(pkg, 'grafana-data'), esmOutput(pkg, 'grafana-data')], treeshake: false, }, diff --git a/packages/grafana-data/src/datetime/datemath.test.ts b/packages/grafana-data/src/datetime/datemath.test.ts index f53bbe8e6e5..3abf59ea43f 100644 --- a/packages/grafana-data/src/datetime/datemath.test.ts +++ b/packages/grafana-data/src/datetime/datemath.test.ts @@ -165,9 +165,17 @@ describe('DateMath', () => { expect(date!.valueOf()).toEqual(dateTime([2014, 1, 3]).valueOf()); }); - it('should handle multiple math expressions', () => { - const date = dateMath.parseDateMath('-2d-6h', dateTime([2014, 1, 5])); - expect(date!.valueOf()).toEqual(dateTime([2014, 1, 2, 18]).valueOf()); + it.each([ + ['-2d-6h', [2014, 1, 5], [2014, 1, 2, 18]], + ['-30m-2d', [2014, 1, 5], [2014, 1, 2, 23, 30]], + ['-2d-1d', [2014, 1, 5], [2014, 1, 2]], + ['-1h-30m', [2014, 1, 5, 12, 0], [2014, 1, 5, 10, 30]], + ['-1d-1h-30m', [2014, 1, 5, 12, 0], [2014, 1, 4, 10, 30]], + ['+1d-6h', [2014, 1, 5], [2014, 1, 5, 18]], + ['-1w-1d', [2014, 1, 14], [2014, 1, 6]], + ])('should handle multiple math expressions: %s', (expression, inputDate, expectedDate) => { + const date = dateMath.parseDateMath(expression, dateTime(inputDate)); + expect(date!.valueOf()).toEqual(dateTime(expectedDate).valueOf()); }); it('should return false when invalid expression', () => { diff --git a/packages/grafana-data/src/field/fieldDisplay.test.ts b/packages/grafana-data/src/field/fieldDisplay.test.ts index 718c0e54430..5ec3ed7ba4f 100644 --- a/packages/grafana-data/src/field/fieldDisplay.test.ts +++ b/packages/grafana-data/src/field/fieldDisplay.test.ts @@ -3,11 +3,18 @@ import { merge } from 'lodash'; import { toDataFrame } from '../dataframe/processDataFrame'; import { createTheme } from '../themes/createTheme'; import { ReducerID } from '../transformations/fieldReducer'; +import { FieldType } from '../types/dataFrame'; import { FieldConfigPropertyItem } from '../types/fieldOverrides'; import { MappingType, SpecialValueMatch, ValueMapping } from '../types/valueMapping'; import { getDisplayProcessor } from './displayProcessor'; -import { fixCellTemplateExpressions, getFieldDisplayValues, GetFieldDisplayValuesOptions } from './fieldDisplay'; +import { + FieldSparkline, + fixCellTemplateExpressions, + getFieldDisplayValues, + GetFieldDisplayValuesOptions, + getSparklineHighlight, +} from './fieldDisplay'; import { standardFieldConfigEditorRegistry } from './standardFieldConfigEditorRegistry'; describe('FieldDisplay', () => { @@ -556,3 +563,71 @@ describe('fixCellTemplateExpressions', () => { ); }); }); + +describe('getSparklineHighlight', () => { + const sparkline: FieldSparkline = { + y: { name: 'A', type: FieldType.number, values: [null, 2, 3, 4, 10, 8, 8, 8, 9, null], config: {} }, + }; + + it.each([ + { + calc: ReducerID.last, + expected: { + type: 'point', + xIdx: 9, + }, + }, + { + calc: ReducerID.max, + expected: { + type: 'point', + xIdx: 4, + }, + }, + { + calc: ReducerID.min, + expected: { + type: 'point', + xIdx: 1, + }, + }, + { + calc: ReducerID.first, + expected: { + type: 'point', + xIdx: 0, + }, + }, + { + calc: ReducerID.firstNotNull, + expected: { + type: 'point', + xIdx: 1, + }, + }, + { + calc: ReducerID.lastNotNull, + expected: { + type: 'point', + xIdx: 8, + }, + }, + { + calc: ReducerID.mean, + expected: { + type: 'line', + y: 6.5, + }, + }, + { + calc: ReducerID.median, + expected: { + type: 'line', + y: 8, + }, + }, + ])('it calculates the correct highlight for the $calc', ({ calc, expected }) => { + const result = getSparklineHighlight(sparkline, calc); + expect(result).toEqual(expected); + }); +}); diff --git a/packages/grafana-data/src/field/fieldDisplay.ts b/packages/grafana-data/src/field/fieldDisplay.ts index 3d82f571926..3496f419395 100644 --- a/packages/grafana-data/src/field/fieldDisplay.ts +++ b/packages/grafana-data/src/field/fieldDisplay.ts @@ -3,7 +3,7 @@ import { isEmpty } from 'lodash'; import { DataFrameView } from '../dataframe/DataFrameView'; import { getTimeField } from '../dataframe/processDataFrame'; import { GrafanaTheme2 } from '../themes/types'; -import { reduceField, ReducerID } from '../transformations/fieldReducer'; +import { isReducerID, reduceField, ReducerID } from '../transformations/fieldReducer'; import { getFieldMatcher } from '../transformations/matchers'; import { FieldMatcherID } from '../transformations/matchers/ids'; import { ScopedVars } from '../types/ScopedVars'; @@ -43,6 +43,7 @@ export interface FieldSparkline { x?: Field; // if this does not exist, use the index timeRange?: TimeRange; // Optionally force an absolute time highlightIndex?: number; + highlightLine?: number; } export interface FieldDisplay { @@ -72,6 +73,76 @@ export interface GetFieldDisplayValuesOptions { export const DEFAULT_FIELD_DISPLAY_VALUES_LIMIT = 25; +interface SparklineHighlightPoint { + type: 'point'; + xIdx: number; +} + +interface SparklineHighlightLine { + type: 'line'; + y: number; +} + +export function getSparklineHighlight( + sparkline: FieldSparkline, + calc: ReducerID +): SparklineHighlightPoint | SparklineHighlightLine | void { + switch (calc) { + case ReducerID.last: + return { type: 'point', xIdx: sparkline.y.values.length - 1 }; + case ReducerID.first: + return { type: 'point', xIdx: 0 }; + case ReducerID.lastNotNull: { + for (let k = sparkline.y.values.length - 1; k >= 0; k--) { + const v = sparkline.y.values[k]; + if (v !== null && v !== undefined && !Number.isNaN(v)) { + return { type: 'point', xIdx: k }; + } + } + return; + } + case ReducerID.firstNotNull: { + for (let k = 0; k < sparkline.y.values.length; k++) { + const v = sparkline.y.values[k]; + if (v !== null && v !== undefined && !Number.isNaN(v)) { + return { type: 'point', xIdx: k }; + } + } + return; + } + case ReducerID.min: { + let minIdx = -1; + let prevMin = Infinity; + for (let k = 0; k < sparkline.y.values.length; k++) { + const v = sparkline.y.values[k]; + if (v !== null && v !== undefined && !Number.isNaN(v) && v < prevMin) { + prevMin = v; + minIdx = k; + } + } + return minIdx >= 0 ? { type: 'point', xIdx: minIdx } : undefined; + } + case ReducerID.max: { + let maxIdx = -1; + let prevMax = -Infinity; + for (let k = 0; k < sparkline.y.values.length; k++) { + const v = sparkline.y.values[k]; + if (v !== null && v !== undefined && !Number.isNaN(v) && v > prevMax) { + prevMax = v; + maxIdx = k; + } + } + return maxIdx >= 0 ? { type: 'point', xIdx: maxIdx } : undefined; + } + case ReducerID.mean: + return { type: 'line', y: reduceField({ field: sparkline.y, reducers: [ReducerID.mean] }).mean }; + case ReducerID.median: + return { type: 'line', y: reduceField({ field: sparkline.y, reducers: [ReducerID.median] }).median }; + default: + return; + } +} + export const getFieldDisplayValues = (options: GetFieldDisplayValuesOptions): FieldDisplay[] => { const { replaceVariables, reduceOptions, timeZone, theme } = options; const calcs = reduceOptions.calcs.length ? reduceOptions.calcs : [ReducerID.last]; @@ -190,62 +261,16 @@ export const getFieldDisplayValues = (options: GetFieldDisplayValuesOptions): Fi y: dataFrame.fields[i], x: timeField, }; - let highlightIdx: number | undefined = (() => { - switch (calc) { - case ReducerID.last: - return sparkline.y.values.length - 1; - case ReducerID.first: - return 0; - // TODO: #112977 enable more reducers for highlight index - // case ReducerID.lastNotNull: { - // for (let k = sparkline.y.values.length - 1; k >= 0; k--) { - // const v = sparkline.y.values[k]; - // if (v !== null && v !== undefined && !Number.isNaN(v)) { - // return k; - // } - // } - // return; - // } - // case ReducerID.firstNotNull: { - // for (let k = 0; k < sparkline.y.values.length; k++) { - // const v = sparkline.y.values[k]; - // if (v !== null && v !== undefined && !Number.isNaN(v)) { - // return k; - // } - // } - // return; - // } - // case ReducerID.min: { - // let minIdx = -1; - // let prevMin = Infinity; - // for (let k = 0; k < sparkline.y.values.length; k++) { - // const v = sparkline.y.values[k]; - // if (v !== null && v !== undefined && !Number.isNaN(v) && v < prevMin) { - // prevMin = v; - // minIdx = k; - // } - // } - // return minIdx >= 0 ? minIdx : undefined; - // } - // case ReducerID.max: { - // let maxIdx = -1; - // let prevMax = -Infinity; - // for (let k = 0; k < sparkline.y.values.length; k++) { - // const v = sparkline.y.values[k]; - // if (v !== null && v !== undefined && !Number.isNaN(v) && v > prevMax) { - // prevMax = v; - // maxIdx = k; - // } - // } - // return maxIdx >= 0 ? maxIdx : undefined; - // } - default: - return; + if (isReducerID(calc)) { + const sparklineHighlight = getSparklineHighlight(sparkline, calc); + switch (sparklineHighlight?.type) { + case 'point': + sparkline.highlightIndex = sparklineHighlight.xIdx; + break; + case 'line': + sparkline.highlightLine = sparklineHighlight.y; + break; } - })(); - - if (typeof highlightIdx === 'number') { - sparkline.highlightIndex = highlightIdx; } } diff --git a/packages/grafana-data/src/field/fieldOverrides.test.ts b/packages/grafana-data/src/field/fieldOverrides.test.ts index 767da439543..b0aa271be3f 100644 --- a/packages/grafana-data/src/field/fieldOverrides.test.ts +++ b/packages/grafana-data/src/field/fieldOverrides.test.ts @@ -9,6 +9,7 @@ import { FieldColorModeId } from '../types/fieldColor'; import { FieldConfigPropertyItem, FieldConfigSource } from '../types/fieldOverrides'; import { InterpolateFunction } from '../types/panel'; import { ThresholdsMode } from '../types/thresholds'; +import { MappingType } from '../types/valueMapping'; import { Registry } from '../utils/Registry'; import { locationUtil } from '../utils/location'; import { mockStandardProperties } from '../utils/tests/mockStandardProperties'; @@ -999,6 +1000,45 @@ describe('setDynamicConfigValue', () => { expect(config.custom.property3).toEqual({}); expect(config.displayName).toBeUndefined(); }); + + it('works correctly with multiple value mappings in the same override', () => { + const config: FieldConfig = { + mappings: [{ type: MappingType.ValueToText, options: { existing: { text: 'existing' } } }], + }; + + setDynamicConfigValue( + config, + { + id: 'mappings', + value: [{ type: MappingType.ValueToText, options: { first: { text: 'first' } } }], + }, + { + fieldConfigRegistry: customFieldRegistry, + data: [], + field: { type: FieldType.number } as Field, + dataFrameIndex: 0, + } + ); + + setDynamicConfigValue( + config, + { + id: 'mappings', + value: [{ type: MappingType.ValueToText, options: { second: { text: 'second' } } }], + }, + { + fieldConfigRegistry: customFieldRegistry, + data: [], + field: { type: FieldType.number } as Field, + dataFrameIndex: 0, + } + ); + + expect(config.mappings).toHaveLength(3); + expect(config.mappings![0]).toEqual({ type: MappingType.ValueToText, options: { existing: { text: 'existing' } } }); + expect(config.mappings![1]).toEqual({ type: MappingType.ValueToText, options: { first: { text: 'first' } } }); + expect(config.mappings![2]).toEqual({ type: MappingType.ValueToText, options: { second: { text: 'second' } } }); + }); }); describe('getLinksSupplier', () => { diff --git a/packages/grafana-data/src/field/fieldOverrides.ts b/packages/grafana-data/src/field/fieldOverrides.ts index 8b345036c64..bf56f811106 100644 --- a/packages/grafana-data/src/field/fieldOverrides.ts +++ b/packages/grafana-data/src/field/fieldOverrides.ts @@ -341,7 +341,7 @@ export function setDynamicConfigValue(config: FieldConfig, value: DynamicConfigV return; } - const val = item.process(value.value, context, item.settings); + let val = item.process(value.value, context, item.settings); const remove = val === undefined || val === null; @@ -352,6 +352,15 @@ export function setDynamicConfigValue(config: FieldConfig, value: DynamicConfigV unset(config, item.path); } } else { + // Merge arrays (e.g. mappings) when multiple overrides target the same field + if (Array.isArray(val)) { + const existingValue = item.isCustom ? get(config.custom, item.path) : get(config, item.path); + + if (Array.isArray(existingValue)) { + val = [...existingValue, ...val]; + } + } + if (item.isCustom) { if (!config.custom) { config.custom = {}; diff --git a/packages/grafana-data/src/internal/index.ts b/packages/grafana-data/src/internal/index.ts index e2dab753baa..1b1e3c64a7d 100644 --- a/packages/grafana-data/src/internal/index.ts +++ b/packages/grafana-data/src/internal/index.ts @@ -106,3 +106,4 @@ export { findNumericFieldMinMax } from '../field/fieldOverrides'; export { type PanelOptionsSupplier } from '../panel/PanelPlugin'; export { sanitize, sanitizeUrl } from '../text/sanitize'; export { type NestedValueAccess, type NestedPanelOptions, isNestedPanelOptions } from '../utils/OptionsUIBuilders'; +export { NewThemeOptionsSchema } from '../themes/createTheme'; diff --git a/packages/grafana-data/src/themes/createColors.ts b/packages/grafana-data/src/themes/createColors.ts index 09b94fd3b3e..ee7beab02d6 100644 --- a/packages/grafana-data/src/themes/createColors.ts +++ b/packages/grafana-data/src/themes/createColors.ts @@ -1,83 +1,103 @@ import { merge } from 'lodash'; +import { z } from 'zod'; import { alpha, darken, emphasize, getContrastRatio, lighten } from './colorManipulator'; import { palette } from './palette'; -import { DeepPartial, ThemeRichColor } from './types'; +import { DeepRequired, ThemeRichColor, ThemeRichColorInputSchema } from './types'; +const ThemeColorsModeSchema = z.enum(['light', 'dark']); /** @internal */ -export type ThemeColorsMode = 'light' | 'dark'; +export type ThemeColorsMode = z.infer; +const createThemeColorsBaseSchema = (color: TColor) => + z + .object({ + mode: ThemeColorsModeSchema, + + primary: color, + secondary: color, + info: color, + error: color, + success: color, + warning: color, + + text: z.object({ + primary: z.string().optional(), + secondary: z.string().optional(), + disabled: z.string().optional(), + link: z.string().optional(), + /** Used for auto white or dark text on colored backgrounds */ + maxContrast: z.string().optional(), + }), + + background: z.object({ + /** Dashboard and body background */ + canvas: z.string().optional(), + /** Primary content pane background (panels etc) */ + primary: z.string().optional(), + /** Cards and elements that need to stand out on the primary background */ + secondary: z.string().optional(), + /** + * For popovers and menu backgrounds. This is the same color as primary in most light themes but in dark + * themes it has a brighter shade to help give it contrast against the primary background. + **/ + elevated: z.string().optional(), + }), + + border: z.object({ + weak: z.string().optional(), + medium: z.string().optional(), + strong: z.string().optional(), + }), + + gradients: z.object({ + brandVertical: z.string().optional(), + brandHorizontal: z.string().optional(), + }), + + action: z.object({ + /** Used for selected menu item / select option */ + selected: z.string().optional(), + /** + * @alpha (Do not use from plugins) + * Used for selected items when background only change is not enough (Currently only used for FilterPill) + **/ + selectedBorder: z.string().optional(), + /** Used for hovered menu item / select option */ + hover: z.string().optional(), + /** Used for button/colored background hover opacity */ + hoverOpacity: z.number().optional(), + /** Used focused menu item / select option */ + focus: z.string().optional(), + /** Used for disabled buttons and inputs */ + disabledBackground: z.string().optional(), + /** Disabled text */ + disabledText: z.string().optional(), + /** Disablerd opacity */ + disabledOpacity: z.number().optional(), + }), + + hoverFactor: z.number(), + contrastThreshold: z.number(), + tonalOffset: z.number(), + }) + .partial(); + +// Need to override the zod type to include the generic properly /** @internal */ -export interface ThemeColorsBase { - mode: ThemeColorsMode; - +export type ThemeColorsBase = DeepRequired< + Omit< + z.infer>, + 'primary' | 'secondary' | 'info' | 'error' | 'success' | 'warning' + > +> & { primary: TColor; secondary: TColor; info: TColor; error: TColor; success: TColor; warning: TColor; - - text: { - primary: string; - secondary: string; - disabled: string; - link: string; - /** Used for auto white or dark text on colored backgrounds */ - maxContrast: string; - }; - - background: { - /** Dashboard and body background */ - canvas: string; - /** Primary content pane background (panels etc) */ - primary: string; - /** Cards and elements that need to stand out on the primary background */ - secondary: string; - /** - * For popovers and menu backgrounds. This is the same color as primary in most light themes but in dark - * themes it has a brighter shade to help give it contrast against the primary background. - **/ - elevated: string; - }; - - border: { - weak: string; - medium: string; - strong: string; - }; - - gradients: { - brandVertical: string; - brandHorizontal: string; - }; - - action: { - /** Used for selected menu item / select option */ - selected: string; - /** - * @alpha (Do not use from plugins) - * Used for selected items when background only change is not enough (Currently only used for FilterPill) - **/ - selectedBorder: string; - /** Used for hovered menu item / select option */ - hover: string; - /** Used for button/colored background hover opacity */ - hoverOpacity: number; - /** Used focused menu item / select option */ - focus: string; - /** Used for disabled buttons and inputs */ - disabledBackground: string; - /** Disabled text */ - disabledText: string; - /** Disablerd opacity */ - disabledOpacity: number; - }; - - hoverFactor: number; - contrastThreshold: number; - tonalOffset: number; -} +}; export interface ThemeHoverStrengh {} @@ -89,8 +109,10 @@ export interface ThemeColors extends ThemeColorsBase { emphasize(color: string, amount?: number): string; } +export const ThemeColorsInputSchema = createThemeColorsBaseSchema(ThemeRichColorInputSchema); + /** @internal */ -export type ThemeColorsInput = DeepPartial>; +export type ThemeColorsInput = z.infer; class DarkColors implements ThemeColorsBase> { mode: ThemeColorsMode = 'dark'; diff --git a/packages/grafana-data/src/themes/createShape.ts b/packages/grafana-data/src/themes/createShape.ts index 42291fb78d0..f454eda6861 100644 --- a/packages/grafana-data/src/themes/createShape.ts +++ b/packages/grafana-data/src/themes/createShape.ts @@ -1,3 +1,5 @@ +import { z } from 'zod'; + /** @beta */ export interface ThemeShape { /** @@ -34,9 +36,12 @@ export interface Radii { } /** @internal */ -export interface ThemeShapeInput { - borderRadius?: number; -} +export const ThemeShapeInputSchema = z.object({ + borderRadius: z.int().nonnegative().optional(), +}); + +/** @internal */ +export type ThemeShapeInput = z.infer; export function createShape(options: ThemeShapeInput): ThemeShape { const baseBorderRadius = options.borderRadius ?? 6; diff --git a/packages/grafana-data/src/themes/createSpacing.ts b/packages/grafana-data/src/themes/createSpacing.ts index 2fa047b3e68..1ba51c61917 100644 --- a/packages/grafana-data/src/themes/createSpacing.ts +++ b/packages/grafana-data/src/themes/createSpacing.ts @@ -1,11 +1,15 @@ // Code based on Material UI // The MIT License (MIT) // Copyright (c) 2014 Call-Em-All +import { z } from 'zod'; /** @internal */ -export type ThemeSpacingOptions = { - gridSize?: number; -}; +export const ThemeSpacingOptionsSchema = z.object({ + gridSize: z.int().positive().optional(), +}); + +/** @internal */ +export type ThemeSpacingOptions = z.infer; /** @internal */ export type ThemeSpacingArgument = number | string; diff --git a/packages/grafana-data/src/themes/createTheme.ts b/packages/grafana-data/src/themes/createTheme.ts index fd4d8080a4e..a4fa773cf52 100644 --- a/packages/grafana-data/src/themes/createTheme.ts +++ b/packages/grafana-data/src/themes/createTheme.ts @@ -1,28 +1,37 @@ +import * as z from 'zod'; + import { createBreakpoints } from './breakpoints'; -import { createColors, ThemeColorsInput } from './createColors'; +import { createColors, ThemeColorsInputSchema } from './createColors'; import { createComponents } from './createComponents'; import { createShadows } from './createShadows'; -import { createShape, ThemeShapeInput } from './createShape'; -import { createSpacing, ThemeSpacingOptions } from './createSpacing'; +import { createShape, ThemeShapeInputSchema } from './createShape'; +import { createSpacing, ThemeSpacingOptionsSchema } from './createSpacing'; import { createTransitions } from './createTransitions'; -import { createTypography, ThemeTypographyInput } from './createTypography'; +import { createTypography, ThemeTypographyInputSchema } from './createTypography'; import { createV1Theme } from './createV1Theme'; -import { createVisualizationColors, ThemeVisualizationColorsInput } from './createVisualizationColors'; +import { createVisualizationColors, ThemeVisualizationColorsInputSchema } from './createVisualizationColors'; import { GrafanaTheme2 } from './types'; import { zIndex } from './zIndex'; -/** @internal */ -export interface NewThemeOptions { - name?: string; - colors?: ThemeColorsInput; - spacing?: ThemeSpacingOptions; - shape?: ThemeShapeInput; - typography?: ThemeTypographyInput; - visualization?: ThemeVisualizationColorsInput; -} +export const NewThemeOptionsSchema = z.object({ + name: z.string(), + id: z.string(), + colors: ThemeColorsInputSchema.optional(), + spacing: ThemeSpacingOptionsSchema.optional(), + shape: ThemeShapeInputSchema.optional(), + typography: ThemeTypographyInputSchema.optional(), + visualization: ThemeVisualizationColorsInputSchema.optional(), +}); /** @internal */ -export function createTheme(options: NewThemeOptions = {}): GrafanaTheme2 { +export type NewThemeOptions = z.infer; + +/** @internal */ +export function createTheme( + options: Omit & { + name?: NewThemeOptions['name']; + } = {} +): GrafanaTheme2 { const { name, colors: colorsInput = {}, diff --git a/packages/grafana-data/src/themes/createTypography.ts b/packages/grafana-data/src/themes/createTypography.ts index 25c5fa7c91b..3504e52d2fa 100644 --- a/packages/grafana-data/src/themes/createTypography.ts +++ b/packages/grafana-data/src/themes/createTypography.ts @@ -1,6 +1,7 @@ // Code based on Material UI // The MIT License (MIT) // Copyright (c) 2014 Call-Em-All +import { z } from 'zod'; import { ThemeColors } from './createColors'; @@ -40,18 +41,20 @@ export interface ThemeTypographyVariant { letterSpacing?: string; } -export interface ThemeTypographyInput { - fontFamily?: string; - fontFamilyMonospace?: string; - fontSize?: number; - fontWeightLight?: number; - fontWeightRegular?: number; - fontWeightMedium?: number; - fontWeightBold?: number; - // hat's the font-size on the html element. +export const ThemeTypographyInputSchema = z.object({ + fontFamily: z.string().optional(), + fontFamilyMonospace: z.string().optional(), + fontSize: z.number().positive().optional(), + fontWeightLight: z.number().positive().optional(), + fontWeightRegular: z.number().positive().optional(), + fontWeightMedium: z.number().positive().optional(), + fontWeightBold: z.number().positive().optional(), + // what's the font-size on the html element. // 16px is the default font-size used by browsers. - htmlFontSize?: number; -} + htmlFontSize: z.number().positive().optional(), +}); + +export type ThemeTypographyInput = z.infer; const defaultFontFamily = "'Inter', 'Helvetica', 'Arial', sans-serif"; const defaultFontFamilyMonospace = "'Roboto Mono', monospace"; diff --git a/packages/grafana-data/src/themes/createVisualizationColors.ts b/packages/grafana-data/src/themes/createVisualizationColors.ts index fca963c9c07..90acbbc2144 100644 --- a/packages/grafana-data/src/themes/createVisualizationColors.ts +++ b/packages/grafana-data/src/themes/createVisualizationColors.ts @@ -1,3 +1,5 @@ +import { z } from 'zod'; + import { FALLBACK_COLOR } from '../types/fieldColor'; import { ThemeColors } from './createColors'; @@ -26,29 +28,44 @@ export interface ThemeVizColor { type ThemeVizColorName = 'red' | 'orange' | 'yellow' | 'green' | 'blue' | 'purple'; -type ThemeVizColorShadeName = - | `super-light-${T}` - | `light-${T}` - | T - | `semi-dark-${T}` - | `dark-${T}`; +const createShadeSchema = (color: T extends ThemeVizColorName ? T : never) => + z.enum([`super-light-${color}`, `light-${color}`, color, `semi-dark-${color}`, `dark-${color}`]); -type ThemeVizHueGeneric = T extends ThemeVizColorName - ? { - name: T; - shades: Array>; - } - : never; +type ThemeVizColorShadeName = z.infer>>; + +const createHueSchema = (color: T extends ThemeVizColorName ? T : never) => + z.object({ + name: z.literal(color), + shades: z.array( + z.object({ + color: z.string(), + name: createShadeSchema(color), + aliases: z.array(z.string()).optional(), + primary: z.boolean().optional(), + }) + ), + }); + +const ThemeVizHueSchema = z.union([ + createHueSchema('red'), + createHueSchema('orange'), + createHueSchema('yellow'), + createHueSchema('green'), + createHueSchema('blue'), + createHueSchema('purple'), +]); /** * @alpha */ -export type ThemeVizHue = ThemeVizHueGeneric; +export type ThemeVizHue = z.infer; -export type ThemeVisualizationColorsInput = { - hues?: ThemeVizHue[]; - palette?: string[]; -}; +export const ThemeVisualizationColorsInputSchema = z.object({ + hues: z.array(ThemeVizHueSchema).optional(), + palette: z.array(z.string()).optional(), +}); + +export type ThemeVisualizationColorsInput = z.infer; /** * @internal diff --git a/packages/grafana-data/src/themes/registry.ts b/packages/grafana-data/src/themes/registry.ts index c4cf352b622..4fca3c5d7be 100644 --- a/packages/grafana-data/src/themes/registry.ts +++ b/packages/grafana-data/src/themes/registry.ts @@ -1,6 +1,6 @@ import { Registry, RegistryItem } from '../utils/Registry'; -import { createTheme } from './createTheme'; +import { createTheme, NewThemeOptionsSchema } from './createTheme'; import * as extraThemes from './themeDefinitions'; import { GrafanaTheme2 } from './types'; @@ -42,9 +42,6 @@ export function getBuiltInThemes(allowedExtras: string[]) { return sortedThemes; } -/** - * There is also a backend list at pkg/services/preference/themes.go - */ const themeRegistry = new Registry(() => { return [ { id: 'system', name: 'System preference', build: getSystemPreferenceTheme }, @@ -53,13 +50,19 @@ const themeRegistry = new Registry(() => { ]; }); -for (const [id, theme] of Object.entries(extraThemes)) { - themeRegistry.register({ - id, - name: theme.name ?? '', - build: () => createTheme(theme), - isExtra: true, - }); +for (const [name, json] of Object.entries(extraThemes)) { + const result = NewThemeOptionsSchema.safeParse(json); + if (!result.success) { + console.error(`Invalid theme definition for theme ${name}: ${result.error.message}`); + } else { + const theme = result.data; + themeRegistry.register({ + id: theme.id, + name: theme.name, + build: () => createTheme(theme), + isExtra: true, + }); + } } function getSystemPreferenceTheme() { diff --git a/packages/grafana-data/src/themes/schema.generated.json b/packages/grafana-data/src/themes/schema.generated.json new file mode 100644 index 00000000000..366ab9c05d6 --- /dev/null +++ b/packages/grafana-data/src/themes/schema.generated.json @@ -0,0 +1,608 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "id": { + "type": "string" + }, + "colors": { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": ["light", "dark"] + }, + "primary": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "main": { + "type": "string" + }, + "shade": { + "type": "string" + }, + "text": { + "type": "string" + }, + "border": { + "type": "string" + }, + "transparent": { + "type": "string" + }, + "borderTransparent": { + "type": "string" + }, + "contrastText": { + "type": "string" + } + }, + "additionalProperties": false + }, + "secondary": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "main": { + "type": "string" + }, + "shade": { + "type": "string" + }, + "text": { + "type": "string" + }, + "border": { + "type": "string" + }, + "transparent": { + "type": "string" + }, + "borderTransparent": { + "type": "string" + }, + "contrastText": { + "type": "string" + } + }, + "additionalProperties": false + }, + "info": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "main": { + "type": "string" + }, + "shade": { + "type": "string" + }, + "text": { + "type": "string" + }, + "border": { + "type": "string" + }, + "transparent": { + "type": "string" + }, + "borderTransparent": { + "type": "string" + }, + "contrastText": { + "type": "string" + } + }, + "additionalProperties": false + }, + "error": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "main": { + "type": "string" + }, + "shade": { + "type": "string" + }, + "text": { + "type": "string" + }, + "border": { + "type": "string" + }, + "transparent": { + "type": "string" + }, + "borderTransparent": { + "type": "string" + }, + "contrastText": { + "type": "string" + } + }, + "additionalProperties": false + }, + "success": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "main": { + "type": "string" + }, + "shade": { + "type": "string" + }, + "text": { + "type": "string" + }, + "border": { + "type": "string" + }, + "transparent": { + "type": "string" + }, + "borderTransparent": { + "type": "string" + }, + "contrastText": { + "type": "string" + } + }, + "additionalProperties": false + }, + "warning": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "main": { + "type": "string" + }, + "shade": { + "type": "string" + }, + "text": { + "type": "string" + }, + "border": { + "type": "string" + }, + "transparent": { + "type": "string" + }, + "borderTransparent": { + "type": "string" + }, + "contrastText": { + "type": "string" + } + }, + "additionalProperties": false + }, + "text": { + "type": "object", + "properties": { + "primary": { + "type": "string" + }, + "secondary": { + "type": "string" + }, + "disabled": { + "type": "string" + }, + "link": { + "type": "string" + }, + "maxContrast": { + "type": "string" + } + }, + "additionalProperties": false + }, + "background": { + "type": "object", + "properties": { + "canvas": { + "type": "string" + }, + "primary": { + "type": "string" + }, + "secondary": { + "type": "string" + }, + "elevated": { + "type": "string" + } + }, + "additionalProperties": false + }, + "border": { + "type": "object", + "properties": { + "weak": { + "type": "string" + }, + "medium": { + "type": "string" + }, + "strong": { + "type": "string" + } + }, + "additionalProperties": false + }, + "gradients": { + "type": "object", + "properties": { + "brandVertical": { + "type": "string" + }, + "brandHorizontal": { + "type": "string" + } + }, + "additionalProperties": false + }, + "action": { + "type": "object", + "properties": { + "selected": { + "type": "string" + }, + "selectedBorder": { + "type": "string" + }, + "hover": { + "type": "string" + }, + "hoverOpacity": { + "type": "number" + }, + "focus": { + "type": "string" + }, + "disabledBackground": { + "type": "string" + }, + "disabledText": { + "type": "string" + }, + "disabledOpacity": { + "type": "number" + } + }, + "additionalProperties": false + }, + "hoverFactor": { + "type": "number" + }, + "contrastThreshold": { + "type": "number" + }, + "tonalOffset": { + "type": "number" + } + }, + "additionalProperties": false + }, + "spacing": { + "type": "object", + "properties": { + "gridSize": { + "type": "integer", + "exclusiveMinimum": 0, + "maximum": 9007199254740991 + } + }, + "additionalProperties": false + }, + "shape": { + "type": "object", + "properties": { + "borderRadius": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + } + }, + "additionalProperties": false + }, + "typography": { + "type": "object", + "properties": { + "fontFamily": { + "type": "string" + }, + "fontFamilyMonospace": { + "type": "string" + }, + "fontSize": { + "type": "number", + "exclusiveMinimum": 0 + }, + "fontWeightLight": { + "type": "number", + "exclusiveMinimum": 0 + }, + "fontWeightRegular": { + "type": "number", + "exclusiveMinimum": 0 + }, + "fontWeightMedium": { + "type": "number", + "exclusiveMinimum": 0 + }, + "fontWeightBold": { + "type": "number", + "exclusiveMinimum": 0 + }, + "htmlFontSize": { + "type": "number", + "exclusiveMinimum": 0 + } + }, + "additionalProperties": false + }, + "visualization": { + "type": "object", + "properties": { + "hues": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "object", + "properties": { + "name": { + "type": "string", + "const": "red" + }, + "shades": { + "type": "array", + "items": { + "type": "object", + "properties": { + "color": { + "type": "string" + }, + "name": { + "type": "string", + "enum": ["super-light-red", "light-red", "red", "semi-dark-red", "dark-red"] + }, + "aliases": { + "type": "array", + "items": { + "type": "string" + } + }, + "primary": { + "type": "boolean" + } + }, + "required": ["color", "name"], + "additionalProperties": false + } + } + }, + "required": ["name", "shades"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "name": { + "type": "string", + "const": "orange" + }, + "shades": { + "type": "array", + "items": { + "type": "object", + "properties": { + "color": { + "type": "string" + }, + "name": { + "type": "string", + "enum": ["super-light-orange", "light-orange", "orange", "semi-dark-orange", "dark-orange"] + }, + "aliases": { + "type": "array", + "items": { + "type": "string" + } + }, + "primary": { + "type": "boolean" + } + }, + "required": ["color", "name"], + "additionalProperties": false + } + } + }, + "required": ["name", "shades"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "name": { + "type": "string", + "const": "yellow" + }, + "shades": { + "type": "array", + "items": { + "type": "object", + "properties": { + "color": { + "type": "string" + }, + "name": { + "type": "string", + "enum": ["super-light-yellow", "light-yellow", "yellow", "semi-dark-yellow", "dark-yellow"] + }, + "aliases": { + "type": "array", + "items": { + "type": "string" + } + }, + "primary": { + "type": "boolean" + } + }, + "required": ["color", "name"], + "additionalProperties": false + } + } + }, + "required": ["name", "shades"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "name": { + "type": "string", + "const": "green" + }, + "shades": { + "type": "array", + "items": { + "type": "object", + "properties": { + "color": { + "type": "string" + }, + "name": { + "type": "string", + "enum": ["super-light-green", "light-green", "green", "semi-dark-green", "dark-green"] + }, + "aliases": { + "type": "array", + "items": { + "type": "string" + } + }, + "primary": { + "type": "boolean" + } + }, + "required": ["color", "name"], + "additionalProperties": false + } + } + }, + "required": ["name", "shades"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "name": { + "type": "string", + "const": "blue" + }, + "shades": { + "type": "array", + "items": { + "type": "object", + "properties": { + "color": { + "type": "string" + }, + "name": { + "type": "string", + "enum": ["super-light-blue", "light-blue", "blue", "semi-dark-blue", "dark-blue"] + }, + "aliases": { + "type": "array", + "items": { + "type": "string" + } + }, + "primary": { + "type": "boolean" + } + }, + "required": ["color", "name"], + "additionalProperties": false + } + } + }, + "required": ["name", "shades"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "name": { + "type": "string", + "const": "purple" + }, + "shades": { + "type": "array", + "items": { + "type": "object", + "properties": { + "color": { + "type": "string" + }, + "name": { + "type": "string", + "enum": ["super-light-purple", "light-purple", "purple", "semi-dark-purple", "dark-purple"] + }, + "aliases": { + "type": "array", + "items": { + "type": "string" + } + }, + "primary": { + "type": "boolean" + } + }, + "required": ["color", "name"], + "additionalProperties": false + } + } + }, + "required": ["name", "shades"], + "additionalProperties": false + } + ] + } + }, + "palette": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + } + }, + "required": ["name", "id"], + "additionalProperties": false +} diff --git a/packages/grafana-data/src/themes/scripts/generateSchema.ts b/packages/grafana-data/src/themes/scripts/generateSchema.ts new file mode 100644 index 00000000000..09369f5e67f --- /dev/null +++ b/packages/grafana-data/src/themes/scripts/generateSchema.ts @@ -0,0 +1,19 @@ +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +import { NewThemeOptionsSchema } from '../createTheme'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +fs.writeFileSync( + path.join(__dirname, '../schema.generated.json'), + JSON.stringify( + NewThemeOptionsSchema.toJSONSchema({ + target: 'draft-07', + }), + undefined, + 2 + ) +); diff --git a/packages/grafana-data/src/themes/themeDefinitions/aubergine.json b/packages/grafana-data/src/themes/themeDefinitions/aubergine.json new file mode 100644 index 00000000000..4baf4f3f439 --- /dev/null +++ b/packages/grafana-data/src/themes/themeDefinitions/aubergine.json @@ -0,0 +1,50 @@ +{ + "name": "Aubergine", + "id": "aubergine", + "colors": { + "mode": "dark", + "border": { + "weak": "#4F2A3D", + "medium": "#6A3C4B", + "strong": "#8C5A69" + }, + "text": { + "primary": "#E5D0D6", + "secondary": "#D1A8C4", + "disabled": "#B7A0A6", + "link": "#A56BB6", + "maxContrast": "#FFFFFF" + }, + "primary": { + "main": "#8C5A69" + }, + "secondary": { + "main": "#6A3C4B", + "text": "#D1A8C4", + "border": "#8C5A69" + }, + "background": { + "canvas": "#2E1F2D", + "primary": "#3C2136", + "secondary": "#4A2D47", + "elevated": "#4A2D47" + }, + "action": { + "hover": "#6A3C4B", + "selected": "#8C5A69", + "selectedBorder": "#FFB300", + "focus": "#A56BB6", + "hoverOpacity": 0.1, + "disabledText": "#B7A0A6", + "disabledBackground": "#4A2D47", + "disabledOpacity": 0.38 + }, + "gradients": { + "brandHorizontal": "linear-gradient(270deg, #6A3C4B 0%, #A56BB6 100%)", + "brandVertical": "linear-gradient(0deg, #6A3C4B 0%, #A56BB6 100%)" + }, + "contrastThreshold": 4, + "hoverFactor": 0.07, + "tonalOffset": 0.15 + } +} diff --git a/packages/grafana-data/src/themes/themeDefinitions/aubergine.ts b/packages/grafana-data/src/themes/themeDefinitions/aubergine.ts deleted file mode 100644 index 967621ebc60..00000000000 --- a/packages/grafana-data/src/themes/themeDefinitions/aubergine.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { NewThemeOptions } from '../createTheme'; - -const aubergineTheme: NewThemeOptions = { - name: 'Aubergine', - colors: { - mode: 'dark', - border: { - weak: '#4F2A3D', - medium: '#6A3C4B', - strong: '#8C5A69', - }, - text: { - primary: '#E5D0D6', - secondary: '#D1A8C4', - disabled: '#B7A0A6', - link: '#A56BB6', - maxContrast: '#FFFFFF', - }, - primary: { - main: '#8C5A69', - }, - secondary: { - main: '#6A3C4B', - text: '#D1A8C4', - border: '#8C5A69', - }, - background: { - canvas: '#2E1F2D', - primary: '#3C2136', - secondary: '#4A2D47', - elevated: '#4A2D47', - }, - action: { - hover: '#6A3C4B', - selected: '#8C5A69', - selectedBorder: '#FFB300', - focus: '#A56BB6', - hoverOpacity: 0.1, - disabledText: '#B7A0A6', - disabledBackground: '#4A2D47', - disabledOpacity: 0.38, - }, - gradients: { - brandHorizontal: 'linear-gradient(270deg, #6A3C4B 0%, #A56BB6 100%)', - brandVertical: 'linear-gradient(0deg, #6A3C4B 0%, #A56BB6 100%)', - }, - contrastThreshold: 4, - hoverFactor: 0.07, - tonalOffset: 0.15, - }, -}; - -export default aubergineTheme; diff --git a/packages/grafana-data/src/themes/themeDefinitions/debug.json b/packages/grafana-data/src/themes/themeDefinitions/debug.json new file mode 100644 index 00000000000..a9cce4c5e21 --- /dev/null +++ b/packages/grafana-data/src/themes/themeDefinitions/debug.json @@ -0,0 +1,60 @@ +{ + "name": "Debug", + "id": "debug", + "colors": { + "mode": "dark", + "background": { + "canvas": "#000033", + "primary": "#000044", + "secondary": "#000055", + "elevated": "#000055" + }, + "text": { + "primary": "#bbbb00", + "secondary": "#888800", + "disabled": "#444400", + "link": "#dddd00", + "maxContrast": "#ffff00" + }, + "border": { + "weak": "#ff000044", + "medium": "#ff000088", + "strong": "#ff0000ff" + }, + "primary": { + "border": "#ff000088", + "text": "#cccc00", + "contrastText": "#ffff00", + "shade": "#9900dd" + }, + "secondary": { + "border": "#ff000088", + "text": "#cccc00", + "contrastText": "#ffff00", + "shade": "#9900dd" + }, + "info": { + "shade": "#9900dd" + }, + "warning": { + "shade": "#9900dd" + }, + "success": { + "shade": "#9900dd" + }, + "error": { + "shade": "#9900dd" + }, + "action": { + "hover": "#9900dd", + "focus": "#6600aa", + "selected": "#440088" + } + }, + "shape": { + "borderRadius": 8 + }, + "spacing": { + "gridSize": 10 + } +} diff --git a/packages/grafana-data/src/themes/themeDefinitions/debug.ts b/packages/grafana-data/src/themes/themeDefinitions/debug.ts deleted file mode 100644 index 22e577faf2c..00000000000 --- a/packages/grafana-data/src/themes/themeDefinitions/debug.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { NewThemeOptions } from '../createTheme'; - -/** - * a very ugly theme that is useful for debugging and checking if the theme is applied correctly - * borders are red, - * backgrounds are blue, - * text is yellow, - * and grafana loves you <3 - * (also corners are rounded, action states (hover, focus, selected) are purple) - */ -const debugTheme: NewThemeOptions = { - name: 'Debug', - colors: { - mode: 'dark', - background: { - canvas: '#000033', - primary: '#000044', - secondary: '#000055', - elevated: '#000055', - }, - text: { - primary: '#bbbb00', - secondary: '#888800', - disabled: '#444400', - link: '#dddd00', - maxContrast: '#ffff00', - }, - border: { - weak: '#ff000044', - medium: '#ff000088', - strong: '#ff0000ff', - }, - primary: { - border: '#ff000088', - text: '#cccc00', - contrastText: '#ffff00', - shade: '#9900dd', - }, - secondary: { - border: '#ff000088', - text: '#cccc00', - contrastText: '#ffff00', - shade: '#9900dd', - }, - info: { - shade: '#9900dd', - }, - warning: { - shade: '#9900dd', - }, - success: { - shade: '#9900dd', - }, - error: { - shade: '#9900dd', - }, - action: { - hover: '#9900dd', - focus: '#6600aa', - selected: '#440088', - }, - }, - shape: { - borderRadius: 8, - }, - spacing: { - gridSize: 10, - }, -}; - -export default debugTheme; diff --git a/packages/grafana-data/src/themes/themeDefinitions/desertbloom.json b/packages/grafana-data/src/themes/themeDefinitions/desertbloom.json new file mode 100644 index 00000000000..1c2304aaff8 --- /dev/null +++ b/packages/grafana-data/src/themes/themeDefinitions/desertbloom.json @@ -0,0 +1,71 @@ +{ + "name": "Desert bloom", + "id": "desertbloom", + "colors": { + "mode": "light", + "border": { + "weak": "rgba(0, 0, 0, 0.12)", + "medium": "rgba(0, 0, 0, 0.20)", + "strong": "rgba(0, 0, 0, 0.30)" + }, + "text": { + "primary": "#333333", + "secondary": "#555555", + "disabled": "rgba(0, 0, 0, 0.5)", + "link": "#1A82E2", + "maxContrast": "#000000" + }, + "primary": { + "main": "#FF6F61", + "text": "#FE6F61", + "border": "#E55B4D", + "name": "primary", + "shade": "#E55B4D", + "transparent": "#FF6F6126", + "contrastText": "#FFFFFF", + "borderTransparent": "#FF6F6140" + }, + "secondary": { + "main": "#FFFFFF", + "text": "#695f53", + "border": "#d9cec0", + "name": "secondary", + "shade": "#d9cec0", + "transparent": "#FFFFFF26", + "contrastText": "#4c4339", + "borderTransparent": "#FFFFFF40" + }, + "info": { + "main": "#1A82E2" + }, + "success": { + "main": "#4CAF50" + }, + "warning": { + "main": "#FFC107" + }, + "background": { + "canvas": "#FFF8F0", + "primary": "#FFFFFF", + "secondary": "#f9f3e8", + "elevated": "#FFFFFF" + }, + "action": { + "hover": "rgba(168, 156, 134, 0.12)", + "selected": "rgba(168, 156, 134, 0.36)", + "selectedBorder": "#FF6F61", + "focus": "rgba(168, 156, 134, 0.50)", + "hoverOpacity": 0.08, + "disabledText": "rgba(168, 156, 134, 0.5)", + "disabledBackground": "rgba(168, 156, 134, 0.06)", + "disabledOpacity": 0.38 + }, + "gradients": { + "brandHorizontal": "linear-gradient(270deg,rgba(255, 111, 97, 1) 0%, rgba(255, 167, 58, 1) 100%)", + "brandVertical": "linear-gradient(0deg, rgba(255, 111, 97, 1) 0%, rgba(255, 167, 58, 1) 100%)" + }, + "contrastThreshold": 3, + "hoverFactor": 0.03, + "tonalOffset": 0.15 + } +} diff --git a/packages/grafana-data/src/themes/themeDefinitions/desertbloom.ts b/packages/grafana-data/src/themes/themeDefinitions/desertbloom.ts deleted file mode 100644 index 8a86b73a0f7..00000000000 --- a/packages/grafana-data/src/themes/themeDefinitions/desertbloom.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { NewThemeOptions } from '../createTheme'; - -const desertBloomTheme: NewThemeOptions = { - name: 'Desert bloom', - colors: { - mode: 'light', - border: { - weak: 'rgba(0, 0, 0, 0.12)', - medium: 'rgba(0, 0, 0, 0.20)', - strong: 'rgba(0, 0, 0, 0.30)', - }, - text: { - primary: '#333333', - secondary: '#555555', - disabled: 'rgba(0, 0, 0, 0.5)', - link: '#1A82E2', - maxContrast: '#000000', - }, - primary: { - main: '#FF6F61', - text: '#FE6F61', - border: '#E55B4D', - name: 'primary', - shade: '#E55B4D', - transparent: '#FF6F6126', - contrastText: '#FFFFFF', - borderTransparent: '#FF6F6140', - }, - secondary: { - main: '#FFFFFF', - text: '#695f53', - border: '#d9cec0', - name: 'secondary', - shade: '#d9cec0', - transparent: '#FFFFFF26', - contrastText: '#4c4339', - borderTransparent: '#FFFFFF40', - }, - info: { - main: '#1A82E2', - }, - success: { - main: '#4CAF50', - }, - warning: { - main: '#FFC107', - }, - background: { - canvas: '#FFF8F0', - primary: '#FFFFFF', - secondary: '#f9f3e8', - elevated: '#FFFFFF', - }, - action: { - hover: 'rgba(168, 156, 134, 0.12)', - selected: 'rgba(168, 156, 134, 0.36)', - selectedBorder: '#FF6F61', - focus: 'rgba(168, 156, 134, 0.50)', - hoverOpacity: 0.08, - disabledText: 'rgba(168, 156, 134, 0.5)', - disabledBackground: 'rgba(168, 156, 134, 0.06)', - disabledOpacity: 0.38, - }, - - gradients: { - brandHorizontal: 'linear-gradient(270deg,rgba(255, 111, 97, 1) 0%, rgba(255, 167, 58, 1) 100%)', - brandVertical: 'linear-gradient(0deg, rgba(255, 111, 97, 1) 0%, rgba(255, 167, 58, 1) 100%)', - }, - contrastThreshold: 3, - hoverFactor: 0.03, - tonalOffset: 0.15, - }, -}; - -export default desertBloomTheme; diff --git a/packages/grafana-data/src/themes/themeDefinitions/gildedgrove.json b/packages/grafana-data/src/themes/themeDefinitions/gildedgrove.json new file mode 100644 index 00000000000..a147afbbe76 --- /dev/null +++ b/packages/grafana-data/src/themes/themeDefinitions/gildedgrove.json @@ -0,0 +1,62 @@ +{ + "name": "Gilded grove", + "id": "gildedgrove", + "colors": { + "mode": "dark", + "border": { + "weak": "rgba(200, 200, 180, 0.12)", + "medium": "rgba(200, 200, 180, 0.20)", + "strong": "rgba(200, 200, 180, 0.30)" + }, + "text": { + "primary": "rgb(250, 250, 239)", + "secondary": "rgba(200, 200, 180, 0.85)", + "disabled": "rgba(200, 200, 180, 0.6)", + "link": "#FEAC34", + "maxContrast": "#FFFFFF" + }, + "primary": { + "main": "#FEAC34", + "text": "#FFD783", + "border": "#FFD783", + "name": "primary", + "shade": "rgb(255, 173, 80)", + "transparent": "#FEAC3426", + "contrastText": "#111614", + "borderTransparent": "#FFD78340" + }, + "secondary": { + "main": "rgba(200, 200, 180, 0.10)", + "shade": "rgba(200, 200, 180, 0.14)", + "transparent": "rgba(200, 200, 180, 0.08)", + "text": "rgb(200, 200, 180)", + "contrastText": "rgb(200, 200, 180)", + "border": "rgba(200, 200, 180, 0.08)", + "name": "secondary", + "borderTransparent": "rgba(200, 200, 180, 0.25)" + }, + "background": { + "canvas": "#111614", + "primary": "#1d2220", + "secondary": "#27312E", + "elevated": "#27312E" + }, + "action": { + "hover": "rgba(200, 200, 180, 0.16)", + "selected": "rgba(200, 200, 180, 0.12)", + "selectedBorder": "#FEAC34", + "focus": "rgba(200, 200, 180, 0.16)", + "hoverOpacity": 0.08, + "disabledText": "rgba(200, 200, 180, 0.6)", + "disabledBackground": "rgba(200, 200, 180, 0.04)", + "disabledOpacity": 0.38 + }, + "gradients": { + "brandHorizontal": "linear-gradient(270deg, #FEAC34 0%, #FFD783 100%)", + "brandVertical": "linear-gradient(0.01deg, #FEAC34 0.01%, #FFD783 99.99%)" + }, + "contrastThreshold": 3, + "hoverFactor": 0.03, + "tonalOffset": 0.15 + } +} diff --git a/packages/grafana-data/src/themes/themeDefinitions/gildedgrove.ts b/packages/grafana-data/src/themes/themeDefinitions/gildedgrove.ts deleted file mode 100644 index bfa3e121329..00000000000 --- a/packages/grafana-data/src/themes/themeDefinitions/gildedgrove.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { NewThemeOptions } from '../createTheme'; - -const gildedGroveTheme: NewThemeOptions = { - name: 'Gilded grove', - colors: { - mode: 'dark', - border: { - weak: 'rgba(200, 200, 180, 0.12)', - medium: 'rgba(200, 200, 180, 0.20)', - strong: 'rgba(200, 200, 180, 0.30)', - }, - text: { - primary: 'rgb(250, 250, 239)', - secondary: 'rgba(200, 200, 180, 0.85)', - disabled: 'rgba(200, 200, 180, 0.6)', - link: '#FEAC34', - maxContrast: '#FFFFFF', - }, - primary: { - main: '#FEAC34', - text: '#FFD783', - border: '#FFD783', - name: 'primary', - shade: 'rgb(255, 173, 80)', - transparent: '#FEAC3426', - contrastText: '#111614', - borderTransparent: '#FFD78340', - }, - secondary: { - main: 'rgba(200, 200, 180, 0.10)', - shade: 'rgba(200, 200, 180, 0.14)', - transparent: 'rgba(200, 200, 180, 0.08)', - text: 'rgb(200, 200, 180)', - contrastText: 'rgb(200, 200, 180)', - border: 'rgba(200, 200, 180, 0.08)', - name: 'secondary', - borderTransparent: 'rgba(200, 200, 180, 0.25)', - }, - background: { - canvas: '#111614', - primary: '#1d2220', - secondary: '#27312E', - elevated: '#27312E', - }, - action: { - hover: 'rgba(200, 200, 180, 0.16)', - selected: 'rgba(200, 200, 180, 0.12)', - selectedBorder: '#FEAC34', - focus: 'rgba(200, 200, 180, 0.16)', - hoverOpacity: 0.08, - disabledText: 'rgba(200, 200, 180, 0.6)', - disabledBackground: 'rgba(200, 200, 180, 0.04)', - disabledOpacity: 0.38, - }, - gradients: { - brandHorizontal: 'linear-gradient(270deg, #FEAC34 0%, #FFD783 100%)', - brandVertical: 'linear-gradient(0.01deg, #FEAC34 0.01%, #FFD783 99.99%)', - }, - contrastThreshold: 3, - hoverFactor: 0.03, - tonalOffset: 0.15, - }, -}; - -export default gildedGroveTheme; diff --git a/packages/grafana-data/src/themes/themeDefinitions/gloom.json b/packages/grafana-data/src/themes/themeDefinitions/gloom.json new file mode 100644 index 00000000000..8558c942511 --- /dev/null +++ b/packages/grafana-data/src/themes/themeDefinitions/gloom.json @@ -0,0 +1,52 @@ +{ + "name": "Gloom", + "id": "gloom", + "colors": { + "mode": "dark", + "border": { + "weak": "rgba(210, 210, 220, 0.12)", + "medium": "rgba(210, 210, 220, 0.20)", + "strong": "rgba(210, 210, 220, 0.30)" + }, + "text": { + "primary": "rgb(210, 210, 220)", + "secondary": "rgba(210, 210, 220, 0.65)", + "disabled": "rgba(210, 210, 220, 0.48)", + "link": "#f99a5c", + "maxContrast": "#FFF" + }, + "primary": { + "main": "#ff934d", + "text": "#f99a5c", + "border": "#ff934d", + "name": "primary" + }, + "secondary": { + "main": "rgba(195, 195, 245, 0.10)", + "shade": "rgba(195, 195, 245, 0.14)", + "transparent": "rgba(195, 195, 245, 0.08)", + "text": "rgba(195, 195, 245)", + "contrastText": "rgb(195, 195, 245)", + "border": "rgba(195, 195, 245, 0.08)" + }, + "background": { + "canvas": "#000", + "primary": "#121118", + "secondary": "#211e28", + "elevated": "#211e28" + }, + "action": { + "hover": "rgba(195, 195, 245, 0.07)", + "selected": "rgba(195, 195, 245, 0.11)", + "selectedBorder": "#ff934d", + "focus": "rgba(195, 195, 245, 0.07)", + "hoverOpacity": 0.05, + "disabledText": "rgba(210, 210, 220, 0.48)", + "disabledBackground": "rgba(210, 210, 220, 0.04)", + "disabledOpacity": 0.38 + }, + "contrastThreshold": 3, + "hoverFactor": 0.03, + "tonalOffset": 0.15 + } +} diff --git a/packages/grafana-data/src/themes/themeDefinitions/gloom.ts b/packages/grafana-data/src/themes/themeDefinitions/gloom.ts deleted file mode 100644 index 49c105626fb..00000000000 --- a/packages/grafana-data/src/themes/themeDefinitions/gloom.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { NewThemeOptions } from '../createTheme'; - -/** - * Torkel's GrafanaCon theme - * very WIP state - */ - -const whiteBase = `210, 210, 220`; -const secondaryBase = `195, 195, 245`; - -//const brandMain = '#3d71d9'; -//const brandText = '#6e9fff'; -const brandMain = '#ff934d'; -const brandText = '#f99a5c'; -const disabledText = `rgba(${whiteBase}, 0.48)`; - -const gloomTheme: NewThemeOptions = { - name: 'Gloom', - colors: { - mode: 'dark', - border: { - weak: `rgba(${whiteBase}, 0.12)`, - medium: `rgba(${whiteBase}, 0.20)`, - strong: `rgba(${whiteBase}, 0.30)`, - }, - - text: { - primary: `rgb(${whiteBase})`, - secondary: `rgba(${whiteBase}, 0.65)`, - disabled: disabledText, - link: brandText, - maxContrast: '#FFF', - }, - - primary: { - main: brandMain, - text: brandText, - border: brandMain, - name: 'primary', - }, - - secondary: { - main: `rgba(${secondaryBase}, 0.10)`, - shade: `rgba(${secondaryBase}, 0.14)`, - transparent: `rgba(${secondaryBase}, 0.08)`, - text: `rgba(${secondaryBase})`, - contrastText: `rgb(${secondaryBase})`, - border: `rgba(${secondaryBase}, 0.08)`, - }, - - background: { - canvas: '#000', - primary: '#121118', - secondary: '#211e28', - elevated: '#211e28', - }, - - action: { - hover: `rgba(${secondaryBase}, 0.07)`, - selected: `rgba(${secondaryBase}, 0.11)`, - selectedBorder: brandMain, - focus: `rgba(${secondaryBase}, 0.07)`, - hoverOpacity: 0.05, - disabledText: disabledText, - disabledBackground: `rgba(${whiteBase}, 0.04)`, - disabledOpacity: 0.38, - }, - - // gradients: { - // brandHorizontal: 'linear-gradient(270deg, #ff934d 0%, #FEAC34 100%)', - // brandVertical: 'linear-gradient(0.01deg, #ff934d 0.01%, #FEAC34 99.99%)', - // }, - - contrastThreshold: 3, - hoverFactor: 0.03, - tonalOffset: 0.15, - }, -}; - -export default gloomTheme; diff --git a/packages/grafana-data/src/themes/themeDefinitions/index.ts b/packages/grafana-data/src/themes/themeDefinitions/index.ts index 151ae00593e..b4270192032 100644 --- a/packages/grafana-data/src/themes/themeDefinitions/index.ts +++ b/packages/grafana-data/src/themes/themeDefinitions/index.ts @@ -1,12 +1,12 @@ -export { default as aubergine } from './aubergine'; -export { default as debug } from './debug'; -export { default as desertbloom } from './desertbloom'; -export { default as gildedgrove } from './gildedgrove'; -export { default as mars } from './mars'; -export { default as matrix } from './matrix'; -export { default as sapphiredusk } from './sapphiredusk'; -export { default as synthwave } from './synthwave'; -export { default as tron } from './tron'; -export { default as victorian } from './victorian'; -export { default as zen } from './zen'; -export { default as gloom } from './gloom'; +export { default as aubergine } from './aubergine.json'; +export { default as debug } from './debug.json'; +export { default as desertbloom } from './desertbloom.json'; +export { default as gildedgrove } from './gildedgrove.json'; +export { default as mars } from './mars.json'; +export { default as matrix } from './matrix.json'; +export { default as sapphiredusk } from './sapphiredusk.json'; +export { default as synthwave } from './synthwave.json'; +export { default as tron } from './tron.json'; +export { default as victorian } from './victorian.json'; +export { default as zen } from './zen.json'; +export { default as gloom } from './gloom.json'; diff --git a/packages/grafana-data/src/themes/themeDefinitions/mars.json b/packages/grafana-data/src/themes/themeDefinitions/mars.json new file mode 100644 index 00000000000..1aeb874f018 --- /dev/null +++ b/packages/grafana-data/src/themes/themeDefinitions/mars.json @@ -0,0 +1,50 @@ +{ + "name": "Mars", + "id": "mars", + "colors": { + "mode": "dark", + "border": { + "weak": "rgba(210, 90, 60, 0.2)", + "medium": "rgba(210, 90, 60, 0.35)", + "strong": "rgba(210, 90, 60, 0.5)" + }, + "text": { + "primary": "#DDDDDD", + "secondary": "#BBBBBB", + "disabled": "rgba(221, 221, 221, 0.5)", + "link": "#FF6F61", + "maxContrast": "#FFFFFF" + }, + "primary": { + "main": "#FF6F61" + }, + "secondary": { + "main": "#6a2f2f", + "text": "#BBBBBB", + "border": "rgba(210, 90, 60, 0.2)" + }, + "background": { + "canvas": "#3C1E1E", + "primary": "#522626", + "secondary": "#6A2F2F", + "elevated": "#6A2F2F" + }, + "action": { + "hover": "rgba(210, 90, 60, 0.16)", + "selected": "rgba(210, 90, 60, 0.12)", + "selectedBorder": "#FF6F61", + "focus": "rgba(210, 90, 60, 0.16)", + "hoverOpacity": 0.08, + "disabledText": "rgba(221, 221, 221, 0.5)", + "disabledBackground": "rgba(210, 90, 60, 0.08)", + "disabledOpacity": 0.38 + }, + "gradients": { + "brandHorizontal": "linear-gradient(270deg, #FF6F61 0%, #D25A3C 100%)", + "brandVertical": "linear-gradient(0.01deg, #FF6F61 0.01%, #D25A3C 99.99%)" + }, + "contrastThreshold": 3, + "hoverFactor": 0.05, + "tonalOffset": 0.2 + } +} diff --git a/packages/grafana-data/src/themes/themeDefinitions/mars.ts b/packages/grafana-data/src/themes/themeDefinitions/mars.ts deleted file mode 100644 index f1db51e23b2..00000000000 --- a/packages/grafana-data/src/themes/themeDefinitions/mars.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { NewThemeOptions } from '../createTheme'; - -const marsTheme: NewThemeOptions = { - name: 'Mars', - colors: { - mode: 'dark', - border: { - weak: 'rgba(210, 90, 60, 0.2)', - medium: 'rgba(210, 90, 60, 0.35)', - strong: 'rgba(210, 90, 60, 0.5)', - }, - text: { - primary: '#DDDDDD', - secondary: '#BBBBBB', - disabled: 'rgba(221, 221, 221, 0.5)', - link: '#FF6F61', - maxContrast: '#FFFFFF', - }, - primary: { - main: '#FF6F61', - }, - secondary: { - main: '#6a2f2f', - text: '#BBBBBB', - border: 'rgba(210, 90, 60, 0.2)', - }, - background: { - canvas: '#3C1E1E', - primary: '#522626', - secondary: '#6A2F2F', - elevated: '#6A2F2F', - }, - action: { - hover: 'rgba(210, 90, 60, 0.16)', - selected: 'rgba(210, 90, 60, 0.12)', - selectedBorder: '#FF6F61', - focus: 'rgba(210, 90, 60, 0.16)', - hoverOpacity: 0.08, - disabledText: 'rgba(221, 221, 221, 0.5)', - disabledBackground: 'rgba(210, 90, 60, 0.08)', - disabledOpacity: 0.38, - }, - gradients: { - brandHorizontal: 'linear-gradient(270deg, #FF6F61 0%, #D25A3C 100%)', - brandVertical: 'linear-gradient(0.01deg, #FF6F61 0.01%, #D25A3C 99.99%)', - }, - contrastThreshold: 3, - hoverFactor: 0.05, - tonalOffset: 0.2, - }, -}; - -export default marsTheme; diff --git a/packages/grafana-data/src/themes/themeDefinitions/matrix.json b/packages/grafana-data/src/themes/themeDefinitions/matrix.json new file mode 100644 index 00000000000..a64a7ccce40 --- /dev/null +++ b/packages/grafana-data/src/themes/themeDefinitions/matrix.json @@ -0,0 +1,41 @@ +{ + "name": "Matrix", + "id": "matrix", + "colors": { + "mode": "dark", + "background": { + "canvas": "#000000", + "primary": "#020202", + "secondary": "#080808", + "elevated": "#080808" + }, + "text": { + "primary": "#00c017", + "secondary": "#008910", + "disabled": "#006a0c", + "link": "#00ff41", + "maxContrast": "#00ff41" + }, + "border": { + "weak": "#008f1144", + "medium": "#008f1188", + "strong": "#008910" + }, + "primary": { + "main": "#008910" + }, + "secondary": { + "text": "#008910" + }, + "gradients": { + "brandVertical": "linear-gradient(0deg, #008910 0%, #00ff41 100%)", + "brandHorizontal": "linear-gradient(90deg, #008910 0%, #00ff41 100%)" + } + }, + "shape": { + "borderRadius": 0 + }, + "typography": { + "fontFamily": "monospace" + } +} diff --git a/packages/grafana-data/src/themes/themeDefinitions/matrix.ts b/packages/grafana-data/src/themes/themeDefinitions/matrix.ts deleted file mode 100644 index 51c58b9b394..00000000000 --- a/packages/grafana-data/src/themes/themeDefinitions/matrix.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { NewThemeOptions } from '../createTheme'; - -const matrixTheme: NewThemeOptions = { - name: 'Matrix', - colors: { - mode: 'dark', - background: { - canvas: '#000000', - primary: '#020202', - secondary: '#080808', - elevated: '#080808', - }, - text: { - primary: '#00c017', - secondary: '#008910', - disabled: '#006a0c', - link: '#00ff41', - maxContrast: '#00ff41', - }, - border: { - weak: '#008f1144', - medium: '#008f1188', - strong: '#008910', - }, - primary: { - main: '#008910', - }, - secondary: { - text: '#008910', - }, - gradients: { - brandVertical: 'linear-gradient(0deg, #008910 0%, #00ff41 100%)', - brandHorizontal: 'linear-gradient(90deg, #008910 0%, #00ff41 100%)', - }, - }, - shape: { - borderRadius: 0, - }, - typography: { - fontFamily: 'monospace', - }, -}; - -export default matrixTheme; diff --git a/packages/grafana-data/src/themes/themeDefinitions/sapphiredusk.json b/packages/grafana-data/src/themes/themeDefinitions/sapphiredusk.json new file mode 100644 index 00000000000..8d5f7731f05 --- /dev/null +++ b/packages/grafana-data/src/themes/themeDefinitions/sapphiredusk.json @@ -0,0 +1,76 @@ +{ + "name": "Sapphire dusk", + "id": "sapphiredusk", + "colors": { + "mode": "dark", + "border": { + "weak": "#232e47", + "medium": "#2c3853", + "strong": "#404d6b" + }, + "text": { + "primary": "#FFFFFF", + "secondary": "#bcccdd", + "disabled": "#838da5", + "link": "#93EBF0", + "maxContrast": "#FFFFFF" + }, + "primary": { + "main": "#93EBF0", + "text": "#a8e9ed", + "border": "#93ebf0", + "name": "primary", + "shade": "#c0f5d9", + "transparent": "#93EBF029", + "contrastText": "#111614", + "borderTransparent": "#93ebf040" + }, + "secondary": { + "main": "#2c364f", + "shade": "#36415e", + "transparent": "rgba(200, 200, 180, 0.08)", + "text": "#d1dfff", + "contrastText": "#acfeff", + "border": "rgba(200, 200, 180, 0.08)", + "name": "secondary", + "borderTransparent": "rgba(200, 200, 180, 0.25)" + }, + "info": { + "main": "#4d4593", + "text": "#a8e9ed", + "border": "#5d54a7" + }, + "error": { + "main": "#c63370" + }, + "success": { + "main": "#1A7F4B" + }, + "warning": { + "main": "#D448EA" + }, + "background": { + "canvas": "#1e273d", + "primary": "#12192e", + "secondary": "#212c47", + "elevated": "#212c47" + }, + "action": { + "hover": "#364057", + "selected": "#364260", + "selectedBorder": "#D448EA", + "focus": "#364057", + "hoverOpacity": 0.08, + "disabledText": "#838da5", + "disabledBackground": "rgba(54, 64, 87, 0.2)", + "disabledOpacity": 0.38 + }, + "gradients": { + "brandHorizontal": "linear-gradient(270deg, #D346EF 0%, #2C83FE 100%)", + "brandVertical": "linear-gradient(0deg, #D346EF 0%, #2C83FE 100%)" + }, + "contrastThreshold": 3, + "hoverFactor": 0.03, + "tonalOffset": 0.15 + } +} diff --git a/packages/grafana-data/src/themes/themeDefinitions/sapphiredusk.ts b/packages/grafana-data/src/themes/themeDefinitions/sapphiredusk.ts deleted file mode 100644 index c777c61b055..00000000000 --- a/packages/grafana-data/src/themes/themeDefinitions/sapphiredusk.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { NewThemeOptions } from '../createTheme'; - -const sapphireDuskTheme: NewThemeOptions = { - name: 'Sapphire dusk', - colors: { - mode: 'dark', - border: { - weak: '#232e47', - medium: '#2c3853', - strong: '#404d6b', - }, - text: { - primary: '#FFFFFF', - secondary: '#bcccdd', - disabled: '#838da5', - link: '#93EBF0', - maxContrast: '#FFFFFF', - }, - primary: { - main: '#93EBF0', - text: '#a8e9ed', - border: '#93ebf0', - name: 'primary', - shade: '#c0f5d9', - transparent: '#93EBF029', - contrastText: '#111614', - borderTransparent: '#93ebf040', - }, - secondary: { - main: '#2c364f', - shade: '#36415e', - transparent: 'rgba(200, 200, 180, 0.08)', - text: '#d1dfff', - contrastText: '#acfeff', - border: 'rgba(200, 200, 180, 0.08)', - name: 'secondary', - borderTransparent: 'rgba(200, 200, 180, 0.25)', - }, - info: { - main: '#4d4593', - text: '#a8e9ed', - border: '#5d54a7', - }, - error: { - main: '#c63370', - }, - success: { - main: '#1A7F4B', - }, - warning: { - main: '#D448EA', - }, - background: { - canvas: '#1e273d', - primary: '#12192e', - secondary: '#212c47', - elevated: '#212c47', - }, - action: { - hover: '#364057', - selected: '#364260', - selectedBorder: '#D448EA', - focus: '#364057', - hoverOpacity: 0.08, - disabledText: '#838da5', - disabledBackground: 'rgba(54, 64, 87, 0.2)', - disabledOpacity: 0.38, - }, - gradients: { - brandHorizontal: 'linear-gradient(270deg, #D346EF 0%, #2C83FE 100%)', - brandVertical: 'linear-gradient(0deg, #D346EF 0%, #2C83FE 100%)', - }, - contrastThreshold: 3, - hoverFactor: 0.03, - tonalOffset: 0.15, - }, -}; - -export default sapphireDuskTheme; diff --git a/packages/grafana-data/src/themes/themeDefinitions/synthwave.json b/packages/grafana-data/src/themes/themeDefinitions/synthwave.json new file mode 100644 index 00000000000..377f09f2585 --- /dev/null +++ b/packages/grafana-data/src/themes/themeDefinitions/synthwave.json @@ -0,0 +1,50 @@ +{ + "name": "Synthwave", + "id": "synthwave", + "colors": { + "mode": "dark", + "border": { + "weak": "rgba(255, 20, 147, 0.12)", + "medium": "rgba(255, 20, 147, 0.20)", + "strong": "rgba(255, 20, 147, 0.30)" + }, + "text": { + "primary": "#E0E0E0", + "secondary": "rgba(224, 224, 224, 0.75)", + "disabled": "rgba(224, 224, 224, 0.5)", + "link": "#FF69B4", + "maxContrast": "#FFFFFF" + }, + "primary": { + "main": "#FF1493" + }, + "secondary": { + "main": "#37183a", + "text": "rgba(224, 224, 224, 0.75)", + "border": "rgba(255, 20, 147, 0.10)" + }, + "background": { + "canvas": "#1A1A2E", + "primary": "#16213E", + "secondary": "#0F3460", + "elevated": "#0F3460" + }, + "action": { + "hover": "rgba(255, 20, 147, 0.16)", + "selected": "rgba(255, 20, 147, 0.12)", + "selectedBorder": "#FF1493", + "focus": "rgba(255, 20, 147, 0.16)", + "hoverOpacity": 0.08, + "disabledText": "rgba(224, 224, 224, 0.5)", + "disabledBackground": "rgba(255, 20, 147, 0.08)", + "disabledOpacity": 0.38 + }, + "gradients": { + "brandHorizontal": "linear-gradient(270deg, #FF1493 0%, #1E90FF 100%)", + "brandVertical": "linear-gradient(0.01deg, #FF1493 0.01%, #1E90FF 99.99%)" + }, + "contrastThreshold": 3, + "hoverFactor": 0.03, + "tonalOffset": 0.15 + } +} diff --git a/packages/grafana-data/src/themes/themeDefinitions/synthwave.ts b/packages/grafana-data/src/themes/themeDefinitions/synthwave.ts deleted file mode 100644 index 5fc53cda0bb..00000000000 --- a/packages/grafana-data/src/themes/themeDefinitions/synthwave.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { NewThemeOptions } from '../createTheme'; - -const synthwaveTheme: NewThemeOptions = { - name: 'Synthwave', - colors: { - mode: 'dark', - border: { - weak: 'rgba(255, 20, 147, 0.12)', - medium: 'rgba(255, 20, 147, 0.20)', - strong: 'rgba(255, 20, 147, 0.30)', - }, - text: { - primary: '#E0E0E0', - secondary: 'rgba(224, 224, 224, 0.75)', - disabled: 'rgba(224, 224, 224, 0.5)', - link: '#FF69B4', - maxContrast: '#FFFFFF', - }, - primary: { - main: '#FF1493', - }, - secondary: { - main: '#37183a', - text: 'rgba(224, 224, 224, 0.75)', - border: 'rgba(255, 20, 147, 0.10)', - }, - background: { - canvas: '#1A1A2E', - primary: '#16213E', - secondary: '#0F3460', - elevated: '#0F3460', - }, - action: { - hover: 'rgba(255, 20, 147, 0.16)', - selected: 'rgba(255, 20, 147, 0.12)', - selectedBorder: '#FF1493', - focus: 'rgba(255, 20, 147, 0.16)', - hoverOpacity: 0.08, - disabledText: 'rgba(224, 224, 224, 0.5)', - disabledBackground: 'rgba(255, 20, 147, 0.08)', - disabledOpacity: 0.38, - }, - gradients: { - brandHorizontal: 'linear-gradient(270deg, #FF1493 0%, #1E90FF 100%)', - brandVertical: 'linear-gradient(0.01deg, #FF1493 0.01%, #1E90FF 99.99%)', - }, - contrastThreshold: 3, - hoverFactor: 0.03, - tonalOffset: 0.15, - }, -}; - -export default synthwaveTheme; diff --git a/packages/grafana-data/src/themes/themeDefinitions/tron.json b/packages/grafana-data/src/themes/themeDefinitions/tron.json new file mode 100644 index 00000000000..a92cf07fcb0 --- /dev/null +++ b/packages/grafana-data/src/themes/themeDefinitions/tron.json @@ -0,0 +1,50 @@ +{ + "name": "Tron", + "id": "tron", + "colors": { + "mode": "dark", + "border": { + "weak": "rgba(0, 255, 255, 0.12)", + "medium": "rgba(0, 255, 255, 0.20)", + "strong": "rgba(0, 255, 255, 0.30)" + }, + "text": { + "primary": "#E0E0E0", + "secondary": "rgba(224, 224, 224, 0.75)", + "disabled": "rgba(224, 224, 224, 0.5)", + "link": "#00FFFF", + "maxContrast": "#FFFFFF" + }, + "primary": { + "main": "#00FFFF" + }, + "secondary": { + "main": "#0b2e36", + "text": "rgba(224, 224, 224, 0.75)", + "border": "rgba(0, 255, 255, 0.10)" + }, + "background": { + "canvas": "#0A0F18", + "primary": "#0F1B2A", + "secondary": "#152234", + "elevated": "#152234" + }, + "action": { + "hover": "rgba(0, 255, 255, 0.16)", + "selected": "rgba(0, 255, 255, 0.12)", + "selectedBorder": "#00FFFF", + "focus": "rgba(0, 255, 255, 0.16)", + "hoverOpacity": 0.08, + "disabledText": "rgba(224, 224, 224, 0.5)", + "disabledBackground": "rgba(0, 255, 255, 0.08)", + "disabledOpacity": 0.38 + }, + "gradients": { + "brandHorizontal": "linear-gradient(270deg, #00FFFF 0%, #29ABE2 100%)", + "brandVertical": "linear-gradient(0.01deg, #00FFFF 0.01%, #29ABE2 99.99%)" + }, + "contrastThreshold": 3, + "hoverFactor": 0.05, + "tonalOffset": 0.2 + } +} diff --git a/packages/grafana-data/src/themes/themeDefinitions/tron.ts b/packages/grafana-data/src/themes/themeDefinitions/tron.ts deleted file mode 100644 index a9f0b8c3ed4..00000000000 --- a/packages/grafana-data/src/themes/themeDefinitions/tron.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { NewThemeOptions } from '../createTheme'; - -const tronTheme: NewThemeOptions = { - name: 'Tron', - colors: { - mode: 'dark', - border: { - weak: 'rgba(0, 255, 255, 0.12)', - medium: 'rgba(0, 255, 255, 0.20)', - strong: 'rgba(0, 255, 255, 0.30)', - }, - text: { - primary: '#E0E0E0', - secondary: 'rgba(224, 224, 224, 0.75)', - disabled: 'rgba(224, 224, 224, 0.5)', - link: '#00FFFF', - maxContrast: '#FFFFFF', - }, - primary: { - main: '#00FFFF', - }, - secondary: { - main: '#0b2e36', - text: 'rgba(224, 224, 224, 0.75)', - border: 'rgba(0, 255, 255, 0.10)', - }, - background: { - canvas: '#0A0F18', - primary: '#0F1B2A', - secondary: '#152234', - elevated: '#152234', - }, - action: { - hover: 'rgba(0, 255, 255, 0.16)', - selected: 'rgba(0, 255, 255, 0.12)', - selectedBorder: '#00FFFF', - focus: 'rgba(0, 255, 255, 0.16)', - hoverOpacity: 0.08, - disabledText: 'rgba(224, 224, 224, 0.5)', - disabledBackground: 'rgba(0, 255, 255, 0.08)', - disabledOpacity: 0.38, - }, - gradients: { - brandHorizontal: 'linear-gradient(270deg, #00FFFF 0%, #29ABE2 100%)', - brandVertical: 'linear-gradient(0.01deg, #00FFFF 0.01%, #29ABE2 99.99%)', - }, - contrastThreshold: 3, - hoverFactor: 0.05, - tonalOffset: 0.2, - }, -}; - -export default tronTheme; diff --git a/packages/grafana-data/src/themes/themeDefinitions/victorian.json b/packages/grafana-data/src/themes/themeDefinitions/victorian.json new file mode 100644 index 00000000000..14483578450 --- /dev/null +++ b/packages/grafana-data/src/themes/themeDefinitions/victorian.json @@ -0,0 +1,54 @@ +{ + "name": "Victorian", + "id": "victorian", + "colors": { + "mode": "dark", + "border": { + "weak": "#3A2C22", + "medium": "#3A2C22", + "strong": "#4B3D32" + }, + "text": { + "primary": "#D9D0A2", + "secondary": "#C4B89B", + "disabled": "#A89F91", + "link": "#C28A4D", + "maxContrast": "#FFFFFF" + }, + "primary": { + "main": "#C28A4D" + }, + "secondary": { + "main": "#3A2C22", + "text": "#C4B89B", + "border": "#4B3D32" + }, + "background": { + "canvas": "#1F1510", + "primary": "#2C1A13", + "secondary": "#402A21", + "elevated": "#402A21" + }, + "action": { + "hover": "#3A2C22", + "selected": "#4B3D32", + "selectedBorder": "#C28A4D", + "focus": "#C28A4D", + "hoverOpacity": 0.1, + "disabledText": "#A89F91", + "disabledBackground": "#402A21", + "disabledOpacity": 0.38 + }, + "gradients": { + "brandHorizontal": "linear-gradient(270deg, #D9D0a1 0%, #C28A4D 100%)", + "brandVertical": "linear-gradient(0.01deg, #D9D0a1 0.01%, #C28A4D 99.99%)" + }, + "contrastThreshold": 4, + "hoverFactor": 0.07, + "tonalOffset": 0.15 + }, + "typography": { + "fontFamily": "\"Georgia\", \"Times New Roman\", serif", + "fontFamilyMonospace": "'Courier New', monospace" + } +} diff --git a/packages/grafana-data/src/themes/themeDefinitions/victorian.ts b/packages/grafana-data/src/themes/themeDefinitions/victorian.ts deleted file mode 100644 index 32ddbcb244e..00000000000 --- a/packages/grafana-data/src/themes/themeDefinitions/victorian.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { NewThemeOptions } from '../createTheme'; - -const victorianTheme: NewThemeOptions = { - name: 'Victorian', - colors: { - mode: 'dark', - border: { - weak: '#3A2C22', - medium: '#3A2C22', - strong: '#4B3D32', - }, - text: { - primary: '#D9D0A2', - secondary: '#C4B89B', - disabled: '#A89F91', - link: '#C28A4D', - maxContrast: '#FFFFFF', - }, - primary: { - main: '#C28A4D', - }, - secondary: { - main: '#3A2C22', - text: '#C4B89B', - border: '#4B3D32', - }, - background: { - canvas: '#1F1510', - primary: '#2C1A13', - secondary: '#402A21', - elevated: '#402A21', - }, - action: { - hover: '#3A2C22', - selected: '#4B3D32', - selectedBorder: '#C28A4D', - focus: '#C28A4D', - hoverOpacity: 0.1, - disabledText: '#A89F91', - disabledBackground: '#402A21', - disabledOpacity: 0.38, - }, - gradients: { - brandHorizontal: 'linear-gradient(270deg, #D9D0a1 0%, #C28A4D 100%)', - brandVertical: 'linear-gradient(0.01deg, #D9D0a1 0.01%, #C28A4D 99.99%)', - }, - contrastThreshold: 4, - hoverFactor: 0.07, - tonalOffset: 0.15, - }, - typography: { - fontFamily: '"Georgia", "Times New Roman", serif', - fontFamilyMonospace: "'Courier New', monospace", - }, -}; - -export default victorianTheme; diff --git a/packages/grafana-data/src/themes/themeDefinitions/zen.json b/packages/grafana-data/src/themes/themeDefinitions/zen.json new file mode 100644 index 00000000000..99a8b900052 --- /dev/null +++ b/packages/grafana-data/src/themes/themeDefinitions/zen.json @@ -0,0 +1,50 @@ +{ + "name": "Zen", + "id": "zen", + "colors": { + "mode": "light", + "text": { + "primary": "#333333", + "secondary": "#666666", + "disabled": "#B8B8B8", + "link": "#4F9F6E", + "maxContrast": "#000000" + }, + "border": { + "weak": "#B1B7B3", + "medium": "#A2A8A2", + "strong": "#7C7F7A" + }, + "primary": { + "main": "#6D8E6D" + }, + "secondary": { + "main": "#E0E0E0", + "text": "#666666", + "border": "#A2A8A2" + }, + "background": { + "canvas": "#F4F4F4", + "primary": "#E9E9E9", + "secondary": "#D8D8D8", + "elevated": "#E9E9E9" + }, + "action": { + "hover": "#D1D1D1", + "selected": "#B8B8B8", + "selectedBorder": "#88B88B", + "hoverOpacity": 0.1, + "focus": "#D1D1D1", + "disabledBackground": "#E0E0E0", + "disabledText": "#B8B8B8", + "disabledOpacity": 0.5 + }, + "gradients": { + "brandHorizontal": "linear-gradient(270deg, #88B88B 0%, #6D8E6D 100%)", + "brandVertical": "linear-gradient(0.01deg, #88B88B 0.01%, #6D8E6D 99.99%)" + }, + "contrastThreshold": 3, + "hoverFactor": 0.03, + "tonalOffset": 0.2 + } +} diff --git a/packages/grafana-data/src/themes/themeDefinitions/zen.ts b/packages/grafana-data/src/themes/themeDefinitions/zen.ts deleted file mode 100644 index f2735f41b74..00000000000 --- a/packages/grafana-data/src/themes/themeDefinitions/zen.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { NewThemeOptions } from '../createTheme'; - -const zenTheme: NewThemeOptions = { - name: 'Zen', - colors: { - mode: 'light', - text: { - primary: '#333333', - secondary: '#666666', - disabled: '#B8B8B8', - link: '#4F9F6E', - maxContrast: '#000000', - }, - border: { - weak: '#B1B7B3', - medium: '#A2A8A2', - strong: '#7C7F7A', - }, - primary: { - main: '#6D8E6D', - }, - secondary: { - main: '#E0E0E0', - text: '#666666', - border: '#A2A8A2', - }, - background: { - canvas: '#F4F4F4', - primary: '#E9E9E9', - secondary: '#D8D8D8', - elevated: '#E9E9E9', - }, - action: { - hover: '#D1D1D1', - selected: '#B8B8B8', - selectedBorder: '#88B88B', - hoverOpacity: 0.1, - focus: '#D1D1D1', - disabledBackground: '#E0E0E0', - disabledText: '#B8B8B8', - disabledOpacity: 0.5, - }, - gradients: { - brandHorizontal: 'linear-gradient(270deg, #88B88B 0%, #6D8E6D 100%)', - brandVertical: 'linear-gradient(0.01deg, #88B88B 0.01%, #6D8E6D 99.99%)', - }, - contrastThreshold: 3, - hoverFactor: 0.03, - tonalOffset: 0.2, - }, -}; - -export default zenTheme; diff --git a/packages/grafana-data/src/themes/types.ts b/packages/grafana-data/src/themes/types.ts index f586937cf3c..d77c53062d3 100644 --- a/packages/grafana-data/src/themes/types.ts +++ b/packages/grafana-data/src/themes/types.ts @@ -1,3 +1,5 @@ +import { z } from 'zod'; + import { GrafanaTheme } from '../types/theme'; import { ThemeBreakpoints } from './breakpoints'; @@ -35,27 +37,36 @@ export interface GrafanaTheme2 { flags: {}; } -/** @alpha */ -export interface ThemeRichColor { +export const ThemeRichColorInputSchema = z.object({ /** color intent (primary, secondary, info, error, etc) */ - name: string; + name: z.string().optional(), /** Main color */ - main: string; + main: z.string().optional(), /** Used for hover */ - shade: string; + shade: z.string().optional(), /** Used for text */ - text: string; + text: z.string().optional(), /** Used for borders */ - border: string; + border: z.string().optional(), /** Used subtly colored backgrounds */ - transparent: string; + transparent: z.string().optional(), /** Used for weak colored borders like larger alert/banner boxes and smaller badges and tags */ - borderTransparent: string; + borderTransparent: z.string().optional(), /** Text color for text ontop of main */ - contrastText: string; -} + contrastText: z.string().optional(), +}); + +export const ThemeRichColorSchema = ThemeRichColorInputSchema.required(); + +/** @alpha */ +export type ThemeRichColor = z.infer; /** @internal */ export type DeepPartial = { [P in keyof T]?: DeepPartial; }; + +/** @internal */ +export type DeepRequired = Required<{ + [P in keyof T]: T[P] extends Required ? T[P] : DeepRequired; +}>; diff --git a/packages/grafana-data/src/transformations/transformers/ids.ts b/packages/grafana-data/src/transformations/transformers/ids.ts index cc2b76fae69..a3d5536c670 100644 --- a/packages/grafana-data/src/transformations/transformers/ids.ts +++ b/packages/grafana-data/src/transformations/transformers/ids.ts @@ -42,5 +42,6 @@ export enum DataTransformerID { formatTime = 'formatTime', formatString = 'formatString', regression = 'regression', + smoothing = 'smoothing', groupToNestedTable = 'groupToNestedTable', } diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts index 981b10dfb1c..aa0581004e1 100644 --- a/packages/grafana-data/src/types/featureToggles.gen.ts +++ b/packages/grafana-data/src/types/featureToggles.gen.ts @@ -207,6 +207,10 @@ export interface FeatureToggles { */ reportingRetries?: boolean; /** + * Enables CSV encoding options in the reporting feature + */ + reportingCsvEncodingOptions?: boolean; + /** * Send query to the same datasource in a single request when using server side expressions. The `cloudWatchBatchQueries` feature toggle should be enabled if this used with CloudWatch. */ sseGroupByDatasource?: boolean; @@ -356,10 +360,6 @@ export interface FeatureToggles { */ dashboardNewLayouts?: boolean; /** - * Use the v2 kubernetes API in the frontend for dashboards - */ - kubernetesDashboardsV2?: boolean; - /** * Enables undo/redo in dynamic dashboards */ dashboardUndoRedo?: boolean; @@ -404,10 +404,6 @@ export interface FeatureToggles { */ tableSharedCrosshair?: boolean; /** - * Use the kubernetes API for feature toggle management in the frontend - */ - kubernetesFeatureToggles?: boolean; - /** * Enabled grafana cloud specific RBAC roles */ cloudRBACRoles?: boolean; @@ -421,6 +417,10 @@ export interface FeatureToggles { */ jitterAlertRulesWithinGroups?: boolean; /** + * Enable audit logging with Kubernetes under app platform + */ + auditLoggingAppPlatform?: boolean; + /** * Enable the secrets management API and services under app platform */ secretsManagementAppPlatform?: boolean; @@ -527,10 +527,6 @@ export interface FeatureToggles { */ dashboardTemplates?: boolean; /** - * Sets the logs table as default visualisation in logs explore - */ - logsExploreTableDefaultVisualization?: boolean; - /** * Enables the new alert list view design */ alertingListViewV2?: boolean; @@ -626,10 +622,6 @@ export interface FeatureToggles { */ exploreLogsAggregatedMetrics?: boolean; /** - * Used in Logs Drilldown to limit the time range - */ - exploreLogsLimitedTimeRange?: boolean; - /** * Enables the gRPC client to authenticate with the App Platform by using ID & access tokens */ appPlatformGrpcClientAuth?: boolean; @@ -657,14 +649,6 @@ export interface FeatureToggles { */ rolePickerDrawer?: boolean; /** - * Enable unified storage search - */ - unifiedStorageSearch?: boolean; - /** - * Enable sprinkles on unified storage search - */ - unifiedStorageSearchSprinkles?: boolean; - /** * Pick the dual write mode from database configs */ managedDualWriter?: boolean; @@ -703,10 +687,6 @@ export interface FeatureToggles { */ passwordlessMagicLinkAuthentication?: boolean; /** - * Display Related Logs in Grafana Metrics Drilldown - */ - exploreMetricsRelatedLogs?: boolean; - /** * Adds support for quotes and special characters in label values for Prometheus queries */ prometheusSpecialCharsInLabelValues?: boolean; @@ -782,20 +762,11 @@ export interface FeatureToggles { */ elasticsearchCrossClusterSearch?: boolean; /** - * Displays the navigation history so the user can navigate back to previous pages - */ - unifiedHistory?: boolean; - /** * Defaults to using the Loki `/labels` API instead of `/series` * @default true */ lokiLabelNamesQueryApi?: boolean; /** - * Enable the investigations backend API - * @default false - */ - investigationsBackend?: boolean; - /** * Enable folder's api server counts * @default false */ @@ -966,7 +937,8 @@ export interface FeatureToggles { */ alertingBulkActionsInUI?: boolean; /** - * Registers AuthZ /apis endpoint + * Deprecated: Use kubernetesAuthzCoreRolesApi, kubernetesAuthzRolesApi, and kubernetesAuthzRoleBindingsApi instead + * @deprecated */ kubernetesAuthzApis?: boolean; /** @@ -982,6 +954,18 @@ export interface FeatureToggles { */ kubernetesAuthzZanzanaSync?: boolean; /** + * Registers AuthZ Core Roles /apis endpoint + */ + kubernetesAuthzCoreRolesApi?: boolean; + /** + * Registers AuthZ Roles /apis endpoint + */ + kubernetesAuthzRolesApi?: boolean; + /** + * Registers AuthZ Role Bindings /apis endpoint + */ + kubernetesAuthzRoleBindingsApi?: boolean; + /** * Enables create, delete, and update mutations for resources owned by IAM identity */ kubernetesAuthnMutation?: boolean; @@ -1000,6 +984,11 @@ export interface FeatureToggles { */ recentlyViewedDashboards?: boolean; /** + * A/A test for recently viewed dashboards feature + * @default false + */ + experimentRecentlyViewedDashboards?: boolean; + /** * Enable configuration of alert enrichments in Grafana Cloud. * @default false */ @@ -1133,11 +1122,6 @@ export interface FeatureToggles { */ pluginContainers?: boolean; /** - * Run search queries through the tempo backend - * @default false - */ - tempoSearchBackendMigration?: boolean; - /** * Prioritize loading plugins from the CDN before other sources * @default false */ @@ -1255,4 +1239,16 @@ export interface FeatureToggles { * Enables support for variables whose values can have multiple properties */ multiPropsVariables?: boolean; + /** + * Enables the ASAP smoothing transformation for time series data + */ + smoothingTransformation?: boolean; + /** + * Enables the creation of keepers that manage secrets stored on AWS secrets manager + */ + secretsManagementAppPlatformAwsKeeper?: boolean; + /** + * Enables profiles exemplars support in profiles drilldown + */ + profilesExemplars?: boolean; } diff --git a/packages/grafana-data/src/types/icon.ts b/packages/grafana-data/src/types/icon.ts index 34e672b66f5..3dc7215a2cf 100644 --- a/packages/grafana-data/src/types/icon.ts +++ b/packages/grafana-data/src/types/icon.ts @@ -52,6 +52,7 @@ export const availableIconsIndex = { bookmark: true, 'book-open': true, 'brackets-curly': true, + brain: true, 'browser-alt': true, bug: true, building: true, diff --git a/packages/grafana-data/src/types/templateVars.ts b/packages/grafana-data/src/types/templateVars.ts index 8b6ed69463b..62ce2862af2 100644 --- a/packages/grafana-data/src/types/templateVars.ts +++ b/packages/grafana-data/src/types/templateVars.ts @@ -103,6 +103,7 @@ export interface IntervalVariableModel extends VariableWithOptions { export interface CustomVariableModel extends VariableWithMultiSupport { type: 'custom'; + valuesFormat?: 'csv' | 'json'; } export interface DataSourceVariableModel extends VariableWithMultiSupport { diff --git a/packages/grafana-data/src/unstable.ts b/packages/grafana-data/src/unstable.ts index 8a42447206f..3200085428a 100644 --- a/packages/grafana-data/src/unstable.ts +++ b/packages/grafana-data/src/unstable.ts @@ -9,5 +9,4 @@ * and be subject to the standard policies */ -// This is a dummy export so typescript doesn't error importing an "empty module" -export const unstable = {}; +export { default as themeJsonSchema } from './themes/schema.generated.json'; diff --git a/packages/grafana-e2e-selectors/src/selectors/components.ts b/packages/grafana-e2e-selectors/src/selectors/components.ts index de04398a3e1..7dd819a1512 100644 --- a/packages/grafana-e2e-selectors/src/selectors/components.ts +++ b/packages/grafana-e2e-selectors/src/selectors/components.ts @@ -535,6 +535,11 @@ export const versionedComponents = { '12.3.0': 'data-testid viz-tooltip-wrapper', }, }, + Gauge: { + Container: { + '12.4.0': 'data-testid gauge container', + }, + }, }, }, VizLegend: { @@ -1288,6 +1293,9 @@ export const versionedComponents = { card: { [MIN_GRAFANA_VERSION]: (name: string) => `data-testid suggestion-${name}`, }, + confirm: { + '12.4.0': (name: string) => `data-testid suggestion-${name} confirm button`, + }, }, ColorSwatch: { name: { diff --git a/packages/grafana-e2e-selectors/src/selectors/pages.ts b/packages/grafana-e2e-selectors/src/selectors/pages.ts index b88dac9099c..35bc4f7c975 100644 --- a/packages/grafana-e2e-selectors/src/selectors/pages.ts +++ b/packages/grafana-e2e-selectors/src/selectors/pages.ts @@ -266,6 +266,9 @@ export const versionedPages = { Controls: { '11.1.0': 'data-testid dashboard controls', }, + ControlsButton: { + '12.3.0': 'data-testid dashboard controls button', + }, SubMenu: { submenu: { [MIN_GRAFANA_VERSION]: 'Dashboard submenu', diff --git a/packages/grafana-i18n/package.json b/packages/grafana-i18n/package.json index 36a9faa541b..93dd9837897 100644 --- a/packages/grafana-i18n/package.json +++ b/packages/grafana-i18n/package.json @@ -29,7 +29,6 @@ "@grafana-app/source": "./src/internal/index.ts" }, "./eslint-plugin": { - "@grafana-app/source": "./src/eslint/index.cjs", "types": "./src/eslint/index.d.ts", "default": "./src/eslint/index.cjs" } diff --git a/packages/grafana-prometheus/src/dashboards/grafana_stats.json b/packages/grafana-prometheus/src/dashboards/grafana_stats.json deleted file mode 100644 index 292f93394f3..00000000000 --- a/packages/grafana-prometheus/src/dashboards/grafana_stats.json +++ /dev/null @@ -1,1187 +0,0 @@ -{ - "_comment": "Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/dashboards/grafana_stats.json", - "__inputs": [ - { - "name": "DS_PROMETHEUS", - "label": "Prometheus", - "description": "", - "type": "datasource", - "pluginId": "prometheus", - "pluginName": "Prometheus" - } - ], - "__requires": [ - { - "type": "grafana", - "id": "grafana", - "name": "Grafana", - "version": "8.1.0-pre" - }, - { - "type": "datasource", - "id": "prometheus", - "name": "Prometheus", - "version": "1.0.0" - }, - { - "type": "panel", - "id": "stat", - "name": "Stat", - "version": "" - }, - { - "type": "panel", - "id": "table-old", - "name": "Table (old)", - "version": "" - }, - { - "type": "panel", - "id": "timeseries", - "name": "Time series", - "version": "" - } - ], - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": "-- Grafana --", - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" - } - ] - }, - "description": "Metrics about Grafana", - "editable": true, - "gnetId": null, - "graphTooltip": 0, - "id": null, - "links": [ - { - "icon": "external link", - "tags": [], - "targetBlank": true, - "title": "Available metrics", - "type": "link", - "url": "/metrics" - }, - { - "icon": "external link", - "tags": [], - "targetBlank": true, - "title": "Grafana docs", - "type": "link", - "url": "https://grafana.com/docs/grafana/latest/" - }, - { - "icon": "external link", - "tags": [], - "targetBlank": true, - "title": "Prometheus docs", - "type": "link", - "url": "http://prometheus.io/docs/introduction/overview/" - } - ], - "panels": [ - { - "cacheTimeout": null, - "datasource": "${DS_PROMETHEUS}", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 0, - "mappings": [ - { - "options": { - "0": { - "text": ":(" - } - }, - "type": "value" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "rgba(222, 3, 3, 0.9)", - "value": null - }, - { - "color": "rgb(234, 245, 234)", - "value": 1 - }, - { - "color": "rgb(235, 244, 235)", - "value": 10000 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 5, - "w": 5, - "x": 0, - "y": 0 - }, - "id": 4, - "interval": null, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": ["mean"], - "fields": "", - "values": false - }, - "text": {}, - "textMode": "auto" - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": "up{job=\"grafana\"}", - "format": "time_series", - "instant": true, - "intervalFactor": 2, - "refId": "A", - "step": 60 - } - ], - "title": "Active instances", - "type": "stat" - }, - { - "cacheTimeout": null, - "datasource": "${DS_PROMETHEUS}", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 5, - "w": 5, - "x": 5, - "y": 0 - }, - "id": 8, - "interval": null, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "none", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": ["mean"], - "fields": "", - "values": false - }, - "text": {}, - "textMode": "auto" - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": "grafana_stat_totals_dashboard", - "format": "time_series", - "instant": true, - "intervalFactor": 2, - "refId": "A", - "step": 60 - } - ], - "title": "Dashboard count", - "type": "stat" - }, - { - "cacheTimeout": null, - "datasource": "${DS_PROMETHEUS}", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 5, - "w": 5, - "x": 10, - "y": 0 - }, - "id": 9, - "interval": null, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "none", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": ["mean"], - "fields": "", - "values": false - }, - "text": {}, - "textMode": "auto" - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": "grafana_stat_total_users", - "format": "time_series", - "instant": true, - "intervalFactor": 2, - "refId": "A", - "step": 60 - } - ], - "title": "User count", - "type": "stat" - }, - { - "cacheTimeout": null, - "datasource": "${DS_PROMETHEUS}", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 5, - "w": 5, - "x": 15, - "y": 0 - }, - "id": 10, - "interval": null, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "none", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": ["mean"], - "fields": "", - "values": false - }, - "text": {}, - "textMode": "auto" - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": "grafana_stat_total_playlists", - "format": "time_series", - "instant": true, - "intervalFactor": 2, - "refId": "A", - "step": 60 - } - ], - "title": "Playlist count", - "type": "stat" - }, - { - "columns": [], - "datasource": "${DS_PROMETHEUS}", - "fontSize": "100%", - "gridPos": { - "h": 5, - "w": 4, - "x": 20, - "y": 0 - }, - "id": 17, - "links": [], - "pageSize": null, - "scroll": false, - "showHeader": true, - "sort": { - "col": 0, - "desc": true - }, - "styles": [ - { - "alias": "Time", - "align": "auto", - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "link": false, - "pattern": "Time", - "type": "hidden" - }, - { - "alias": "", - "align": "auto", - "colorMode": null, - "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], - "decimals": 0, - "pattern": "/.*/", - "thresholds": [], - "type": "number", - "unit": "short" - } - ], - "targets": [ - { - "expr": "topk(1, grafana_info or grafana_build_info)", - "format": "time_series", - "instant": true, - "intervalFactor": 2, - "legendFormat": "{{version}}", - "refId": "A", - "step": 20 - } - ], - "title": "Grafana version", - "transform": "timeseries_to_rows", - "type": "table-old" - }, - { - "datasource": "${DS_PROMETHEUS}", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 2, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "400" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#447EBC", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "500" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#BF1B00", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 10, - "w": 10, - "x": 0, - "y": 5 - }, - "id": 15, - "links": [], - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single" - } - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": "sum by (status_code) (irate(grafana_http_request_duration_seconds_count[5m]))", - "format": "time_series", - "intervalFactor": 3, - "legendFormat": "{{status_code}}", - "refId": "B", - "step": 15, - "target": "dev.grafana.cb-office.alerting.active_alerts" - } - ], - "timeFrom": null, - "timeShift": null, - "title": "http status codes", - "type": "timeseries" - }, - { - "datasource": "${DS_PROMETHEUS}", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 2, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "400" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#447EBC", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "500" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#BF1B00", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 10, - "w": 10, - "x": 10, - "y": 5 - }, - "id": 11, - "links": [], - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single" - } - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": "sum(irate(grafana_api_response_status_total[5m]))", - "format": "time_series", - "intervalFactor": 4, - "legendFormat": "api", - "refId": "A", - "step": 20 - }, - { - "expr": "sum(irate(grafana_proxy_response_status_total[5m]))", - "format": "time_series", - "intervalFactor": 4, - "legendFormat": "proxy", - "refId": "B", - "step": 20 - }, - { - "expr": "sum(irate(grafana_page_response_status_total[5m]))", - "format": "time_series", - "intervalFactor": 4, - "legendFormat": "web", - "refId": "C", - "step": 20 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Requests by routing group", - "type": "timeseries" - }, - { - "columns": [], - "datasource": "${DS_PROMETHEUS}", - "fontSize": "100%", - "gridPos": { - "h": 10, - "w": 4, - "x": 20, - "y": 5 - }, - "height": "", - "id": 12, - "links": [], - "pageSize": null, - "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": "hidden" - }, - { - "alias": "", - "align": "auto", - "colorMode": null, - "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], - "decimals": 0, - "pattern": "/.*/", - "thresholds": [], - "type": "number", - "unit": "short" - } - ], - "targets": [ - { - "expr": "sort(topk(8, sum by (handler) (grafana_http_request_duration_seconds_count)))", - "format": "time_series", - "instant": true, - "intervalFactor": 10, - "legendFormat": "{{handler}}", - "refId": "A", - "step": 100 - } - ], - "title": "Most used handlers", - "transform": "timeseries_to_rows", - "type": "table-old" - }, - { - "datasource": "${DS_PROMETHEUS}", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 2, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": true, - "stacking": { - "group": "A", - "mode": "normal" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "alerting" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#890F02", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "ok" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#7EB26D", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 5, - "w": 12, - "x": 0, - "y": 15 - }, - "id": 6, - "links": [], - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single" - } - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": "increase(grafana_alerting_active_alerts[1m])", - "format": "time_series", - "intervalFactor": 3, - "legendFormat": "{{state}}", - "refId": "A", - "step": 15 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Grafana active alerts", - "type": "timeseries" - }, - { - "datasource": "${DS_PROMETHEUS}", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 2, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": true, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "alerting" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#890F02", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "alertname" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#BF1B00", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "firing alerts" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#BF1B00", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "ok" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#7EB26D", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 5, - "w": 12, - "x": 12, - "y": 15 - }, - "id": 18, - "links": [], - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single" - } - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": " sum (ALERTS)", - "format": "time_series", - "intervalFactor": 3, - "legendFormat": "firing alerts", - "refId": "A", - "step": 15 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Prometheus alerts", - "type": "timeseries" - }, - { - "datasource": "${DS_PROMETHEUS}", - "description": "Aggregated over all Grafana nodes.", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 2, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": true, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "avg gc duration" - }, - "properties": [ - { - "id": "unit", - "value": "decbytes" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "allocated memory" - }, - "properties": [ - { - "id": "unit", - "value": "decbytes" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "used memory" - }, - "properties": [ - { - "id": "unit", - "value": "decbytes" - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "memory usage" - }, - "properties": [ - { - "id": "unit", - "value": "decbytes" - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 24, - "x": 0, - "y": 20 - }, - "id": 7, - "links": [], - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single" - } - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": "sum(go_goroutines{job=\"grafana\"})", - "format": "time_series", - "hide": false, - "intervalFactor": 4, - "legendFormat": "go routines", - "refId": "A", - "step": 8, - "target": "select metric", - "type": "timeserie" - }, - { - "expr": "sum(process_resident_memory_bytes{job=\"grafana\"})", - "format": "time_series", - "intervalFactor": 4, - "legendFormat": "memory usage", - "refId": "B", - "step": 8 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Grafana performance", - "type": "timeseries" - } - ], - "revision": "1.0", - "schemaVersion": 30, - "tags": ["grafana", "prometheus"], - "templating": { - "list": [] - }, - "time": { - "from": "now-6h", - "to": "now" - }, - "timepicker": { - "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"] - }, - "timezone": "", - "title": "Grafana metrics", - "uid": "isFoa0z7k", - "version": 3 -} diff --git a/packages/grafana-prometheus/src/dashboards/prometheus_2_stats.json b/packages/grafana-prometheus/src/dashboards/prometheus_2_stats.json deleted file mode 100644 index 5a6fbdf8518..00000000000 --- a/packages/grafana-prometheus/src/dashboards/prometheus_2_stats.json +++ /dev/null @@ -1,1403 +0,0 @@ -{ - "_comment": "Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/dashboards/prometheus_2_stats.json", - "__inputs": [ - { - "name": "DS_GDEV-PROMETHEUS", - "label": "gdev-prometheus", - "description": "", - "type": "datasource", - "pluginId": "prometheus", - "pluginName": "Prometheus" - } - ], - "__requires": [ - { - "type": "grafana", - "id": "grafana", - "name": "Grafana", - "version": "8.1.0-pre" - }, - { - "type": "datasource", - "id": "prometheus", - "name": "Prometheus", - "version": "1.0.0" - }, - { - "type": "panel", - "id": "stat", - "name": "Stat", - "version": "" - }, - { - "type": "panel", - "id": "timeseries", - "name": "Time series", - "version": "" - } - ], - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": "-- Grafana --", - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" - } - ] - }, - "editable": true, - "gnetId": null, - "graphTooltip": 1, - "id": null, - "links": [ - { - "icon": "info", - "tags": [], - "targetBlank": true, - "title": "Grafana Docs", - "tooltip": "", - "type": "link", - "url": "https://grafana.com/docs/grafana/latest/" - }, - { - "icon": "info", - "tags": [], - "targetBlank": true, - "title": "Prometheus Docs", - "type": "link", - "url": "http://prometheus.io/docs/introduction/overview/" - } - ], - "panels": [ - { - "datasource": "${DS_GDEV-PROMETHEUS}", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "min": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "prometheus" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#C15C17", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "{instance=\"localhost:9090\",job=\"prometheus\"}" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#CCA300", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 6, - "w": 6, - "x": 0, - "y": 0 - }, - "id": 3, - "links": [], - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single" - } - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": "sum(irate(prometheus_tsdb_head_samples_appended_total{job=\"prometheus\"}[5m]))", - "format": "time_series", - "hide": false, - "interval": "", - "intervalFactor": 2, - "legendFormat": "samples", - "metric": "", - "refId": "A", - "step": 20 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Samples Appended", - "type": "timeseries" - }, - { - "datasource": "${DS_GDEV-PROMETHEUS}", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 6, - "w": 6, - "x": 6, - "y": 0 - }, - "id": 14, - "links": [], - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single" - } - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": "topk(5, max(scrape_duration_seconds) by (job))", - "format": "time_series", - "interval": "", - "intervalFactor": 2, - "legendFormat": "{{job}}", - "metric": "", - "refId": "A", - "step": 20 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Scrape Duration", - "type": "timeseries" - }, - { - "datasource": "${DS_GDEV-PROMETHEUS}", - "description": "", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": true, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "min": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "bytes" - }, - "overrides": [] - }, - "gridPos": { - "h": 6, - "w": 6, - "x": 12, - "y": 0 - }, - "id": 16, - "links": [], - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single" - } - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": "sum(process_resident_memory_bytes{job=\"prometheus\"})", - "format": "time_series", - "hide": false, - "interval": "", - "intervalFactor": 2, - "legendFormat": "p8s process resident memory", - "refId": "D", - "step": 20 - }, - { - "expr": "process_virtual_memory_bytes{job=\"prometheus\"}", - "format": "time_series", - "hide": false, - "intervalFactor": 2, - "legendFormat": "virtual memory", - "refId": "C", - "step": 20 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Memory Profile", - "type": "timeseries" - }, - { - "cacheTimeout": null, - "datasource": "${DS_GDEV-PROMETHEUS}", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "0": { - "text": "None" - } - }, - "type": "value" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "rgba(50, 172, 45, 0.97)", - "value": null - }, - { - "color": "rgba(237, 129, 40, 0.89)", - "value": 0.1 - }, - { - "color": "rgba(245, 54, 54, 0.9)", - "value": 1 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 6, - "w": 6, - "x": 18, - "y": 0 - }, - "id": 37, - "interval": null, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": ["max"], - "fields": "", - "values": false - }, - "text": {}, - "textMode": "auto" - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": "prometheus_tsdb_wal_corruptions_total{job=\"prometheus\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "", - "refId": "A", - "step": 60 - } - ], - "title": "WAL Corruptions", - "type": "stat" - }, - { - "datasource": "${DS_GDEV-PROMETHEUS}", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": true, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [] - }, - "gridPos": { - "h": 6, - "w": 6, - "x": 0, - "y": 6 - }, - "id": 29, - "links": [], - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single" - } - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": "sum(prometheus_tsdb_head_active_appenders{job=\"prometheus\"})", - "format": "time_series", - "interval": "", - "intervalFactor": 2, - "legendFormat": "active_appenders", - "metric": "", - "refId": "A", - "step": 20 - }, - { - "expr": "sum(process_open_fds{job=\"prometheus\"})", - "format": "time_series", - "interval": "", - "intervalFactor": 2, - "legendFormat": "open_fds", - "refId": "B", - "step": 20 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Active Appenders", - "type": "timeseries" - }, - { - "datasource": "${DS_GDEV-PROMETHEUS}", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "prometheus" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#F9BA8F", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "{instance=\"localhost:9090\",interval=\"5s\",job=\"prometheus\"}" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#F9BA8F", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 6, - "w": 6, - "x": 6, - "y": 6 - }, - "id": 2, - "links": [], - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single" - } - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": "prometheus_tsdb_blocks_loaded{job=\"prometheus\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "blocks", - "refId": "A", - "step": 20 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Blocks Loaded", - "type": "timeseries" - }, - { - "datasource": "${DS_GDEV-PROMETHEUS}", - "description": "", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [] - }, - "gridPos": { - "h": 6, - "w": 6, - "x": 12, - "y": 6 - }, - "id": 33, - "links": [], - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single" - } - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": "prometheus_tsdb_head_chunks{job=\"prometheus\"}", - "format": "time_series", - "interval": "", - "intervalFactor": 2, - "legendFormat": "chunks", - "refId": "A", - "step": 20 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Head Chunks", - "type": "timeseries" - }, - { - "datasource": "${DS_GDEV-PROMETHEUS}", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": true, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "min": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "duration-p99" - }, - "properties": [ - { - "id": "unit", - "value": "s" - } - ] - } - ] - }, - "gridPos": { - "h": 6, - "w": 6, - "x": 18, - "y": 6 - }, - "id": 36, - "links": [], - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single" - } - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": "prometheus_tsdb_head_gc_duration_seconds{job=\"prometheus\",quantile=\"0.99\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "duration-p99", - "refId": "A", - "step": 20 - }, - { - "expr": "irate(prometheus_tsdb_head_gc_duration_seconds_count{job=\"prometheus\"}[5m])", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "collections", - "refId": "B", - "step": 20 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Head Block GC Activity", - "type": "timeseries" - }, - { - "datasource": "${DS_GDEV-PROMETHEUS}", - "description": "", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "min": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "duration-p99" - }, - "properties": [ - { - "id": "unit", - "value": "s" - } - ] - } - ] - }, - "gridPos": { - "h": 6, - "w": 8, - "x": 0, - "y": 12 - }, - "id": 20, - "links": [], - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single" - } - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": "histogram_quantile(0.99, sum(rate(prometheus_tsdb_compaction_duration_bucket{job=\"prometheus\"}[5m])) by (le))", - "format": "time_series", - "hide": false, - "interval": "", - "intervalFactor": 2, - "legendFormat": "duration-{{p99}}", - "refId": "A", - "step": 20 - }, - { - "expr": "irate(prometheus_tsdb_compactions_total{job=\"prometheus\"}[5m])", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "compactions", - "refId": "B", - "step": 20 - }, - { - "expr": "irate(prometheus_tsdb_compactions_failed_total{job=\"prometheus\"}[5m])", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "failed", - "refId": "C", - "step": 20 - }, - { - "expr": "irate(prometheus_tsdb_compactions_triggered_total{job=\"prometheus\"}[5m])", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "triggered", - "refId": "D", - "step": 20 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Compaction Activity", - "type": "timeseries" - }, - { - "datasource": "${DS_GDEV-PROMETHEUS}", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": true, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [] - }, - "gridPos": { - "h": 6, - "w": 8, - "x": 8, - "y": 12 - }, - "id": 32, - "links": [], - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single" - } - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": "rate(prometheus_tsdb_reloads_total{job=\"prometheus\"}[5m])", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "reloads", - "refId": "A", - "step": 20 - }, - { - "expr": "rate(prometheus_tsdb_reloads_failures_total{job=\"prometheus\"}[5m])", - "format": "time_series", - "hide": false, - "intervalFactor": 2, - "legendFormat": "failures", - "refId": "B", - "step": 20 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Reload Count", - "type": "timeseries" - }, - { - "datasource": "${DS_GDEV-PROMETHEUS}", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": true, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [] - }, - "gridPos": { - "h": 6, - "w": 8, - "x": 16, - "y": 12 - }, - "id": 38, - "links": [], - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single" - } - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": "prometheus_engine_query_duration_seconds{job=\"prometheus\", quantile=\"0.99\"}", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "{{slice}}_p99", - "refId": "A", - "step": 20 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Query Durations", - "type": "timeseries" - }, - { - "datasource": "${DS_GDEV-PROMETHEUS}", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 0, - "y": 18 - }, - "id": 35, - "links": [], - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single" - } - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": "max(prometheus_rule_group_duration_seconds{job=\"prometheus\"}) by (quantile)", - "format": "time_series", - "interval": "", - "intervalFactor": 2, - "legendFormat": "{{quantile}}", - "refId": "A", - "step": 10 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Rule Group Eval Duration", - "type": "timeseries" - }, - { - "datasource": "${DS_GDEV-PROMETHEUS}", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": true, - "stacking": { - "group": "A", - "mode": "normal" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 12, - "x": 12, - "y": 18 - }, - "id": 39, - "links": [], - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single" - } - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": "rate(prometheus_rule_group_iterations_missed_total{job=\"prometheus\"}[5m])", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "missed", - "refId": "B", - "step": 10 - }, - { - "expr": "rate(prometheus_rule_group_iterations_total{job=\"prometheus\"}[5m])", - "format": "time_series", - "intervalFactor": 2, - "legendFormat": "iterations", - "refId": "A", - "step": 10 - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Rule Group Eval Activity", - "type": "timeseries" - } - ], - "refresh": "1m", - "revision": "1.0", - "schemaVersion": 30, - "tags": ["prometheus"], - "templating": { - "list": [] - }, - "time": { - "from": "now-1h", - "to": "now" - }, - "timepicker": { - "now": true, - "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"] - }, - "timezone": "browser", - "title": "Prometheus 2.0 Stats", - "uid": "UDdpyzz7z", - "version": 1 -} diff --git a/packages/grafana-prometheus/src/dashboards/prometheus_stats.json b/packages/grafana-prometheus/src/dashboards/prometheus_stats.json deleted file mode 100644 index 42ea6e7a4d5..00000000000 --- a/packages/grafana-prometheus/src/dashboards/prometheus_stats.json +++ /dev/null @@ -1,834 +0,0 @@ -{ - "_comment": "Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/dashboards/prometheus_stats.json", - "__inputs": [ - { - "name": "DS_GDEV-PROMETHEUS", - "label": "gdev-prometheus", - "description": "", - "type": "datasource", - "pluginId": "prometheus", - "pluginName": "Prometheus" - } - ], - "__requires": [ - { - "type": "grafana", - "id": "grafana", - "name": "Grafana", - "version": "8.1.0-pre" - }, - { - "type": "datasource", - "id": "prometheus", - "name": "Prometheus", - "version": "1.0.0" - }, - { - "type": "panel", - "id": "stat", - "name": "Stat", - "version": "" - }, - { - "type": "panel", - "id": "text", - "name": "Text", - "version": "" - }, - { - "type": "panel", - "id": "timeseries", - "name": "Time series", - "version": "" - } - ], - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": "-- Grafana --", - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" - } - ] - }, - "editable": true, - "gnetId": null, - "graphTooltip": 0, - "id": null, - "iteration": 1624859749459, - "links": [ - { - "icon": "info", - "tags": [], - "targetBlank": true, - "title": "Grafana Docs", - "tooltip": "", - "type": "link", - "url": "https://grafana.com/docs/grafana/latest/" - }, - { - "icon": "info", - "tags": [], - "targetBlank": true, - "title": "Prometheus Docs", - "type": "link", - "url": "http://prometheus.io/docs/introduction/overview/" - } - ], - "panels": [ - { - "cacheTimeout": null, - "datasource": "${DS_GDEV-PROMETHEUS}", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 1, - "mappings": [ - { - "options": { - "match": "null", - "result": { - "text": "N/A" - } - }, - "type": "special" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { - "h": 5, - "w": 6, - "x": 0, - "y": 0 - }, - "id": 5, - "interval": null, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "none", - "graphMode": "none", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": ["lastNotNull"], - "fields": "", - "values": false - }, - "text": {}, - "textMode": "auto" - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": "(time() - process_start_time_seconds{job=\"prometheus\", instance=~\"$node\"})", - "intervalFactor": 2, - "refId": "A" - } - ], - "title": "Uptime", - "type": "stat" - }, - { - "cacheTimeout": null, - "datasource": "${DS_GDEV-PROMETHEUS}", - "fieldConfig": { - "defaults": { - "color": { - "fixedColor": "rgb(31, 120, 193)", - "mode": "fixed" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "rgba(50, 172, 45, 0.97)", - "value": null - }, - { - "color": "rgba(237, 129, 40, 0.89)", - "value": 1 - }, - { - "color": "rgba(245, 54, 54, 0.9)", - "value": 5 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 5, - "w": 6, - "x": 6, - "y": 0 - }, - "id": 6, - "interval": null, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "none", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": ["lastNotNull"], - "fields": "", - "values": false - }, - "text": {}, - "textMode": "auto" - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": "prometheus_local_storage_memory_series{instance=~\"$node\"}", - "intervalFactor": 2, - "refId": "A" - } - ], - "title": "Local Storage Memory Series", - "type": "stat" - }, - { - "cacheTimeout": null, - "datasource": "${DS_GDEV-PROMETHEUS}", - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [ - { - "options": { - "0": { - "text": "Empty" - } - }, - "type": "value" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "rgba(50, 172, 45, 0.97)", - "value": null - }, - { - "color": "rgba(237, 129, 40, 0.89)", - "value": 500 - }, - { - "color": "rgba(245, 54, 54, 0.9)", - "value": 4000 - } - ] - }, - "unit": "none" - }, - "overrides": [] - }, - "gridPos": { - "h": 5, - "w": 6, - "x": 12, - "y": 0 - }, - "id": 7, - "interval": null, - "links": [], - "maxDataPoints": 100, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "horizontal", - "reduceOptions": { - "calcs": ["lastNotNull"], - "fields": "", - "values": false - }, - "text": {}, - "textMode": "auto" - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": "prometheus_local_storage_indexing_queue_length{instance=~\"$node\"}", - "intervalFactor": 2, - "refId": "A" - } - ], - "title": "Internal Storage Queue Length", - "type": "stat" - }, - { - "datasource": null, - "editable": true, - "error": false, - "gridPos": { - "h": 5, - "w": 6, - "x": 18, - "y": 0 - }, - "id": 9, - "links": [], - "options": { - "content": "Prometheus\n\n

You're using Prometheus, an open-source systems monitoring and alerting toolkit originally built at SoundCloud. For more information, check out the Grafana and Prometheus projects.

", - "mode": "html" - }, - "pluginVersion": "8.1.0-pre", - "style": {}, - "transparent": true, - "type": "text" - }, - { - "datasource": "${DS_GDEV-PROMETHEUS}", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 2, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "prometheus" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#C15C17", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "{instance=\"localhost:9090\",job=\"prometheus\"}" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#C15C17", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 6, - "w": 18, - "x": 0, - "y": 5 - }, - "id": 3, - "links": [], - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single" - } - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": "rate(prometheus_local_storage_ingested_samples_total{instance=~\"$node\"}[5m])", - "interval": "", - "intervalFactor": 2, - "legendFormat": "{{job}}", - "metric": "", - "refId": "A" - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Samples ingested (rate-5m)", - "type": "timeseries" - }, - { - "datasource": null, - "editable": true, - "error": false, - "gridPos": { - "h": 6, - "w": 4, - "x": 18, - "y": 5 - }, - "id": 8, - "links": [], - "options": { - "content": "#### Samples Ingested\nThis graph displays the count of samples ingested by the Prometheus server, as measured over the last 5 minutes, per time series in the range vector. When troubleshooting an issue on IRC or GitHub, this is often the first stat requested by the Prometheus team. ", - "mode": "markdown" - }, - "pluginVersion": "8.1.0-pre", - "style": {}, - "transparent": true, - "type": "text" - }, - { - "datasource": "${DS_GDEV-PROMETHEUS}", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 2, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [ - { - "matcher": { - "id": "byName", - "options": "prometheus" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#F9BA8F", - "mode": "fixed" - } - } - ] - }, - { - "matcher": { - "id": "byName", - "options": "{instance=\"localhost:9090\",interval=\"5s\",job=\"prometheus\"}" - }, - "properties": [ - { - "id": "color", - "value": { - "fixedColor": "#F9BA8F", - "mode": "fixed" - } - } - ] - } - ] - }, - "gridPos": { - "h": 7, - "w": 10, - "x": 0, - "y": 11 - }, - "id": 2, - "links": [], - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single" - } - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": "rate(prometheus_target_interval_length_seconds_count{instance=~\"$node\"}[5m])", - "intervalFactor": 2, - "legendFormat": "{{job}}", - "refId": "A" - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Target Scrapes (last 5m)", - "type": "timeseries" - }, - { - "datasource": "${DS_GDEV-PROMETHEUS}", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 2, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "short" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 8, - "x": 10, - "y": 11 - }, - "id": 14, - "links": [], - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single" - } - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": "prometheus_target_interval_length_seconds{quantile!=\"0.01\", quantile!=\"0.05\",instance=~\"$node\"}", - "interval": "", - "intervalFactor": 2, - "legendFormat": "{{quantile}} ({{interval}})", - "metric": "", - "refId": "A" - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Scrape Duration", - "type": "timeseries" - }, - { - "datasource": null, - "editable": true, - "error": false, - "gridPos": { - "h": 7, - "w": 6, - "x": 18, - "y": 11 - }, - "id": 11, - "links": [], - "options": { - "content": "#### Scrapes\nPrometheus scrapes metrics from instrumented jobs, either directly or via an intermediary push gateway for short-lived jobs. Target scrapes will show how frequently targets are scraped, as measured over the last 5 minutes, per time series in the range vector. Scrape Duration will show how long the scrapes are taking, with percentiles available as series. ", - "mode": "markdown" - }, - "pluginVersion": "8.1.0-pre", - "style": {}, - "transparent": true, - "type": "text" - }, - { - "datasource": "${DS_GDEV-PROMETHEUS}", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 2, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "never", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "links": [], - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - }, - "unit": "percentunit" - }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 18, - "x": 0, - "y": 18 - }, - "id": 12, - "links": [], - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom" - }, - "tooltip": { - "mode": "single" - } - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "expr": "prometheus_evaluator_duration_seconds{quantile!=\"0.01\", quantile!=\"0.05\",instance=~\"$node\"}", - "interval": "", - "intervalFactor": 2, - "legendFormat": "{{quantile}}", - "refId": "A" - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Rule Eval Duration", - "type": "timeseries" - }, - { - "datasource": null, - "editable": true, - "error": false, - "gridPos": { - "h": 7, - "w": 6, - "x": 18, - "y": 18 - }, - "id": 15, - "links": [], - "options": { - "content": "#### Rule Evaluation Duration\nThis graph panel plots the duration for all evaluations to execute. The 50th percentile, 90th percentile and 99th percentile are shown as three separate series to help identify outliers that may be skewing the data.", - "mode": "markdown" - }, - "pluginVersion": "8.1.0-pre", - "style": {}, - "transparent": true, - "type": "text" - } - ], - "refresh": false, - "revision": "1.0", - "schemaVersion": 30, - "tags": ["prometheus"], - "templating": { - "list": [ - { - "allValue": null, - "current": {}, - "datasource": "${DS_GDEV-PROMETHEUS}", - "definition": "", - "description": null, - "error": null, - "hide": 0, - "includeAll": false, - "label": "HOST:", - "multi": false, - "name": "node", - "options": [], - "query": { - "query": "label_values(prometheus_build_info, instance)", - "refId": "gdev-prometheus-node-Variable-Query" - }, - "refresh": 1, - "regex": "", - "skipUrlSync": false, - "sort": 1, - "tagValuesQuery": "", - "tagsQuery": "", - "type": "query", - "useTags": false - } - ] - }, - "time": { - "from": "now-5m", - "to": "now" - }, - "timepicker": { - "now": true, - "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"] - }, - "timezone": "browser", - "title": "Prometheus Stats", - "uid": "rpfmFFz7z", - "version": 2 -} diff --git a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.test.tsx index f57fbb59bd6..a91179fad3e 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.test.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.test.tsx @@ -48,7 +48,7 @@ describe('MetricsModal', () => { operations: [], }; - setup(query, ['with-labels'], true); + setup(query, ['with-labels']); await waitFor(() => { expect(screen.getByText('with-labels')).toBeInTheDocument(); }); @@ -220,6 +220,10 @@ function createDatasource(withLabels?: boolean) { // display different results if their labels are selected in the PromVisualQuery if (withLabels) { languageProvider.queryMetricsMetadata = jest.fn().mockResolvedValue({ + ALERTS: { + type: 'gauge', + help: 'alerts help text', + }, 'with-labels': { type: 'with-labels-type', help: 'with-labels-help', @@ -297,7 +301,7 @@ function createProps(query: PromVisualQuery, datasource: PrometheusDatasource, m }; } -function setup(query: PromVisualQuery, metrics: string[], withlabels?: boolean) { +function setup(query: PromVisualQuery, metrics: string[]) { const withLabels: boolean = query.labels.length > 0; const datasource = createDatasource(withLabels); const props = createProps(query, datasource, metrics); diff --git a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.tsx b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.tsx index 59c4c703ccf..bf92a3ddc77 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.tsx @@ -138,7 +138,7 @@ const MetricsModalContent = (props: MetricsModalProps) => { export const MetricsModal = (props: MetricsModalProps) => { return ( - + ); diff --git a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModalContext.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModalContext.test.tsx index 955b2c1b585..46082f476b5 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModalContext.test.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModalContext.test.tsx @@ -4,6 +4,7 @@ import { ReactNode } from 'react'; import { TimeRange } from '@grafana/data'; import { PrometheusLanguageProviderInterface } from '../../../language_provider'; +import { getMockTimeRange } from '../../../test/mocks/datasource'; import { DEFAULT_RESULTS_PER_PAGE, MetricsModalContextProvider, useMetricsModal } from './MetricsModalContext'; import { generateMetricData } from './helpers'; @@ -25,7 +26,9 @@ const mockLanguageProvider: PrometheusLanguageProviderInterface = { // Helper to create wrapper component const createWrapper = (languageProvider = mockLanguageProvider) => { return ({ children }: { children: ReactNode }) => ( - {children} + + {children} + ); }; @@ -167,6 +170,7 @@ describe('MetricsModalContext', () => { it('should handle empty metadata response', async () => { (mockLanguageProvider.queryMetricsMetadata as jest.Mock).mockResolvedValue({}); + (mockLanguageProvider.queryLabelValues as jest.Mock).mockResolvedValue(['metric1', 'metric2']); const { result } = renderHook(() => useMetricsModal(), { wrapper: createWrapper(), @@ -176,7 +180,18 @@ describe('MetricsModalContext', () => { expect(result.current.isLoading).toBe(false); }); - expect(result.current.filteredMetricsData).toEqual([]); + expect(result.current.filteredMetricsData).toEqual([ + { + value: 'metric1', + type: 'counter', + description: 'Test metric', + }, + { + value: 'metric2', + type: 'counter', + description: 'Test metric', + }, + ]); }); it('should handle metadata fetch error', async () => { @@ -239,6 +254,7 @@ describe('MetricsModalContext', () => { })); (mockLanguageProvider.queryMetricsMetadata as jest.Mock).mockResolvedValue({ + ALERTS: { type: 'gauge', help: 'Test alerts help' }, test_metric: { type: 'counter', help: 'Test metric' }, }); @@ -250,7 +266,7 @@ describe('MetricsModalContext', () => { expect(result.current.isLoading).toBe(false); }); - expect(result.current.filteredMetricsData).toHaveLength(1); + expect(result.current.filteredMetricsData).toHaveLength(2); expect(result.current.selectedTypes).toEqual([]); }); @@ -318,7 +334,7 @@ describe('MetricsModalContext', () => { }; const { getByTestId } = render( - + ); diff --git a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModalContext.tsx b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModalContext.tsx index 3361b448547..117e3aad56e 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModalContext.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModalContext.tsx @@ -52,11 +52,13 @@ const MetricsModalContext = createContext( type MetricsModalContextProviderProps = { languageProvider: PrometheusLanguageProviderInterface; + timeRange: TimeRange; }; export const MetricsModalContextProvider: FC> = ({ children, languageProvider, + timeRange, }) => { const [isLoading, setIsLoading] = useState(true); const [metricsData, setMetricsData] = useState([]); @@ -111,8 +113,16 @@ export const MetricsModalContextProvider: FC generateMetricData(m, languageProvider)); + setMetricsData(processedData); } else { const processedData = Object.keys(metadata).map((m) => generateMetricData(m, languageProvider)); setMetricsData(processedData); @@ -122,7 +132,7 @@ export const MetricsModalContextProvider: FC diff --git a/packages/grafana-schema/src/raw/composable/grafanapyroscope/dataquery/x/GrafanaPyroscopeDataQuery_types.gen.ts b/packages/grafana-schema/src/raw/composable/grafanapyroscope/dataquery/x/GrafanaPyroscopeDataQuery_types.gen.ts index f323c53b037..c297dc86114 100644 --- a/packages/grafana-schema/src/raw/composable/grafanapyroscope/dataquery/x/GrafanaPyroscopeDataQuery_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/grafanapyroscope/dataquery/x/GrafanaPyroscopeDataQuery_types.gen.ts @@ -25,6 +25,10 @@ export interface GrafanaPyroscopeDataQuery extends common.DataQuery { * Allows to group the results. */ groupBy: Array; + /** + * If set to true, exemplars will be requested + */ + includeExemplars: boolean; /** * Specifies the query label selectors. */ @@ -49,6 +53,7 @@ export interface GrafanaPyroscopeDataQuery extends common.DataQuery { export const defaultGrafanaPyroscopeDataQuery: Partial = { groupBy: [], + includeExemplars: false, labelSelector: '{}', spanSelector: [], }; diff --git a/packages/grafana-schema/src/raw/composable/newgauge/panelcfg/x/NewGaugePanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/newgauge/panelcfg/x/NewGaugePanelCfg_types.gen.ts index 7c29eb7b463..c0f8481a7f5 100644 --- a/packages/grafana-schema/src/raw/composable/newgauge/panelcfg/x/NewGaugePanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/newgauge/panelcfg/x/NewGaugePanelCfg_types.gen.ts @@ -35,6 +35,7 @@ export interface Options extends common.SingleStatBaseOptions { showThresholdLabels: boolean; showThresholdMarkers: boolean; sparkline?: boolean; + textMode?: ('auto' | 'value_and_name' | 'value' | 'name' | 'none'); } export const defaultOptions: Partial = { @@ -48,4 +49,5 @@ export const defaultOptions: Partial = { showThresholdLabels: false, showThresholdMarkers: true, sparkline: true, + textMode: 'auto', }; 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 f2423566ff5..bc1c1cbcbf4 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 @@ -211,6 +211,10 @@ export interface VariableModel { * Type of variable */ type: VariableType; + /** + * Optional, indicates whether a custom type variable uses CSV or JSON to define its values + */ + valuesFormat?: ('csv' | 'json'); } export const defaultVariableModel: Partial = { @@ -220,6 +224,7 @@ export const defaultVariableModel: Partial = { options: [], skipUrlSync: false, staticOptions: [], + valuesFormat: 'csv', }; /** diff --git a/packages/grafana-schema/src/schema/dashboard/v2_examples.ts b/packages/grafana-schema/src/schema/dashboard/v2_examples.ts index e0f10d0f770..294e0262f95 100644 --- a/packages/grafana-schema/src/schema/dashboard/v2_examples.ts +++ b/packages/grafana-schema/src/schema/dashboard/v2_examples.ts @@ -317,6 +317,7 @@ export const handyTestingSchema: Spec = { query: 'option1, option2', skipUrlSync: false, allowCustomValue: true, + valuesFormat: 'csv', }, }, { diff --git a/packages/grafana-schema/src/schema/dashboard/v2alpha1/types.spec.gen.ts b/packages/grafana-schema/src/schema/dashboard/v2alpha1/types.spec.gen.ts index 78068b9412d..aa1d1e19539 100644 --- a/packages/grafana-schema/src/schema/dashboard/v2alpha1/types.spec.gen.ts +++ b/packages/grafana-schema/src/schema/dashboard/v2alpha1/types.spec.gen.ts @@ -300,7 +300,7 @@ export interface FieldConfig { description?: string; // An explicit path to the field in the datasource. When the frame meta includes a path, // This will default to `${frame.meta.path}/${field.name} - // + // // When defined, this value can be used as an identifier within the datasource scope, and // may be used to update the results path?: string; @@ -1353,6 +1353,7 @@ export interface CustomVariableSpec { skipUrlSync: boolean; description?: string; allowCustomValue: boolean; + valuesFormat?: "csv" | "json"; } export const defaultCustomVariableSpec = (): CustomVariableSpec => ({ @@ -1365,6 +1366,7 @@ export const defaultCustomVariableSpec = (): CustomVariableSpec => ({ hide: "dontHide", skipUrlSync: false, allowCustomValue: true, + valuesFormat: undefined, }); // Group variable kind @@ -1549,4 +1551,3 @@ export const defaultSpec = (): Spec => ({ title: "", variables: [], }); - diff --git a/packages/grafana-schema/src/schema/dashboard/v2beta1/types.spec.gen.ts b/packages/grafana-schema/src/schema/dashboard/v2beta1/types.spec.gen.ts index 6a05bed3f1c..1749a57c459 100644 --- a/packages/grafana-schema/src/schema/dashboard/v2beta1/types.spec.gen.ts +++ b/packages/grafana-schema/src/schema/dashboard/v2beta1/types.spec.gen.ts @@ -1359,6 +1359,7 @@ export interface CustomVariableSpec { skipUrlSync: boolean; description?: string; allowCustomValue: boolean; + valuesFormat?: "csv" | "json"; } export const defaultCustomVariableSpec = (): CustomVariableSpec => ({ diff --git a/packages/grafana-test-utils/src/fixtures/scopes.ts b/packages/grafana-test-utils/src/fixtures/scopes.ts new file mode 100644 index 00000000000..1d7c6ee0143 --- /dev/null +++ b/packages/grafana-test-utils/src/fixtures/scopes.ts @@ -0,0 +1,500 @@ +/** + * Types for Scopes API - matching @grafana/data types + */ + +export interface ScopeFilter { + key: string; + value: string; + operator: 'equals' | 'not-equals' | 'regex-match' | 'regex-not-match'; +} + +export interface ScopeSpec { + title: string; + filters: ScopeFilter[]; +} + +export interface Scope { + metadata: { + name: string; + }; + spec: ScopeSpec; +} + +export interface ScopeNodeSpec { + nodeType: 'container' | 'leaf'; + title: string; + description?: string; + disableMultiSelect?: boolean; + linkType?: 'scope'; + linkId?: string; + parentName: string; +} + +export interface ScopeNode { + metadata: { + name: string; + }; + spec: ScopeNodeSpec; +} + +export interface ScopeDashboardBindingSpec { + dashboard: string; + scope: string; +} + +export interface ScopeDashboardBindingStatus { + dashboardTitle: string; + groups?: string[]; +} + +export interface ScopeDashboardBinding { + metadata: { + name: string; + }; + spec: ScopeDashboardBindingSpec; + status: ScopeDashboardBindingStatus; +} + +export interface ScopeNavigation { + metadata: { + name: string; + }; + spec: { + url: string; + scope: string; + subScope?: string; + preLoadSubScopeChildren?: boolean; + expandOnLoad?: boolean; + disableSubScopeSelection?: boolean; + }; + status: { + title: string; + groups?: string[]; + }; +} + +export const MOCK_SCOPES: Scope[] = [ + { + metadata: { name: 'cloud' }, + spec: { + title: 'Cloud', + filters: [{ key: 'cloud', value: '.*', operator: 'regex-match' }], + }, + }, + { + metadata: { name: 'dev' }, + spec: { + title: 'Dev', + filters: [{ key: 'cloud', value: 'dev', operator: 'equals' }], + }, + }, + { + metadata: { name: 'ops' }, + spec: { + title: 'Ops', + filters: [{ key: 'cloud', value: 'ops', operator: 'equals' }], + }, + }, + { + metadata: { name: 'prod' }, + spec: { + title: 'Prod', + filters: [{ key: 'cloud', value: 'prod', operator: 'equals' }], + }, + }, + { + metadata: { name: 'grafana' }, + spec: { + title: 'Grafana', + filters: [{ key: 'app', value: 'grafana', operator: 'equals' }], + }, + }, + { + metadata: { name: 'mimir' }, + spec: { + title: 'Mimir', + filters: [{ key: 'app', value: 'mimir', operator: 'equals' }], + }, + }, + { + metadata: { name: 'loki' }, + spec: { + title: 'Loki', + filters: [{ key: 'app', value: 'loki', operator: 'equals' }], + }, + }, + { + metadata: { name: 'tempo' }, + spec: { + title: 'Tempo', + filters: [{ key: 'app', value: 'tempo', operator: 'equals' }], + }, + }, + { + metadata: { name: 'dev-env' }, + spec: { + title: 'Development', + filters: [{ key: 'environment', value: 'dev', operator: 'equals' }], + }, + }, + { + metadata: { name: 'prod-env' }, + spec: { + title: 'Production', + filters: [{ key: 'environment', value: 'prod', operator: 'equals' }], + }, + }, +]; + +const dashboardBindingsGenerator = ( + scopes: string[], + dashboards: Array<{ dashboardTitle: string; dashboardKey?: string; groups?: string[] }> +) => + scopes.reduce((scopeAcc, scopeTitle) => { + const scope = scopeTitle.toLowerCase().replaceAll(' ', '-').replaceAll('/', '-'); + + return [ + ...scopeAcc, + ...dashboards.reduce((acc, { dashboardTitle, groups, dashboardKey }, idx) => { + dashboardKey = dashboardKey ?? dashboardTitle.toLowerCase().replaceAll(' ', '-').replaceAll('/', '-'); + const group = !groups + ? '' + : groups.length === 1 + ? groups[0] === '' + ? '' + : `${groups[0].toLowerCase().replaceAll(' ', '-').replaceAll('/', '-')}-` + : `multiple${idx}-`; + const dashboard = `${group}${dashboardKey}`; + + return [ + ...acc, + { + metadata: { name: `${scope}-${dashboard}` }, + spec: { + dashboard, + scope, + }, + status: { + dashboardTitle, + groups, + }, + }, + ]; + }, []), + ]; + }, []); + +export const MOCK_SCOPE_DASHBOARD_BINDINGS: ScopeDashboardBinding[] = [ + ...dashboardBindingsGenerator( + ['Grafana'], + [ + { dashboardTitle: 'Data Sources', groups: ['General'] }, + { dashboardTitle: 'Usage', groups: ['General'] }, + { dashboardTitle: 'Frontend Errors', groups: ['Observability'] }, + { dashboardTitle: 'Frontend Logs', groups: ['Observability'] }, + { dashboardTitle: 'Backend Errors', groups: ['Observability'] }, + { dashboardTitle: 'Backend Logs', groups: ['Observability'] }, + { dashboardTitle: 'Usage Overview', groups: ['Usage'] }, + { dashboardTitle: 'Data Sources', groups: ['Usage'] }, + { dashboardTitle: 'Stats', groups: ['Usage'] }, + { dashboardTitle: 'Overview', groups: [''] }, + { dashboardTitle: 'Frontend' }, + { dashboardTitle: 'Stats' }, + ] + ), + ...dashboardBindingsGenerator( + ['Loki', 'Tempo', 'Mimir'], + [ + { dashboardTitle: 'Ingester', groups: ['Components', 'Investigations'] }, + { dashboardTitle: 'Distributor', groups: ['Components', 'Investigations'] }, + { dashboardTitle: 'Compacter', groups: ['Components', 'Investigations'] }, + { dashboardTitle: 'Datasource Errors', groups: ['Observability', 'Investigations'] }, + { dashboardTitle: 'Datasource Logs', groups: ['Observability', 'Investigations'] }, + { dashboardTitle: 'Overview' }, + { dashboardTitle: 'Stats', dashboardKey: 'another-stats' }, + ] + ), + ...dashboardBindingsGenerator( + ['Dev', 'Ops', 'Prod'], + [ + { dashboardTitle: 'Overview', groups: ['Cardinality Management'] }, + { dashboardTitle: 'Metrics', groups: ['Cardinality Management'] }, + { dashboardTitle: 'Labels', groups: ['Cardinality Management'] }, + { dashboardTitle: 'Overview', groups: ['Usage Insights'] }, + { dashboardTitle: 'Data Sources', groups: ['Usage Insights'] }, + { dashboardTitle: 'Query Errors', groups: ['Usage Insights'] }, + { dashboardTitle: 'Alertmanager', groups: ['Usage Insights'] }, + { dashboardTitle: 'Metrics Ingestion', groups: ['Usage Insights'] }, + { dashboardTitle: 'Billing/Usage' }, + ] + ), +]; + +export const MOCK_NODES: ScopeNode[] = [ + { + metadata: { name: 'applications' }, + spec: { + nodeType: 'container', + title: 'Applications', + description: 'Application Scopes', + parentName: '', + }, + }, + { + metadata: { name: 'cloud' }, + spec: { + nodeType: 'container', + title: 'Cloud', + description: 'Cloud Scopes', + disableMultiSelect: true, + linkType: 'scope', + linkId: 'cloud', + parentName: '', + }, + }, + { + metadata: { name: 'applications-grafana' }, + spec: { + nodeType: 'leaf', + title: 'Grafana', + description: 'Grafana', + linkType: 'scope', + linkId: 'grafana', + parentName: 'applications', + }, + }, + { + metadata: { name: 'applications-mimir' }, + spec: { + nodeType: 'leaf', + title: 'Mimir', + description: 'Mimir', + linkType: 'scope', + linkId: 'mimir', + parentName: 'applications', + }, + }, + { + metadata: { name: 'applications-loki' }, + spec: { + nodeType: 'leaf', + title: 'Loki', + description: 'Loki', + linkType: 'scope', + linkId: 'loki', + parentName: 'applications', + }, + }, + { + metadata: { name: 'applications-tempo' }, + spec: { + nodeType: 'leaf', + title: 'Tempo', + description: 'Tempo', + linkType: 'scope', + linkId: 'tempo', + parentName: 'applications', + }, + }, + { + metadata: { name: 'applications-cloud' }, + spec: { + nodeType: 'container', + title: 'Cloud', + description: 'Application/Cloud Scopes', + linkType: 'scope', + linkId: 'cloud', + parentName: 'applications', + }, + }, + { + metadata: { name: 'applications-cloud-dev' }, + spec: { + nodeType: 'leaf', + title: 'Dev', + description: 'Dev', + linkType: 'scope', + linkId: 'dev', + parentName: 'applications-cloud', + }, + }, + { + metadata: { name: 'applications-cloud-ops' }, + spec: { + nodeType: 'leaf', + title: 'Ops', + description: 'Ops', + linkType: 'scope', + linkId: 'ops', + parentName: 'applications-cloud', + }, + }, + { + metadata: { name: 'applications-cloud-prod' }, + spec: { + nodeType: 'leaf', + title: 'Prod', + description: 'Prod', + linkType: 'scope', + linkId: 'prod', + parentName: 'applications-cloud', + }, + }, + { + metadata: { name: 'cloud-dev' }, + spec: { + nodeType: 'leaf', + title: 'Dev', + description: 'Dev', + linkType: 'scope', + linkId: 'dev', + parentName: 'cloud', + }, + }, + { + metadata: { name: 'cloud-ops' }, + spec: { + nodeType: 'leaf', + title: 'Ops', + description: 'Ops', + linkType: 'scope', + linkId: 'ops', + parentName: 'cloud', + }, + }, + { + metadata: { name: 'cloud-prod' }, + spec: { + nodeType: 'leaf', + title: 'Prod', + description: 'Prod', + linkType: 'scope', + linkId: 'prod', + parentName: 'cloud', + }, + }, + { + metadata: { name: 'cloud-applications' }, + spec: { + nodeType: 'container', + title: 'Applications', + description: 'Cloud/Application Scopes', + parentName: 'cloud', + }, + }, + { + metadata: { name: 'cloud-applications-grafana' }, + spec: { + nodeType: 'leaf', + title: 'Grafana', + description: 'Grafana', + linkType: 'scope', + linkId: 'grafana', + parentName: 'cloud-applications', + }, + }, + { + metadata: { name: 'cloud-applications-mimir' }, + spec: { + nodeType: 'leaf', + title: 'Mimir', + description: 'Mimir', + linkType: 'scope', + linkId: 'mimir', + parentName: 'cloud-applications', + }, + }, + { + metadata: { name: 'cloud-applications-loki' }, + spec: { + nodeType: 'leaf', + title: 'Loki', + description: 'Loki', + linkType: 'scope', + linkId: 'loki', + parentName: 'cloud-applications', + }, + }, + { + metadata: { name: 'cloud-applications-tempo' }, + spec: { + nodeType: 'leaf', + title: 'Tempo', + description: 'Tempo', + linkType: 'scope', + linkId: 'tempo', + parentName: 'cloud-applications', + }, + }, + { + metadata: { name: 'environments' }, + spec: { + nodeType: 'container', + title: 'Environments', + description: 'Environment Scopes', + disableMultiSelect: true, + parentName: '', + }, + }, + { + metadata: { name: 'environments-dev' }, + spec: { + nodeType: 'container', + title: 'Development', + description: 'Development Environment', + linkType: 'scope', + linkId: 'dev-env', + parentName: 'environments', + }, + }, + { + metadata: { name: 'environments-prod' }, + spec: { + nodeType: 'container', + title: 'Production', + description: 'Production Environment', + linkType: 'scope', + linkId: 'prod-env', + parentName: 'environments', + }, + }, +]; + +export const MOCK_SUB_SCOPE_MIMIR_ITEMS: ScopeNavigation[] = [ + { + metadata: { name: 'mimir-item-1' }, + spec: { + scope: 'mimir', + url: '/d/mimir-dashboard-1', + }, + status: { + title: 'Mimir Dashboard 1', + groups: ['General'], + }, + }, + { + metadata: { name: 'mimir-item-2' }, + spec: { + scope: 'mimir', + url: '/d/mimir-dashboard-2', + }, + status: { + title: 'Mimir Dashboard 2', + groups: ['Observability'], + }, + }, +]; + +export const MOCK_SUB_SCOPE_LOKI_ITEMS: ScopeNavigation[] = [ + { + metadata: { name: 'loki-item-1' }, + spec: { + scope: 'loki', + url: '/d/loki-dashboard-1', + }, + status: { + title: 'Loki Dashboard 1', + groups: ['General'], + }, + }, +]; diff --git a/packages/grafana-test-utils/src/handlers/all-handlers.ts b/packages/grafana-test-utils/src/handlers/all-handlers.ts index 5fa473b55d5..83a34d7455f 100644 --- a/packages/grafana-test-utils/src/handlers/all-handlers.ts +++ b/packages/grafana-test-utils/src/handlers/all-handlers.ts @@ -12,6 +12,7 @@ import appPlatformDashboardv0alpha1Handlers from './apis/dashboard.grafana.app/v import appPlatformDashboardv1beta1Handlers from './apis/dashboard.grafana.app/v1beta1/handlers'; import appPlatformFolderv1beta1Handlers from './apis/folder.grafana.app/v1beta1/handlers'; import appPlatformIamv0alpha1Handlers from './apis/iam.grafana.app/v0alpha1/handlers'; +import appPlatformScopev0alpha1Handlers from './apis/scope.grafana.app/v0alpha1/handlers'; const allHandlers: HttpHandler[] = [ // Legacy handlers @@ -29,6 +30,7 @@ const allHandlers: HttpHandler[] = [ ...appPlatformFolderv1beta1Handlers, ...appPlatformIamv0alpha1Handlers, ...appPlatformCollectionsv1alpha1Handlers, + ...appPlatformScopev0alpha1Handlers, ]; export default allHandlers; diff --git a/packages/grafana-test-utils/src/handlers/apis/scope.grafana.app/v0alpha1/handlers.ts b/packages/grafana-test-utils/src/handlers/apis/scope.grafana.app/v0alpha1/handlers.ts new file mode 100644 index 00000000000..098548caad7 --- /dev/null +++ b/packages/grafana-test-utils/src/handlers/apis/scope.grafana.app/v0alpha1/handlers.ts @@ -0,0 +1,131 @@ +import { HttpResponse, http } from 'msw'; + +import { + MOCK_NODES, + MOCK_SCOPES, + MOCK_SCOPE_DASHBOARD_BINDINGS, + MOCK_SUB_SCOPE_LOKI_ITEMS, + MOCK_SUB_SCOPE_MIMIR_ITEMS, + ScopeNavigation, +} from '../../../../fixtures/scopes'; +import { getErrorResponse } from '../../../helpers'; + +const API_BASE = '/apis/scope.grafana.app/v0alpha1/namespaces/:namespace'; + +/** + * GET /apis/scope.grafana.app/v0alpha1/namespaces/:namespace/scopes/:name + * + * Fetches a single scope by name. + */ +const getScopeHandler = () => + http.get<{ namespace: string; name: string }>(`${API_BASE}/scopes/:name`, ({ params }) => { + const { name } = params; + const scope = MOCK_SCOPES.find((s) => s.metadata.name === name); + + if (!scope) { + return HttpResponse.json(getErrorResponse(`scopes.scope.grafana.app "${name}" not found`, 404), { + status: 404, + }); + } + + return HttpResponse.json(scope); + }); + +/** + * GET /apis/scope.grafana.app/v0alpha1/namespaces/:namespace/scopenodes/:name + * + * Fetches a single scope node by name. + */ +const getScopeNodeHandler = () => + http.get<{ namespace: string; name: string }>(`${API_BASE}/scopenodes/:name`, ({ params }) => { + const { name } = params; + const node = MOCK_NODES.find((n) => n.metadata.name === name); + + if (!node) { + return HttpResponse.json(getErrorResponse(`scopenodes.scope.grafana.app "${name}" not found`, 404), { + status: 404, + }); + } + + return HttpResponse.json(node); + }); + +/** + * GET /apis/scope.grafana.app/v0alpha1/namespaces/:namespace/find/scope_node_children + * + * Finds scope node children based on parent and query filters. + */ +const findScopeNodeChildrenHandler = () => + http.get(`${API_BASE}/find/scope_node_children`, ({ request }) => { + const url = new URL(request.url); + const parent = url.searchParams.get('parent') ?? ''; + const query = url.searchParams.get('query') ?? ''; + const limitParam = url.searchParams.get('limit'); + const names = url.searchParams.getAll('names'); + + let filtered = MOCK_NODES.filter( + (node) => node.spec.parentName === parent && node.spec.title.toLowerCase().includes(query.toLowerCase()) + ); + + if (names.length > 0) { + filtered = MOCK_NODES.filter((node) => names.includes(node.metadata.name)); + } + + if (limitParam) { + const limit = parseInt(limitParam, 10); + filtered = filtered.slice(0, limit); + } + + return HttpResponse.json({ + items: filtered, + }); + }); + +/** + * GET /apis/scope.grafana.app/v0alpha1/namespaces/:namespace/find/scope_dashboard_bindings + * + * Finds scope dashboard bindings for the given scope names. + */ +const findScopeDashboardBindingsHandler = () => + http.get(`${API_BASE}/find/scope_dashboard_bindings`, ({ request }) => { + const url = new URL(request.url); + const scopeNames = url.searchParams.getAll('scope'); + + const bindings = MOCK_SCOPE_DASHBOARD_BINDINGS.filter((b) => scopeNames.includes(b.spec.scope)); + + return HttpResponse.json({ + items: bindings, + }); + }); + +/** + * GET /apis/scope.grafana.app/v0alpha1/namespaces/:namespace/find/scope_navigations + * + * Finds scope navigations for the given scope names. + */ +const findScopeNavigationsHandler = () => + http.get(`${API_BASE}/find/scope_navigations`, ({ request }) => { + const url = new URL(request.url); + const scopeNames = url.searchParams.getAll('scope'); + + let items: ScopeNavigation[] = []; + + if (scopeNames.includes('mimir')) { + items = [...items, ...MOCK_SUB_SCOPE_MIMIR_ITEMS]; + } + if (scopeNames.includes('loki')) { + items = [...items, ...MOCK_SUB_SCOPE_LOKI_ITEMS]; + } + + return HttpResponse.json({ + items, + }); + }); + +export default [ + getScopeHandler(), + getScopeNodeHandler(), + findScopeNodeChildrenHandler(), + findScopeDashboardBindingsHandler(), + findScopeNavigationsHandler(), +]; diff --git a/packages/grafana-test-utils/src/unstable.ts b/packages/grafana-test-utils/src/unstable.ts index d03bc685d9e..698d57a774c 100644 --- a/packages/grafana-test-utils/src/unstable.ts +++ b/packages/grafana-test-utils/src/unstable.ts @@ -2,3 +2,12 @@ import { wellFormedTree } from './fixtures/folders'; export const getFolderFixtures = wellFormedTree; export { MOCK_TEAMS, MOCK_TEAM_GROUPS } from './fixtures/teams'; +export { + MOCK_SCOPES, + MOCK_NODES, + MOCK_SCOPE_DASHBOARD_BINDINGS, + MOCK_SUB_SCOPE_MIMIR_ITEMS, + MOCK_SUB_SCOPE_LOKI_ITEMS, +} from './fixtures/scopes'; +export { default as allHandlers } from './handlers/all-handlers'; +export { default as scopeHandlers } from './handlers/apis/scope.grafana.app/v0alpha1/handlers'; diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index 478c44704ed..e7b908fc08c 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -137,23 +137,23 @@ "@babel/core": "7.28.0", "@faker-js/faker": "^9.0.0", "@rollup/plugin-node-resolve": "16.0.1", - "@storybook/addon-a11y": "^8.6.2", - "@storybook/addon-actions": "^8.6.2", - "@storybook/addon-docs": "^8.6.2", - "@storybook/addon-essentials": "^8.6.2", - "@storybook/addon-storysource": "^8.6.2", + "@storybook/addon-a11y": "^8.6.15", + "@storybook/addon-actions": "^8.6.15", + "@storybook/addon-docs": "^8.6.15", + "@storybook/addon-essentials": "^8.6.15", + "@storybook/addon-storysource": "^8.6.15", "@storybook/addon-webpack5-compiler-swc": "^2.1.0", - "@storybook/blocks": "^8.6.2", - "@storybook/components": "^8.6.2", - "@storybook/core-events": "^8.6.2", - "@storybook/manager-api": "^8.6.2", + "@storybook/blocks": "^8.6.15", + "@storybook/components": "^8.6.15", + "@storybook/core-events": "^8.6.15", + "@storybook/manager-api": "^8.6.15", "@storybook/mdx2-csf": "1.1.0", "@storybook/preset-scss": "1.0.3", - "@storybook/preview-api": "^8.6.2", - "@storybook/react": "^8.6.2", - "@storybook/react-webpack5": "^8.6.2", + "@storybook/preview-api": "^8.6.15", + "@storybook/react": "^8.6.15", + "@storybook/react-webpack5": "^8.6.15", "@storybook/test-runner": "^0.23.0", - "@storybook/theming": "^8.6.2", + "@storybook/theming": "^8.6.15", "@testing-library/dom": "10.4.1", "@testing-library/jest-dom": "6.6.4", "@testing-library/react": "16.3.0", @@ -200,7 +200,7 @@ "rollup-plugin-node-externals": "^8.0.0", "rollup-plugin-svg-import": "3.0.0", "sass-loader": "16.0.5", - "storybook": "^8.6.2", + "storybook": "^8.6.15", "style-loader": "4.0.0", "typescript": "5.9.2", "webpack": "5.101.0" diff --git a/packages/grafana-ui/src/components/Drawer/Drawer.tsx b/packages/grafana-ui/src/components/Drawer/Drawer.tsx index 00039adfc3f..7d115e3f9d0 100644 --- a/packages/grafana-ui/src/components/Drawer/Drawer.tsx +++ b/packages/grafana-ui/src/components/Drawer/Drawer.tsx @@ -1,9 +1,7 @@ import { css, cx } from '@emotion/css'; +import { FloatingFocusManager, useFloating } from '@floating-ui/react'; import RcDrawer from '@rc-component/drawer'; -import { useDialog } from '@react-aria/dialog'; -import { FocusScope } from '@react-aria/focus'; -import { useOverlay } from '@react-aria/overlays'; -import { ReactNode, useCallback, useEffect, useState } from 'react'; +import { ReactNode, useCallback, useEffect, useId, useState } from 'react'; import * as React from 'react'; import { GrafanaTheme2 } from '@grafana/data'; @@ -81,17 +79,16 @@ export function Drawer({ const styles = useStyles2(getStyles); const wrapperStyles = useStyles2(getWrapperStyles, size); const dragStyles = useStyles2(getDragStyles); + const titleId = useId(); - const overlayRef = React.useRef(null); - const { dialogProps, titleProps } = useDialog({}, overlayRef); - const { overlayProps } = useOverlay( - { - isDismissable: false, - isOpen: true, - onClose, + const { context, refs } = useFloating({ + open: true, + onOpenChange: (open) => { + if (!open) { + onClose?.(); + } }, - overlayRef - ); + }); // Adds body class while open so the toolbar nav can hide some actions while drawer is open useBodyClassWhileOpen(); @@ -117,6 +114,8 @@ export function Drawer({ minWidth, }, }} + aria-label={typeof title === 'string' ? selectors.components.Drawer.General.title(title) : undefined} + aria-labelledby={typeof title !== 'string' ? titleId : undefined} width={''} motion={{ motionAppear: true, @@ -129,18 +128,8 @@ export function Drawer({ motionName: styles.maskMotion, }} > - -
+ +
{/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
{typeof title === 'string' ? ( - + {title} {subtitle && ( @@ -169,13 +158,13 @@ export function Drawer({ )} ) : ( - title +
{title}
)} {tabs &&
{tabs}
}
{!scrollableContent ? content : {content}}
- +
); } diff --git a/packages/grafana-ui/src/components/InteractiveTable/InteractiveTable.tsx b/packages/grafana-ui/src/components/InteractiveTable/InteractiveTable.tsx index d5a25e2e480..1b06c7daa87 100644 --- a/packages/grafana-ui/src/components/InteractiveTable/InteractiveTable.tsx +++ b/packages/grafana-ui/src/components/InteractiveTable/InteractiveTable.tsx @@ -153,6 +153,10 @@ interface BaseProps { * Optional way to set how the table is sorted from the beginning. Must be memoized. */ initialSortBy?: Array>; + /** + * Disable the ability to remove sorting on columns (none -> asc -> desc -> asc) + */ + disableSortRemove?: boolean; } interface WithExpandableRow extends BaseProps { @@ -191,6 +195,7 @@ export function InteractiveTable({ showExpandAll = false, fetchData, initialSortBy = [], + disableSortRemove, }: Props) { const styles = useStyles2(getStyles); const tableColumns = useMemo(() => { @@ -222,6 +227,7 @@ export function InteractiveTable({ disableMultiSort: true, // If fetchData is provided, we disable client-side sorting manualSortBy: Boolean(fetchData), + disableSortRemove, getRowId, initialState: { hiddenColumns: [ diff --git a/packages/grafana-ui/src/components/InteractiveTable/types.ts b/packages/grafana-ui/src/components/InteractiveTable/types.ts index 47263d4730e..5b84f4c568b 100644 --- a/packages/grafana-ui/src/components/InteractiveTable/types.ts +++ b/packages/grafana-ui/src/components/InteractiveTable/types.ts @@ -26,4 +26,8 @@ export interface Column { * If the provided function returns `false` the column will be hidden. */ visible?: (data: TableData[]) => boolean; + /** + * Determines starting sort direction when the column header is clicked. + */ + sortDescFirst?: boolean; } diff --git a/packages/grafana-ui/src/components/InteractiveTable/utils.ts b/packages/grafana-ui/src/components/InteractiveTable/utils.ts index 2b664b16f6d..050419fe1d1 100644 --- a/packages/grafana-ui/src/components/InteractiveTable/utils.ts +++ b/packages/grafana-ui/src/components/InteractiveTable/utils.ts @@ -33,6 +33,7 @@ export function getColumns( disableSortBy: !Boolean(column.sortType), width: column.disableGrow ? 0 : undefined, visible: column.visible, + ...(column.sortDescFirst !== undefined && { sortDescFirst: column.sortDescFirst }), ...(column.cell && { Cell: column.cell }), })), ]; diff --git a/packages/grafana-ui/src/components/Modal/Modal.tsx b/packages/grafana-ui/src/components/Modal/Modal.tsx index aaeb2c3e426..f6ea73c3d31 100644 --- a/packages/grafana-ui/src/components/Modal/Modal.tsx +++ b/packages/grafana-ui/src/components/Modal/Modal.tsx @@ -1,9 +1,7 @@ import { cx } from '@emotion/css'; -import { useDialog } from '@react-aria/dialog'; -import { FocusScope } from '@react-aria/focus'; -import { OverlayContainer, useOverlay } from '@react-aria/overlays'; -import { PropsWithChildren, useRef, type JSX } from 'react'; -import * as React from 'react'; +import { FloatingFocusManager, useDismiss, useFloating, useInteractions, useRole } from '@floating-ui/react'; +import { OverlayContainer } from '@react-aria/overlays'; +import { PropsWithChildren, ReactNode, useId, type JSX } from 'react'; import { t } from '@grafana/i18n'; @@ -66,23 +64,26 @@ export function Modal(props: PropsWithChildren) { trapFocus = true, } = props; const styles = useStyles2(getModalStyles); + const titleId = useId(); - const ref = useRef(null); - - // Handle interacting outside the dialog and pressing - // the Escape key to close the modal. - const { overlayProps, underlayProps } = useOverlay( - { isKeyboardDismissDisabled: !closeOnEscape, isOpen, onClose: onDismiss }, - ref - ); - - // Get props for the dialog and its title - const { dialogProps, titleProps } = useDialog( - { - 'aria-label': ariaLabel, + const { context, refs } = useFloating({ + open: isOpen, + onOpenChange: (open) => { + if (!open) { + onDismiss?.(); + } }, - ref - ); + }); + + const dismiss = useDismiss(context, { + enabled: closeOnEscape, + }); + + const role = useRole(context, { + role: 'dialog', + }); + + const { getFloatingProps } = useInteractions([dismiss, role]); if (!isOpen) { return null; @@ -96,12 +97,17 @@ export function Modal(props: PropsWithChildren) { role="presentation" className={styles.modalBackdrop} onClick={onClickBackdrop || (closeOnBackdropClick ? onDismiss : undefined)} - {...underlayProps} /> - -
+ +
- {typeof title === 'string' && } + {typeof title === 'string' && } { // FIXME: custom title components won't get an accessible title. // Do we really want to support them or shall we just limit this ModalTabsHeader? @@ -118,12 +124,12 @@ export function Modal(props: PropsWithChildren) {
{children}
- +
); } -function ModalButtonRow({ leftItems, children }: { leftItems?: React.ReactNode; children: React.ReactNode }) { +function ModalButtonRow({ leftItems, children }: { leftItems?: ReactNode; children: ReactNode }) { const styles = useStyles2(getModalStyles); if (leftItems) { diff --git a/packages/grafana-ui/src/components/PanelChrome/PanelChrome.tsx b/packages/grafana-ui/src/components/PanelChrome/PanelChrome.tsx index 8eace0b38b8..f969bbcf3f0 100644 --- a/packages/grafana-ui/src/components/PanelChrome/PanelChrome.tsx +++ b/packages/grafana-ui/src/components/PanelChrome/PanelChrome.tsx @@ -248,15 +248,17 @@ export function PanelChrome({ const onContentPointerDown = React.useCallback( (evt: React.PointerEvent) => { - // Ignore clicks inside buttons, links, canvas and svg elments + // When selected, ignore clicks inside buttons, links, canvas and svg elments // This does prevent a clicks inside a graphs from selecting panel as there is normal div above the canvas element that intercepts the click - if (evt.target instanceof Element && evt.target.closest('button,a,canvas,svg')) { + if (isSelected && evt.target instanceof Element && evt.target.closest('button,a,canvas,svg')) { + // Stop propagation otherwise row config editor will get selected + evt.stopPropagation(); return; } onSelect?.(evt); }, - [onSelect] + [isSelected, onSelect] ); const headerContent = ( diff --git a/packages/grafana-ui/src/components/RadialGauge/RadialArcPath.tsx b/packages/grafana-ui/src/components/RadialGauge/RadialArcPath.tsx index f59614acd53..f60fafe36f3 100644 --- a/packages/grafana-ui/src/components/RadialGauge/RadialArcPath.tsx +++ b/packages/grafana-ui/src/components/RadialGauge/RadialArcPath.tsx @@ -1,8 +1,9 @@ -import { useId, memo, HTMLAttributes, ReactNode } from 'react'; +import { useId, memo, HTMLAttributes, SVGProps } from 'react'; import { FieldDisplay } from '@grafana/data'; -import { getBarEndcapColors, getGradientCss, getEndpointMarkerColors } from './colors'; +import { RadialArcPathEndpointMarks } from './RadialArcPathEndpointMarks'; +import { getBarEndcapColors, getGradientCss } from './colors'; import { RadialShape, RadialGaugeDimensions, GradientStop } from './types'; import { drawRadialArcPath, toRad } from './utils'; @@ -29,11 +30,6 @@ interface RadialArcPathPropsWithGradient extends RadialArcPathPropsBase { type RadialArcPathProps = RadialArcPathPropsWithColor | RadialArcPathPropsWithGradient; -const ENDPOINT_MARKER_MIN_ANGLE = 10; -const DOT_OPACITY = 0.5; -const DOT_RADIUS_FACTOR = 0.4; -const MAX_DOT_RADIUS = 8; - export const RadialArcPath = memo( ({ arcLengthDeg, @@ -50,14 +46,13 @@ export const RadialArcPath = memo( }: RadialArcPathProps) => { const id = useId(); - const bgDivStyle: HTMLAttributes['style'] = { width: '100%', height: '100%' }; - if ('color' in rest) { - bgDivStyle.backgroundColor = rest.color; - } else { - bgDivStyle.backgroundImage = getGradientCss(rest.gradient, shape); - } + const isGradient = 'gradient' in rest; - const { radius, centerX, centerY, barWidth } = dimensions; + const { vizWidth, vizHeight, radius, centerX, centerY, barWidth } = dimensions; + const pad = Math.ceil(Math.max(2, barWidth / 2)); // pad to cover stroke caps and glow in Safari + const boxX = Math.round(centerX - radius - barWidth - pad); + const boxY = Math.round(centerY - radius - barWidth - pad); + const boxSize = Math.round((radius + barWidth) * 2 + pad * 2); const path = drawRadialArcPath(angle, arcLengthDeg, dimensions, roundedBars); @@ -69,78 +64,71 @@ export const RadialArcPath = memo( const xEnd = centerX + radius * Math.cos(endRadians); const yEnd = centerY + radius * Math.sin(endRadians); - const dotRadius = - endpointMarker === 'point' ? Math.min((barWidth / 2) * DOT_RADIUS_FACTOR, MAX_DOT_RADIUS) : barWidth / 2; + const bgDivStyle: HTMLAttributes['style'] = { width: boxSize, height: vizHeight, marginLeft: boxX }; + const pathProps: SVGProps = {}; + if (isGradient) { + bgDivStyle.backgroundImage = getGradientCss(rest.gradient, shape); + pathProps.fill = 'none'; + pathProps.stroke = 'white'; + } else { + bgDivStyle.backgroundColor = rest.color; + pathProps.fill = 'none'; + pathProps.stroke = rest.color; + } let barEndcapColors: [string, string] | undefined; - let endpointMarks: ReactNode = null; - if ('gradient' in rest) { - if (endpointMarker && (rest.gradient?.length ?? 0) > 0) { - switch (endpointMarker) { - case 'point': - const [pointColorStart, pointColorEnd] = getEndpointMarkerColors( - rest.gradient!, - fieldDisplay.display.percent - ); - endpointMarks = ( - <> - {arcLengthDeg > ENDPOINT_MARKER_MIN_ANGLE && ( - - )} - - - ); - break; - case 'glow': - const offsetAngle = toRad(ENDPOINT_MARKER_MIN_ANGLE); - const xStartMark = centerX + radius * Math.cos(endRadians + offsetAngle); - const yStartMark = centerY + radius * Math.sin(endRadians + offsetAngle); - endpointMarks = - arcLengthDeg > ENDPOINT_MARKER_MIN_ANGLE ? ( - - ) : null; - break; - default: - break; - } - } - - if (barEndcaps) { - barEndcapColors = getBarEndcapColors(rest.gradient, fieldDisplay.display.percent); - } + if (barEndcaps) { + barEndcapColors = isGradient + ? getBarEndcapColors(rest.gradient, fieldDisplay.display.percent) + : [rest.color, rest.color]; } + const pathEl = ( + + ); + return ( <> - {/* FIXME: optimize this by only using clippath + foreign obj for gradients */} - - - + {isGradient && ( + + + + {pathEl} + + + )} - -
- + {isGradient ? ( + +
+ + ) : ( + pathEl + )} {barEndcapColors?.[0] && } {barEndcapColors?.[1] && ( )} - {endpointMarks} + {endpointMarker && ( + + )} ); } diff --git a/packages/grafana-ui/src/components/RadialGauge/RadialArcPathEndpointMarks.test.tsx b/packages/grafana-ui/src/components/RadialGauge/RadialArcPathEndpointMarks.test.tsx new file mode 100644 index 00000000000..af601e65c21 --- /dev/null +++ b/packages/grafana-ui/src/components/RadialGauge/RadialArcPathEndpointMarks.test.tsx @@ -0,0 +1,143 @@ +import { render, RenderResult } from '@testing-library/react'; + +import { FieldDisplay } from '@grafana/data'; + +import { RadialArcPathEndpointMarks, RadialArcPathEndpointMarksProps } from './RadialArcPathEndpointMarks'; +import { RadialGaugeDimensions } from './types'; + +const ser = new XMLSerializer(); + +const expectHTML = (result: RenderResult, expected: string) => { + let actual = ser.serializeToString(result.asFragment()).replace(/xmlns=".*?" /g, ''); + expect(actual).toEqual(expected.replace(/^\s*|\n/gm, '')); +}; + +describe('RadialArcPathEndpointMarks', () => { + const defaultDimensions = Object.freeze({ + centerX: 100, + centerY: 100, + radius: 80, + barWidth: 20, + vizWidth: 200, + vizHeight: 200, + margin: 10, + barIndex: 0, + thresholdsBarRadius: 0, + thresholdsBarWidth: 0, + thresholdsBarSpacing: 0, + scaleLabelsFontSize: 0, + scaleLabelsSpacing: 0, + scaleLabelsRadius: 0, + gaugeBottomY: 0, + }) satisfies RadialGaugeDimensions; + + const defaultFieldDisplay = Object.freeze({ + name: 'Test', + field: {}, + display: { text: '50', numeric: 50, color: '#FF0000' }, + hasLinks: false, + }) satisfies FieldDisplay; + + const defaultProps = Object.freeze({ + arcLengthDeg: 90, + dimensions: defaultDimensions, + fieldDisplay: defaultFieldDisplay, + startAngle: 0, + xStart: 100, + xEnd: 150, + yStart: 100, + yEnd: 50, + }) satisfies Omit; + + it('renders the expected marks when endpointMarker is "point" w/ a static color', () => { + expectHTML( + render( + + + + ), + '' + ); + }); + + it('renders the expected marks when endpointMarker is "point" w/ a gradient color', () => { + expectHTML( + render( + + + + ), + '' + ); + }); + + it('renders the expected marks when endpointMarker is "glow" w/ a static color', () => { + expectHTML( + render( + + + + ), + '' + ); + }); + + it('renders the expected marks when endpointMarker is "glow" w/ a gradient color', () => { + expectHTML( + render( + + + + ), + '' + ); + }); + + it('does not render the start mark when arcLengthDeg is less than the minimum angle for "point" endpointMarker', () => { + expectHTML( + render( + + + + ), + '' + ); + }); + + it('does not render anything when arcLengthDeg is less than the minimum angle for "glow" endpointMarker', () => { + expectHTML( + render( + + + + ), + '' + ); + }); + + it('does not render anything if endpointMarker is some other value', () => { + expectHTML( + render( + + {/* @ts-ignore: confirming the component doesn't throw */} + + + ), + '' + ); + }); +}); diff --git a/packages/grafana-ui/src/components/RadialGauge/RadialArcPathEndpointMarks.tsx b/packages/grafana-ui/src/components/RadialGauge/RadialArcPathEndpointMarks.tsx new file mode 100644 index 00000000000..7bd9a8c435f --- /dev/null +++ b/packages/grafana-ui/src/components/RadialGauge/RadialArcPathEndpointMarks.tsx @@ -0,0 +1,98 @@ +import { FieldDisplay } from '@grafana/data'; + +import { getEndpointMarkerColors, getGuideDotColor } from './colors'; +import { GradientStop, RadialGaugeDimensions } from './types'; +import { toRad } from './utils'; + +interface RadialArcPathEndpointMarksPropsBase { + arcLengthDeg: number; + dimensions: RadialGaugeDimensions; + fieldDisplay: FieldDisplay; + endpointMarker: 'point' | 'glow'; + roundedBars?: boolean; + startAngle: number; + glowFilter?: string; + endpointMarkerGlowFilter?: string; + xStart: number; + xEnd: number; + yStart: number; + yEnd: number; +} + +interface RadialArcPathEndpointMarksPropsWithColor extends RadialArcPathEndpointMarksPropsBase { + color: string; +} + +interface RadialArcPathEndpointMarksPropsWithGradient extends RadialArcPathEndpointMarksPropsBase { + gradient: GradientStop[]; +} + +export type RadialArcPathEndpointMarksProps = + | RadialArcPathEndpointMarksPropsWithColor + | RadialArcPathEndpointMarksPropsWithGradient; + +const ENDPOINT_MARKER_MIN_ANGLE = 10; +const DOT_OPACITY = 0.5; +const DOT_RADIUS_FACTOR = 0.4; +const MAX_DOT_RADIUS = 8; + +export function RadialArcPathEndpointMarks({ + startAngle: angle, + arcLengthDeg, + dimensions, + endpointMarker, + fieldDisplay, + xStart, + xEnd, + yStart, + yEnd, + roundedBars, + endpointMarkerGlowFilter, + glowFilter, + ...rest +}: RadialArcPathEndpointMarksProps) { + const isGradient = 'gradient' in rest; + const { radius, centerX, centerY, barWidth } = dimensions; + const endRadians = toRad(angle + arcLengthDeg); + + switch (endpointMarker) { + case 'point': { + const [pointColorStart, pointColorEnd] = isGradient + ? getEndpointMarkerColors(rest.gradient, fieldDisplay.display.percent) + : [getGuideDotColor(rest.color), getGuideDotColor(rest.color)]; + + const dotRadius = + endpointMarker === 'point' ? Math.min((barWidth / 2) * DOT_RADIUS_FACTOR, MAX_DOT_RADIUS) : barWidth / 2; + + return ( + <> + {arcLengthDeg > ENDPOINT_MARKER_MIN_ANGLE && ( + + )} + + + ); + } + case 'glow': + const offsetAngle = toRad(ENDPOINT_MARKER_MIN_ANGLE); + const xStartMark = centerX + radius * Math.cos(endRadians + offsetAngle); + const yStartMark = centerY + radius * Math.sin(endRadians + offsetAngle); + if (arcLengthDeg <= ENDPOINT_MARKER_MIN_ANGLE) { + break; + } + return ( + + ); + default: + break; + } + + return null; +} diff --git a/packages/grafana-ui/src/components/RadialGauge/RadialGauge.story.tsx b/packages/grafana-ui/src/components/RadialGauge/RadialGauge.story.tsx index b0574ef3f87..5c5faa64db7 100644 --- a/packages/grafana-ui/src/components/RadialGauge/RadialGauge.story.tsx +++ b/packages/grafana-ui/src/components/RadialGauge/RadialGauge.story.tsx @@ -32,24 +32,6 @@ const meta: Meta = { controls: { exclude: ['theme', 'values', 'vizCount'], }, - a11y: { - config: { - rules: [ - { - id: 'scrollable-region-focusable', - selector: 'body', - enabled: false, - }, - // NOTE: this is necessary due to a false positive with the filered svg glow in one of the examples. - // The color-contrast in this component should be accessible! - { - id: 'color-contrast', - selector: 'text', - enabled: false, - }, - ], - }, - }, }, args: { barWidthFactor: 0.2, diff --git a/packages/grafana-ui/src/components/RadialGauge/RadialGauge.tsx b/packages/grafana-ui/src/components/RadialGauge/RadialGauge.tsx index 1251a364230..e60a3dfde31 100644 --- a/packages/grafana-ui/src/components/RadialGauge/RadialGauge.tsx +++ b/packages/grafana-ui/src/components/RadialGauge/RadialGauge.tsx @@ -1,7 +1,8 @@ import { css, cx } from '@emotion/css'; -import { useId } from 'react'; +import { useId, ReactNode } from 'react'; import { DisplayValueAlignmentFactors, FALLBACK_COLOR, FieldDisplay, GrafanaTheme2, TimeRange } from '@grafana/data'; +import { selectors } from '@grafana/e2e-selectors'; import { t } from '@grafana/i18n'; import { useStyles2, useTheme2 } from '../../themes/ThemeContext'; @@ -106,14 +107,14 @@ export function RadialGauge(props: RadialGaugeProps) { const startAngle = shape === 'gauge' ? 250 : 0; const endAngle = shape === 'gauge' ? 110 : 360; - const defs: React.ReactNode[] = []; - const graphics: React.ReactNode[] = []; - let sparklineElement: React.ReactNode | null = null; + const defs: ReactNode[] = []; + const graphics: ReactNode[] = []; + let sparklineElement: ReactNode | null = null; for (let barIndex = 0; barIndex < values.length; barIndex++) { const displayValue = values[barIndex]; const { angle, angleRange } = getValueAngleForValue(displayValue, startAngle, endAngle); - const gradientStops = buildGradientColors(gradient, theme, displayValue); + const gradientStops = gradient ? buildGradientColors(theme, displayValue) : undefined; const color = displayValue.display.color ?? FALLBACK_COLOR; const dimensions = calculateDimensions( width, @@ -130,7 +131,9 @@ export function RadialGauge(props: RadialGaugeProps) { // FIXME: I want to move the ids for these filters into a context which the children // can reference via a hook, rather than passing them down as props const spotlightGradientId = `spotlight-${barIndex}-${gaugeId}`; + const spotlightGradientRef = endpointMarker === 'glow' ? `url(#${spotlightGradientId})` : undefined; const glowFilterId = `glow-${gaugeId}`; + const glowFilterRef = glowBar ? `url(#${glowFilterId})` : undefined; if (endpointMarker === 'glow') { defs.push( @@ -153,7 +156,7 @@ export function RadialGauge(props: RadialGaugeProps) { fieldDisplay={displayValue} angleRange={angleRange} startAngle={startAngle} - glowFilter={`url(#${glowFilterId})`} + glowFilter={glowFilterRef} segmentCount={segmentCount} segmentSpacing={segmentSpacing} shape={shape} @@ -169,8 +172,8 @@ export function RadialGauge(props: RadialGaugeProps) { angleRange={angleRange} startAngle={startAngle} roundedBars={roundedBars} - glowFilter={`url(#${glowFilterId})`} - endpointMarkerGlowFilter={`url(#${spotlightGradientId})`} + glowFilter={glowFilterRef} + endpointMarkerGlowFilter={spotlightGradientRef} shape={shape} gradient={gradientStops} fieldDisplay={displayValue} @@ -182,7 +185,7 @@ export function RadialGauge(props: RadialGaugeProps) { // These elements are only added for first value / bar if (barIndex === 0) { if (glowBar) { - defs.push(); + defs.push(); } if (glowCenter) { @@ -233,7 +236,7 @@ export function RadialGauge(props: RadialGaugeProps) { endAngle={endAngle} angleRange={angleRange} roundedBars={roundedBars} - glowFilter={`url(#${glowFilterId})`} + glowFilter={glowFilterRef} shape={shape} gradient={gradientStops} /> @@ -259,7 +262,7 @@ export function RadialGauge(props: RadialGaugeProps) { const body = ( <> - {defs} + {defs.length > 0 && {defs}} {graphics} {sparklineElement} @@ -275,7 +278,11 @@ export function RadialGauge(props: RadialGaugeProps) { } return ( -
+
{body}
); diff --git a/packages/grafana-ui/src/components/RadialGauge/RadialSparkline.tsx b/packages/grafana-ui/src/components/RadialGauge/RadialSparkline.tsx index 2d6c45a14bf..4a52d5241d5 100644 --- a/packages/grafana-ui/src/components/RadialGauge/RadialSparkline.tsx +++ b/packages/grafana-ui/src/components/RadialGauge/RadialSparkline.tsx @@ -67,7 +67,7 @@ export const RadialSparkline = memo( return (
- +
); } diff --git a/packages/grafana-ui/src/components/RadialGauge/RadialText.tsx b/packages/grafana-ui/src/components/RadialGauge/RadialText.tsx index 69ab16e450e..dc094b7261c 100644 --- a/packages/grafana-ui/src/components/RadialGauge/RadialText.tsx +++ b/packages/grafana-ui/src/components/RadialGauge/RadialText.tsx @@ -1,4 +1,3 @@ -import { css } from '@emotion/css'; import { memo } from 'react'; import { @@ -9,7 +8,6 @@ import { GrafanaTheme2, } from '@grafana/data'; -import { useStyles2 } from '../../themes/ThemeContext'; import { calculateFontSize } from '../../utils/measureText'; import { RadialShape, RadialTextMode, RadialGaugeDimensions } from './types'; @@ -50,7 +48,6 @@ export const RadialText = memo( valueManualFontSize, nameManualFontSize, }: RadialTextProps) => { - const styles = useStyles2(getStyles); const { centerX, centerY, radius, barWidth } = dimensions; if (textMode === 'none') { @@ -106,10 +103,9 @@ export const RadialText = memo( const valueY = showName ? centerY - nameHeight * (1 - VALUE_SPACE_PERCENTAGE) : centerY; const nameY = showValue ? valueY + valueHeight * VALUE_SPACE_PERCENTAGE : centerY; const nameColor = showValue ? theme.colors.text.secondary : theme.colors.text.primary; - const suffixShift = (valueFontSize - unitFontSize * LINE_HEIGHT_FACTOR) / 2; // adjust the text up on gauges and when sparklines are present - let yOffset = 0; + let yOffset = valueFontSize / 4; if (shape === 'gauge') { // we render from the center of the gauge, so move up by half of half of the total height yOffset -= (valueHeight + nameHeight) / 4; @@ -126,15 +122,12 @@ export const RadialText = memo( y={valueY} fontSize={valueFontSize} fill={theme.colors.text.primary} - className={styles.text} textAnchor="middle" - dominantBaseline="middle" + dominantBaseline="text-bottom" > {displayValue.prefix ?? ''} {displayValue.text} - - {displayValue.suffix ?? ''} - + {displayValue.suffix ?? ''} )} {showName && ( @@ -143,7 +136,7 @@ export const RadialText = memo( x={centerX} y={nameY} textAnchor="middle" - dominantBaseline="middle" + dominantBaseline="text-bottom" fill={nameColor} > {displayValue.title} @@ -155,9 +148,3 @@ export const RadialText = memo( ); RadialText.displayName = 'RadialText'; - -const getStyles = (_theme: GrafanaTheme2) => ({ - text: css({ - verticalAlign: 'bottom', - }), -}); diff --git a/packages/grafana-ui/src/components/RadialGauge/__snapshots__/utils.test.ts.snap b/packages/grafana-ui/src/components/RadialGauge/__snapshots__/utils.test.ts.snap index db4c1c40882..9d12b97a6c3 100644 --- a/packages/grafana-ui/src/components/RadialGauge/__snapshots__/utils.test.ts.snap +++ b/packages/grafana-ui/src/components/RadialGauge/__snapshots__/utils.test.ts.snap @@ -1,17 +1,17 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`RadialGauge utils drawRadialArcPath should draw correct path for center x and y 1`] = `"M 150 110 A 90 90 0 1 1 149.98429203681178 110.00000137077838 A 10 10 0 0 1 149.98778269529805 130.00000106616096 A 70 70 0 1 0 150 130 A 10 10 0 0 1 150 110 Z"`; +exports[`RadialGauge utils drawRadialArcPath should draw correct path for center x and y 1`] = `"M 150 120 A 80 80 0 1 1 149.98603736605492 120.00000121846968"`; -exports[`RadialGauge utils drawRadialArcPath should draw correct path for half arc 1`] = `"M 100 10 A 90 90 0 0 1 100 190 L 100 170 A 70 70 0 0 0 100 30 L 100 10 Z"`; +exports[`RadialGauge utils drawRadialArcPath should draw correct path for half arc 1`] = `"M 100 20 A 80 80 0 0 1 100 180"`; -exports[`RadialGauge utils drawRadialArcPath should draw correct path for narrow bar width 1`] = `"M 100 17.5 A 82.5 82.5 0 0 1 100 182.5 L 100 177.5 A 77.5 77.5 0 0 0 100 22.5 L 100 17.5 Z"`; +exports[`RadialGauge utils drawRadialArcPath should draw correct path for narrow bar width 1`] = `"M 100 20 A 80 80 0 0 1 100 180"`; -exports[`RadialGauge utils drawRadialArcPath should draw correct path for narrow radius 1`] = `"M 100 40 A 60 60 0 0 1 100 160 L 100 140 A 40 40 0 0 0 100 60 L 100 40 Z"`; +exports[`RadialGauge utils drawRadialArcPath should draw correct path for narrow radius 1`] = `"M 100 50 A 50 50 0 0 1 100 150"`; -exports[`RadialGauge utils drawRadialArcPath should draw correct path for quarter arc 1`] = `"M 100 10 A 90 90 0 0 1 190 100 L 170 100 A 70 70 0 0 0 100 30 L 100 10 Z"`; +exports[`RadialGauge utils drawRadialArcPath should draw correct path for quarter arc 1`] = `"M 100 20 A 80 80 0 0 1 180 100"`; -exports[`RadialGauge utils drawRadialArcPath should draw correct path for rounded bars 1`] = `"M 100 10 A 90 90 0 1 1 10 100.00000000000001 A 10 10 0 0 1 30 100.00000000000001 A 70 70 0 1 0 100 30 A 10 10 0 0 1 100 10 Z"`; +exports[`RadialGauge utils drawRadialArcPath should draw correct path for rounded bars 1`] = `"M 100 20 A 80 80 0 1 1 20 100.00000000000001"`; -exports[`RadialGauge utils drawRadialArcPath should draw correct path for three quarter arc 1`] = `"M 100 10 A 90 90 0 1 1 10 100.00000000000001 L 30 100.00000000000001 A 70 70 0 1 0 100 30 L 100 10 Z"`; +exports[`RadialGauge utils drawRadialArcPath should draw correct path for three quarter arc 1`] = `"M 100 20 A 80 80 0 1 1 20 100.00000000000001"`; -exports[`RadialGauge utils drawRadialArcPath should draw correct path for wide bar width 1`] = `"M 100 -5 A 105 105 0 0 1 100 205 L 100 155 A 55 55 0 0 0 100 45 L 100 -5 Z"`; +exports[`RadialGauge utils drawRadialArcPath should draw correct path for wide bar width 1`] = `"M 100 20 A 80 80 0 0 1 100 180"`; diff --git a/packages/grafana-ui/src/components/RadialGauge/colors.test.ts b/packages/grafana-ui/src/components/RadialGauge/colors.test.ts index 321e95bb921..36a4c70d619 100644 --- a/packages/grafana-ui/src/components/RadialGauge/colors.test.ts +++ b/packages/grafana-ui/src/components/RadialGauge/colors.test.ts @@ -1,6 +1,6 @@ import { defaultsDeep } from 'lodash'; -import { createTheme, FALLBACK_COLOR, Field, FieldDisplay, FieldType, ThresholdsMode } from '@grafana/data'; +import { createTheme, Field, FieldDisplay, FieldType, ThresholdsMode } from '@grafana/data'; import { FieldColorModeId } from '@grafana/schema'; import { @@ -50,35 +50,9 @@ describe('RadialGauge color utils', () => { }, }); - it('should return the baseColor if gradient is false-y', () => { - expect( - buildGradientColors(false, createTheme(), buildFieldDisplay(createField(FieldColorModeId.Fixed)), '#FF0000') - ).toEqual([ - { color: '#FF0000', percent: 0 }, - { color: '#FF0000', percent: 1 }, - ]); - - expect( - buildGradientColors(undefined, createTheme(), buildFieldDisplay(createField(FieldColorModeId.Fixed)), '#FF0000') - ).toEqual([ - { color: '#FF0000', percent: 0 }, - { color: '#FF0000', percent: 1 }, - ]); - }); - - it('uses the fallback color if no baseColor is set', () => { - expect(buildGradientColors(false, createTheme(), buildFieldDisplay(createField(FieldColorModeId.Fixed)))).toEqual( - [ - { color: FALLBACK_COLOR, percent: 0 }, - { color: FALLBACK_COLOR, percent: 1 }, - ] - ); - }); - it('should map threshold colors correctly (with baseColor if displayProcessor does not return colors)', () => { expect( buildGradientColors( - true, createTheme(), buildFieldDisplay(createField(FieldColorModeId.Thresholds), { view: { getFieldDisplayProcessor: jest.fn(() => jest.fn(() => ({ color: '#444444' }))) }, @@ -89,14 +63,13 @@ describe('RadialGauge color utils', () => { it('should map threshold colors correctly (with baseColor if displayProcessor does not return colors)', () => { expect( - buildGradientColors(true, createTheme(), buildFieldDisplay(createField(FieldColorModeId.Thresholds)), '#FF0000') + buildGradientColors(createTheme(), buildFieldDisplay(createField(FieldColorModeId.Thresholds)), '#FF0000') ).toMatchSnapshot(); }); it('should return gradient colors for continuous color modes', () => { expect( buildGradientColors( - true, createTheme(), buildFieldDisplay(createField(FieldColorModeId.ContinuousCividis)), '#00FF00' @@ -107,7 +80,6 @@ describe('RadialGauge color utils', () => { it.each(['dark', 'light'] as const)('should return gradient colors for by-value color mode in %s theme', (mode) => { expect( buildGradientColors( - true, createTheme({ colors: { mode } }), buildFieldDisplay(createField(FieldColorModeId.ContinuousBlues)) ) @@ -117,7 +89,6 @@ describe('RadialGauge color utils', () => { it.each(['dark', 'light'] as const)('should return gradient colors for fixed color mode in %s theme', (mode) => { expect( buildGradientColors( - true, createTheme({ colors: { mode } }), buildFieldDisplay(createField(FieldColorModeId.Fixed)), '#442299' diff --git a/packages/grafana-ui/src/components/RadialGauge/colors.ts b/packages/grafana-ui/src/components/RadialGauge/colors.ts index 61160a9f826..a05817a7a54 100644 --- a/packages/grafana-ui/src/components/RadialGauge/colors.ts +++ b/packages/grafana-ui/src/components/RadialGauge/colors.ts @@ -7,18 +7,10 @@ import { GradientStop, RadialShape } from './types'; import { getFieldConfigMinMax, getFieldDisplayProcessor, getValuePercentageForValue } from './utils'; export function buildGradientColors( - gradient = false, theme: GrafanaTheme2, fieldDisplay: FieldDisplay, baseColor = fieldDisplay.display.color ?? FALLBACK_COLOR ): GradientStop[] { - if (!gradient) { - return [ - { color: baseColor, percent: 0 }, - { color: baseColor, percent: 1 }, - ]; - } - const colorMode = getFieldColorMode(fieldDisplay.field.color?.mode); // thresholds get special handling @@ -183,7 +175,7 @@ export function getGradientCss(gradientStops: GradientStop[], shape: RadialShape const GRAY_05 = '#111217'; const GRAY_90 = '#fbfbfb'; const CONTRAST_THRESHOLD_MAX = 4.5; -const getGuideDotColor = (color: string): string => { +export const getGuideDotColor = (color: string): string => { const darkColor = GRAY_05; const lightColor = GRAY_90; return colorManipulator.getContrastRatio(darkColor, color) >= CONTRAST_THRESHOLD_MAX ? darkColor : lightColor; diff --git a/packages/grafana-ui/src/components/RadialGauge/effects.tsx b/packages/grafana-ui/src/components/RadialGauge/effects.tsx index c48307f177e..2d3ae3daf21 100644 --- a/packages/grafana-ui/src/components/RadialGauge/effects.tsx +++ b/packages/grafana-ui/src/components/RadialGauge/effects.tsx @@ -1,15 +1,21 @@ -import { GrafanaTheme2 } from '@grafana/data'; +import { colorManipulator, GrafanaTheme2 } from '@grafana/data'; import { RadialGaugeDimensions } from './types'; +// some utility transparent white colors for gradients +const TRANSPARENT_WHITE = '#ffffff00'; +const MOSTLY_TRANSPARENT_WHITE = '#ffffff88'; +const MOSTLY_OPAQUE_WHITE = '#ffffffbb'; +const OPAQUE_WHITE = '#ffffff'; + +const MIN_GLOW_SIZE = 0.75; +const GLOW_FACTOR = 0.08; + export interface GlowGradientProps { id: string; barWidth: number; } -const MIN_GLOW_SIZE = 0.75; -const GLOW_FACTOR = 0.08; - export function GlowGradient({ id, barWidth }: GlowGradientProps) { // 0.75 is the minimum glow size, and it scales with bar width const glowSize = MIN_GLOW_SIZE + barWidth * GLOW_FACTOR; @@ -25,16 +31,7 @@ export function GlowGradient({ id, barWidth }: GlowGradientProps) { ); } -const CENTER_GLOW_OPACITY = 0.15; - -export function CenterGlowGradient({ gaugeId, color }: { gaugeId: string; color: string }) { - return ( - - - - - ); -} +const CENTER_GLOW_OPACITY = 0.25; export interface CenterGlowProps { dimensions: RadialGaugeDimensions; @@ -44,13 +41,14 @@ export interface CenterGlowProps { export function MiddleCircleGlow({ dimensions, gaugeId, color }: CenterGlowProps) { const gradientId = `circle-glow-${gaugeId}`; + const transparentColor = color ? colorManipulator.alpha(color, CENTER_GLOW_OPACITY) : color; return ( <> - - + + @@ -60,19 +58,15 @@ export function MiddleCircleGlow({ dimensions, gaugeId, color }: CenterGlowProps ); } -export function SpotlightGradient({ - id, - dimensions, - roundedBars, - angle, - theme, -}: { +interface SpotlightGradientProps { id: string; dimensions: RadialGaugeDimensions; angle: number; roundedBars: boolean; theme: GrafanaTheme2; -}) { +} + +export function SpotlightGradient({ id, dimensions, roundedBars, angle, theme }: SpotlightGradientProps) { if (theme.isLight) { return null; } @@ -86,9 +80,9 @@ export function SpotlightGradient({ return ( - - - {roundedBars && } + + + {roundedBars && } ); } diff --git a/packages/grafana-ui/src/components/RadialGauge/types.ts b/packages/grafana-ui/src/components/RadialGauge/types.ts index cc233dd524c..111c7aef7d6 100644 --- a/packages/grafana-ui/src/components/RadialGauge/types.ts +++ b/packages/grafana-ui/src/components/RadialGauge/types.ts @@ -2,6 +2,8 @@ export type RadialTextMode = 'auto' | 'value_and_name' | 'value' | 'name' | 'non export type RadialShape = 'circle' | 'gauge'; export interface RadialGaugeDimensions { + vizHeight: number; + vizWidth: number; margin: number; radius: number; centerX: number; diff --git a/packages/grafana-ui/src/components/RadialGauge/utils.test.ts b/packages/grafana-ui/src/components/RadialGauge/utils.test.ts index b9b2e4ad8f3..70ee54a6337 100644 --- a/packages/grafana-ui/src/components/RadialGauge/utils.test.ts +++ b/packages/grafana-ui/src/components/RadialGauge/utils.test.ts @@ -283,7 +283,9 @@ describe('RadialGauge utils', () => { }); describe('drawRadialArcPath', () => { - const defaultDims: RadialGaugeDimensions = Object.freeze({ + const defaultDims = Object.freeze({ + vizHeight: 220, + vizWidth: 220, centerX: 100, centerY: 100, radius: 80, @@ -297,7 +299,7 @@ describe('RadialGauge utils', () => { scaleLabelsSpacing: 0, scaleLabelsRadius: 0, gaugeBottomY: 0, - }); + }) satisfies RadialGaugeDimensions; it.each([ { description: 'quarter arc', startAngle: 0, endAngle: 90 }, @@ -324,11 +326,6 @@ describe('RadialGauge utils', () => { expect(drawRadialArcPath(0, 360, defaultDims)).toEqual(drawRadialArcPath(0, 359.99, defaultDims)); expect(drawRadialArcPath(0, 380, defaultDims)).toEqual(drawRadialArcPath(0, 380, defaultDims)); }); - - it('should return empty string if inner radius collapses to zero or below', () => { - const smallRadiusDims = { ...defaultDims, radius: 5, barWidth: 20 }; - expect(drawRadialArcPath(0, 180, smallRadiusDims)).toBe(''); - }); }); }); @@ -341,7 +338,9 @@ describe('RadialGauge utils', () => { describe('getOptimalSegmentCount', () => { it('should adjust segment count based on dimensions and spacing', () => { - const dimensions: RadialGaugeDimensions = { + const dimensions = { + vizHeight: 220, + vizWidth: 220, centerX: 100, centerY: 100, radius: 80, @@ -355,7 +354,7 @@ describe('RadialGauge utils', () => { scaleLabelsSpacing: 0, scaleLabelsRadius: 0, gaugeBottomY: 0, - }; + } satisfies RadialGaugeDimensions; expect(getOptimalSegmentCount(dimensions, 2, 10, 360)).toBe(8); expect(getOptimalSegmentCount(dimensions, 1, 5, 360)).toBe(5); diff --git a/packages/grafana-ui/src/components/RadialGauge/utils.ts b/packages/grafana-ui/src/components/RadialGauge/utils.ts index e26cf5eed2a..a18efc42699 100644 --- a/packages/grafana-ui/src/components/RadialGauge/utils.ts +++ b/packages/grafana-ui/src/components/RadialGauge/utils.ts @@ -155,6 +155,8 @@ export function calculateDimensions( } return { + vizWidth: width, + vizHeight: height, margin, gaugeBottomY: centerY + belowCenterY, radius: innerRadius, @@ -185,7 +187,7 @@ export function drawRadialArcPath( dimensions: RadialGaugeDimensions, roundedBars?: boolean ): string { - const { radius, centerX, centerY, barWidth } = dimensions; + const { radius, centerX, centerY } = dimensions; // For some reason a 100% full arc cannot be rendered if (endAngle >= 360) { @@ -197,66 +199,12 @@ export function drawRadialArcPath( const largeArc = endAngle > 180 ? 1 : 0; - const outerR = radius + barWidth / 2; - const innerR = Math.max(0, radius - barWidth / 2); - if (innerR <= 0) { - return ''; // cannot draw arc with 0 inner radius - } + let x1 = centerX + radius * Math.cos(startRadians); + let y1 = centerY + radius * Math.sin(startRadians); + let x2 = centerX + radius * Math.cos(endRadians); + let y2 = centerY + radius * Math.sin(endRadians); - // get points for both an inner and outer arc. we draw - // the arc entirely with a path's fill instead of using stroke - // so that it can be used as a clip-path. - const ox1 = centerX + outerR * Math.cos(startRadians); - const oy1 = centerY + outerR * Math.sin(startRadians); - const ox2 = centerX + outerR * Math.cos(endRadians); - const oy2 = centerY + outerR * Math.sin(endRadians); - - const ix1 = centerX + innerR * Math.cos(startRadians); - const iy1 = centerY + innerR * Math.sin(startRadians); - const ix2 = centerX + innerR * Math.cos(endRadians); - const iy2 = centerY + innerR * Math.sin(endRadians); - - // calculate the cap width in case we're drawing rounded bars - const capR = barWidth / 2; - - const pathParts = [ - // start at outer start - 'M', - ox1, - oy1, - // outer arc from start to end (clockwise) - 'A', - outerR, - outerR, - 0, - largeArc, - 1, - ox2, - oy2, - ]; - - if (roundedBars) { - // rounded end cap: small arc connecting outer end to inner end - pathParts.push('A', capR, capR, 0, 0, 1, ix2, iy2); - } else { - // straight line to inner end (square butt) - pathParts.push('L', ix2, iy2); - } - - // inner arc from end back to start (counter-clockwise) - pathParts.push('A', innerR, innerR, 0, largeArc, 0, ix1, iy1); - - if (roundedBars) { - // rounded start cap: small arc connecting inner start back to outer start - pathParts.push('A', capR, capR, 0, 0, 1, ox1, oy1); - } else { - // straight line back to outer start (square butt) - pathParts.push('L', ox1, oy1); - } - - pathParts.push('Z'); - - return pathParts.join(' '); + return ['M', x1, y1, 'A', radius, radius, 0, largeArc, 1, x2, y2].join(' '); } export function getAngleBetweenSegments(segmentSpacing: number, segmentCount: number, range: number) { diff --git a/packages/grafana-ui/src/components/SecretTextArea/SecretTextArea.tsx b/packages/grafana-ui/src/components/SecretTextArea/SecretTextArea.tsx index a10ad157120..5b919c05ec2 100644 --- a/packages/grafana-ui/src/components/SecretTextArea/SecretTextArea.tsx +++ b/packages/grafana-ui/src/components/SecretTextArea/SecretTextArea.tsx @@ -14,6 +14,8 @@ export type Props = React.ComponentProps & { isConfigured: boolean; /** Called when the user clicks on the "Reset" button in order to clear the secret */ onReset: () => void; + /** If true, the text area will grow to fill available width. */ + grow?: boolean; }; export const CONFIGURED_TEXT = 'configured'; @@ -35,11 +37,11 @@ const getStyles = (theme: GrafanaTheme2) => { * * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-secrettextarea--docs */ -export const SecretTextArea = ({ isConfigured, onReset, ...props }: Props) => { +export const SecretTextArea = ({ isConfigured, onReset, grow, ...props }: Props) => { const styles = useStyles2(getStyles); return ( - + {!isConfigured &&