diff --git a/.betterer.results b/.betterer.results
index 214207392aa..76cbf6455d5 100644
--- a/.betterer.results
+++ b/.betterer.results
@@ -615,16 +615,6 @@ exports[`better eslint`] = {
[0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"]
],
- "packages/grafana-ui/src/components/PageLayout/PageToolbar.tsx:5381": [
- [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"],
- [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"],
- [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"],
- [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"]
- ],
- "packages/grafana-ui/src/components/Pagination/Pagination.tsx:5381": [
- [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"],
- [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"]
- ],
"packages/grafana-ui/src/components/PanelChrome/PanelContext.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 724208ddb45..a0adc29fbc5 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -757,6 +757,7 @@ embed.go @grafana/grafana-as-code
/.github/pr-commands.json @tolzhabayev
/.github/renovate.json5 @grafana/frontend-ops
/.github/actions/test-coverage-processor/action.yml @grafana/grafana-backend-group
+/.github/actions/setup-grafana-bench/ @Proximyst
/.github/workflows/add-to-whats-new.yml @grafana/docs-tooling
/.github/workflows/auto-triager/ @grafana/plugins-platform-frontend
/.github/workflows/alerting-swagger-gen.yml @grafana/alerting-backend
diff --git a/.github/actions/setup-grafana-bench/action.yml b/.github/actions/setup-grafana-bench/action.yml
new file mode 100644
index 00000000000..624ad243b7b
--- /dev/null
+++ b/.github/actions/setup-grafana-bench/action.yml
@@ -0,0 +1,44 @@
+name: 'Setup Grafana Bench'
+description: 'Sets up and installs Grafana Bench'
+
+inputs:
+ github-app-name:
+ description: 'Name of the GitHub App in Vault'
+ required: false
+ default: 'grafana-ci-bot'
+ branch:
+ description: 'The branch to install from'
+ required: false
+ default: 'main'
+
+runs:
+ using: "composite"
+ steps:
+ - name: Retrieve GitHub App secrets
+ id: get-secrets
+ uses: grafana/shared-workflows/actions/get-vault-secrets@get-vault-secrets-v1.0.1
+ with:
+ repo_secrets: |
+ APP_ID=${{ inputs.github-app-name }}:app-id
+ APP_INSTALLATION_ID=${{ inputs.github-app-name }}:app-installation-id
+ PRIVATE_KEY=${{ inputs.github-app-name }}:private-key
+
+ - name: Generate GitHub App token
+ id: generate_token
+ uses: actions/create-github-app-token@v1
+ with:
+ app-id: ${{ env.APP_ID }}
+ private-key: ${{ env.PRIVATE_KEY }}
+ repositories: "grafana-bench"
+ owner: "grafana"
+
+ - name: Setup Bench
+ shell: bash
+ env:
+ GH_TOKEN: ${{ steps.generate_token.outputs.token }}
+ run: |
+ git clone https://x-access-token:${GH_TOKEN}@github.com/grafana/grafana-bench.git ../grafana-bench
+
+ cd ../grafana-bench
+ git switch ${{ inputs.branch }}
+ go install .
diff --git a/.github/workflows/pr-backend-code-checks.yml b/.github/workflows/pr-backend-code-checks.yml
index daf48f4c391..37073dc28c4 100644
--- a/.github/workflows/pr-backend-code-checks.yml
+++ b/.github/workflows/pr-backend-code-checks.yml
@@ -21,8 +21,13 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
- go-version: '1.23.7'
+ go-version-file: go.mod
cache: true
+
+ - name: Verify code generation
+ run: |
+ CODEGEN_VERIFY=1 make gen-cue
+ CODEGEN_VERIFY=1 make gen-jsonnet
- name: Validate go.mod
run: go run scripts/modowners/modowners.go check go.mod
diff --git a/.github/workflows/pr-backend-unit-tests.yml b/.github/workflows/pr-backend-unit-tests.yml
index 4b264547957..99ec9b0ea49 100644
--- a/.github/workflows/pr-backend-unit-tests.yml
+++ b/.github/workflows/pr-backend-unit-tests.yml
@@ -39,17 +39,13 @@ jobs:
run: |
sudo apt-get update
sudo apt-get install -y build-essential shared-mime-info
-
- - name: Verify code generation
- run: |
- CODEGEN_VERIFY=1 make gen-cue
- CODEGEN_VERIFY=1 make gen-jsonnet
+ go install github.com/mfridman/tparse@c1754a1f484ac5cd422697b0fec635177ddc8507 # v0.17.0
- name: Generate Go code
run: make gen-go
- name: Run unit tests
- run: COVER_OPTS="-coverprofile=be-unit.cov -coverpkg=github.com/grafana/grafana/..." make test-go-unit
+ run: COVER_OPTS="-coverprofile=be-unit.cov -coverpkg=github.com/grafana/grafana/..." GO_TEST_OUTPUT="/tmp/unit.log" make test-go-unit
- name: Process and upload coverage
uses: ./.github/actions/test-coverage-processor
@@ -61,6 +57,22 @@ jobs:
codecov-flag: 'be-unit'
codecov-name: 'be-unit'
+ - name: Install Grafana Bench
+ # We can't allow forks here, as we need secret access.
+ if: ${{ github.event_name != 'pull_request' }}
+ uses: ./.github/actions/setup-grafana-bench
+
+ - name: Process output for Bench
+ if: ${{ github.event_name != 'pull_request' }}
+ run: |
+ grafana-bench report \
+ --trigger pr-backend-unit-tests-oss \
+ --report-input go \
+ --report-output log \
+ --grafana-version "$(git rev-parse HEAD)" \
+ --suite-name grafana-oss-unit-tests \
+ /tmp/unit.log
+
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
diff --git a/Makefile b/Makefile
index f2f37e34812..842ce5b65e9 100644
--- a/Makefile
+++ b/Makefile
@@ -17,6 +17,7 @@ GO_RACE_FLAG := $(if $(GO_RACE),-race)
GO_BUILD_FLAGS += $(if $(GO_BUILD_DEV),-dev)
GO_BUILD_FLAGS += $(if $(GO_BUILD_TAGS),-build-tags=$(GO_BUILD_TAGS))
GO_BUILD_FLAGS += $(GO_RACE_FLAG)
+GO_TEST_OUTPUT := $(shell [ -n "$(GO_TEST_OUTPUT)" ] && echo '-json | tee $(GO_TEST_OUTPUT) | tparse -all')
GIT_BASE = remotes/origin/main
# GNU xargs has flag -r, and BSD xargs (e.g. MacOS) has that behaviour by default
@@ -248,7 +249,7 @@ test-go: test-go-unit test-go-integration
.PHONY: test-go-unit
test-go-unit: ## Run unit tests for backend with flags.
@echo "test backend unit tests"
- $(GO) test $(GO_RACE_FLAG) -short -covermode=atomic -coverprofile=unit.cov -timeout=30m $(GO_TEST_FILES)
+ $(GO) test $(GO_RACE_FLAG) -short -covermode=atomic -coverprofile=unit.cov -timeout=30m $(GO_TEST_FILES) $(GO_TEST_OUTPUT)
.PHONY: test-go-unit-pretty
test-go-unit-pretty: check-tparse
@@ -261,7 +262,7 @@ test-go-unit-pretty: check-tparse
.PHONY: test-go-integration
test-go-integration: ## Run integration tests for backend with flags.
@echo "test backend integration tests"
- $(GO) test $(GO_RACE_FLAG) -count=1 -run "^TestIntegration" -covermode=atomic -coverprofile=integration.cov -timeout=5m $(GO_INTEGRATION_TESTS)
+ $(GO) test $(GO_RACE_FLAG) -count=1 -run "^TestIntegration" -covermode=atomic -coverprofile=integration.cov -timeout=5m $(GO_INTEGRATION_TESTS) $(GO_TEST_OUTPUT)
.PHONY: test-go-integration-alertmanager
test-go-integration-alertmanager: ## Run integration tests for the remote alertmanager (config taken from the mimir_backend block).
diff --git a/conf/defaults.ini b/conf/defaults.ini
index 30d1147da84..5903a21bd50 100644
--- a/conf/defaults.ini
+++ b/conf/defaults.ini
@@ -1530,6 +1530,13 @@ basic_auth_password =
# Request timeout for recording rule writes.
timeout = 10s
+# Default data source UID to write to if not specified in the rule definition.
+# Only has effect if the grafanaManagedRecordRulesDatasources feature toggle is enabled.
+default_datasource_uid =
+
+# Suffix to apply to the data source URL for remote write requests.
+remote_write_path_suffix = /push
+
# Optional custom headers to include in recording rule write requests.
[recording_rules.custom_headers]
# exampleHeader = exampleValue
diff --git a/conf/sample.ini b/conf/sample.ini
index 747e4fad9ea..b6afeccfcf3 100644
--- a/conf/sample.ini
+++ b/conf/sample.ini
@@ -1512,6 +1512,13 @@ basic_auth_password =
# Request timeout for recording rule writes.
timeout = 30s
+# Default data source UID to write to if not specified in the rule definition.
+# Only has effect if the grafanaManagedRecordRulesDatasources feature toggle is enabled.
+default_datasource_uid =
+
+# Suffix to apply to the data source URL for remote write requests.
+remote_write_path_suffix = /push
+
# Optional custom headers to include in recording rule write requests.
[recording_rules.custom_headers]
# exampleHeader = exampleValue
diff --git a/docs/Makefile b/docs/Makefile
index 36b7e4f41be..7bdbe026293 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -9,6 +9,6 @@ include docs.mk
.PHONY: sources/panels-visualizations/query-transform-data/transform-data/index.md
sources/panels-visualizations/query-transform-data/transform-data/index.md: ## Generate the Transform Data page source.
- cd $(CURDIR)/.. && npx tsc ./scripts/docs/generate-transformations.ts && \
- node -e "require('./scripts/docs/generate-transformations').buildMarkdownContent()" && \
+ cd $(CURDIR)/.. && \
+ npx tsx ./scripts/docs/generate-transformations.ts && \
npx prettier -w $(CURDIR)/$@
diff --git a/docs/docs.mk b/docs/docs.mk
index dfb6e9e501c..09308dc8604 100644
--- a/docs/docs.mk
+++ b/docs/docs.mk
@@ -125,7 +125,7 @@ update: ## Fetch the latest version of this Makefile and the `make-docs` script
TOPIC_TYPES := concept multiple-tasks reference section task tutorial visualization
.PHONY: $(patsubst %,topic/%,$(TOPIC_TYPES))
topic/%: ## Create a topic from the Writers' Toolkit template. Specify the topic type as the target, for example, `make topic/task TOPIC_PATH=sources/my-new-topic.md`.
-topic/%:
+$(patsubst %,topic/%,$(TOPIC_TYPES)):
$(if $(TOPIC_PATH),,$(error "You must set the TOPIC_PATH variable to the path where the $(@F) topic will be created. For example: make $(@) TOPIC_PATH=sources/my-new-topic.md"))
mkdir -p $(dir $(TOPIC_PATH))
curl -s -o $(TOPIC_PATH) https://raw.githubusercontent.com/grafana/writers-toolkit/refs/heads/main/docs/static/templates/$(@F)-template.md
diff --git a/docs/make-docs b/docs/make-docs
index 80c89aea7ce..f6d72f905dc 100755
--- a/docs/make-docs
+++ b/docs/make-docs
@@ -8,6 +8,12 @@
# [Semantic versioning](https://semver.org/) is used to help the reader identify the significance of changes.
# Changes are relevant to this script and the support docs.mk GNU Make interface.
#
+# ## 8.5.2 (2025-02-28)
+#
+# ### Fixed
+#
+# - topic/ targets are no longer no-ops as a result of 8.5.1.
+#
# ## 8.5.1 (2025-02-18)
#
# ### Fixed
diff --git a/docs/sources/administration/plugin-management/index.md b/docs/sources/administration/plugin-management/index.md
index 5d89d1204c5..1f43832b69b 100644
--- a/docs/sources/administration/plugin-management/index.md
+++ b/docs/sources/administration/plugin-management/index.md
@@ -128,7 +128,7 @@ unzip my-plugin-0.2.0.zip -d YOUR_PLUGIN_DIR/my-plugin
The path to the plugin directory is defined in the configuration file. For more information, refer to [Configuration](../../setup-grafana/configure-grafana/#plugins).
-#### Install a plugin using Grafana configuration
+#### Install a plugin using Grafana configuration
{{% admonition type="note" %}}
This feature requires Grafana 11.5.0 or later.
diff --git a/docs/sources/developers/http_api/group_attribute_sync.md b/docs/sources/developers/http_api/group_attribute_sync.md
index 82f4f67c0f8..f6d5e752297 100644
--- a/docs/sources/developers/http_api/group_attribute_sync.md
+++ b/docs/sources/developers/http_api/group_attribute_sync.md
@@ -22,8 +22,7 @@ The Group Attribute Sync API allows you to configure [group attribute sync featu
> **Note:** Available in [Grafana Enterprise](https://grafana.com/docs/grafana//introduction/grafana-enterprise) and [Grafana Cloud](https://grafana.com/docs/grafana-cloud/)
{{% admonition type="note" %}}
-This feature is behind the `groupAttributeSync` feature toggle.
-You can enable feature toggles through configuration file or environment variables. See configuration [docs](/docs/grafana//setup-grafana/configure-grafana/#feature_toggles) for details.
+This feature is currently in [private preview](https://grafana.com/docs/release-life-cycle/#private-preview) and behind the `groupAttributeSync` feature toggle. Please contact support to have this feature enabled.
{{% /admonition %}}
## List group mappings
diff --git a/docs/sources/panels-visualizations/query-transform-data/transform-data/index.md b/docs/sources/panels-visualizations/query-transform-data/transform-data/index.md
index 9fef087e422..cfc5a5e29e5 100644
--- a/docs/sources/panels-visualizations/query-transform-data/transform-data/index.md
+++ b/docs/sources/panels-visualizations/query-transform-data/transform-data/index.md
@@ -104,6 +104,16 @@ When there are multiple transformations, Grafana applies them in the order they
The order in which Grafana applies transformations directly impacts the results. For example, if you use a Reduce transformation to condense all the results of one column into a single value, then you can only apply transformations to that single value.
+## Dashboard variables in transformations
+
+All text input fields in transformations accept [variable syntax](ref:dashboard-variable):
+
+{{< figure src="/media/docs/grafana/panels-visualizations/screenshot-transformation-variables-v11.6.png" alt="Transformation with a mock variable in a text field" >}}
+
+When you use dashboard variables in transformations, the variables are automatically interpolated before the transformations are applied to the data.
+
+For an example, refer to [Use a dashboard variable](#use-a-dashboard-variable) in the **Filter fields by name** transformation.
+
## Add a transformation function to data
The following steps guide you in adding a transformation to data. This documentation does not include steps for each type of transformation. For a complete list of transformations, refer to [Transformation functions](#transformation-functions).
diff --git a/docs/sources/panels-visualizations/visualizations/traces/index.md b/docs/sources/panels-visualizations/visualizations/traces/index.md
index ac99c3a07bd..d89ea25b559 100644
--- a/docs/sources/panels-visualizations/visualizations/traces/index.md
+++ b/docs/sources/panels-visualizations/visualizations/traces/index.md
@@ -59,7 +59,7 @@ For more information about traces and how to use them, refer to the following do
- [Tempo data source](ref:tempo-data-source)
- [Getting started with Tempo](/docs/tempo/latest/getting-started)
-{{< figure src="/static/img/docs/explore/trace-view-9-4.png" class="docs-image--no-shadow" max-width= "900px" caption="Screenshot of the trace view" >}}
+{{< figure src="/media/docs/grafana/panels-visualizations/screenshot-traces-visualization-11.5.png" max-width= "700px" alt="Screenshot of the trace view" >}}
{{< docs/play title="Traces Panel" url="https://play.grafana.org/d/edodkfmj0tce8f/" >}}
@@ -77,7 +77,7 @@ To use this procedure, you need:
- A Grafana instance
- A [Tempo data source](ref:tempo-data-source) connected to your Grafana instance
-### Add the traces visualization query {#add-the-traces-panel-query}
+### Steps {#add-the-traces-panel-query}
To view and analyze traces data in a dashboard, you need to add the traces visualization to your dashboard and define a query using the panel editor.
The query determines the data that is displayed in the visualization.
@@ -100,19 +100,19 @@ This procedure uses dashboard variables and templates to allow you to enter trac
1. In the query editor, click the **TraceQL** query type tab.
1. Enter `${traceId}` in the TraceQL query field to create a dashboard variable. This variable is used as the template query.
- {{< figure src="/static/img/docs/panels/traces/screenshot-traces-template-query.png" caption="Add a template query" >}}
+ {{< figure src="/static/img/docs/panels/traces/screenshot-traces-template-query.png" alt="Add a template query" >}}
1. Click **Back to dashboard**.
1. Click **Settings** and go to the **Variables** tab.
1. Add a new variable called `traceId`, of variable type **Custom**, giving it a label if required.
- {{< figure src="/media/docs/grafana/dashboards/screenshot-traces-custom-variable-11.2.png" max-width="50%" caption="Add a Custom variable" >}}
+ {{< figure src="/media/docs/grafana/panels-visualizations/screenshot-traces-custom-variable-v11.5.png" max-width="400px" alt="Add a template query" >}}
1. Click **Save dashboard**.
1. Click **Back to dashboard** and **Exit edit**.
1. Verify that the panel works by using a valid trace ID for the data source used for the trace panel and editing the ID in the dashboard variable.
- {{< figure src="/static/img/docs/panels/traces/screenshot-traces-traceid-panel.png" caption="Results of query in trace panel" >}}
+ {{< figure src="/static/img/docs/panels/traces/screenshot-traces-traceid-panel.png" alt="Results of query in trace panel" >}}
## Add TraceQL with table visualizations
@@ -127,14 +127,14 @@ It’s more useful to instead be able to use TraceQL queries to search for speci
1. Under the **Panel options**, enter a **Title** for your trace panel or have Grafana create one using [generative AI features](ref:generative-ai-features).
1. Add an appropriate TraceQL query to search for traces that you would like to visualize in the dashboard. This example uses a simple, static query. You can write the TraceQL query as a template query to take advantage of other dashboard variables, if they exist. This lets you create dynamic queries based on these variables.
- {{< figure src="/static/img/docs/panels/traces/screenshot-traces-dynamic-query.png" caption="Create a dynamic query" >}}
+ {{< figure src="/static/img/docs/panels/traces/screenshot-traces-dynamic-query.png" alt="Create a dynamic query" >}}
1. Click **Save dashboard**.
1. Click **Back to dashboard** and **Exit edit**.
When results are returned from a query, the results are rendered in the panel’s table.
-{{< figure src="/static/img/docs/panels/traces/screenshot-traces-returned-query.png" caption="Results of a returned query in the panel table" >}}
+{{< figure src="/static/img/docs/panels/traces/screenshot-traces-returned-query.png" alt="Results of a returned query in the panel table" >}}
### Use a variable to add other links to traces
@@ -146,12 +146,12 @@ To create a set of data links in the panel, use the following steps:
1. Add a **Title** for the data link.
1. Find the UUID of the dashboard by looking in your browser’s address bar when the full dashboard is being rendered. Because this is a link to a dashboard in the same Grafana stack, only the path of the dashboard is required.
- {{< figure src="/static/img/docs/panels/traces/screensnot-traces-uuid-url.png" caption="Unique identifier for the dashboard" >}}
+ {{< figure src="/static/img/docs/panels/traces/screensnot-traces-uuid-url.png" alt="Unique identifier for the dashboard" >}}
1. In the **URL** field, make a self-reference to the dashboard that contains both of the panels. This self-reference uses the value of the selected trace in the table to fill in the dashboard variable. Use the path for the dashboard from the previous step and then fill in the value of `traceId` using the selected results from the TraceQL table.
The trace ID is exposed using the `traceID` data field in the returned results, so use that as the value for the dashboard variable.
- {{< figure src="/static/img/docs/panels/traces/screenshot-traces-edit-link.png" caption="Edit link and add the Trace link" >}}
+ {{< figure src="/static/img/docs/panels/traces/screenshot-traces-edit-link.png" alt="Edit link and add the Trace link" >}}
1. Select **Save** to save the data link.
1. Click **Save dashboard**.
@@ -159,24 +159,35 @@ To create a set of data links in the panel, use the following steps:
You should now see a list of matching traces in the table visualization. While selecting the **TraceID** or **SpanID** fields will give you the option to either open the **Explore** page to visualize the trace or following the data link, selecting any other field (such as **Start time**, **Name** or **Duration**) automatically follows the data link, filling in the `traceId` dashboard variable, and then shows the relevant trace in the trace panel.
-{{< figure src="/static/img/docs/panels/traces/screenshot-traces-trace-link.png" caption="Selecting the trace link" >}}
+{{< figure src="/static/img/docs/panels/traces/screenshot-traces-trace-link.png" alt="Selecting the trace link" >}}
{{< figure src="/static/img/docs/panels/traces/screenshot-traces-trace-link-follow.png" caption="Follow the trace link populates the trace ID and displays the traces view" >}}
-## Panel options
+## Configuration options
+
+{{< docs/shared lookup="visualizations/config-options-intro.md" source="grafana" version="" >}}
+
+### Panel options
{{< docs/shared lookup="visualizations/panel-options.md" source="grafana" version="" >}}
-## Span filters
+### Span filters options
The **Span filters** options control the initial state of the span filters when the visualization loads, allowing you to customize your trace analysis view.
-- **Find in trace** - Set the initial value to focus on spans relevant to your query.
-- **Show matches only** - Toggle the switch on to display only spans that match the defined filter criteria. This helps simplify trace interpretation.
-- **Show critical path only** - Toggle the switch on to highlight only the spans in the critical path, which helps identify performance bottlenecks and their impact on overall latency.
-- **Service name** and **Service name operator** - Define a specific service or pattern to narrow analysis to spans related to particular services.
-- **Span name** and **Span name operator** - Filter spans by name or pattern to focus on specific span types or processes.
-- **Min duration** and **Max duration** - Set duration thresholds to exclude spans outside the desired time range.
-- **Tags** - Add one or more tags to further refine the filtering criteria so only relevant spans are displayed.
+The following options support variable interpolation, where you can set the service name to a variable `$var` and the visualization will replace it with the value for the variable named `$var` in the span filters: **Service name**, **Span name**, **Min duration**, **Max duration**, and **Tags**.
-The options support variable interpolation, where you can set the service name to a variable `$var` and the visualization will replace it with the value for the variable named `$var` in the span filters. This applies to the service name, span name, duration fields, and tags.
+
+
+| Option | Description |
+| ------ | ----------- |
+| Find in trace | Set the initial value to focus on spans relevant to your query. |
+| Show matches only | Toggle the switch on to display only spans that match the defined filter criteria. This helps simplify trace interpretation. |
+| Show critical path only | Toggle the switch on to highlight only the spans in the critical path, which helps identify performance bottlenecks and their impact on overall latency. |
+| Service name | Along with the **Service name operator**, define a specific service or pattern to narrow analysis to spans related to particular services. |
+| Span name | Along with the **Span name operator**, filter spans by name or pattern to focus on specific span types or processes. |
+| Min duration | Set the minimum duration threshold to exclude spans outside the desired time range. |
+| Max duration | Set the maximum duration threshold to exclude spans outside the desired time range. |
+| Tags | Add one or more tags to further refine the filtering criteria so only relevant spans are displayed. |
+
+
diff --git a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md
index a4a4163bb49..fbc2e986f46 100644
--- a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md
+++ b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md
@@ -64,6 +64,7 @@ Most [generally available](https://grafana.com/docs/release-life-cycle/#general-
| `groupToNestedTableTransformation` | Enables the group to nested table transformation | Yes |
| `newPDFRendering` | New implementation for the dashboard-to-PDF rendering | Yes |
| `tlsMemcached` | Use TLS-enabled memcached in the enterprise caching feature | Yes |
+| `ssoSettingsSAML` | Use the new SSO Settings API to configure the SAML connector | Yes |
| `cloudWatchNewLabelParsing` | Updates CloudWatch label parsing to be more accurate | Yes |
| `accessActionSets` | Introduces action sets for resource permissions. Also ensures that all folder editors and admins can create subfolders without needing any additional permissions. | Yes |
| `newDashboardSharingComponent` | Enables the new sharing drawer design | Yes |
@@ -111,7 +112,6 @@ Most [generally available](https://grafana.com/docs/release-life-cycle/#general-
| `regressionTransformation` | Enables regression analysis transformation |
| `onPremToCloudMigrations` | Enable the Grafana Migration Assistant, which helps you easily migrate on-prem resources, such as dashboards, folders, and data source configurations, to your Grafana Cloud stack. |
| `alertingSaveStateCompressed` | Enables the compressed protobuf-based alert state storage |
-| `ssoSettingsSAML` | Use the new SSO Settings API to configure the SAML connector |
| `azureMonitorPrometheusExemplars` | Allows configuration of Azure Monitor as a data source that can provide Prometheus exemplars |
| `ssoSettingsLDAP` | Use the new SSO Settings API to configure LDAP |
| `improvedExternalSessionHandling` | Enables improved support for OAuth external sessions. After enabling this feature, users might need to re-authenticate themselves. |
diff --git a/docs/sources/setup-grafana/configure-security/configure-group-attribute-sync.md b/docs/sources/setup-grafana/configure-security/configure-group-attribute-sync.md
index 0ebe9f3db6c..ff963122050 100644
--- a/docs/sources/setup-grafana/configure-security/configure-group-attribute-sync.md
+++ b/docs/sources/setup-grafana/configure-security/configure-group-attribute-sync.md
@@ -16,8 +16,7 @@ Groups are mapped to [fixed](https://grafana.com/docs/grafana//
> **Note:** Available in [Grafana Enterprise](https://grafana.com/docs/grafana//introduction/grafana-enterprise) and [Grafana Cloud](/docs/grafana-cloud/).
{{% admonition type="note" %}}
-This feature is behind the `groupAttributeSync` feature toggle.
-You can enable feature toggles through configuration file or environment variables. See configuration [docs](/docs/grafana//setup-grafana/configure-grafana/#feature_toggles) for details.
+This feature is currently in [private preview](https://grafana.com/docs/release-life-cycle/#private-preview) and behind the `groupAttributeSync` feature toggle. Please contact support to have this feature enabled.
{{% /admonition %}}
When a user logs in, Grafana checks the user's external group memberships and the configured group to role mappings to assign the corresponding roles to the user.
diff --git a/go.mod b/go.mod
index 5c095fd2c6b..708e5dc5bd6 100644
--- a/go.mod
+++ b/go.mod
@@ -76,14 +76,14 @@ require (
github.com/googleapis/go-sql-spanner v1.11.1 // @grafana/grafana-search-and-storage
github.com/gorilla/mux v1.8.1 // @grafana/grafana-backend-group
github.com/gorilla/websocket v1.5.3 // @grafana/grafana-app-platform-squad
- github.com/grafana/alerting v0.0.0-20250305143710-aae4827ec061 // @grafana/alerting-backend
+ github.com/grafana/alerting v0.0.0-20250307175047-1d263576d356 // @grafana/alerting-backend
github.com/grafana/authlib v0.0.0-20250225105729-99e678595501 // @grafana/identity-access-team
github.com/grafana/authlib/types v0.0.0-20250224151205-5ef97131cc82 // @grafana/identity-access-team
github.com/grafana/dataplane/examples v0.0.1 // @grafana/observability-metrics
github.com/grafana/dataplane/sdata v0.0.9 // @grafana/observability-metrics
github.com/grafana/dskit v0.0.0-20241105154643-a6b453a88040 // @grafana/grafana-backend-group
github.com/grafana/e2e v0.1.1 // @grafana-app-platform-squad
- github.com/grafana/gofpdf v0.0.0-20231002120153-857cc45be447 // @grafana/sharing-squad
+ github.com/grafana/gofpdf v0.0.0-20250307124105-3b9c5d35577f // @grafana/sharing-squad
github.com/grafana/gomemcache v0.0.0-20240805133030-fdaf6a95408e // @grafana/grafana-operator-experience-squad
github.com/grafana/grafana-app-sdk v0.31.0 // @grafana/grafana-app-platform-squad
github.com/grafana/grafana-app-sdk/logging v0.30.0 // @grafana/grafana-app-platform-squad
@@ -135,7 +135,7 @@ require (
github.com/openfga/openfga v1.8.6 // @grafana/identity-access-team
github.com/openzipkin/zipkin-go v0.4.3 // @grafana/oss-big-tent
github.com/patrickmn/go-cache v2.1.0+incompatible // @grafana/alerting-backend
- github.com/phpdave11/gofpdi v1.0.13 // @grafana/sharing-squad
+ github.com/phpdave11/gofpdi v1.0.14 // @grafana/sharing-squad
github.com/prometheus/alertmanager v0.27.0 // @grafana/alerting-backend
github.com/prometheus/client_golang v1.21.0 // @grafana/alerting-backend
github.com/prometheus/client_model v0.6.1 // @grafana/grafana-backend-group
diff --git a/go.sum b/go.sum
index e7f53d7658d..e3dd3df3c82 100644
--- a/go.sum
+++ b/go.sum
@@ -1559,8 +1559,8 @@ github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7Fsg
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/grafana/alerting v0.0.0-20250305143710-aae4827ec061 h1:2s0xCzcxw8MlzLbbrEkghmwQpXjwkcRJYSItBQ1ZD0U=
-github.com/grafana/alerting v0.0.0-20250305143710-aae4827ec061/go.mod h1:hdGB3dSl8Ma9Rjo2YiAEAjMkZ5HiNJbNDqRKDefRZrM=
+github.com/grafana/alerting v0.0.0-20250307175047-1d263576d356 h1:71o8Bxw/wg+aBRUASiGux67gDEUC2bqq3I+x2hw8eIc=
+github.com/grafana/alerting v0.0.0-20250307175047-1d263576d356/go.mod h1:hdGB3dSl8Ma9Rjo2YiAEAjMkZ5HiNJbNDqRKDefRZrM=
github.com/grafana/authlib v0.0.0-20250225105729-99e678595501 h1:FTuDRy/Shw8yOdG+v1DnkeuaCAl8fvwgcfaG9Wccuhg=
github.com/grafana/authlib v0.0.0-20250225105729-99e678595501/go.mod h1:XVpdLhaeYqz414FmGnW00/0vTe1x8c0GRH3KaeRtyg0=
github.com/grafana/authlib/types v0.0.0-20250224151205-5ef97131cc82 h1:DnRUYiAotHXnrfYJCvhH1NkiyWVcPm5Pd+P7Ugqt/d8=
@@ -1573,8 +1573,8 @@ github.com/grafana/dskit v0.0.0-20241105154643-a6b453a88040 h1:IR+UNYHqaU31t8/TA
github.com/grafana/dskit v0.0.0-20241105154643-a6b453a88040/go.mod h1:SPLNCARd4xdjCkue0O6hvuoveuS1dGJjDnfxYe405YQ=
github.com/grafana/e2e v0.1.1 h1:/b6xcv5BtoBnx8cZnCiey9DbjEc8z7gXHO5edoeRYxc=
github.com/grafana/e2e v0.1.1/go.mod h1:RpNLgae5VT+BUHvPE+/zSypmOXKwEu4t+tnEMS1ATaE=
-github.com/grafana/gofpdf v0.0.0-20231002120153-857cc45be447 h1:jxJJ5z0GxqhWFbQUsys3BHG8jnmniJ2Q74tXAG1NaDo=
-github.com/grafana/gofpdf v0.0.0-20231002120153-857cc45be447/go.mod h1:IxsY6mns6Q5sAnWcrptrgUrSglTZJXH/kXr9nbpb/9I=
+github.com/grafana/gofpdf v0.0.0-20250307124105-3b9c5d35577f h1:5xkjl5Y/j2QefJKOtTfyD1wXlVsQ2yEXmd0u82h5obs=
+github.com/grafana/gofpdf v0.0.0-20250307124105-3b9c5d35577f/go.mod h1:+O5QxOwwgP10jedZHapzXY+IPKTnzHBtIs5UUb9G+kI=
github.com/grafana/gomemcache v0.0.0-20240805133030-fdaf6a95408e h1:UlEET0InuoFautfaFp8lDrNF7rPHYXuBMrzwWx9XqFY=
github.com/grafana/gomemcache v0.0.0-20240805133030-fdaf6a95408e/go.mod h1:IGRj8oOoxwJbHBYl1+OhS9UjQR0dv6SQOep7HqmtyFU=
github.com/grafana/grafana-api-golang-client v0.27.0 h1:zIwMXcbCB4n588i3O2N6HfNcQogCNTd/vPkEXTr7zX8=
@@ -2126,10 +2126,10 @@ github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xl
github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s=
github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY=
-github.com/phpdave11/gofpdi v1.0.7/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
-github.com/phpdave11/gofpdi v1.0.13 h1:o61duiW8M9sMlkVXWlvP92sZJtGKENvW3VExs6dZukQ=
github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
+github.com/phpdave11/gofpdi v1.0.14 h1:jlcDIJ6ObCh3X9nANGEK6RY5wbUKHJ5unBjrzG4i89A=
+github.com/phpdave11/gofpdi v1.0.14/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
diff --git a/go.work.sum b/go.work.sum
index 4a000692438..f6e5d6a58a9 100644
--- a/go.work.sum
+++ b/go.work.sum
@@ -1168,6 +1168,7 @@ github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/phpdave11/gofpdf v1.4.2 h1:KPKiIbfwbvC/wOncwhrpRdXVj2CZTCFlw4wnoyjtHfQ=
+github.com/phpdave11/gofpdi v1.0.14 h1:jlcDIJ6ObCh3X9nANGEK6RY5wbUKHJ5unBjrzG4i89A=
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=
diff --git a/package.json b/package.json
index bde0ffe3dac..77b946e8711 100644
--- a/package.json
+++ b/package.json
@@ -278,8 +278,8 @@
"@grafana/prometheus": "workspace:*",
"@grafana/runtime": "workspace:*",
"@grafana/saga-icons": "workspace:*",
- "@grafana/scenes": "6.1.4",
- "@grafana/scenes-react": "6.1.4",
+ "@grafana/scenes": "6.2.1",
+ "@grafana/scenes-react": "6.2.1",
"@grafana/schema": "workspace:*",
"@grafana/sql": "workspace:*",
"@grafana/ui": "workspace:*",
diff --git a/packages/grafana-data/src/transformations/fieldReducer.ts b/packages/grafana-data/src/transformations/fieldReducer.ts
index 71a3c4c2344..56006b7b43e 100644
--- a/packages/grafana-data/src/transformations/fieldReducer.ts
+++ b/packages/grafana-data/src/transformations/fieldReducer.ts
@@ -131,6 +131,14 @@ export enum ReducerID {
p99 = 'p99',
}
+export function getFieldTypeForReducer(id: ReducerID, fallback: FieldType): FieldType {
+ return id === ReducerID.count
+ ? FieldType.number
+ : id === ReducerID.allIsNull || id === ReducerID.allIsZero
+ ? FieldType.boolean
+ : fallback;
+}
+
export function isReducerID(id: string): id is ReducerID {
return Object.keys(ReducerID).includes(id);
}
diff --git a/packages/grafana-data/src/transformations/transformers/groupBy.test.ts b/packages/grafana-data/src/transformations/transformers/groupBy.test.ts
index cbdcc0c402f..abfcc57c2c0 100644
--- a/packages/grafana-data/src/transformations/transformers/groupBy.test.ts
+++ b/packages/grafana-data/src/transformations/transformers/groupBy.test.ts
@@ -368,4 +368,97 @@ describe('GroupBy transformer', () => {
expect(result[0].fields).toEqual(expected);
});
});
+
+ it('should retain "time" field type when used as aggregation (max, etc)', async () => {
+ const testSeries = toDataFrame({
+ name: 'A',
+ fields: [
+ { name: 'user', type: FieldType.string, values: ['A', 'B', 'A', 'B'] },
+ { name: 'time', type: FieldType.time, values: [7, 2, 1, 5] },
+ ],
+ });
+
+ const cfg: DataTransformerConfig = {
+ id: DataTransformerID.groupBy,
+ options: {
+ fields: {
+ user: {
+ operation: GroupByOperationID.groupBy,
+ aggregations: [],
+ },
+ time: {
+ operation: GroupByOperationID.aggregate,
+ aggregations: [ReducerID.max],
+ },
+ },
+ },
+ };
+
+ await expect(transformDataFrame([cfg], [testSeries])).toEmitValuesWith((received) => {
+ const result = received[0];
+ const expected: Field[] = [
+ {
+ name: 'user',
+ type: FieldType.string,
+ values: ['A', 'B'],
+ config: {},
+ },
+ {
+ name: 'time (max)',
+ type: FieldType.time,
+ values: [7, 5],
+ config: {},
+ },
+ ];
+
+ expect(result[0].fields).toEqual(expected);
+ });
+ });
+
+ it('should retain "time" field type when used as aggregation (max, etc)', async () => {
+ const testSeries = toDataFrame({
+ refId: 'A',
+ fields: [
+ { name: 'user', type: FieldType.string, values: ['A', 'B', 'A', 'B'] },
+ { name: 'time', type: FieldType.time, values: [7, 2, 1, 5] },
+ ],
+ });
+
+ const cfg: DataTransformerConfig = {
+ id: DataTransformerID.groupBy,
+ options: {
+ fields: {
+ user: {
+ operation: GroupByOperationID.groupBy,
+ aggregations: [],
+ },
+ time: {
+ operation: GroupByOperationID.aggregate,
+ aggregations: [ReducerID.max],
+ },
+ },
+ },
+ };
+
+ await expect(transformDataFrame([cfg], [testSeries])).toEmitValuesWith((received) => {
+ const result = received[0];
+ const expected: Field[] = [
+ {
+ name: 'user',
+ type: FieldType.string,
+ values: ['A', 'B'],
+ config: {},
+ },
+ {
+ name: 'time (max)',
+ type: FieldType.time,
+ values: [7, 5],
+ config: {},
+ },
+ ];
+
+ expect(result[0].refId).toEqual('A');
+ expect(result[0].fields).toEqual(expected);
+ });
+ });
});
diff --git a/packages/grafana-data/src/transformations/transformers/groupBy.ts b/packages/grafana-data/src/transformations/transformers/groupBy.ts
index 7bcb2ebc3e2..3ee7b106ffb 100644
--- a/packages/grafana-data/src/transformations/transformers/groupBy.ts
+++ b/packages/grafana-data/src/transformations/transformers/groupBy.ts
@@ -1,10 +1,9 @@
import { map } from 'rxjs/operators';
-import { guessFieldTypeForField } from '../../dataframe/processDataFrame';
import { getFieldDisplayName } from '../../field/fieldState';
-import { DataFrame, Field, FieldType } from '../../types/dataFrame';
+import { DataFrame, Field } from '../../types/dataFrame';
import { DataTransformerInfo, TransformationApplicabilityLevels } from '../../types/transformations';
-import { reduceField, ReducerID } from '../fieldReducer';
+import { getFieldTypeForReducer, reduceField, ReducerID } from '../fieldReducer';
import { DataTransformerID } from './ids';
import { findMaxFields } from './utils';
@@ -112,16 +111,16 @@ export const groupByTransformer: DataTransformerInfo
const aggregationField: Field = {
name: `${fieldName} (${aggregation})`,
values: valuesByAggregation[aggregation] ?? [],
- type: FieldType.other,
+ type: getFieldTypeForReducer(aggregation, field.type),
config: {},
};
- aggregationField.type = detectFieldType(aggregation, field, aggregationField);
fields.push(aggregationField);
}
}
processed.push({
+ ...frame,
fields,
length: valuesByGroupKey.size,
});
@@ -146,20 +145,6 @@ const shouldCalculateField = (field: Field, options: GroupByTransformerOptions):
);
};
-function detectFieldType(aggregation: string, sourceField: Field, targetField: Field): FieldType {
- switch (aggregation) {
- case ReducerID.allIsNull:
- return FieldType.boolean;
- case ReducerID.last:
- case ReducerID.lastNotNull:
- case ReducerID.first:
- case ReducerID.firstNotNull:
- return sourceField.type;
- default:
- return guessFieldTypeForField(targetField) ?? FieldType.string;
- }
-}
-
/**
* Groups values together by key. This will create a mapping of strings
* to _FieldMaps_ that will then be used to group values on.
diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts
index adc5f4641e8..350a9bf7b5a 100644
--- a/packages/grafana-data/src/types/featureToggles.gen.ts
+++ b/packages/grafana-data/src/types/featureToggles.gen.ts
@@ -256,4 +256,6 @@ export interface FeatureToggles {
rendererDisableAppPluginsPreload?: boolean;
assetSriChecks?: boolean;
alertRuleRestore?: boolean;
+ grafanaManagedRecordingRulesDatasources?: boolean;
+ inviteUserExperimental?: boolean;
}
diff --git a/packages/grafana-e2e-selectors/src/selectors/pages.ts b/packages/grafana-e2e-selectors/src/selectors/pages.ts
index ae0a8e08d3f..75d7c8dd4d0 100644
--- a/packages/grafana-e2e-selectors/src/selectors/pages.ts
+++ b/packages/grafana-e2e-selectors/src/selectors/pages.ts
@@ -206,9 +206,6 @@ export const versionedPages = {
shareSnapshot: {
'11.2.0': 'data-testid new share button share snapshot',
},
- inviteUser: {
- '11.5.0': 'data-testid new share button invite user',
- },
},
},
NewExportButton: {
diff --git a/packages/grafana-runtime/src/unstable/ScopesContext.ts b/packages/grafana-runtime/src/services/ScopesContext.ts
similarity index 100%
rename from packages/grafana-runtime/src/unstable/ScopesContext.ts
rename to packages/grafana-runtime/src/services/ScopesContext.ts
diff --git a/packages/grafana-runtime/src/services/index.ts b/packages/grafana-runtime/src/services/index.ts
index 496246bd6c4..3ceef02923a 100644
--- a/packages/grafana-runtime/src/services/index.ts
+++ b/packages/grafana-runtime/src/services/index.ts
@@ -56,3 +56,4 @@ export {
export { isPluginExtensionLink, isPluginExtensionComponent } from './pluginExtensions/utils';
export { setCurrentUser } from './user';
export { RuntimeDataSource } from './RuntimeDataSource';
+export { ScopesContext, type ScopesContextValueState, type ScopesContextValue, useScopes } from './ScopesContext';
diff --git a/packages/grafana-runtime/src/unstable.ts b/packages/grafana-runtime/src/unstable.ts
index 472372a9a8e..5cf9253a7c4 100644
--- a/packages/grafana-runtime/src/unstable.ts
+++ b/packages/grafana-runtime/src/unstable.ts
@@ -9,9 +9,5 @@
* and be subject to the standard policies
*/
-export {
- ScopesContext,
- type ScopesContextValueState,
- type ScopesContextValue,
- useScopes,
-} from './unstable/ScopesContext';
+// Dummy export to make it a valid module. Remove when we have real exports.
+export const unstable = {};
diff --git a/packages/grafana-ui/src/components/PageLayout/PageToolbar.tsx b/packages/grafana-ui/src/components/PageLayout/PageToolbar.tsx
index fa9a77c9d12..521b059ea8e 100644
--- a/packages/grafana-ui/src/components/PageLayout/PageToolbar.tsx
+++ b/packages/grafana-ui/src/components/PageLayout/PageToolbar.tsx
@@ -7,6 +7,7 @@ import { selectors } from '@grafana/e2e-selectors';
import { useStyles2 } from '../../themes/ThemeContext';
import { getFocusStyles } from '../../themes/mixins';
import { IconName } from '../../types';
+import { t } from '../../utils/i18n';
import { Icon } from '../Icon/Icon';
import { IconButton } from '../IconButton/IconButton';
import { Link } from '../Link/Link';
@@ -82,6 +83,15 @@ export const PageToolbar = memo(
>
);
+ const goBackLabel = t('grafana-ui.page-toolbar.go-back', 'Go back (Esc)');
+ const searchParentFolderLabel = t(
+ 'grafana-ui.page-toolbar.search-parent-folder',
+ 'Search dashboard in the {{parent}} folder',
+ { parent }
+ );
+ const searchDashboardNameLabel = t('grafana-ui.page-toolbar.search-dashboard-name', 'Search dashboard by name');
+ const searchLinksLabel = t('grafana-ui.page-toolbar.search-links', 'Search links');
+
return (