Merge remote-tracking branch 'origin/main' into ds-apiserver-with-configs

This commit is contained in:
Ryan McKinley
2025-07-09 14:35:20 -07:00
1005 changed files with 5390 additions and 6095 deletions
+2 -49
View File
@@ -1687,15 +1687,6 @@ exports[`better eslint`] = {
"public/app/features/dashboard-scene/serialization/transformToV1TypesUtils.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
],
"public/app/features/dashboard-scene/settings/GeneralSettingsEditView.tsx:5381": [
[0, 0, 0, "Add noMargin prop to Field components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "0"],
[0, 0, 0, "Add noMargin prop to Field components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "1"],
[0, 0, 0, "Add noMargin prop to Field components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "2"],
[0, 0, 0, "Add noMargin prop to Field components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "3"],
[0, 0, 0, "Add noMargin prop to Field components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "4"],
[0, 0, 0, "Add noMargin prop to Field components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "5"],
[0, 0, 0, "Add noMargin prop to Field components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "6"]
],
"public/app/features/dashboard-scene/settings/annotations/AnnotationSettingsEdit.tsx:5381": [
[0, 0, 0, "Add noMargin prop to Field components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "0"],
[0, 0, 0, "Add noMargin prop to Field components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "1"],
@@ -2547,10 +2538,10 @@ exports[`better eslint`] = {
"public/app/features/plugins/loader/sharedDependencies.ts:5381": [
[0, 0, 0, "* import is invalid because \'Layout,HorizontalGroup,VerticalGroup\' from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"]
],
"public/app/features/plugins/sandbox/distortion_map.ts:5381": [
"public/app/features/plugins/sandbox/distortions.ts:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
],
"public/app/features/plugins/sandbox/sandbox_plugin_loader.ts:5381": [
"public/app/features/plugins/sandbox/sandboxPluginLoader.ts:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"],
[0, 0, 0, "Do not use any type assertions.", "1"],
[0, 0, 0, "Do not use any type assertions.", "2"]
@@ -3130,9 +3121,6 @@ exports[`better eslint`] = {
"public/app/plugins/datasource/cloud-monitoring/types/types.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
],
"public/app/plugins/datasource/cloud-monitoring/webpack.config.ts:5381": [
[0, 0, 0, "Do not re-export imported variable (\`config\`)", "0"]
],
"public/app/plugins/datasource/cloudwatch/components/ConfigEditor/ConfigEditor.tsx:5381": [
[0, 0, 0, "Add noMargin prop to Field components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "0"],
[0, 0, 0, "Add noMargin prop to Field components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "1"],
@@ -3299,9 +3287,6 @@ exports[`better eslint`] = {
[0, 0, 0, "Do not use any type assertions.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
],
"public/app/plugins/datasource/grafana-testdata-datasource/webpack.config.ts:5381": [
[0, 0, 0, "Do not re-export imported variable (\`config\`)", "0"]
],
"public/app/plugins/datasource/grafana/components/AnnotationQueryEditor.tsx:5381": [
[0, 0, 0, "Add noMargin prop to Field components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "0"],
[0, 0, 0, "Add noMargin prop to Field components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "1"],
@@ -3653,9 +3638,6 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "2"],
[0, 0, 0, "Unexpected any. Specify a different type.", "3"]
],
"public/app/plugins/datasource/tempo/webpack.config.ts:5381": [
[0, 0, 0, "Do not re-export imported variable (\`config\`)", "0"]
],
"public/app/plugins/datasource/zipkin/QueryField.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
@@ -3666,9 +3648,6 @@ exports[`better eslint`] = {
"public/app/plugins/datasource/zipkin/utils/transforms.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
],
"public/app/plugins/datasource/zipkin/webpack.config.ts:5381": [
[0, 0, 0, "Do not re-export imported variable (\`config\`)", "0"]
],
"public/app/plugins/panel/annolist/AnnoListPanel.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
],
@@ -4012,9 +3991,6 @@ exports[`better eslint`] = {
[0, 0, 0, "Do not use any type assertions.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
],
"public/app/types/acl.ts:5381": [
[0, 0, 0, "Do not re-export imported variable (\`OrgRole\`)", "0"]
],
"public/app/types/alerting.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
@@ -4036,29 +4012,6 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "7"],
[0, 0, 0, "Unexpected any. Specify a different type.", "8"]
],
"public/app/types/index.ts:5381": [
[0, 0, 0, "Do not re-export imported variable (\`CoreEvents\`)", "0"],
[0, 0, 0, "Do not use export all (\`export * from ...\`)", "1"],
[0, 0, 0, "Do not use export all (\`export * from ...\`)", "2"],
[0, 0, 0, "Do not use export all (\`export * from ...\`)", "3"],
[0, 0, 0, "Do not use export all (\`export * from ...\`)", "4"],
[0, 0, 0, "Do not use export all (\`export * from ...\`)", "5"],
[0, 0, 0, "Do not use export all (\`export * from ...\`)", "6"],
[0, 0, 0, "Do not use export all (\`export * from ...\`)", "7"],
[0, 0, 0, "Do not use export all (\`export * from ...\`)", "8"],
[0, 0, 0, "Do not use export all (\`export * from ...\`)", "9"],
[0, 0, 0, "Do not use export all (\`export * from ...\`)", "10"],
[0, 0, 0, "Do not use export all (\`export * from ...\`)", "11"],
[0, 0, 0, "Do not use export all (\`export * from ...\`)", "12"],
[0, 0, 0, "Do not use export all (\`export * from ...\`)", "13"],
[0, 0, 0, "Do not use export all (\`export * from ...\`)", "14"],
[0, 0, 0, "Do not use export all (\`export * from ...\`)", "15"],
[0, 0, 0, "Do not use export all (\`export * from ...\`)", "16"],
[0, 0, 0, "Do not use export all (\`export * from ...\`)", "17"],
[0, 0, 0, "Do not use export all (\`export * from ...\`)", "18"],
[0, 0, 0, "Do not use export all (\`export * from ...\`)", "19"],
[0, 0, 0, "Do not use export all (\`export * from ...\`)", "20"]
],
"public/app/types/jquery/jquery.d.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
@@ -7,6 +7,7 @@ on:
jobs:
download-sources-from-crowdin:
if: github.repository == 'grafana/grafana'
uses: grafana/grafana-github-actions/.github/workflows/crowdin-download.yml@main
with:
crowdin_project_id: 5
@@ -14,6 +14,7 @@ on:
jobs:
upload-sources-to-crowdin:
if: github.repository == 'grafana/grafana'
uses: grafana/grafana-github-actions/.github/workflows/crowdin-upload.yml@main
with:
crowdin_project_id: 5
+46 -36
View File
@@ -1,29 +1,56 @@
# Contributing to Grafana
# Contribute to Grafana
Thank you for your interest in contributing to Grafana! We welcome all people who want to contribute in a healthy and constructive manner within our community. To help us create a safe and positive community experience for all, we require all participants to adhere to the [Code of Conduct](CODE_OF_CONDUCT.md).
This document is a guide to help you through the process of contributing to Grafana.
This document is a guide to help you through the process of making technical contributions to Grafana.
## Become a contributor
Whether you're a new contributer or a seasoned veteran we hope these resources help you connect with the community:
You can contribute to Grafana in several ways. Here are some examples:
Interact and be heard:
- Contribute to the Grafana codebase.
- Report and triage bugs.
- Develop community plugins and dashboards.
- Write technical documentation and blog posts, for users and contributors.
- Organize meetups and user groups in your local area.
- Help others by answering questions about Grafana.
- Forums: Do you have a problem, question, or curiosity? Visit our [forums](https://gra.fan/fromgithubtoforums) for a reservoir of knowledge- submit your own questions and answers!
- Meetups: Craving in-person connections without the long journeys? [Join your local Grafana & Friends meetup group](https://gra.fan/githubtomeetup)!
- Community Slack: Eager for real-time connections with fellow users? Begin a conversation on [Slack](https://gra.fan/githubtoslack).
Learn:
- YouTube: From getting started to exploring newer projects like Pyroscope and Beyla, the [Grafana YouTube channel](https://gra.fan/githubtoyoutube) has what you need to get started!
- Meetups: Join a [group near you](https://gra.fan/githubtomeetup) to learn from local experts and ask questions in real time.
Share your story:
- Meetups and blogs: We’d love to feature your OSS Grafana Labs use case or story at an upcoming Grafana & Friends meetup or on the Grafana blog! Submit your idea [here](https://gra.fan/githubtocca) and we’ll connect with you on next steps if accepted.
## Make technical contributions
We welcome your technical contributions! Here are some examples:
- Contribute to the Grafana codebase- check out these [help-wanted issues](<(https://github.com/grafana/grafana/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22)>)
- Develop community [plugins](https://grafana.com/developers/plugin-tools)
- Report [bugs](https://github.com/grafana/grafana/issues/new?template=0-bug-report.yaml)
- [Triage issues](https://github.com/grafana/grafana/blob/4414b92e93440cc9ed0f281989ee71dc16216a15/contribute/triage-issues.md)
- Report [security vulnerabilities](https://github.com/grafana/grafana/security/policy)
- Submit a [feature request](https://github.com/grafana/grafana/issues/new?template=1-feature_requests.md)
- Write [technical documentation](https://github.com/grafana/grafana/blob/4414b92e93440cc9ed0f281989ee71dc16216a15/contribute/documentation/README.md)
**Please note:** We do not currently accept contributions for translations. Please do not submit pull requests translating grafana.json files - they will be rejected. We do accept contributions to mark up phrases for translation. See [Internationalization](contribute/internationalization.md).
For more ways to contribute, check out the [Open Source Guides](https://opensource.guide/how-to-contribute/).
### Your first contribution
Unsure where to begin contributing to Grafana? Start by browsing issues labeled `beginner friendly` or `help wanted`.
- [Beginner-friendly](https://github.com/grafana/grafana/issues?q=is%3Aopen+is%3Aissue+label%3A%22beginner+friendly%22) issues are generally straightforward to complete.
- [Help wanted](https://github.com/grafana/grafana/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) issues are problems we would like the community to help us with regardless of complexity.
If you're looking to make a code change, see how to set up your environment for [local development](contribute/developer-guide.md).
When you're ready to contribute, it's time to [create a pull request](/contribute/create-pull-request.md).
### Develop a plugin
Developing a Grafana plugin is a fantastic way to share your unique ideas with the community, extend the platform’s capabilities, and make a real impact on how people visualize and understand their data. Check out our guide to creating [plugins](https://grafana.com/developers/plugin-tools)
### Report bugs
Before submitting a new issue, try to make sure someone hasn't already reported the problem. Look through the [existing issues](https://github.com/grafana/grafana/issues) for similar issues.
Report a bug by submitting a [bug report](https://github.com/grafana/grafana/issues/new?labels=type%3A+bug&template=1-bug_report.md). Make sure that you provide as much information as possible on how to reproduce the bug.
Report a bug by submitting a [bug report](https://github.com/grafana/grafana/issues/new?template=0-bug-report.yaml). Make sure that you provide as much information as possible on how to reproduce the bug.
Follow the issue template and add additional information that will help us replicate the problem.
@@ -38,42 +65,25 @@ For a dashboard related issues:
For authentication and alerting Grafana server logs are useful.
#### Security issues
If you believe you've found a security vulnerability, please read our [security policy](https://github.com/grafana/grafana/security/policy) for more details.
### Suggest enhancements
If you have an idea of how to improve Grafana, submit a [feature request](https://github.com/grafana/grafana/issues/new?assignees=&labels=type%2Ffeature-request&projects=&template=1-feature_requests.md).
We want to make Grafana accessible to even more people. Submit an [accessibility issue](https://github.com/grafana/grafana/issues/new?labels=type%3A+accessibility&template=3-accessibility.md) to help us understand what we can improve.
### Write documentation
To edit or write technical content, refer to [Contribute to our documentation](/contribute/documentation/README.md). We welcome your expertise and input as our body of technical content grows.
### Triage issues
If you don't have the knowledge or time to code, consider helping with _issue triage_. The community will thank you for saving them time by spending some of yours.
Read more about the ways you can [Triage issues](/contribute/triage-issues.md).
### Answering questions
#### Security issues
If you have a question and you can't find the answer in the [documentation](https://grafana.com/docs/), the next step is to ask it on the [community site](https://community.grafana.com/).
If you believe you've found a security vulnerability, please read our [security policy](https://github.com/grafana/grafana/security/policy) for more details on reporting.
It's important to us to help these users, and we'd love your help. Sign up to our [community site](https://community.grafana.com/), and start helping other Grafana users by answering their questions.
### Suggest enhancements
### Your first contribution
If you have an idea of how to improve Grafana, submit a [feature request](https://github.com/grafana/grafana/issues/new?template=1-feature_requests.md).
Unsure where to begin contributing to Grafana? Start by browsing issues labeled `beginner friendly` or `help wanted`.
We want to make Grafana accessible to even more people. Submit an [accessibility issue](https://github.com/grafana/grafana/issues/new?template=2-accessibility.md) to help us understand what we can improve.
- [Beginner-friendly](https://github.com/grafana/grafana/issues?q=is%3Aopen+is%3Aissue+label%3A%22beginner+friendly%22) issues are generally straightforward to complete.
- [Help wanted](https://github.com/grafana/grafana/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) issues are problems we would like the community to help us with regardless of complexity.
### Write documentation
If you're looking to make a code change, see how to set up your environment for [local development](contribute/developer-guide.md).
When you're ready to contribute, it's time to [create a pull request](/contribute/create-pull-request.md).
To edit or write technical content, refer to [Contribute to our documentation](/contribute/documentation/README.md). We welcome your expertise and input as our body of technical content grows.
#### Contributor License Agreement (CLA)
@@ -14,8 +14,6 @@ import (
v0alpha1 "github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/alerting/v0alpha1"
)
var ()
var appManifestData = app.ManifestData{
AppName: "alerting",
Group: "notifications.alerting.grafana.app",
@@ -16,8 +16,6 @@ import (
v2alpha1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1"
)
var ()
var appManifestData = app.ManifestData{
AppName: "dashboard",
Group: "dashboard.grafana.app",
-2
View File
@@ -14,8 +14,6 @@ import (
v1beta1 "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1"
)
var ()
var appManifestData = app.ManifestData{
AppName: "folder",
Group: "folder.grafana.app",
@@ -82,7 +82,7 @@ Most [generally available](https://grafana.com/docs/release-life-cycle/#general-
| `alertingMigrationUI` | Enables the alerting migration UI, to migrate data source-managed rules to Grafana-managed rules | Yes |
| `alertingImportYAMLUI` | Enables a UI feature for importing rules from a Prometheus file to Grafana-managed rules | Yes |
| `unifiedNavbars` | Enables unified navbars | |
| `tabularNumbers` | Use fixed-width numbers globally in the UI | Yes |
| `tabularNumbers` | Use fixed-width numbers globally in the UI | |
## Public preview feature toggles
@@ -239,10 +239,6 @@ Ensure that you have followed the steps in [Create the Microsoft Entra ID applic
## Configure Azure AD authentication client using the Grafana UI
{{< admonition type="note" >}}
Available in Public Preview in Grafana 10.4 behind the `ssoSettingsApi` feature toggle.
{{< /admonition >}}
As a Grafana Admin, you can configure your Azure AD/Entra ID OAuth client from within Grafana using the Grafana UI. To do this, navigate to the **Administration > Authentication > Azure AD** page and fill in the form. If you have a current configuration in the Grafana configuration file, the form will be pre-populated with those values. Otherwise the form will contain default values.
After you have filled in the form, click **Save** to save the configuration. If the save was successful, Grafana will apply the new configurations.
@@ -255,10 +251,6 @@ If you run Grafana in high availability mode, configuration changes may not get
## Configure Azure AD authentication client using the Terraform provider
{{< admonition type="note" >}}
Available in Public Preview in Grafana 10.4 behind the `ssoSettingsApi` feature toggle. Supported in the Terraform provider since v2.12.0.
{{< /admonition >}}
```terraform
resource "grafana_sso_settings" "azuread_sso_settings" {
provider_name = "azuread"
@@ -49,10 +49,6 @@ If Users use the same email address in Azure AD that they use with other authent
## Configure generic OAuth authentication client using the Grafana UI
{{< admonition type="note" >}}
Available behind the `ssoSettingsAPI` feature toggle, which is enabled by default.
{{< /admonition >}}
As a Grafana Admin, you can configure Generic OAuth client from within Grafana using the Generic OAuth UI. To do this, navigate to **Administration > Authentication > Generic OAuth** page and fill in the form. If you have a current configuration in the Grafana configuration file then the form will be pre-populated with those values otherwise the form will contain default values.
After you have filled in the form, click **Save** to save the configuration. If the save was successful, Grafana will apply the new configurations.
@@ -67,10 +63,6 @@ Refer to [configuration options](#configuration-options) for more information.
## Configure generic OAuth authentication client using the Terraform provider
{{< admonition type="note" >}}
Available behind the `ssoSettingsAPI` feature toggle, which is enabled by default. Supported in the Terraform provider since v2.12.0.
{{< /admonition >}}
```terraform
resource "grafana_sso_settings" "generic_sso_settings" {
provider_name = "generic_oauth"
@@ -43,10 +43,6 @@ Ensure you know how to create a GitHub OAuth app. Consult GitHub's documentation
## Configure GitHub authentication client using the Grafana UI
{{< admonition type="note" >}}
Available behind the `ssoSettingsAPI` feature toggle, which is enabled by default.
{{< /admonition >}}
As a Grafana Admin, you can configure GitHub OAuth client from within Grafana using the GitHub UI. To do this, navigate to **Administration > Authentication > GitHub** page and fill in the form. If you have a current configuration in the Grafana configuration file, the form will be pre-populated with those values. Otherwise the form will contain default values.
After you have filled in the form, click **Save**. If the save was successful, Grafana will apply the new configurations.
@@ -61,10 +57,6 @@ Refer to [configuration options](#configuration-options) for more information.
## Configure GitHub authentication client using the Terraform provider
{{< admonition type="note" >}}
Available behind the `ssoSettingsAPI` feature toggle, which is enabled by default. Supported in the Terraform provider since v2.12.0.
{{< /admonition >}}
```terraform
resource "grafana_sso_settings" "github_sso_settings" {
provider_name = "github"
@@ -57,10 +57,6 @@ Refer to [configuration options](#configuration-options) for more information.
## Configure GitLab authentication client using the Terraform provider
{{< admonition type="note" >}}
Available behind the `ssoSettingsAPI` feature toggle, which is enabled by default. Supported in the Terraform provider since v2.12.0.
{{< /admonition >}}
```terraform
resource "grafana_sso_settings" "gitlab_sso_settings" {
provider_name = "gitlab"
@@ -45,10 +45,6 @@ First, you need to create a Google OAuth Client:
## Configure Google authentication client using the Grafana UI
{{< admonition type="note" >}}
Available behind the `ssoSettingsAPI` feature toggle, which is enabled by default.
{{< /admonition >}}
As a Grafana Admin, you can configure Google OAuth client from within Grafana using the Google UI. To do this, navigate to **Administration > Authentication > Google** page and fill in the form. If you have a current configuration in the Grafana configuration file then the form will be pre-populated with those values otherwise the form will contain default values.
After you have filled in the form, click **Save**. If the save was successful, Grafana will apply the new configurations.
@@ -61,10 +57,6 @@ If you run Grafana in high availability mode, configuration changes may not get
## Configure Google authentication client using the Terraform provider
{{< admonition type="note" >}}
Available behind the `ssoSettingsAPI` feature toggle, which is enabled by default. Supported in the Terraform provider since v2.12.0.
{{< /admonition >}}
```terraform
resource "grafana_sso_settings" "google_sso_settings" {
provider_name = "google"
@@ -101,10 +101,6 @@ If you want to configure the role for all users in the Okta directory, you can a
## Configure Okta authentication client using the Grafana UI
{{< admonition type="note" >}}
Available behind the `ssoSettingsAPI` feature toggle, which is enabled by default.
{{< /admonition >}}
As a Grafana Admin, you can configure Okta OAuth2 client from within Grafana using the Okta UI. To do this, navigate to **Administration > Authentication > Okta** page and fill in the form. If you have a current configuration in the Grafana configuration file then the form will be pre-populated with those values otherwise the form will contain default values.
After you have filled in the form, click **Save**. If the save was successful, Grafana will apply the new configurations.
@@ -119,10 +115,6 @@ Refer to [configuration options](#configuration-options) for more information.
## Configure Okta authentication client using the Terraform provider
{{< admonition type="note" >}}
Available behind the `ssoSettingsAPI` feature toggle, which is enabled by default. Supported in the Terraform provider since v2.12.0.
{{< /admonition >}}
```terraform
resource "grafana_sso_settings" "okta_sso_settings" {
provider_name = "okta"
@@ -40,7 +40,7 @@ If you are using Okta or Azure AD as Identity Provider, see the following docume
- [Configure SAML with Okta](https://grafana.com/docs/grafana/<GRAFANA_VERSION>/setup-grafana/configure-security/configure-authentication/saml/configure-saml-with-okta/)
{{< admonition type="note" >}}
The API and Terraform support are available in Public Preview in Grafana v11.1 behind the `ssoSettingsSAML` feature toggle. You must also enable the `ssoSettingsApi` flag.
The API and Terraform support are available in Public Preview in Grafana v11.1 behind the `ssoSettingsSAML` feature toggle.
{{< /admonition >}}
All methods offer the same configuration options. However, if you want to keep all of Grafana authentication settings in one place, use the Grafana configuration file or the Terraform provider. If you are a Grafana Cloud user, you do not have access to Grafana configuration file. Instead, configure SAML through the other methods.
@@ -3,8 +3,8 @@
"version": "12.1.0-pre",
"private": true,
"scripts": {
"build": "webpack -c ./webpack.config.ts --env production",
"dev": "webpack -w -c ./webpack.config.ts --env development",
"build": "NODE_OPTIONS='--experimental-strip-types --no-warnings=ExperimentalWarning' webpack -c ./webpack.config.ts --env production",
"dev": "NODE_OPTIONS='--experimental-strip-types --no-warnings=ExperimentalWarning' webpack -w -c ./webpack.config.ts --env development",
"typecheck": "tsc --noEmit",
"lint": "eslint --cache --ignore-path ./.gitignore --ext .js,.jsx,.ts,.tsx ."
},
@@ -1,7 +1,7 @@
import CopyWebpackPlugin from 'copy-webpack-plugin';
import grafanaConfig from '@grafana/plugin-configs/webpack.config';
import grafanaConfig, { type Env } from '@grafana/plugin-configs/webpack.config.ts';
import { mergeWithCustomize, unique } from 'webpack-merge';
import { Configuration } from 'webpack';
import { type Configuration } from 'webpack';
function skipFiles(f: string): boolean {
if (f.includes('/dist/')) {
@@ -19,7 +19,7 @@ function skipFiles(f: string): boolean {
return true;
}
const config = async (env: Record<string, unknown>): Promise<Configuration> => {
const config = async (env: Env): Promise<Configuration> => {
const baseConfig = await grafanaConfig(env);
const customConfig = {
plugins: [
@@ -3,8 +3,8 @@
"version": "12.1.0-pre",
"private": true,
"scripts": {
"build": "webpack -c ./webpack.config.ts --env production",
"dev": "webpack -w -c ./webpack.config.ts --env development",
"build": "NODE_OPTIONS='--experimental-strip-types --no-warnings=ExperimentalWarning' webpack -c ./webpack.config.ts --env production",
"dev": "NODE_OPTIONS='--experimental-strip-types --no-warnings=ExperimentalWarning' webpack -w -c ./webpack.config.ts --env development",
"typecheck": "tsc --noEmit",
"lint": "eslint --cache --ignore-path ./.gitignore --ext .js,.jsx,.ts,.tsx ."
},
@@ -1,7 +1,7 @@
import CopyWebpackPlugin from 'copy-webpack-plugin';
import grafanaConfig from '@grafana/plugin-configs/webpack.config';
import grafanaConfig, { type Env } from '@grafana/plugin-configs/webpack.config.ts';
import { mergeWithCustomize, unique } from 'webpack-merge';
import { Configuration } from 'webpack';
import { type Configuration } from 'webpack';
function skipFiles(f: string): boolean {
if (f.includes('/dist/')) {
@@ -19,7 +19,7 @@ function skipFiles(f: string): boolean {
return true;
}
const config = async (env: Record<string, unknown>): Promise<Configuration> => {
const config = async (env: Env): Promise<Configuration> => {
const baseConfig = await grafanaConfig(env);
const customConfig = {
plugins: [
+2 -2
View File
@@ -99,14 +99,14 @@ require (
github.com/grafana/grafana-api-golang-client v0.27.0 // @grafana/alerting-backend
github.com/grafana/grafana-app-sdk v0.39.2 // @grafana/grafana-app-platform-squad
github.com/grafana/grafana-app-sdk/logging v0.39.1 // @grafana/grafana-app-platform-squad
github.com/grafana/grafana-aws-sdk v1.0.2 // @grafana/aws-datasources
github.com/grafana/grafana-aws-sdk v1.0.3 // @grafana/aws-datasources
github.com/grafana/grafana-azure-sdk-go/v2 v2.1.6 // @grafana/partner-datasources
github.com/grafana/grafana-cloud-migration-snapshot v1.6.0 // @grafana/grafana-operator-experience-squad
github.com/grafana/grafana-google-sdk-go v0.4.1 // @grafana/partner-datasources
github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79 // @grafana/grafana-backend-group
github.com/grafana/grafana-plugin-sdk-go v0.278.0 // @grafana/plugins-platform-backend
github.com/grafana/loki/v3 v3.2.1 // @grafana/observability-logs
github.com/grafana/nanogit v0.0.0-20250625082556-a4828b879bbb // @grafana-app-platform-squad
github.com/grafana/nanogit v0.0.0-20250709085038-55508a6a9f40 // @grafana-app-platform-squad
github.com/grafana/otel-profiling-go v0.5.1 // @grafana/grafana-backend-group
github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // @grafana/observability-traces-and-profiling
github.com/grafana/pyroscope/api v1.2.1-0.20250415190842-3ff7247547ae // @grafana/observability-traces-and-profiling
+4 -4
View File
@@ -1610,8 +1610,8 @@ github.com/grafana/grafana-app-sdk v0.39.2 h1:ymfr+1318t+JC9U2OYrzVpGmNG/aJONUmF
github.com/grafana/grafana-app-sdk v0.39.2/go.mod h1:t0m6q561lpoHQCixS9LUHFUhUzDClzNtm7BH60gHVSY=
github.com/grafana/grafana-app-sdk/logging v0.39.1 h1:lI5rbrheuwVPuyIM6LIuEYOCSpgmXahfKtqeMyhbGPU=
github.com/grafana/grafana-app-sdk/logging v0.39.1/go.mod h1:WhDENSnaGHtyVVwZGVnAR7YLvh2xlLDYR3D7E6h7XVk=
github.com/grafana/grafana-aws-sdk v1.0.2 h1:98eBuHYFmgvH0xO9kKf4RBsEsgQRp8EOA/9yhDIpkss=
github.com/grafana/grafana-aws-sdk v1.0.2/go.mod h1:hO7q7yWV+t6dmiyJjMa3IbuYnYkBua+G/IAlOPVIYKE=
github.com/grafana/grafana-aws-sdk v1.0.3 h1:FtGiTrdlPXuQmLqeZdyNjjkNKOOdvQ4sxWw8MtJc6ow=
github.com/grafana/grafana-aws-sdk v1.0.3/go.mod h1:hO7q7yWV+t6dmiyJjMa3IbuYnYkBua+G/IAlOPVIYKE=
github.com/grafana/grafana-azure-sdk-go/v2 v2.1.6 h1:OfCkitCuomzZKW1WYHrG8MxKwtMhALb7jqoj+487eTg=
github.com/grafana/grafana-azure-sdk-go/v2 v2.1.6/go.mod h1:V7y2BmsWxS3A9Ohebwn4OiSfJJqi//4JQydQ8fHTduo=
github.com/grafana/grafana-cloud-migration-snapshot v1.6.0 h1:S4kHwr//AqhtL9xHBtz1gqVgZQeCRGTxjgsRBAkpjKY=
@@ -1654,8 +1654,8 @@ github.com/grafana/loki/pkg/push v0.0.0-20231124142027-e52380921608 h1:ZYk42718k
github.com/grafana/loki/pkg/push v0.0.0-20231124142027-e52380921608/go.mod h1:f3JSoxBTPXX5ec4FxxeC19nTBSxoTz+cBgS3cYLMcr0=
github.com/grafana/loki/v3 v3.2.1 h1:VB7u+KHfvL5aHAxgoVBvz5wVhsdGuqKC7uuOFOOe7jw=
github.com/grafana/loki/v3 v3.2.1/go.mod h1:WvdLl6wOS+yahaeQY+xhD2m2XzkHDfKr5FZaX7D/X2Y=
github.com/grafana/nanogit v0.0.0-20250625082556-a4828b879bbb h1:JR672zBiCkfiKuRRsU76TRC2q12q0VfZl2SP8jBIAJQ=
github.com/grafana/nanogit v0.0.0-20250625082556-a4828b879bbb/go.mod h1:tN93IZUaAmnSWgL0IgnKdLv6DNeIhTJGvl1wvQMrWco=
github.com/grafana/nanogit v0.0.0-20250709085038-55508a6a9f40 h1:wsIgOI4Ou1o/UtxtJlemLufpVBpMdcXVJxedk0wLoCM=
github.com/grafana/nanogit v0.0.0-20250709085038-55508a6a9f40/go.mod h1:ToqLjIdvV3AZQa3K6e5m9hy/nsGaUByc2dWQlctB9iA=
github.com/grafana/otel-profiling-go v0.5.1 h1:stVPKAFZSa7eGiqbYuG25VcqYksR6iWvF3YH66t4qL8=
github.com/grafana/otel-profiling-go v0.5.1/go.mod h1:ftN/t5A/4gQI19/8MoWurBEtC6gFw8Dns1sJZ9W4Tls=
github.com/grafana/prometheus-alertmanager v0.25.1-0.20250620093340-be61a673dee6 h1:oJnbhG6ZNy10AjsgNeAtAKeGHogIGOMfAsBH6fYYa5M=
+4 -4
View File
@@ -180,7 +180,7 @@
"cypress": "14.3.2",
"cypress-file-upload": "5.0.8",
"cypress-recurse": "^1.35.3",
"esbuild": "0.25.0",
"esbuild": "0.25.6",
"esbuild-loader": "4.3.0",
"esbuild-plugin-browserslist": "^1.0.0",
"eslint": "9.19.0",
@@ -192,13 +192,13 @@
"eslint-plugin-jsx-a11y": "6.10.2",
"eslint-plugin-lodash": "8.0.0",
"eslint-plugin-no-barrel-files": "^1.1.1",
"eslint-plugin-react": "7.37.4",
"eslint-plugin-react": "7.37.5",
"eslint-plugin-react-hooks": "5.1.0",
"eslint-plugin-testing-library": "^7.0.0",
"eslint-plugin-unicorn": "^56.0.0",
"eslint-scope": "^8.1.0",
"eslint-webpack-plugin": "4.2.0",
"expose-loader": "5.0.0",
"expose-loader": "5.0.1",
"fishery": "^2.2.2",
"fork-ts-checker-webpack-plugin": "9.0.2",
"glob": "11.0.1",
@@ -279,7 +279,7 @@
"@grafana/faro-web-sdk": "^1.13.2",
"@grafana/faro-web-tracing": "^1.13.2",
"@grafana/flamegraph": "workspace:*",
"@grafana/google-sdk": "0.3.2",
"@grafana/google-sdk": "0.3.4",
"@grafana/i18n": "workspace:*",
"@grafana/lezer-logql": "0.2.8",
"@grafana/llm": "0.22.1",
+1 -1
View File
@@ -92,7 +92,7 @@
"@types/react": "18.3.18",
"@types/react-dom": "18.3.5",
"@types/tinycolor2": "1.4.6",
"esbuild": "0.25.0",
"esbuild": "0.25.6",
"react": "18.3.1",
"react-dom": "18.3.1",
"rimraf": "6.0.1",
@@ -999,7 +999,7 @@ export interface FeatureToggles {
preferLibraryPanelTitle?: boolean;
/**
* Use fixed-width numbers globally in the UI
* @default true
* @default false
*/
tabularNumbers?: boolean;
/**
+1 -1
View File
@@ -42,7 +42,7 @@
"@rollup/plugin-node-resolve": "16.0.1",
"@types/node": "22.15.0",
"@types/semver": "7.7.0",
"esbuild": "0.25.0",
"esbuild": "0.25.6",
"rimraf": "6.0.1",
"rollup": "^4.22.4",
"rollup-plugin-esbuild": "6.2.0",
+1 -1
View File
@@ -73,7 +73,7 @@
"@types/react-virtualized-auto-sizer": "1.0.4",
"@types/tinycolor2": "1.4.6",
"babel-jest": "29.7.0",
"esbuild": "0.25.0",
"esbuild": "0.25.6",
"jest": "^29.6.4",
"jest-canvas-mock": "2.5.2",
"rollup": "^4.22.4",
@@ -6,6 +6,7 @@
"dependencies": {
"tslib": "2.8.1"
},
"type": "module",
"devDependencies": {
"@grafana/tsconfig": "^2.0.0",
"@swc/core": "1.10.12",
+3 -11
View File
@@ -4,19 +4,11 @@
"alwaysStrict": true,
"declaration": false,
"resolveJsonModule": true,
"moduleResolution": "bundler"
},
"ts-node": {
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"moduleResolution": "Node",
"esModuleInterop": true
},
"transpileOnly": true
"moduleResolution": "bundler",
"noEmit": true,
"allowImportingTsExtensions": true
},
"extends": "@grafana/tsconfig",
"exclude": ["**/*.test.ts", "**/*.test.tsx", "**/*.spec.ts", "**/*.spec.tsx"],
"include": ["./types", "."]
}
@@ -0,0 +1,23 @@
declare module 'replace-in-file-webpack-plugin' {
import { Compiler, Plugin } from 'webpack';
interface ReplaceRule {
search: string | RegExp;
replace: string | ((match: string) => string);
}
interface ReplaceOption {
dir?: string;
files?: string[];
test?: RegExp | RegExp[];
rules: ReplaceRule[];
}
class ReplaceInFilePlugin extends Plugin {
constructor(options?: ReplaceOption[]);
options: ReplaceOption[];
apply(compiler: Compiler): void;
}
export = ReplaceInFilePlugin;
}
+9 -2
View File
@@ -3,12 +3,19 @@ import { glob } from 'glob';
import path from 'path';
import process from 'process';
// Support for node 22 and 24. Due to the many changes in importing json files
// across recent node versions we load the json files using fs for simplicity.
function loadJson(path: string) {
const rawJson = fs.readFileSync(path, 'utf8');
return JSON.parse(rawJson);
}
export function getPackageJson() {
return require(path.resolve(process.cwd(), 'package.json'));
return loadJson(path.resolve(process.cwd(), 'package.json'));
}
export function getPluginJson() {
return require(path.resolve(process.cwd(), 'plugin.json'));
return loadJson(path.resolve(process.cwd(), 'plugin.json'));
}
export async function getEntries(): Promise<Record<string, string>> {
@@ -2,15 +2,14 @@ import CopyWebpackPlugin from 'copy-webpack-plugin';
import ESLintPlugin from 'eslint-webpack-plugin';
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
import path from 'path';
// @ts-expect-error - there are no types for this package
import ReplaceInFileWebpackPlugin from 'replace-in-file-webpack-plugin';
import TerserPlugin from 'terser-webpack-plugin';
import { type Configuration, BannerPlugin } from 'webpack';
import webpack, { type Configuration } from 'webpack';
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
import VirtualModulesPlugin from 'webpack-virtual-modules';
import { DIST_DIR } from './constants';
import { getPackageJson, getPluginJson, getEntries, hasLicense } from './utils';
import { DIST_DIR } from './constants.ts';
import { getPackageJson, getPluginJson, getEntries, hasLicense } from './utils.ts';
function skipFiles(f: string): boolean {
if (f.includes('/dist/')) {
@@ -32,7 +31,7 @@ function skipFiles(f: string): boolean {
return true;
}
type Env = {
export type Env = {
[key: string]: true | string | Env;
};
@@ -54,9 +53,13 @@ const config = async (env: Env): Promise<Configuration> => {
cache: {
type: 'filesystem',
buildDependencies: {
config: [__filename],
config: [import.meta.filename],
},
cacheDirectory: path.resolve(__dirname, '../../node_modules/.cache/webpack', path.basename(process.cwd())),
cacheDirectory: path.resolve(
import.meta.dirname,
'../../node_modules/.cache/webpack',
path.basename(process.cwd())
),
},
context: process.cwd(),
@@ -114,7 +117,7 @@ const config = async (env: Env): Promise<Configuration> => {
test: /module\.tsx?$/,
use: [
{
loader: require.resolve('imports-loader'),
loader: 'imports-loader',
options: {
imports: `side-effects grafana-public-path`,
},
@@ -125,10 +128,10 @@ const config = async (env: Env): Promise<Configuration> => {
exclude: /(node_modules)/,
test: /\.[tj]sx?$/,
use: {
loader: require.resolve('swc-loader'),
loader: 'swc-loader',
options: {
jsc: {
baseUrl: path.resolve(__dirname),
baseUrl: path.resolve(import.meta.dirname),
target: 'es2015',
loose: false,
parser: {
@@ -209,7 +212,7 @@ const config = async (env: Env): Promise<Configuration> => {
plugins: [
virtualPublicPath,
// Insert create plugin version information into the bundle so Grafana will load from cdn with script tags.
new BannerPlugin({
new webpack.BannerPlugin({
banner: '/* [create-plugin] version: 5.22.0 */',
raw: true,
entryOnly: true,
@@ -264,7 +267,7 @@ const config = async (env: Env): Promise<Configuration> => {
extensions: ['.ts', '.tsx'],
lintDirtyModulesOnly: true, // don't lint on start, only lint changed files
cacheLocation: path.resolve(
__dirname,
import.meta.dirname,
'../../node_modules/.cache/eslint-webpack-plugin',
path.basename(process.cwd()),
'.eslintcache'
+1 -1
View File
@@ -90,7 +90,7 @@
"@types/node": "22.15.0",
"@types/pluralize": "^0.0.33",
"@types/prismjs": "1.26.5",
"esbuild": "0.25.0",
"esbuild": "0.25.6",
"i18next-parser": "9.3.0",
"jest": "29.7.0",
"jest-environment-jsdom": "29.7.0",
+1 -1
View File
@@ -78,7 +78,7 @@
"@types/lodash": "4.17.20",
"@types/react": "18.3.18",
"@types/react-dom": "18.3.5",
"esbuild": "0.25.0",
"esbuild": "0.25.6",
"lodash": "4.17.21",
"react": "18.3.1",
"react-dom": "18.3.1",
+1 -1
View File
@@ -38,7 +38,7 @@
"devDependencies": {
"@grafana/tsconfig": "^2.0.0",
"@rollup/plugin-node-resolve": "16.0.1",
"esbuild": "0.25.0",
"esbuild": "0.25.6",
"glob": "^11.0.0",
"rimraf": "6.0.1",
"rollup": "^4.22.4",
@@ -15,6 +15,7 @@ export const pluginVersion = "12.1.0-pre";
export interface Options {
controlsStorageKey?: string;
dedupStrategy: common.LogsDedupStrategy;
detailsMode?: ('inline' | 'sidebar');
displayedFields?: Array<string>;
enableInfiniteScrolling?: boolean;
enableLogDetails: boolean;
+2 -2
View File
@@ -181,8 +181,8 @@
"core-js": "3.40.0",
"css-loader": "7.1.2",
"csstype": "3.1.3",
"esbuild": "0.25.0",
"expose-loader": "5.0.0",
"esbuild": "0.25.6",
"expose-loader": "5.0.1",
"fs-extra": "^11.2.0",
"mock-raf": "1.0.1",
"msw": "^2.10.2",
@@ -2,6 +2,8 @@ import { css, keyframes } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { getIconPath } from '../Icon/utils';
const slideUpIn = keyframes({
'0%': {
opacity: 0,
@@ -58,143 +60,146 @@ const slideDownOut = keyframes({
},
});
export const getCascaderStyles = (theme: GrafanaTheme2) => ({
dropdown: css({
'&.rc-cascader-dropdown': {
position: 'absolute',
// Required, otherwise the portal that the popup is shown in will render under other components
zIndex: 9999,
export const getCascaderStyles = (theme: GrafanaTheme2) => {
const iconPath = getIconPath('angle-right');
return {
dropdown: css({
'&.rc-cascader-dropdown': {
position: 'absolute',
// Required, otherwise the portal that the popup is shown in will render under other components
zIndex: 9999,
'&-hidden': {
display: 'none',
},
},
'.rc-cascader': {
'&-menus': {
overflow: 'hidden',
background: theme.colors.background.elevated,
border: `none`,
borderRadius: theme.shape.radius.default,
boxShadow: theme.shadows.z3,
whiteSpace: 'nowrap',
'&.slide-up-enter, &.slide-up-appear': {
animationDuration: '0.3s',
animationFillMode: 'both',
transformOrigin: '0 0',
opacity: 0,
animationTimingFunction: 'cubic-bezier(0.08, 0.82, 0.17, 1)',
animationPlayState: 'paused',
},
'&.slide-up-enter.slide-up-enter-active.rc-cascader-menus-placement, &.slide-up-appear.slide-up-appear-active.rc-cascader-menus-placement':
{
'&-bottomLeft': {
animationName: slideUpIn,
animationPlayState: 'running',
},
'&-topLeft': {
animationName: slideDownIn,
animationPlayState: 'running',
},
},
'&.slide-up-leave': {
animationDuration: '0.3s',
animationFillMode: 'both',
transformOrigin: '0 0',
opacity: 1,
animationTimingFunction: 'cubic-bezier(0.6, 0.04, 0.98, 0.34)',
animationPlayState: 'paused',
'&.slide-up-leave-active.rc-cascader-menus-placement': {
'&-bottomLeft': {
animationName: slideUpOut,
animationPlayState: 'running',
},
'&-topLeft': {
animationName: slideDownOut,
animationPlayState: 'running',
},
},
'&-hidden': {
display: 'none',
},
},
'&-menu': {
display: 'inline-block',
maxWidth: '50vw',
height: '192px',
listStyle: 'none',
margin: 0,
padding: theme.spacing(0.5),
borderRight: `1px solid ${theme.colors.border.weak}`,
overflow: 'auto',
'&:last-child': {
borderRight: 0,
},
'&-item': {
height: theme.spacing(4),
lineHeight: theme.spacing(4),
padding: theme.spacing(0, 4, 0, 2),
borderRadius: theme.shape.radius.default,
cursor: 'pointer',
whiteSpace: 'nowrap',
'.rc-cascader': {
'&-menus': {
overflow: 'hidden',
textOverflow: 'ellipsis',
transition: 'all 0.3s ease',
position: 'relative',
background: theme.colors.background.elevated,
border: `none`,
borderRadius: theme.shape.radius.default,
boxShadow: theme.shadows.z3,
whiteSpace: 'nowrap',
'&:hover': {
background: theme.colors.action.hover,
'&.slide-up-enter, &.slide-up-appear': {
animationDuration: '0.3s',
animationFillMode: 'both',
transformOrigin: '0 0',
opacity: 0,
animationTimingFunction: 'cubic-bezier(0.08, 0.82, 0.17, 1)',
animationPlayState: 'paused',
},
'&-disabled': {
cursor: 'not-allowed',
color: theme.colors.text.disabled,
'&.slide-up-enter.slide-up-enter-active.rc-cascader-menus-placement, &.slide-up-appear.slide-up-appear-active.rc-cascader-menus-placement':
{
'&-bottomLeft': {
animationName: slideUpIn,
animationPlayState: 'running',
},
'&:hover': {
background: 'transparent',
'&-topLeft': {
animationName: slideDownIn,
animationPlayState: 'running',
},
},
'&:after': {
position: 'absolute',
right: '12px',
content: "'loading'",
color: theme.colors.text.disabled,
fontStyle: 'italic',
'&.slide-up-leave': {
animationDuration: '0.3s',
animationFillMode: 'both',
transformOrigin: '0 0',
opacity: 1,
animationTimingFunction: 'cubic-bezier(0.6, 0.04, 0.98, 0.34)',
animationPlayState: 'paused',
'&.slide-up-leave-active.rc-cascader-menus-placement': {
'&-bottomLeft': {
animationName: slideUpOut,
animationPlayState: 'running',
},
'&-topLeft': {
animationName: slideDownOut,
animationPlayState: 'running',
},
},
},
},
'&-active': {
color: theme.colors.text.maxContrast,
background: theme.colors.background.secondary,
'&-menu': {
display: 'inline-block',
maxWidth: '50vw',
height: '192px',
listStyle: 'none',
margin: 0,
padding: theme.spacing(0.5),
borderRight: `1px solid ${theme.colors.border.weak}`,
overflow: 'auto',
'&:last-child': {
borderRight: 0,
},
'&-item': {
height: theme.spacing(4),
lineHeight: theme.spacing(4),
padding: theme.spacing(0, 4, 0, 2),
borderRadius: theme.shape.radius.default,
cursor: 'pointer',
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
transition: 'all 0.3s ease',
position: 'relative',
'&:hover': {
background: theme.colors.action.hover,
},
},
'&-expand': {
position: 'relative',
'&-disabled': {
cursor: 'not-allowed',
color: theme.colors.text.disabled,
'&:after': {
'&:hover': {
background: 'transparent',
},
'&:after': {
position: 'absolute',
right: '12px',
content: "'loading'",
color: theme.colors.text.disabled,
fontStyle: 'italic',
},
},
'&-active': {
color: theme.colors.text.maxContrast,
background: theme.colors.background.secondary,
content: "''",
height: theme.spacing(3),
mask: 'url(../img/icons/unicons/angle-right.svg)',
maskType: 'luminance',
position: 'absolute',
right: 0,
top: theme.spacing(0.5),
width: theme.spacing(3),
'&:hover': {
background: theme.colors.action.hover,
},
},
'&-expand': {
position: 'relative',
'&:after': {
background: theme.colors.text.primary,
content: "''",
height: theme.spacing(3),
mask: `url(${iconPath})`,
maskType: 'luminance',
position: 'absolute',
right: 0,
top: theme.spacing(0.5),
width: theme.spacing(3),
},
},
},
},
},
},
}),
});
}),
};
};
@@ -8,7 +8,7 @@ import { useStyles2 } from '../../themes/ThemeContext';
import { IconName, IconType, IconSize } from '../../types/icon';
import { spin } from '../../utils/keyframes';
import { getIconRoot, getIconSubDir, getSvgSize } from './utils';
import { getIconPath, getSvgSize } from './utils';
export interface IconProps extends Omit<React.SVGProps<SVGElement>, 'onLoad' | 'onError' | 'ref'> {
name: IconName;
@@ -53,12 +53,10 @@ export const Icon = React.forwardRef<SVGElement, IconProps>(
// handle the deprecated 'fa fa-spinner'
const iconName: IconName = name === 'fa fa-spinner' ? 'spinner' : name;
const iconRoot = getIconRoot();
const svgSize = getSvgSize(size);
const svgHgt = svgSize;
const svgWid = name.startsWith('gf-bar-align') ? 16 : name.startsWith('gf-interp') ? 30 : svgSize;
const subDir = getIconSubDir(iconName, type);
const svgPath = `${iconRoot}${subDir}/${iconName}.svg`;
const svgPath = getIconPath(iconName, type);
const composedClassName = cx(
styles.icon,
@@ -60,3 +60,9 @@ export function getIconRoot(): string {
return iconRoot;
}
export function getIconPath(name: IconName, type: IconType = 'default'): string {
const iconRoot = getIconRoot();
const subDir = getIconSubDir(name, type);
return `${iconRoot}${subDir}/${name}.svg`;
}
@@ -42,7 +42,8 @@ export function TableCellActions(props: TableCellActionsProps) {
dataProjection: 'EPSG:4326',
});
mode = TableCellInspectorMode.code;
} else if ('cellType' in cellOptions && cellOptions.cellType === TableCellDisplayMode.JSONView) {
}
if (cellOptions.type === TableCellDisplayMode.JSONView) {
mode = TableCellInspectorMode.code;
}
@@ -141,6 +141,14 @@ describe('TableNG Cells renderers', () => {
expect(container).toBeInTheDocument();
expect(container.childNodes).toHaveLength(1);
});
it('should return AutoCell when cellOptions is unmapped', () => {
const field = createField(FieldType.string);
const { container } = renderCell(field, { type: 'number' } as unknown as TableCellOptions);
expect(container).toBeInTheDocument();
expect(container.childNodes).toHaveLength(1);
});
});
});
@@ -109,7 +109,7 @@ export function getCellRenderer(field: Field, cellOptions: TableCellOptions): Ta
if (cellType === TableCellDisplayMode.Auto) {
return getAutoRendererResult(field);
}
return CELL_RENDERERS[cellType];
return CELL_RENDERERS[cellType] ?? AUTO_RENDERER;
}
/** @internal */
@@ -81,13 +81,14 @@ export function TableNG(props: TableNGProps) {
onSortByChange,
showTypeIcons,
structureRev,
transparent,
width,
} = props;
const theme = useTheme2();
const styles = useStyles2(getGridStyles, {
enablePagination,
noHeader,
transparent,
});
const panelContext = usePanelContext();
@@ -244,21 +245,9 @@ export function TableNG(props: TableNGProps) {
},
sortColumns,
rowHeight,
headerRowClass: styles.headerRow,
headerRowHeight: headerHeight,
bottomSummaryRows: hasFooter ? [{}] : undefined,
}) satisfies Partial<DataGridProps<TableRow, TableSummaryRow>>,
[
enableVirtualization,
resizeHandler,
sortColumns,
headerHeight,
styles.headerRow,
rowHeight,
hasFooter,
setSortColumns,
onSortByChange,
]
[enableVirtualization, resizeHandler, sortColumns, rowHeight, hasFooter, setSortColumns, onSortByChange]
);
interface Schema {
@@ -437,6 +426,7 @@ export function TableNG(props: TableNGProps) {
return result;
}
const hasNestedHeaders = firstNestedData.meta?.custom?.noHeader !== true;
const renderRow = renderRowFactory(firstNestedData.fields, panelContext, expandedRows, enableSharedCrosshair);
const { columns: nestedColumns, cellRootRenderers: nestedCellRootRenderers } = fromFields(
firstNestedData.fields,
@@ -486,11 +476,20 @@ export function TableNG(props: TableNGProps) {
}
const expandedRecords = applySort(frameToRecords(nestedData), nestedData.fields, sortColumns);
if (!expandedRecords.length) {
return (
<div className={styles.noDataNested}>
<Trans i18nKey="grafana-ui.table.nested-table.no-data">No data</Trans>
</div>
);
}
return (
<DataGrid<TableRow, TableSummaryRow>
{...commonDataGridProps}
className={cx(styles.grid, styles.gridNested)}
headerRowClass={cx(styles.headerRow, { [styles.displayNone]: !hasNestedHeaders })}
headerRowHeight={hasNestedHeaders ? defaultHeaderHeight : 0}
columns={nestedColumns}
rows={expandedRecords}
renderers={{ renderRow, renderCell: renderCellRoot }}
@@ -509,6 +508,7 @@ export function TableNG(props: TableNGProps) {
crossFilterOrder,
crossFilterRows,
data,
defaultHeaderHeight,
defaultRowHeight,
enableSharedCrosshair,
expandedRows,
@@ -552,6 +552,8 @@ export function TableNG(props: TableNGProps) {
className={styles.grid}
columns={structureRevColumns}
rows={paginatedRows}
headerRowClass={cx(styles.headerRow, { [styles.displayNone]: noHeader })}
headerRowHeight={headerHeight}
onCellClick={({ column, row }, { clientX, clientY, preventGridDefault }) => {
// Note: could be column.field; JS says yes, but TS says no!
const field = columns[column.idx].field;
@@ -693,17 +695,20 @@ const renderRowFactory =
const getGridStyles = (
theme: GrafanaTheme2,
{ enablePagination, noHeader }: { enablePagination?: boolean; noHeader?: boolean }
{ enablePagination, transparent }: { enablePagination?: boolean; transparent?: boolean }
) => ({
grid: css({
'--rdg-background-color': theme.colors.background.primary,
'--rdg-header-background-color': theme.colors.background.primary,
'--rdg-border-color': theme.isDark ? '#282b30' : '#ebebec',
'--rdg-background-color': transparent ? theme.colors.background.canvas : theme.colors.background.primary,
'--rdg-header-background-color': transparent ? theme.colors.background.canvas : theme.colors.background.primary,
'--rdg-border-color': theme.colors.border.weak,
'--rdg-color': theme.colors.text.primary,
// note: this cannot have any transparency since default cells that
// overlay/overflow on hover inherit this background and need to occlude cells below
'--rdg-row-hover-background-color': theme.isDark ? '#212428' : '#f4f5f5',
'--rdg-row-background-color': transparent ? theme.colors.background.canvas : theme.colors.background.primary,
'--rdg-row-hover-background-color': transparent
? theme.colors.background.primary
: theme.colors.background.secondary,
// TODO: magic 32px number is unfortunate. it would be better to have the content
// flow using flexbox rather than hard-coding this size via a calc
@@ -723,15 +728,24 @@ const getGridStyles = (
}),
gridNested: css({
height: '100%',
width: `calc(100% - ${COLUMN.EXPANDER_WIDTH - 1}px)`,
width: `calc(100% - ${COLUMN.EXPANDER_WIDTH - TABLE.CELL_PADDING * 2 - 1}px)`,
overflow: 'visible',
marginLeft: COLUMN.EXPANDER_WIDTH - 1,
marginLeft: COLUMN.EXPANDER_WIDTH - TABLE.CELL_PADDING - 1,
marginBlock: TABLE.CELL_PADDING,
}),
cellNested: css({
'&[aria-selected=true]': {
outline: 'none',
},
}),
noDataNested: css({
height: TABLE.NESTED_NO_DATA_HEIGHT,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: theme.colors.text.secondary,
fontSize: theme.typography.h4.fontSize,
}),
cellActions: css({
display: 'none',
position: 'absolute',
@@ -739,7 +753,7 @@ const getGridStyles = (
margin: 'auto',
height: '100%',
color: theme.colors.text.primary,
background: theme.isDark ? 'rgba(0, 0, 0, 0.3)' : 'rgba(255, 255, 255, 0.7)',
background: theme.isDark ? 'rgba(0, 0, 0, 0.7)' : 'rgba(255, 255, 255, 0.7)',
padding: theme.spacing.x0_5,
paddingInlineStart: theme.spacing.x1,
}),
@@ -752,12 +766,14 @@ const getGridStyles = (
headerRow: css({
paddingBlockStart: 0,
fontWeight: 'normal',
...(noHeader ? { display: 'none' } : {}),
'& .rdg-cell': {
height: '100%',
alignItems: 'flex-end',
},
}),
displayNone: css({
display: 'none',
}),
paginationContainer: css({
alignItems: 'center',
display: 'flex',
@@ -835,6 +851,7 @@ const getCellStyles = (
whiteSpace: 'pre-line',
height: 'fit-content',
minWidth: 'fit-content',
paddingBlock: (rowHeight - TABLE.LINE_HEIGHT) / 2 - 1,
}),
},
}),
@@ -14,5 +14,6 @@ export const TABLE = {
SCROLL_BAR_WIDTH: 8,
SCROLL_BAR_MARGIN: 2,
LINE_HEIGHT: 22,
NESTED_NO_DATA_HEIGHT: 60,
BORDER_RIGHT: 0.666667,
};
@@ -503,9 +503,13 @@ export function useRowHeight({
return 0;
}
// Ensure we have a minimum height (defaultHeight) for the nested table even if data is empty
const rowCount = row.data?.length ?? 0;
return Math.max(defaultHeight, defaultHeight * rowCount + headerHeight);
if (rowCount === 0) {
return TABLE.NESTED_NO_DATA_HEIGHT + TABLE.CELL_PADDING * 2;
}
const nestedHeaderHeight = row.data?.meta?.custom?.noHeader ? 0 : defaultHeight;
return Math.max(defaultHeight, defaultHeight * rowCount + nestedHeaderHeight + TABLE.CELL_PADDING * 2);
}
// regular rows
@@ -519,7 +523,6 @@ export function useRowHeight({
fields,
hasNestedFrames,
hasWrappedCols,
headerHeight,
maxWrapCellOptions,
colWidths,
]);
@@ -131,6 +131,7 @@ export interface BaseTableProps {
enablePagination?: boolean;
cellHeight?: TableCellHeight;
structureRev?: number;
transparent?: boolean;
/** @alpha Used by SparklineCell when provided */
timeRange?: TimeRange;
enableSharedCrosshair?: boolean;
+1 -1
View File
@@ -74,7 +74,7 @@ func (hs *HTTPServer) SetHomeDashboard(c *contextmodel.ReqContext) response.Resp
func (hs *HTTPServer) GetUserPreferences(c *contextmodel.ReqContext) response.Response {
userID, err := identity.UserIdentifier(c.GetID())
if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to update user preferences", err)
return response.Error(http.StatusUnauthorized, "Not a valid identity", err)
}
return prefapi.GetPreferencesFor(c.Req.Context(), hs.DashboardService, hs.preferenceService, hs.Features, c.GetOrgID(), userID, 0)
+1 -53
View File
@@ -9,88 +9,36 @@ require (
google.golang.org/protobuf v1.36.6
gopkg.in/yaml.v3 v3.0.1
k8s.io/apimachinery v0.33.2
k8s.io/apiserver v0.33.2
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738
)
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/cenkalti/backoff/v5 v5.0.2 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/coreos/go-semver v0.3.1 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/gnostic-models v0.6.9 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
github.com/jonboulle/clockwork v0.5.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/onsi/ginkgo/v2 v2.22.2 // indirect
github.com/onsi/gomega v1.36.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.22.0 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.64.0 // indirect
github.com/prometheus/procfs v0.16.1 // indirect
github.com/spf13/pflag v1.0.6 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.etcd.io/bbolt v1.4.0 // indirect
go.etcd.io/etcd/api/v3 v3.5.21 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.21 // indirect
go.etcd.io/etcd/client/v3 v3.5.21 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
go.opentelemetry.io/otel v1.36.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0 // indirect
go.opentelemetry.io/otel/metric v1.36.0 // indirect
go.opentelemetry.io/otel/sdk v1.36.0 // indirect
go.opentelemetry.io/otel/trace v1.36.0 // indirect
go.opentelemetry.io/proto/otlp v1.6.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.36.0 // indirect
golang.org/x/net v0.41.0 // indirect
golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/term v0.32.0 // indirect
golang.org/x/text v0.26.0 // indirect
golang.org/x/time v0.11.0 // indirect
golang.org/x/tools v0.34.0 // indirect
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
k8s.io/api v0.33.2 // indirect
k8s.io/client-go v0.33.2 // indirect
k8s.io/component-base v0.33.2 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect
-209
View File
@@ -1,41 +1,11 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8=
github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/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/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
@@ -46,156 +16,58 @@ github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw=
github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
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/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e h1:BTKk7LHuG1kmAkucwTA7DuMbKpKvJTKrGdBmUNO4dfQ=
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e/go.mod h1:IA4SOwun8QyST9c5UNs/fN37XL6boXXDvRYFcFwbipg=
github.com/grpc-ecosystem/go-grpc-middleware 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-prometheus v1.2.1-0.20191002090509-6af20e3a5340 h1:uGoIog/wiQHI9GAxXO5TJbT0wWKH3O9HhOJW1F9c3fY=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340/go.mod h1:3bDW6wMZJB7tiONtC/1Xpicra6Wp5GgbTbQWCbI5fkc=
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I=
github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
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/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/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.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/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/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/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
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 v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.64.0 h1:pdZeA+g617P7oGv1CzdTzyeShxAGrTBsolKNOLQPGO4=
github.com/prometheus/common v0.64.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.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.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE=
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 h1:S2dVYn90KE98chqDkyE9Z4N61UnQd+KOfgp5Iu53llk=
github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk=
go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk=
go.etcd.io/etcd/api/v3 v3.5.21 h1:A6O2/JDb3tvHhiIz3xf9nJ7REHvtEFJJ3veW3FbCnS8=
go.etcd.io/etcd/api/v3 v3.5.21/go.mod h1:c3aH5wcvXv/9dqIw2Y810LDXJfhSYdHQ0vxmP3CCHVY=
go.etcd.io/etcd/client/pkg/v3 v3.5.21 h1:lPBu71Y7osQmzlflM9OfeIV2JlmpBjqBNlLtcoBqUTc=
go.etcd.io/etcd/client/pkg/v3 v3.5.21/go.mod h1:BgqT/IXPjK9NkeSDjbzwsHySX3yIle2+ndz28nVsjUs=
go.etcd.io/etcd/client/v2 v2.305.21 h1:eLiFfexc2mE+pTLz9WwnoEsX5JTTpLCYVivKkmVXIRA=
go.etcd.io/etcd/client/v2 v2.305.21/go.mod h1:OKkn4hlYNf43hpjEM3Ke3aRdUkhSl8xjKjSf8eCq2J8=
go.etcd.io/etcd/client/v3 v3.5.21 h1:T6b1Ow6fNjOLOtM0xSoKNQt1ASPCLWrF9XMHcH9pEyY=
go.etcd.io/etcd/client/v3 v3.5.21/go.mod h1:mFYy67IOqmbRf/kRUvsHixzo3iG+1OF2W2+jVIQRAnU=
go.etcd.io/etcd/pkg/v3 v3.5.21 h1:jUItxeKyrDuVuWhdh0HtjUANwyuzcb7/FAeUfABmQsk=
go.etcd.io/etcd/pkg/v3 v3.5.21/go.mod h1:wpZx8Egv1g4y+N7JAsqi2zoUiBIUWznLjqJbylDjWgU=
go.etcd.io/etcd/raft/v3 v3.5.21 h1:dOmE0mT55dIUsX77TKBLq+RgyumsQuYeiRQnW/ylugk=
go.etcd.io/etcd/raft/v3 v3.5.21/go.mod h1:fmcuY5R2SNkklU4+fKVBQi2biVp5vafMrWUEj4TJ4Cs=
go.etcd.io/etcd/server/v3 v3.5.21 h1:9w0/k12majtgarGmlMVuhwXRI2ob3/d1Ik3X5TKo0yU=
go.etcd.io/etcd/server/v3 v3.5.21/go.mod h1:G1mOzdwuzKT1VRL7SqRchli/qcFrtLBTAQ4lV20sXXo=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0 h1:dNzwXjZKpMpE2JhmO+9HsPl42NIXFIFSUSSs0fiqra0=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0/go.mod h1:90PoxvaEB5n6AOdZvi+yWJQoE95U8Dhhw2bSyRqnTD0=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0 h1:JgtbA0xkWHnTmYk7YusopJFX6uleBmAuZ8n05NEh8nQ=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0/go.mod h1:179AK5aar5R3eS9FucPy6rggvU0g52cvKId8pv4+v0c=
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
@@ -204,139 +76,58 @@ go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFw
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
go.opentelemetry.io/proto/otlp v1.6.0 h1:jQjP+AQyTf+Fe7OKj/MfkDrmK4MNVtw2NpXsf9fefDI=
go.opentelemetry.io/proto/otlp v1.6.0/go.mod h1:cicgGehlFuNdgZkcALOCh3VE6K/u2tAjzlRhDwmVpZc=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
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.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
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.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
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.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb h1:ITgPrl429bc6+2ZraNSzMDk3I95nmQln2fuPstKwFDE=
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:sAo5UzpjUwgFBCzupwhcLcxHVDK7vG5IqI30YnwX2eE=
google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237 h1:Kog3KlB4xevJlAcbbbzPfRG0+X9fdoGM+UBRKVz6Wr0=
google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237/go.mod h1:ezi0AVyMKDWy5xAncvjLWH7UcLBB5n7y2fQ8MzjJcto=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 h1:cJfm9zPbe1e873mHJzmQ1nwVEeRDU/T1wXDK2kUSU34=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/api v0.33.2 h1:YgwIS5jKfA+BZg//OQhkJNIfie/kmRsO0BmNaVSimvY=
k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs=
k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY=
k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/apiserver v0.33.2 h1:KGTRbxn2wJagJowo29kKBp4TchpO1DRO3g+dB/KOJN4=
k8s.io/apiserver v0.33.2/go.mod h1:9qday04wEAMLPWWo9AwqCZSiIn3OYSZacDyu/AcoM/M=
k8s.io/client-go v0.33.2 h1:z8CIcc0P581x/J1ZYf4CNzRKxRvQAwoAolYPbtQes+E=
k8s.io/client-go v0.33.2/go.mod h1:9mCgT4wROvL948w6f6ArJNb7yQd7QsvqavDeZHvNmHo=
k8s.io/component-base v0.33.2 h1:sCCsn9s/dG3ZrQTX/Us0/Sx2R0G5kwa0wbZFYoVp/+0=
k8s.io/component-base v0.33.2/go.mod h1:/41uw9wKzuelhN+u+/C59ixxf4tYQKW7p32ddkYNe2k=
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-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8=
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro=
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8=
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo=
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
-26
View File
@@ -4,10 +4,8 @@ import (
"fmt"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apiserver/pkg/registry/generic"
"github.com/grafana/grafana/pkg/apimachinery/utils"
)
@@ -33,7 +31,6 @@ var SecureValuesResourceInfo = utils.NewResourceInfo(
{Name: "Description", Type: "string", Format: "string", Description: "Short description that explains the purpose of this SecureValue"},
{Name: "Keeper", Type: "string", Format: "string", Description: "Storage of the secure value"},
{Name: "Ref", Type: "string", Format: "string", Description: "If present, the reference to a secret"},
{Name: "Status", Type: "string", Format: "string", Description: "The status of the secure value"},
},
// Decodes the object into a concrete type. Return order in the slice must be the same as in `Definition`.
Reader: func(obj any) ([]interface{}, error) {
@@ -44,7 +41,6 @@ var SecureValuesResourceInfo = utils.NewResourceInfo(
r.Spec.Description,
r.Spec.Keeper,
r.Spec.Ref,
r.Status.Phase,
}, nil
}
@@ -92,13 +88,6 @@ var (
AddToScheme = localSchemeBuilder.AddToScheme
)
// Adds the status phase to the selectable fields, besides the generic metadata name and namespace.
func SelectableSecureValueFields(obj *SecureValue) fields.Set {
return generic.MergeFieldsSets(generic.ObjectMetaFieldsSet(&obj.ObjectMeta, false), fields.Set{
"status.phase": string(obj.Status.Phase),
})
}
// Adds the list of known types to the given scheme.
func AddKnownTypes(scheme *runtime.Scheme, version string) error {
// TODO: do we need a type for the secure value decrypt?
@@ -112,20 +101,5 @@ func AddKnownTypes(scheme *runtime.Scheme, version string) error {
// &secretV0.SecureValueActivityList{},
)
err := scheme.AddFieldLabelConversionFunc(
SecureValuesResourceInfo.GroupVersionKind(),
func(label, value string) (string, string, error) {
fieldSet := SelectableSecureValueFields(&SecureValue{})
for key := range fieldSet {
if label == key {
return label, value, nil
}
}
return "", "", fmt.Errorf("field label not supported for %s: %s", SecureValuesResourceInfo.GroupVersionKind(), label)
},
)
if err != nil {
return err
}
return nil
}
+4 -27
View File
@@ -11,41 +11,18 @@ type SecureValue struct {
// Standard object's metadata. It can only be one of `metav1.ObjectMeta` or `metav1.ListMeta`.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
// +optional
metav1.ObjectMeta `json:"metadata,omitempty"`
metav1.ObjectMeta `json:"metadata"`
// This is the actual secure value schema.
Spec SecureValueSpec `json:"spec"`
// Read-only observed status of the `SecureValue`.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
Status SecureValueStatus `json:"status,omitempty"`
Status SecureValueStatus `json:"status"`
}
// +enum
type SecureValuePhase string
const (
// When the `SecureValue` is created, it will start in `Pending` phase to create the underlying secret asynchronously.
SecureValuePhasePending SecureValuePhase = "Pending"
// If the creation of the secret is successful, it will move to the `Succeeded` phase.
SecureValuePhaseSucceeded SecureValuePhase = "Succeeded"
// If the creation of the secret fails, it will move to the `Failed` phase.
// Check the additional `status` fields for more information on what caused the failure.
// This state is unrecoverable.
SecureValuePhaseFailed SecureValuePhase = "Failed"
)
type SecureValueStatus struct {
// High-level summary of where the `SecureValue` is in its lifecycle.
// One of: `Pending`, `Succeeded` or `Failed`.
Phase SecureValuePhase `json:"phase"`
// A human readable message indicating details about why the `SecureValue` is in this phase.
// Only applicable if the `phase=Failed`.
// +optional
Message string `json:"message,omitempty"`
Version int64 `json:"version"`
// +optional
ExternalID string `json:"externalId,omitempty"`
@@ -94,7 +71,7 @@ type SecureValueList struct {
// Standard list's metadata. It can only be one of `metav1.ObjectMeta` or `metav1.ListMeta`.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
// +optional
metav1.ListMeta `json:"metadata,omitempty"`
metav1.ListMeta `json:"metadata"`
// Slice containing all secure values. This will NOT output decrypted values.
Items []SecureValue `json:"items"`
@@ -598,7 +598,7 @@ func schema_pkg_apis_secret_v0alpha1_SecureValue(ref common.ReferenceCallback) c
},
},
},
Required: []string{"spec"},
Required: []string{"spec", "status"},
},
},
Dependencies: []string{
@@ -734,20 +734,11 @@ func schema_pkg_apis_secret_v0alpha1_SecureValueStatus(ref common.ReferenceCallb
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"phase": {
"version": {
SchemaProps: spec.SchemaProps{
Description: "High-level summary of where the `SecureValue` is in its lifecycle. One of: `Pending`, `Succeeded` or `Failed`.\n\nPossible enum values:\n - `\"Failed\"` If the creation of the secret fails, it will move to the `Failed` phase. Check the additional `status` fields for more information on what caused the failure. This state is unrecoverable.\n - `\"Pending\"` When the `SecureValue` is created, it will start in `Pending` phase to create the underlying secret asynchronously.\n - `\"Succeeded\"` If the creation of the secret is successful, it will move to the `Succeeded` phase.",
Default: "",
Type: []string{"string"},
Format: "",
Enum: []interface{}{"Failed", "Pending", "Succeeded"},
},
},
"message": {
SchemaProps: spec.SchemaProps{
Description: "A human readable message indicating details about why the `SecureValue` is in this phase. Only applicable if the `phase=Failed`.",
Type: []string{"string"},
Format: "",
Default: 0,
Type: []string{"integer"},
Format: "int64",
},
},
"externalId": {
@@ -757,7 +748,7 @@ func schema_pkg_apis_secret_v0alpha1_SecureValueStatus(ref common.ReferenceCallb
},
},
},
Required: []string{"phase"},
Required: []string{"version"},
},
},
}
@@ -6,3 +6,4 @@ API rule violation: names_match,github.com/grafana/grafana/pkg/apis/secret/v0alp
API rule violation: names_match,github.com/grafana/grafana/pkg/apis/secret/v0alpha1,KeeperSpec,Azure
API rule violation: names_match,github.com/grafana/grafana/pkg/apis/secret/v0alpha1,KeeperSpec,HashiCorp
API rule violation: names_match,github.com/grafana/grafana/pkg/apis/secret/v0alpha1,SecureValueStatus,ExternalID
API rule violation: streaming_list_type_json_tags,github.com/grafana/grafana/pkg/apis/secret/v0alpha1,SecureValueList,ListMeta
+53 -5
View File
@@ -1,4 +1,4 @@
// Code generated by mockery v2.10.6. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package filestorage
@@ -17,6 +17,10 @@ type MockFileStorage struct {
func (_m *MockFileStorage) CreateFolder(ctx context.Context, path string) error {
ret := _m.Called(ctx, path)
if len(ret) == 0 {
panic("no return value specified for CreateFolder")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
r0 = rf(ctx, path)
@@ -31,6 +35,10 @@ func (_m *MockFileStorage) CreateFolder(ctx context.Context, path string) error
func (_m *MockFileStorage) Delete(ctx context.Context, path string) error {
ret := _m.Called(ctx, path)
if len(ret) == 0 {
panic("no return value specified for Delete")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
r0 = rf(ctx, path)
@@ -45,6 +53,10 @@ func (_m *MockFileStorage) Delete(ctx context.Context, path string) error {
func (_m *MockFileStorage) DeleteFolder(ctx context.Context, path string, options *DeleteFolderOptions) error {
ret := _m.Called(ctx, path, options)
if len(ret) == 0 {
panic("no return value specified for DeleteFolder")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string, *DeleteFolderOptions) error); ok {
r0 = rf(ctx, path, options)
@@ -59,7 +71,16 @@ func (_m *MockFileStorage) DeleteFolder(ctx context.Context, path string, option
func (_m *MockFileStorage) Get(ctx context.Context, path string, options *GetFileOptions) (*File, bool, error) {
ret := _m.Called(ctx, path, options)
if len(ret) == 0 {
panic("no return value specified for Get")
}
var r0 *File
var r1 bool
var r2 error
if rf, ok := ret.Get(0).(func(context.Context, string, *GetFileOptions) (*File, bool, error)); ok {
return rf(ctx, path, options)
}
if rf, ok := ret.Get(0).(func(context.Context, string, *GetFileOptions) *File); ok {
r0 = rf(ctx, path, options)
} else {
@@ -68,14 +89,12 @@ func (_m *MockFileStorage) Get(ctx context.Context, path string, options *GetFil
}
}
var r1 bool
if rf, ok := ret.Get(1).(func(context.Context, string, *GetFileOptions) bool); ok {
r1 = rf(ctx, path, options)
} else {
r1 = ret.Get(1).(bool)
}
var r2 error
if rf, ok := ret.Get(2).(func(context.Context, string, *GetFileOptions) error); ok {
r2 = rf(ctx, path, options)
} else {
@@ -89,7 +108,15 @@ func (_m *MockFileStorage) Get(ctx context.Context, path string, options *GetFil
func (_m *MockFileStorage) List(ctx context.Context, folderPath string, paging *Paging, options *ListOptions) (*ListResponse, error) {
ret := _m.Called(ctx, folderPath, paging, options)
if len(ret) == 0 {
panic("no return value specified for List")
}
var r0 *ListResponse
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, *Paging, *ListOptions) (*ListResponse, error)); ok {
return rf(ctx, folderPath, paging, options)
}
if rf, ok := ret.Get(0).(func(context.Context, string, *Paging, *ListOptions) *ListResponse); ok {
r0 = rf(ctx, folderPath, paging, options)
} else {
@@ -98,7 +125,6 @@ func (_m *MockFileStorage) List(ctx context.Context, folderPath string, paging *
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, string, *Paging, *ListOptions) error); ok {
r1 = rf(ctx, folderPath, paging, options)
} else {
@@ -112,6 +138,10 @@ func (_m *MockFileStorage) List(ctx context.Context, folderPath string, paging *
func (_m *MockFileStorage) Upsert(ctx context.Context, command *UpsertFileCommand) error {
ret := _m.Called(ctx, command)
if len(ret) == 0 {
panic("no return value specified for Upsert")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, *UpsertFileCommand) error); ok {
r0 = rf(ctx, command)
@@ -122,10 +152,14 @@ func (_m *MockFileStorage) Upsert(ctx context.Context, command *UpsertFileComman
return r0
}
// close provides a mock function with given fields:
// close provides a mock function with no fields
func (_m *MockFileStorage) close() error {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for close")
}
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
@@ -135,3 +169,17 @@ func (_m *MockFileStorage) close() error {
return r0
}
// NewMockFileStorage creates a new instance of MockFileStorage. 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 NewMockFileStorage(t interface {
mock.TestingT
Cleanup(func())
}) *MockFileStorage {
mock := &MockFileStorage{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}
+1 -1
View File
@@ -36,7 +36,7 @@ func TestIntegrationSocialService_ProvideService(t *testing.T) {
expectedGenericOAuthSkipOrgRoleSync bool
}{
{
name: "should load all social connectors when ssoSettingsApi is enabled",
name: "should load all social connectors",
expectedSocialMapLength: 7,
expectedGenericOAuthSkipOrgRoleSync: false,
},
@@ -1,4 +1,4 @@
// Code generated by mockery v2.27.1. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package socialtest
@@ -31,6 +31,10 @@ func (_m *MockSocialConnector) AuthCodeURL(state string, opts ...oauth2.AuthCode
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
if len(ret) == 0 {
panic("no return value specified for AuthCodeURL")
}
var r0 string
if rf, ok := ret.Get(0).(func(string, ...oauth2.AuthCodeOption) string); ok {
r0 = rf(state, opts...)
@@ -45,6 +49,10 @@ func (_m *MockSocialConnector) AuthCodeURL(state string, opts ...oauth2.AuthCode
func (_m *MockSocialConnector) Client(ctx context.Context, t *oauth2.Token) *http.Client {
ret := _m.Called(ctx, t)
if len(ret) == 0 {
panic("no return value specified for Client")
}
var r0 *http.Client
if rf, ok := ret.Get(0).(func(context.Context, *oauth2.Token) *http.Client); ok {
r0 = rf(ctx, t)
@@ -68,6 +76,10 @@ func (_m *MockSocialConnector) Exchange(ctx context.Context, code string, authOp
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
if len(ret) == 0 {
panic("no return value specified for Exchange")
}
var r0 *oauth2.Token
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, ...oauth2.AuthCodeOption) (*oauth2.Token, error)); ok {
@@ -90,10 +102,14 @@ func (_m *MockSocialConnector) Exchange(ctx context.Context, code string, authOp
return r0, r1
}
// GetOAuthInfo provides a mock function with given fields:
// GetOAuthInfo provides a mock function with no fields
func (_m *MockSocialConnector) GetOAuthInfo() *social.OAuthInfo {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for GetOAuthInfo")
}
var r0 *social.OAuthInfo
if rf, ok := ret.Get(0).(func() *social.OAuthInfo); ok {
r0 = rf()
@@ -110,6 +126,10 @@ func (_m *MockSocialConnector) GetOAuthInfo() *social.OAuthInfo {
func (_m *MockSocialConnector) IsEmailAllowed(email string) bool {
ret := _m.Called(email)
if len(ret) == 0 {
panic("no return value specified for IsEmailAllowed")
}
var r0 bool
if rf, ok := ret.Get(0).(func(string) bool); ok {
r0 = rf(email)
@@ -120,10 +140,14 @@ func (_m *MockSocialConnector) IsEmailAllowed(email string) bool {
return r0
}
// IsSignupAllowed provides a mock function with given fields:
// IsSignupAllowed provides a mock function with no fields
func (_m *MockSocialConnector) IsSignupAllowed() bool {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for IsSignupAllowed")
}
var r0 bool
if rf, ok := ret.Get(0).(func() bool); ok {
r0 = rf()
@@ -138,6 +162,10 @@ func (_m *MockSocialConnector) IsSignupAllowed() bool {
func (_m *MockSocialConnector) SupportBundleContent(_a0 *bytes.Buffer) error {
ret := _m.Called(_a0)
if len(ret) == 0 {
panic("no return value specified for SupportBundleContent")
}
var r0 error
if rf, ok := ret.Get(0).(func(*bytes.Buffer) error); ok {
r0 = rf(_a0)
@@ -152,6 +180,10 @@ func (_m *MockSocialConnector) SupportBundleContent(_a0 *bytes.Buffer) error {
func (_m *MockSocialConnector) TokenSource(ctx context.Context, t *oauth2.Token) oauth2.TokenSource {
ret := _m.Called(ctx, t)
if len(ret) == 0 {
panic("no return value specified for TokenSource")
}
var r0 oauth2.TokenSource
if rf, ok := ret.Get(0).(func(context.Context, *oauth2.Token) oauth2.TokenSource); ok {
r0 = rf(ctx, t)
@@ -168,6 +200,10 @@ func (_m *MockSocialConnector) TokenSource(ctx context.Context, t *oauth2.Token)
func (_m *MockSocialConnector) UserInfo(ctx context.Context, client *http.Client, token *oauth2.Token) (*social.BasicUserInfo, error) {
ret := _m.Called(ctx, client, token)
if len(ret) == 0 {
panic("no return value specified for UserInfo")
}
var r0 *social.BasicUserInfo
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *http.Client, *oauth2.Token) (*social.BasicUserInfo, error)); ok {
@@ -190,13 +226,12 @@ func (_m *MockSocialConnector) UserInfo(ctx context.Context, client *http.Client
return r0, r1
}
type mockConstructorTestingTNewMockSocialConnector interface {
// NewMockSocialConnector creates a new instance of MockSocialConnector. 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 NewMockSocialConnector(t interface {
mock.TestingT
Cleanup(func())
}
// NewMockSocialConnector creates a new instance of MockSocialConnector. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockSocialConnector(t mockConstructorTestingTNewMockSocialConnector) *MockSocialConnector {
}) *MockSocialConnector {
mock := &MockSocialConnector{}
mock.Mock.Test(t)
@@ -46,10 +46,6 @@ func DefaultService(cfg *config.PluginManagementCfg) *Service {
// Base returns the base path for the specified plugin.
func (s *Service) Base(n PluginInfo) (string, error) {
if n.class == plugins.ClassCore {
baseDir := getBaseDir(n.fs.Base())
return path.Join("public/app/plugins", string(n.pluginJSON.Type), baseDir), nil
}
if n.class == plugins.ClassCDN {
return n.fs.Base(), nil
}
@@ -64,7 +60,6 @@ func (s *Service) Base(n PluginInfo) (string, error) {
if s.cdn.PluginSupported(n.parent.pluginJSON.ID) {
return s.cdn.AssetURL(n.parent.pluginJSON.ID, n.parent.pluginJSON.Info.Version, relPath)
}
return path.Join("public/plugins", n.parent.pluginJSON.ID, relPath), nil
}
return path.Join("public/plugins", n.pluginJSON.ID), nil
@@ -73,32 +68,12 @@ func (s *Service) Base(n PluginInfo) (string, error) {
// Module returns the module.js path for the specified plugin.
func (s *Service) Module(n PluginInfo) (string, error) {
if n.class == plugins.ClassCore {
if filepath.Base(n.fs.Base()) == "dist" {
// The core plugin has been built externally, use the module from the dist folder
} else {
baseDir := getBaseDir(n.fs.Base())
return path.Join("core:plugin", baseDir), nil
if filepath.Base(n.fs.Base()) != "dist" {
return path.Join("core:plugin", filepath.Base(n.fs.Base())), nil
}
}
if n.class == plugins.ClassCDN {
return pluginscdn.JoinPath(n.fs.Base(), "module.js")
}
if s.cdn.PluginSupported(n.pluginJSON.ID) {
return s.cdn.AssetURL(n.pluginJSON.ID, n.pluginJSON.Info.Version, "module.js")
}
if n.parent != nil {
relPath, err := n.parent.fs.Rel(n.fs.Base())
if err != nil {
return "", err
}
if s.cdn.PluginSupported(n.parent.pluginJSON.ID) {
return s.cdn.AssetURL(n.parent.pluginJSON.ID, n.parent.pluginJSON.Info.Version, path.Join(relPath, "module.js"))
}
return path.Join("public/plugins", n.parent.pluginJSON.ID, relPath, "module.js"), nil
}
return path.Join("public/plugins", n.pluginJSON.ID, "module.js"), nil
return s.RelativeURL(n, "module.js")
}
// RelativeURL returns the relative URL for an arbitrary plugin asset.
@@ -145,15 +120,6 @@ func (s *Service) DefaultLogoPath(pluginType plugins.Type) string {
return path.Join("public/img", fmt.Sprintf("icn-%s.svg", string(pluginType)))
}
func getBaseDir(pluginDir string) string {
baseDir := filepath.Base(pluginDir)
// Decoupled core plugins will be suffixed with "dist" if they have been built
if baseDir == "dist" {
return filepath.Base(strings.TrimSuffix(pluginDir, baseDir))
}
return baseDir
}
func (s *Service) GetTranslations(n PluginInfo) (map[string]string, error) {
pathToTranslations, err := s.RelativeURL(n, "locales")
if err != nil {
@@ -78,7 +78,7 @@ func TestService(t *testing.T) {
base, err = svc.Base(NewPluginInfo(jsonData["table-old"], plugins.ClassCore, tableOldFS, nil))
require.NoError(t, err)
require.Equal(t, "public/app/plugins/table-old", base)
require.Equal(t, "public/plugins/table-old", base)
parentFS := pluginFS(oneCDNURL)
parentFS.RelFunc = func(_ string) (string, error) {
@@ -243,9 +243,9 @@ func TestService_ChildPlugins(t *testing.T) {
return childInfo
},
expected: expected{
module: "public/plugins/parent/child/module.js",
baseURL: "public/plugins/parent/child",
relURL: "public/plugins/parent/child/path/to/file.txt",
module: "public/plugins/child/module.js",
baseURL: "public/plugins/child",
relURL: "public/plugins/child/path/to/file.txt",
},
},
{
@@ -256,8 +256,8 @@ func TestService_ChildPlugins(t *testing.T) {
},
expected: expected{
module: "core:plugin/parent",
baseURL: "public/app/plugins/parent",
relURL: "public/app/plugins/parent/path/to/file.txt",
baseURL: "public/plugins/parent",
relURL: "public/plugins/parent/path/to/file.txt",
},
},
{
@@ -268,8 +268,8 @@ func TestService_ChildPlugins(t *testing.T) {
},
expected: expected{
module: "public/plugins/parent/module.js",
baseURL: "public/app/plugins/parent",
relURL: "public/app/plugins/parent/path/to/file.txt",
baseURL: "public/plugins/parent",
relURL: "public/plugins/parent/path/to/file.txt",
},
},
{
+3 -3
View File
@@ -85,8 +85,8 @@ func TestLoader_Load(t *testing.T) {
Description: "Data source for Amazon AWS monitoring service",
Keywords: []string{"aws", "amazon"},
Logos: plugins.Logos{
Small: "public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png",
Large: "public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png",
Small: "public/plugins/cloudwatch/img/amazon-web-services.png",
Large: "public/plugins/cloudwatch/img/amazon-web-services.png",
},
Links: []plugins.InfoLink{
{Name: "Raise issue", URL: "https://github.com/grafana/grafana/issues/new"},
@@ -123,7 +123,7 @@ func TestLoader_Load(t *testing.T) {
QueryOptions: map[string]bool{"minInterval": true},
},
Module: "core:plugin/cloudwatch",
BaseURL: "public/app/plugins/datasource/cloudwatch",
BaseURL: "public/plugins/cloudwatch",
FS: mustNewStaticFSForTests(t, filepath.Join(corePluginDir, "app/plugins/datasource/cloudwatch")),
Signature: plugins.SignatureStatusInternal,
Class: plugins.ClassCore,
@@ -1,12 +1,11 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package legacy
import (
context "context"
"github.com/grafana/grafana/pkg/storage/unified/resourcepb"
resourcepb "github.com/grafana/grafana/pkg/storage/unified/resourcepb"
mock "github.com/stretchr/testify/mock"
)
+1 -1
View File
@@ -236,7 +236,7 @@ func (b *FolderAPIBuilder) Mutate(ctx context.Context, a admission.Attributes, _
if !ok {
return fmt.Errorf("obj is not folders.Folder")
}
f.Spec.Title = strings.Trim(f.Spec.Title, "")
f.Spec.Title = strings.Trim(f.Spec.Title, " ")
return nil
}
return nil
+14 -4
View File
@@ -479,7 +479,7 @@ func TestFolderAPIBuilder_Mutate_Create(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := b.Validate(context.Background(), admission.NewAttributesRecord(
admAttr := admission.NewAttributesRecord(
tt.input,
nil,
folders.SchemeGroupVersion.WithKind("folder"),
@@ -491,13 +491,18 @@ func TestFolderAPIBuilder_Mutate_Create(t *testing.T) {
nil,
true,
&user.SignedInUser{},
), nil)
)
err := b.Validate(context.Background(), admAttr, nil)
if tt.wantErr {
require.Error(t, err)
return
}
require.NoError(t, err)
err = b.Mutate(context.Background(), admAttr, nil)
require.NoError(t, err)
require.Equal(t, tt.input, tt.expected)
})
}
}
@@ -585,7 +590,7 @@ func TestFolderAPIBuilder_Mutate_Update(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := b.Validate(context.Background(), admission.NewAttributesRecord(
admAttr := admission.NewAttributesRecord(
tt.input,
existingObj,
folders.SchemeGroupVersion.WithKind("folder"),
@@ -597,13 +602,18 @@ func TestFolderAPIBuilder_Mutate_Update(t *testing.T) {
nil,
true,
&user.SignedInUser{},
), nil)
)
err := b.Validate(context.Background(), admAttr, nil)
if tt.wantErr {
require.Error(t, err)
return
}
require.NoError(t, err)
err = b.Mutate(context.Background(), admAttr, nil)
require.NoError(t, err)
require.Equal(t, tt.input, tt.expected)
})
}
}
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package export
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package export
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package jobs
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package jobs
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package migrate
@@ -9,7 +9,7 @@ import (
mock "github.com/stretchr/testify/mock"
"github.com/grafana/grafana/pkg/storage/unified/resourcepb"
resourcepb "github.com/grafana/grafana/pkg/storage/unified/resourcepb"
)
// MockBulkStoreClient is an autogenerated mock type for the BulkStoreClient type
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package migrate
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package migrate
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package jobs
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package jobs
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package jobs
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package jobs
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package sync
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package sync
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package sync
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package sync
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package sync
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package jobs
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package repository
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package repository
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package repository
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package repository
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package repository
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package github
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package github
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package github
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package repository
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package gogit
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package gogit
@@ -595,7 +595,7 @@ func (r *gitRepository) resolveRefToHash(ctx context.Context, ref string) (hash.
// Try to parse ref as a hash first
refHash, err := hash.FromHex(ref)
if err == nil && refHash != nil {
if err == nil && refHash != hash.Zero {
// Valid hash, return it
return refHash, nil
}
@@ -604,9 +604,9 @@ func (r *gitRepository) resolveRefToHash(ctx context.Context, ref string) (hash.
branchRef, err := r.client.GetRef(ctx, ref)
if err != nil {
if errors.Is(err, nanogit.ErrObjectNotFound) {
return nil, fmt.Errorf("ref not found: %s: %w", ref, repository.ErrRefNotFound)
return hash.Zero, fmt.Errorf("ref not found: %s: %w", ref, repository.ErrRefNotFound)
}
return nil, fmt.Errorf("get ref %s: %w", ref, err)
return hash.Zero, fmt.Errorf("get ref %s: %w", ref, err)
}
return branchRef.Hash, nil
@@ -695,7 +695,7 @@ func TestGitRepository_Read(t *testing.T) {
Hash: hash.Hash{},
}, nil)
mockClient.GetCommitReturns(&nanogit.Commit{
Tree: hash.Hash([]byte("tree-hash")),
Tree: hash.MustFromHex("abcdef1234567890abcdef1234567890abcdef12"),
}, nil)
mockClient.GetTreeByPathReturns(&nanogit.Tree{
Hash: hash.Hash{},
@@ -1191,7 +1191,7 @@ func TestGitRepository_LatestRef(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3}, // Non-empty hash
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}, // Non-empty hash
}, nil)
},
gitConfig: RepositoryConfig{
@@ -1412,11 +1412,11 @@ func TestGitRepository_CompareFiles(t *testing.T) {
// Return refs for base and ref
mockClient.GetRefReturnsOnCall(0, nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
mockClient.GetRefReturnsOnCall(1, nanogit.Ref{
Name: "refs/heads/feature",
Hash: hash.Hash{4, 5, 6},
Hash: hash.Hash{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23},
}, nil)
// Return comparison results
@@ -1449,11 +1449,11 @@ func TestGitRepository_CompareFiles(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturnsOnCall(0, nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
mockClient.GetRefReturnsOnCall(1, nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
mockClient.CompareCommitsReturns([]nanogit.CommitFile{}, nil)
@@ -1547,7 +1547,7 @@ func TestGitRepository_ensureBranchExists(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/feature",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
},
gitConfig: RepositoryConfig{
@@ -1565,7 +1565,7 @@ func TestGitRepository_ensureBranchExists(t *testing.T) {
// Second call - get source branch
mockClient.GetRefReturnsOnCall(1, nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
// CreateRef succeeds
mockClient.CreateRefReturns(nil)
@@ -1862,7 +1862,7 @@ func TestGitRepository_resolveRefToHash(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
},
gitConfig: RepositoryConfig{
@@ -1887,7 +1887,7 @@ func TestGitRepository_resolveRefToHash(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/feature",
Hash: hash.Hash{4, 5, 6},
Hash: hash.Hash{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23},
}, nil)
},
gitConfig: RepositoryConfig{
@@ -1939,7 +1939,7 @@ func TestGitRepository_resolveRefToHash(t *testing.T) {
if tt.wantError {
require.Error(t, err)
require.Nil(t, refHash)
require.Equal(t, hash.Zero, refHash)
} else {
require.NoError(t, err)
require.NotNil(t, refHash)
@@ -2212,7 +2212,7 @@ func TestGitRepository_EdgeCases(t *testing.T) {
mockClient := &mocks.FakeClient{}
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
mockWriter := &mocks.FakeStagedWriter{}
@@ -2251,7 +2251,7 @@ func TestGitRepository_EdgeCases(t *testing.T) {
mockClient := &mocks.FakeClient{}
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
mockClient.GetCommitReturns(&nanogit.Commit{Tree: hash.Hash{}}, nil)
mockClient.GetBlobByPathReturns(&nanogit.Blob{}, errors.New("some read error"))
@@ -2401,7 +2401,7 @@ func TestGitRepository_ResolveRefToHash_EdgeCases(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/invalid-hex",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
},
ref: "invalid-hex-zzz",
@@ -2412,7 +2412,7 @@ func TestGitRepository_ResolveRefToHash_EdgeCases(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/feature",
Hash: hash.Hash{4, 5, 6},
Hash: hash.Hash{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23},
}, nil)
},
ref: "refs/heads/feature",
@@ -2423,7 +2423,7 @@ func TestGitRepository_ResolveRefToHash_EdgeCases(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/tags/v1.0.0",
Hash: hash.Hash{7, 8, 9},
Hash: hash.Hash{7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26},
}, nil)
},
ref: "refs/tags/v1.0.0",
@@ -2540,11 +2540,11 @@ func TestGitRepository_CompareFiles_EdgeCases(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturnsOnCall(0, nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
mockClient.GetRefReturnsOnCall(1, nanogit.Ref{
Name: "refs/heads/feature",
Hash: hash.Hash{4, 5, 6},
Hash: hash.Hash{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23},
}, nil)
mockClient.CompareCommitsReturns(nil, errors.New("compare error"))
},
@@ -2558,11 +2558,11 @@ func TestGitRepository_CompareFiles_EdgeCases(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturnsOnCall(0, nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
mockClient.GetRefReturnsOnCall(1, nanogit.Ref{
Name: "refs/heads/feature",
Hash: hash.Hash{4, 5, 6},
Hash: hash.Hash{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23},
}, nil)
mockClient.CompareCommitsReturns([]nanogit.CommitFile{
{
@@ -2580,11 +2580,11 @@ func TestGitRepository_CompareFiles_EdgeCases(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturnsOnCall(0, nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
mockClient.GetRefReturnsOnCall(1, nanogit.Ref{
Name: "refs/heads/feature",
Hash: hash.Hash{4, 5, 6},
Hash: hash.Hash{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23},
}, nil)
mockClient.CompareCommitsReturns([]nanogit.CommitFile{
{
@@ -2606,11 +2606,11 @@ func TestGitRepository_CompareFiles_EdgeCases(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturnsOnCall(0, nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
mockClient.GetRefReturnsOnCall(1, nanogit.Ref{
Name: "refs/heads/feature",
Hash: hash.Hash{4, 5, 6},
Hash: hash.Hash{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23},
}, nil)
mockClient.CompareCommitsReturns([]nanogit.CommitFile{
{
@@ -2683,7 +2683,7 @@ func TestGitRepository_ReadTree_EdgeCases(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
mockClient.GetFlatTreeReturns(nil, errors.New("flat tree error"))
},
@@ -2694,23 +2694,23 @@ func TestGitRepository_ReadTree_EdgeCases(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
mockClient.GetFlatTreeReturns(&nanogit.FlatTree{
Entries: []nanogit.FlatTreeEntry{
{
Path: "other/file.yaml", // Outside configs/
Hash: hash.Hash{4, 5, 6},
Hash: hash.Hash{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23},
Type: protocol.ObjectTypeBlob,
},
{
Path: "configs/included.yaml", // Inside configs/
Hash: hash.Hash{7, 8, 9},
Hash: hash.Hash{7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26},
Type: protocol.ObjectTypeBlob,
},
{
Path: "configs/dir", // Directory without trailing slash
Hash: hash.Hash{10, 11, 12},
Hash: hash.Hash{10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29},
Type: protocol.ObjectTypeTree,
},
},
@@ -2828,7 +2828,7 @@ func TestGitRepository_ensureBranchExists_ErrorConditions(t *testing.T) {
// Second call - get source branch
mockClient.GetRefReturnsOnCall(1, nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
// CreateRef fails
mockClient.CreateRefReturns(errors.New("create ref failed"))
@@ -2880,10 +2880,10 @@ func TestGitRepository_Read_EdgeCases(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121315"),
}, nil)
mockClient.GetCommitReturns(&nanogit.Commit{
Tree: hash.Hash([]byte("tree-hash")),
Tree: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockClient.GetTreeByPathReturns(nil, errors.New("tree error"))
},
@@ -2895,7 +2895,7 @@ func TestGitRepository_Read_EdgeCases(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockClient.GetCommitReturns(nil, errors.New("commit error"))
},
@@ -2907,10 +2907,10 @@ func TestGitRepository_Read_EdgeCases(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockClient.GetCommitReturns(&nanogit.Commit{
Tree: hash.Hash{4, 5, 6},
Hash: hash.MustFromHex("0102030405060708092a0b0c0d0e0f1011121314"),
}, nil)
mockClient.GetBlobByPathReturns(nil, errors.New("blob error"))
},
@@ -2965,7 +2965,7 @@ func TestGitRepository_Create_ErrorConditions(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
mockClient.NewStagedWriterReturns(nil, errors.New("staged writer error"))
},
@@ -2977,7 +2977,7 @@ func TestGitRepository_Create_ErrorConditions(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockWriter := &mocks.FakeStagedWriter{}
mockWriter.CreateBlobReturns(hash.Hash{}, errors.New("create blob error"))
@@ -3030,7 +3030,7 @@ func TestGitRepository_Update_ErrorConditions(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
mockClient.NewStagedWriterReturns(nil, errors.New("staged writer error"))
},
@@ -3042,7 +3042,7 @@ func TestGitRepository_Update_ErrorConditions(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockWriter := &mocks.FakeStagedWriter{}
mockWriter.UpdateBlobReturns(hash.Hash{}, errors.New("update blob error"))
@@ -3096,7 +3096,7 @@ func TestGitRepository_Delete_ErrorConditions(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockClient.NewStagedWriterReturns(nil, errors.New("staged writer error"))
},
@@ -3109,7 +3109,7 @@ func TestGitRepository_Delete_ErrorConditions(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockWriter := &mocks.FakeStagedWriter{}
mockWriter.DeleteBlobReturns(hash.Hash{}, errors.New("delete blob error"))
@@ -3124,7 +3124,7 @@ func TestGitRepository_Delete_ErrorConditions(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockWriter := &mocks.FakeStagedWriter{}
mockWriter.DeleteTreeReturns(hash.Hash{}, errors.New("delete tree error"))
@@ -3139,7 +3139,7 @@ func TestGitRepository_Delete_ErrorConditions(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockWriter := &mocks.FakeStagedWriter{}
mockWriter.DeleteTreeReturns(hash.Hash{}, nanogit.ErrObjectNotFound)
@@ -3186,7 +3186,7 @@ func TestGitRepository_CompareFiles_EmptyBase(t *testing.T) {
// Only setup for ref resolution
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/feature",
Hash: hash.Hash{4, 5, 6},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockClient.CompareCommitsReturns([]nanogit.CommitFile{
{
@@ -3218,8 +3218,8 @@ func TestGitRepository_CompareFiles_EmptyBase(t *testing.T) {
// Verify CompareCommits was called with empty base hash and feature hash
require.Equal(t, 1, mockClient.CompareCommitsCallCount())
_, baseHash, refHash := mockClient.CompareCommitsArgsForCall(0)
require.Nil(t, baseHash) // Empty hash for empty base
require.Equal(t, hash.Hash{4, 5, 6}, refHash)
require.Equal(t, hash.Zero, baseHash) // Empty hash for empty base
require.Equal(t, hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"), refHash)
}
func TestGitRepository_EmptyRefHandling(t *testing.T) {
@@ -3237,7 +3237,7 @@ func TestGitRepository_EmptyRefHandling(t *testing.T) {
mockClient := &mocks.FakeClient{}
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockWriter := &mocks.FakeStagedWriter{}
@@ -3299,7 +3299,7 @@ func TestGitRepository_CompareFiles_ResolveErrors(t *testing.T) {
// First call succeeds for base
mockClient.GetRefReturnsOnCall(0, nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
// Second call fails for ref
mockClient.GetRefReturnsOnCall(1, nanogit.Ref{}, errors.New("ref error"))
@@ -3341,14 +3341,14 @@ func TestGitRepository_Read_EmptyRef(t *testing.T) {
mockClient := &mocks.FakeClient{}
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockClient.GetCommitReturns(&nanogit.Commit{
Tree: hash.Hash{4, 5, 6},
Tree: hash.Hash{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23},
}, nil)
mockClient.GetBlobByPathReturns(&nanogit.Blob{
Content: []byte("file content"),
Hash: hash.Hash{7, 8, 9},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
gitRepo := &gitRepository{
@@ -3376,13 +3376,13 @@ func TestGitRepository_ReadTree_EmptyRef(t *testing.T) {
mockClient := &mocks.FakeClient{}
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockClient.GetFlatTreeReturns(&nanogit.FlatTree{
Entries: []nanogit.FlatTreeEntry{
{
Path: "configs/test.yaml",
Hash: hash.Hash{4, 5, 6},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
Type: protocol.ObjectTypeBlob,
},
},
@@ -3504,17 +3504,17 @@ func TestGitRepository_Write_DefaultRef(t *testing.T) {
// First call for Read check - file not found
mockClient.GetRefReturnsOnCall(0, nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockClient.GetCommitReturns(&nanogit.Commit{
Tree: hash.Hash{4, 5, 6},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockClient.GetBlobByPathReturns(&nanogit.Blob{}, nanogit.ErrObjectNotFound)
// Second call for Create
mockClient.GetRefReturnsOnCall(1, nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockWriter := &mocks.FakeStagedWriter{}
mockWriter.CreateBlobReturns(hash.Hash{}, nil)
@@ -3545,14 +3545,14 @@ func TestGitRepository_Read_RefInFileInfo(t *testing.T) {
mockClient := &mocks.FakeClient{}
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/feature",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockClient.GetCommitReturns(&nanogit.Commit{
Tree: hash.Hash{4, 5, 6},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockClient.GetBlobByPathReturns(&nanogit.Blob{
Content: []byte("file content"),
Hash: hash.Hash{7, 8, 9},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
gitRepo := &gitRepository{
@@ -3582,10 +3582,10 @@ func TestGitRepository_Read_GetTreeByPath_NotFound(t *testing.T) {
mockClient := &mocks.FakeClient{}
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockClient.GetCommitReturns(&nanogit.Commit{
Tree: hash.Hash([]byte("tree-hash")),
Tree: hash.Hash{30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49},
}, nil)
mockClient.GetTreeByPathReturns(nil, nanogit.ErrObjectNotFound)
@@ -3614,7 +3614,7 @@ func TestGitRepository_ReadTree_GetFlatTree_NotFound(t *testing.T) {
mockClient := &mocks.FakeClient{}
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockClient.GetFlatTreeReturns(nil, nanogit.ErrObjectNotFound)
@@ -3655,11 +3655,11 @@ func TestGitRepository_CompareFiles_FilesOutsideConfiguredPath_AllStatuses(t *te
mockClient := &mocks.FakeClient{}
mockClient.GetRefReturnsOnCall(0, nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockClient.GetRefReturnsOnCall(1, nanogit.Ref{
Name: "refs/heads/feature",
Hash: hash.Hash{4, 5, 6},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121315"),
}, nil)
mockClient.CompareCommitsReturns([]nanogit.CommitFile{
{
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package repository
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package repository
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package resources
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package resources
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package resources
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package resources
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package resources
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package resources
@@ -26,64 +26,6 @@ func (_m *MockRepositoryResources) EXPECT() *MockRepositoryResources_Expecter {
return &MockRepositoryResources_Expecter{mock: &_m.Mock}
}
// WriteResourceFileFromObject provides a mock function with given fields: ctx, obj, options
func (_m *MockRepositoryResources) WriteResourceFileFromObject(ctx context.Context, obj *unstructured.Unstructured, options WriteOptions) (string, error) {
ret := _m.Called(ctx, obj, options)
if len(ret) == 0 {
panic("no return value specified for WriteResourceFileFromObject")
}
var r0 string
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *unstructured.Unstructured, WriteOptions) (string, error)); ok {
return rf(ctx, obj, options)
}
if rf, ok := ret.Get(0).(func(context.Context, *unstructured.Unstructured, WriteOptions) string); ok {
r0 = rf(ctx, obj, options)
} else {
r0 = ret.Get(0).(string)
}
if rf, ok := ret.Get(1).(func(context.Context, *unstructured.Unstructured, WriteOptions) error); ok {
r1 = rf(ctx, obj, options)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockRepositoryResources_WriteResourceFileFromObject_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WriteResourceFileFromObject'
type MockRepositoryResources_WriteResourceFileFromObject_Call struct {
*mock.Call
}
// WriteResourceFileFromObject is a helper method to define mock.On call
// - ctx context.Context
// - obj *unstructured.Unstructured
// - options WriteOptions
func (_e *MockRepositoryResources_Expecter) WriteResourceFileFromObject(ctx interface{}, obj interface{}, options interface{}) *MockRepositoryResources_WriteResourceFileFromObject_Call {
return &MockRepositoryResources_WriteResourceFileFromObject_Call{Call: _e.mock.On("WriteResourceFileFromObject", ctx, obj, options)}
}
func (_c *MockRepositoryResources_WriteResourceFileFromObject_Call) Run(run func(ctx context.Context, obj *unstructured.Unstructured, options WriteOptions)) *MockRepositoryResources_WriteResourceFileFromObject_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(*unstructured.Unstructured), args[2].(WriteOptions))
})
return _c
}
func (_c *MockRepositoryResources_WriteResourceFileFromObject_Call) Return(_a0 string, _a1 error) *MockRepositoryResources_WriteResourceFileFromObject_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockRepositoryResources_WriteResourceFileFromObject_Call) RunAndReturn(run func(context.Context, *unstructured.Unstructured, WriteOptions) (string, error)) *MockRepositoryResources_WriteResourceFileFromObject_Call {
_c.Call.Return(run)
return _c
}
// EnsureFolderExists provides a mock function with given fields: ctx, folder, parentID
func (_m *MockRepositoryResources) EnsureFolderExists(ctx context.Context, folder Folder, parentID string) error {
ret := _m.Called(ctx, folder, parentID)
@@ -520,6 +462,64 @@ func (_c *MockRepositoryResources_Stats_Call) RunAndReturn(run func(context.Cont
return _c
}
// WriteResourceFileFromObject provides a mock function with given fields: ctx, obj, options
func (_m *MockRepositoryResources) WriteResourceFileFromObject(ctx context.Context, obj *unstructured.Unstructured, options WriteOptions) (string, error) {
ret := _m.Called(ctx, obj, options)
if len(ret) == 0 {
panic("no return value specified for WriteResourceFileFromObject")
}
var r0 string
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *unstructured.Unstructured, WriteOptions) (string, error)); ok {
return rf(ctx, obj, options)
}
if rf, ok := ret.Get(0).(func(context.Context, *unstructured.Unstructured, WriteOptions) string); ok {
r0 = rf(ctx, obj, options)
} else {
r0 = ret.Get(0).(string)
}
if rf, ok := ret.Get(1).(func(context.Context, *unstructured.Unstructured, WriteOptions) error); ok {
r1 = rf(ctx, obj, options)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockRepositoryResources_WriteResourceFileFromObject_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WriteResourceFileFromObject'
type MockRepositoryResources_WriteResourceFileFromObject_Call struct {
*mock.Call
}
// WriteResourceFileFromObject is a helper method to define mock.On call
// - ctx context.Context
// - obj *unstructured.Unstructured
// - options WriteOptions
func (_e *MockRepositoryResources_Expecter) WriteResourceFileFromObject(ctx interface{}, obj interface{}, options interface{}) *MockRepositoryResources_WriteResourceFileFromObject_Call {
return &MockRepositoryResources_WriteResourceFileFromObject_Call{Call: _e.mock.On("WriteResourceFileFromObject", ctx, obj, options)}
}
func (_c *MockRepositoryResources_WriteResourceFileFromObject_Call) Run(run func(ctx context.Context, obj *unstructured.Unstructured, options WriteOptions)) *MockRepositoryResources_WriteResourceFileFromObject_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(*unstructured.Unstructured), args[2].(WriteOptions))
})
return _c
}
func (_c *MockRepositoryResources_WriteResourceFileFromObject_Call) Return(_a0 string, _a1 error) *MockRepositoryResources_WriteResourceFileFromObject_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockRepositoryResources_WriteResourceFileFromObject_Call) RunAndReturn(run func(context.Context, *unstructured.Unstructured, WriteOptions) (string, error)) *MockRepositoryResources_WriteResourceFileFromObject_Call {
_c.Call.Return(run)
return _c
}
// WriteResourceFromFile provides a mock function with given fields: ctx, path, ref
func (_m *MockRepositoryResources) WriteResourceFromFile(ctx context.Context, path string, ref string) (string, schema.GroupVersionKind, error) {
ret := _m.Called(ctx, path, ref)

Some files were not shown because too many files have changed in this diff Show More