diff --git a/conf/defaults.ini b/conf/defaults.ini
index 70053cf6526..33cc2bdc9cd 100644
--- a/conf/defaults.ini
+++ b/conf/defaults.ini
@@ -1969,4 +1969,6 @@ domain = grafana.net
 snapshot_folder = ""
 # Link to form to give feedback on the feature
 feedback_url = https://docs.google.com/forms/d/e/1FAIpQLSeEE33vhbSpR8A8S1A1ocZ1ByVRRwiRl1GZr2FSrEer_tSa8w/viewform?usp=sf_link
+# How frequently should the frontend UI poll for changes while resources are migrating
+frontend_poll_interval = 2s
 
diff --git a/conf/sample.ini b/conf/sample.ini
index a23a17e1b14..780a2031fbc 100644
--- a/conf/sample.ini
+++ b/conf/sample.ini
@@ -1900,3 +1900,5 @@ timeout = 30s
 ;snapshot_folder = ""
 # Link to form to give feedback on the feature
 ;feedback_url = ""
+# How frequently should the frontend UI poll for changes while resources are migrating
+;frontend_poll_interval = 2s
diff --git a/docs/sources/datasources/loki/_index.md b/docs/sources/datasources/loki/_index.md
index e8eda35660f..1dc0024779d 100644
--- a/docs/sources/datasources/loki/_index.md
+++ b/docs/sources/datasources/loki/_index.md
@@ -76,7 +76,7 @@ Once you've added the Loki data source, you can [configure it](#configure-the-da
 To troubleshoot configuration and other issues, check the log file located at `/var/log/grafana/grafana.log` on Unix systems, or in `<grafana_install_dir>/data/log` on other platforms and manual installations.
 {{% /admonition %}}
 
-## Provision the Loki data source
+## Provision the data source
 
 You can define and configure the data source in YAML files as part of Grafana's provisioning system.
 For more information about provisioning, and for available configuration options, refer to [Provisioning Grafana](ref:provisioning-data-sources).
diff --git a/docs/sources/explore/trace-integration.md b/docs/sources/explore/trace-integration.md
index fbf20324291..da14c571cbc 100644
--- a/docs/sources/explore/trace-integration.md
+++ b/docs/sources/explore/trace-integration.md
@@ -1,5 +1,4 @@
 ---
-description: Tracing in Explore
 keywords:
   - explore
   - trace
@@ -8,167 +7,161 @@ labels:
     - cloud
     - enterprise
     - oss
-title: Tracing in Explore
+title: Traces in Explore
 weight: 20
 ---
 
-# Tracing in Explore
+# Traces in Explore
 
-You can use Explore to query and visualize traces from tracing data sources.
+You can use Explore to query and visualize traces from tracing data sources. Supported data sources include:
 
-Supported data sources are:
-
-- [Tempo]({{< relref "../datasources/tempo/" >}}) (supported ingestion formats: OpenTelemetry, Jaeger, and Zipkin)
-- [Jaeger]({{< relref "../datasources/jaeger/" >}})
-- [Zipkin]({{< relref "../datasources/zipkin/" >}})
+- [Tempo](/docs/grafana/<GRAFANA_VERSION>/datasources/tempo/)
+- [Jaeger](/docs/grafana/<GRAFANA_VERSION>/datasources/jaeger/)
+- [Zipkin](/docs/grafana/<GRAFANA_VERSION>/datasources/zipkin/)
 - [X-Ray](https://grafana.com/grafana/plugins/grafana-x-ray-datasource)
-- [Azure Monitor Application Insights]({{< relref "../datasources/azure-monitor/" >}})
+- [Azure Monitor](/docs/grafana/latest/datasources/azure-monitor/)
 - [ClickHouse](https://github.com/grafana/clickhouse-datasource)
-- [New Relic](https://grafana.com/grafana/plugins/grafana-newrelic-datasource)
-- [Infinity](https://grafana.com/grafana/plugins/yesoreyeram-infinity-datasource)
+- [New Relic](/docs/plugins/grafana-newrelic-datasource/latest/)
+- [Infinity](/docs/plugins/yesoreyeram-infinity-datasource/latest/)
 
-For information on how to configure queries for the data sources listed above, refer to the documentation for specific data source.
+Here are some references to learn more about traces and how you can use them:
 
-## Query editor
+- [Introduction to tracing](https://grafana.com/docs/tempo/<TEMPO_VERSION>/introduction/)
+- [Trace structure](https://grafana.com/docs/tempo/<TEMPO_VERSION>/traceql/trace-structure/#trace-structure)
+- [Traces and telemetry](https://grafana.com/docs/tempo/<TEMPO_VERSION>/introduction/telemetry/)
+- [Using traces to find solutions to problems](https://grafana.com/docs/tempo/<TEMPO_VERSION>/introduction/solutions-with-traces/)
+- [Best practices for tracing](/docs/grafana/<GRAFANA_VERSION>/datasources/tempo/tracing-best-practices/)
 
-You can query and search tracing data using a data source's query editor.
+## Query editors
 
-Each data source can have it's own query editor. The query editor for the Tempo data source is slightly different than the query editor for the Jaeger data source.
+You can query and search tracing data using a data source's query editor. Note that data sources in Grafana have unique query editors.
 
-For information on querying each data source, refer to their documentation:
-
-- [Tempo query editor]({{< relref "../datasources/tempo/query-editor" >}})
-- [Jaeger query editor]({{< relref "../datasources/jaeger/#query-the-data-source" >}})
-- [Zipkin query editor]({{< relref "../datasources/zipkin/#query-the-data-source" >}})
-- [Azure Monitor Application Insights query editor]({{< relref "../datasources/azure-monitor/query-editor/#query-application-insights-traces" >}})
-- [ClickHouse query editor](https://clickhouse.com/docs/en/integrations/grafana/query-builder#traces)
+For information on how to use the query editor to create queries for tracing data sources, refer to the documentation for each individual data source.
 
 ## Trace view
 
-This section explains the elements of the Trace View.
+Grafana's trace view provides an overview of a request as it travels through your system. The following sections provide detail on various elements of the trace view.
 
-{{< figure src="/media/docs/tempo/screenshot-grafana-trace-view.png" class="docs-image--no-shadow" max-width= "900px" caption="Screenshot of the trace view" >}}
+{{< figure src="/media/docs/tempo/screenshot-grafana-trace-view.png" class="docs-image--no-shadow" max-width= "900px" caption="Trace view" >}}
 
 ### Header
 
-{{< figure src="/media/docs/tempo/screenshot-grafana-trace-view-header.png" class="docs-image--no-shadow" max-width= "750px" caption="Screenshot of the trace view header" >}}
+The trace view header includes the following:
 
-- Header title: Shows the name of the root span and trace ID.
-- Search: Highlights spans containing the searched text.
-- Metadata: Various metadata about the trace.
+- **Header title** - Shows the name of the root span and trace ID.
+- **Search** - Highlights spans containing the searched text.
+- **Metadata** - Various metadata about the trace.
+
+{{< figure src="/media/docs/tempo/screenshot-grafana-trace-view-header.png" class="docs-image--no-shadow" max-width= "750px" caption="Trace view header" >}}
 
 ### Minimap
 
-{{< figure src="/media/docs/tempo/screenshot-grafana-trace-view-minimap.png" class="docs-image--no-shadow" max-width= "900px" caption="Screenshot of the trace view minimap" >}}
+**Minimap** displays a condensed view of the trace timeline. Drag your mouse over the minimap to zoom into a smaller time range. This also updates the main timeline, making it easier to view shorter spans
+When zoomed in, hovering over the minimap displays **Reset selection**, which resets the zoom.
 
-Shows condensed view or the trace timeline. Drag your mouse over the minimap to zoom into smaller time range. Zooming will also update the main timeline, so it is easy to see shorter spans. Hovering over the minimap, when zoomed, will show Reset Selection button which resets the zoom.
-
-### Span filters
-
-![Screenshot of span filtering](/media/docs/tempo/screenshot-grafana-tempo-span-filters-v10-1.png)
-
-Using span filters, you can filter your spans in the trace timeline viewer. The more filters you add, the more specific are the filtered spans.
-
-You can add one or more of the following filters:
-
-- Resource service name
-- Span name
-- Duration
-- Tags (which include tags, process tags, and log fields)
-
-To only show the spans you have matched, you can press the `Show matches only` toggle.
-
-{{< youtube id="VP2XV3IIc80" >}}
+{{< figure src="/media/docs/tempo/screenshot-grafana-trace-view-minimap.png" class="docs-image--no-shadow" max-width= "900px" caption="Trace view minimap example" >}}
 
 ### Timeline
 
-{{< figure src="/media/docs/tempo/screenshot-grafana-trace-view-timeline.png" class="docs-image--no-shadow" max-width= "900px"  caption="Screenshot of the trace view timeline" >}}
+Timeline shows list of spans within the trace. Each span row consists of the following components:
 
-Shows list of spans within the trace. Each span row consists of these components:
+- **Expand children** - Expands or collapses all the children spans of the selected span.
+- **Service name** - Name of the service logged the span.
+- **Operation name** - Name of the operation that this span represents.
+- **Span duration bar** - Visual representation of the operation duration within the trace.
 
-- Expand children button: Expands or collapses all the children spans of selected span.
-- Service name: Name of the service logged the span.
-- Operation name: Name of the operation that this span represents.
-- Span duration bar: Visual representation of the operation duration within the trace.
+Click anywhere on the span row to reveal span details.
 
-Clicking anywhere on the span row shows span details.
+{{< figure src="/media/docs/tempo/screenshot-grafana-trace-view-timeline.png" class="docs-image--no-shadow" max-width= "900px"  caption="Trace view timeline" >}}
 
 ### Span details
 
-{{< figure src="/media/docs/tempo/screenshot-grafana-trace-view-span-details.png" class="docs-image--no-shadow" max-width= "900px"  caption="Screenshot of the trace view span details" >}}
+Traces are composed of one or more spans.
+A span is a unit of work within a trace that has a start time relative to the beginning of the trace, a duration and an operation name for the unit of work.
+It usually has a reference to a parent span, unless it’s the first span, the root span, in a trace.
+It frequently includes key/value attributes that are relevant to the span itself, for example the HTTP method used in the request, as well as other metadata such as the service name, sub-span events, or links to other spans.
 
-- Operation name.
-- Span metadata.
-- Tags: Any tags associated with this span.
-- Process metadata: Metadata about the process that logged this span.
-- Logs: List of logs logged by this span and associated key values. In case of Zipkin logs section shows Zipkin annotations.
+You can expand any span in a trace and view the details, including the span and resource attributes.
+
+For more information about spans and traces, refer to [Introduction to tracing](https://grafana.com/docs/tempo/latest/introduction/) in the Tempo documentation.
+
+Span details include:
+
+- **Span attributes** - Key/value pairs that provides context for spans. For example, if the span deals with calling another service via HTTP, an attribute could include the HTTP URL (maybe as the span attribute key `http.url`) and the HTTP status code returned (as the span attribute `http.status_code`).
+
+- **Resource attributes** - Key/value pairs that describe the context of how the span was collected.
+
+Refer to [Span and resource attributes](/docs/tempo/<TEMPO_VERSION>/operations/best-practices/#span-and-resource-attributes) for more detail.
+
+{{< figure src="/media/docs/tempo/screenshot-grafana-trace-view-span-details.png" class="docs-image--no-shadow" max-width= "900px"  caption="Trace view span details" >}}
+
+### Span filters
+
+Span filters allow you to refine the spans displayed in the trace timeline viewer.
+The more filters you add, the more specific the filtered spans become.
+Click on a trace to access Span filters.
+
+![Screenshot of span filtering](/media/docs/tempo/screenshot-grafana-tempo-span-filters-v10-1.png)
+
+You can add one or more of the following filters:
+
+- **Service name** - Filter by selecting a service name from the dropdown.
+- **Span name** - Filter by selecting a span name from the dropdown.
+- **Duration** - Filter by duration. Accepted units include ns, us, ms, s, m, h.
+- **Tags** - Filter by tags, process tags, or log fields in your span.
+
+To only show the spans you have matched, toggle **Show matches only**.
+
+Refer to [Span filters](/docs/grafana/<GRAFANA_VERSION>/datasources/tempo/span-filters/) for more in depth information.
+
+Watch the following video to learn more about filtering trace spans in Grafana:
+{{< youtube id="VP2XV3IIc80" >}}
 
 ### Trace to logs
 
-You can navigate from a span in a trace view directly to logs relevant for that span. This feature is available for Tempo, Jaeger, and Zipkin data sources. Refer to their [relevant documentation](/docs/grafana/latest/datasources/tempo/#trace-to-logs) for configuration instructions.
-
-{{< figure src="/media/docs/tempo/screenshot-grafana-trace-view-trace-to-logs.png" class="docs-image--no-shadow" max-width= "900px" caption="Screenshot of the trace view in Explore with icon next to the spans" >}}
+You can navigate from a span in a trace view directly to logs relevant for that span.
+This feature is available for the Tempo, Jaeger, and Zipkin data sources.
+Refer to each individual data source's documentation for configuration instructions.
 
 Click the document icon to open a split view in Explore with the configured data source and query relevant logs for the span.
 
+{{< figure src="/media/docs/tempo/screenshot-grafana-trace-view-trace-to-logs.png" class="docs-image--no-shadow" max-width= "900px" caption="Trace to logs" >}}
+
 ### Trace to metrics
 
-{{% admonition type="note" %}}
-This feature is currently in beta and behind the `traceToMetrics` feature toggle.
-{{% /admonition %}}
+You can navigate from a span in a trace view directly to metrics relevant for that span.
+This feature is available for the Tempo, Jaeger, and Zipkin data sources.
 
-You can navigate from a span in a trace view directly to metrics relevant for that span. This feature is available for Tempo, Jaeger, and Zipkin data sources. Refer to their [relevant documentation](/docs/grafana/latest/datasources/tempo/configure-tempo-data-source/#trace-to-metrics) for configuration instructions.
+Refer to each individual data source's documentation for configuration instructions.
+For Tempo, refer to [Trace to metrics configuration](https://grafana.com/docs/grafana/<GRAFANA_VERSION>/datasources/tempo/configure-tempo-data-source/#trace-to-metrics).
 
 ### Trace to profiles
 
 Using Trace to profiles, you can use Grafana’s ability to correlate different signals by adding the functionality to link between traces and profiles.
-Refer to the [relevant documentation](/docs/grafana/latest/datasources/tempo/configure-tempo-data-source#trace-to-profiles) for configuration instructions.
+
+For Tempo refer to [Trace to profiles](/docs/grafana/<GRAFANA_VERSION>/datasources/tempo/configure-tempo-data-source#trace-to-profiles) for configuration instructions.
 
 {{< figure src="/static/img/docs/tempo/profiles/tempo-trace-to-profile.png" max-width="900px" class="docs-image--no-shadow" alt="Selecting a link in the span queries the profile data source" >}}
 
 ## Node graph
 
-You can optionally expand the node graph for the displayed trace. Depending on the data source, this can show spans of the trace as nodes in the graph, or as some additional context like service graph based on the current trace.
+You can also expand the node graph for a displayed trace. If the data source supports it, this displays spans of the trace as nodes in the graph, or provides additional context, such as a service graph based on the current trace.
 
-{{< figure src="/media/docs/tempo/screenshot-grafana-node-graph.png" class="docs-image--no-shadow" max-width= "900px"  caption="Screenshot of the node graph" >}}
+Refer to [Node graph](/docs/grafana/<GRAFANA_VERSION>/panels-visualizations/visualizations/node-graph/) for additional information.
 
-## Service Graph
+{{< admonition type="note" >}}
+The node graph requires data to be returned from the data source in a specific format to display correctly. Refer to [Data API](/docs/grafana/<GRAFANA_VERSION>/panels-visualizations/visualizations/node-graph/#data-api), [Nodes data frame structure](/docs/grafana/latest/panels-visualizations/visualizations/node-graph/#nodes-data-frame-structure) and [Node graph data requirements](/docs/grafana/latest/panels-visualizations/visualizations/node-graph/#data-requirements) for additional information and configuration instructions.
+{{< /admonition >}}
 
-The Service Graph visualizes the span metrics (traces data for rates, error rates, and durations (RED)) and service graphs.
-Once the requirements are set up, this pre-configured view is immediately available.
+{{< figure src="/media/docs/tempo/screenshot-grafana-node-graph.png" class="docs-image--no-shadow" max-width= "900px"  caption="Node graph" >}}
 
-For more information, refer to the [Service Graph view section]({{< relref "../datasources/tempo/#open-the-service-graph-view" >}}) of the Tempo data source page and the [service graph view page](/docs/tempo/latest/metrics-generator/service-graph-view/) in the Tempo documentation.
+## Service graph
 
-{{< figure src="/static/img/docs/grafana-cloud/apm-overview.png" class="docs-image--no-shadow" max-width= "900px" caption="Screenshot of the Service Graph view" >}}
+A service graph visualizes span metrics, including rates, error rates, and durations (RED), along with service relationships. Once the requirements are configured, this pre-configured view is immediately available.
 
-## Data API
+For additional information refer to the following documentation:
 
-This visualization needs a specific shape of the data to be returned from the data source in order to correctly display it.
+- [Service Graph and Service Graph view](/docs/grafana/<GRAFANA_VERSION>/datasources/tempo/service-graph/)
+- [Service graph view](/docs/tempo/<TEMPO_VERSION>/metrics-generator/service-graph-view/) in Tempo documentation
 
-Data source needs to return data frame and set `frame.meta.preferredVisualisationType = 'trace'`.
-
-### Data frame structure
-
-Required fields:
-
-| Field name   | Type                | Description                                                                                                                         |
-| ------------ | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
-| traceID      | string              | Identifier for the entire trace. There should be only one trace in the data frame.                                                  |
-| spanID       | string              | Identifier for the current span. SpanIDs should be unique per trace.                                                                |
-| parentSpanID | string              | SpanID of the parent span to create child parent relationship in the trace view. Can be `undefined` for root span without a parent. |
-| serviceName  | string              | Name of the service this span is part of.                                                                                           |
-| serviceTags  | TraceKeyValuePair[] | List of tags relevant for the service.                                                                                              |
-| startTime    | number              | Start time of the span in millisecond epoch time.                                                                                   |
-| duration     | number              | Duration of the span in milliseconds.                                                                                               |
-
-Optional fields:
-
-| Field name     | Type                | Description                                                        |
-| -------------- | ------------------- | ------------------------------------------------------------------ |
-| logs           | TraceLog[]          | List of logs associated with the current span.                     |
-| tags           | TraceKeyValuePair[] | List of tags associated with the current span.                     |
-| warnings       | string[]            | List of warnings associated with the current span.                 |
-| stackTraces    | string[]            | List of stack traces associated with the current span.             |
-| errorIconColor | string              | Color of the error icon in case span is tagged with `error: true`. |
-
-For details about the types see [TraceSpanRow](https://github.com/grafana/grafana/blob/main/packages/grafana-data/src/types/trace.ts#L28), [TraceKeyValuePair](https://github.com/grafana/grafana/blob/main/packages/grafana-data/src/types/trace.ts#L4) and [TraceLog](https://github.com/grafana/grafana/blob/main/packages/grafana-data/src/types/trace.ts#L12).
+{{< figure src="/static/img/docs/grafana-cloud/apm-overview.png" class="docs-image--no-shadow" max-width= "900px" caption="Service graph view" >}}
diff --git a/docs/sources/introduction/grafana-enterprise.md b/docs/sources/introduction/grafana-enterprise.md
index 2d29889a0d6..2eae40170b8 100644
--- a/docs/sources/introduction/grafana-enterprise.md
+++ b/docs/sources/introduction/grafana-enterprise.md
@@ -80,6 +80,7 @@ With a Grafana Enterprise license, you also get access to premium data sources,
 - [Azure Devops](/grafana/plugins/grafana-azuredevops-datasource)
 - [Catchpoint](/grafana/plugins/grafana-catchpoint-datasource)
 - [Cloudflare](/grafana/plugins/grafana-cloudflare-datasource)
+- [CockroachDB](/grafana/plugins/grafana-cockroachdb-datasource)
 - [Databricks](/grafana/plugins/grafana-databricks-datasource)
 - [DataDog](/grafana/plugins/grafana-datadog-datasource)
 - [Dynatrace](/grafana/plugins/grafana-dynatrace-datasource)
diff --git a/docs/sources/panels-visualizations/visualizations/time-series/index.md b/docs/sources/panels-visualizations/visualizations/time-series/index.md
index 00aa41bb1d7..5a1907da8d2 100644
--- a/docs/sources/panels-visualizations/visualizations/time-series/index.md
+++ b/docs/sources/panels-visualizations/visualizations/time-series/index.md
@@ -59,21 +59,26 @@ refs:
       destination: /docs/grafana/<GRAFANA_VERSION>/alerting/alerting-rules/create-grafana-managed-rule/
     - pattern: /docs/grafana-cloud/
       destination: /docs/grafana-cloud/alerting-and-irm/alerting/alerting-rules/create-grafana-managed-rule/
+  panel-editor-alerts:
+    - pattern: /docs/grafana/
+      destination: /docs/grafana/<GRAFANA_VERSION>/panels-visualizations/panel-editor-overview/#data-section
+    - pattern: /docs/grafana-cloud/
+      destination: /docs/grafana-cloud/visualizations/panels-visualizations/panel-editor-overview/#data-section
 ---
 
 # Time series
 
-Time series visualizations are the default and primary way to visualize data points over intervals of time as a graph. They can render series as lines, points, or bars. They're versatile enough to display almost any time-series data.
+Time series visualizations are the default way to visualize data points over intervals of time, as a graph. They can render series as lines, points, or bars and are versatile enough to display almost any time-series data.
 
 {{< figure src="/static/img/docs/time-series-panel/time_series_small_example.png" max-width="1200px" alt="Time series" >}}
 
 {{< admonition type="note" >}}
-You can migrate from the old Graph visualization to the new time series visualization. To migrate, open the panel and click the **Migrate** button in the side pane.
+You can migrate from the legacy Graph visualization to the time series visualization. To migrate, open the panel and click the **Migrate** button in the side pane.
 {{< /admonition >}}
 
 ## Configure a time series visualization
 
-The following video guides you through the creation steps and common customizations of time series visualizations and is great for beginners:
+The following video guides you through the creation steps and common customizations of time series visualizations, and is great for beginners:
 
 {{< youtube id="RKtW87cPxsw" >}}
 
@@ -81,40 +86,37 @@ The following video guides you through the creation steps and common customizati
 
 ## Supported data formats
 
-Time series visualizations require time series data; that is a sequence of measurements, ordered in time, where every row in the table represents one individual measurement at a specific time. Learn more about [time series data](https://grafana.com/docs/grafana/<GRAFANA_VERSION>/fundamentals/timeseries/).
+Time series visualizations require time-series data&mdash;a sequence of measurements, ordered in time, and formatted as a table&mdash;where every row in the table represents one individual measurement at a specific time. Learn more about [time-series data](https://grafana.com/docs/grafana/<GRAFANA_VERSION>/fundamentals/timeseries/).
 
 ## Alert rules
 
-You can [link alert rules](ref:link-alert) to time series visualizations to observe when alerts fire and are resolved in the form of annotations. In addition, you can create alert rules from the **Alert** tab within the panel editor.
+You can [link alert rules](ref:link-alert) to time series visualizations in the form of annotations to observe when alerts fire and are resolved. In addition, you can create alert rules from the **Alert** tab within the [panel editor](ref:panel-editor-alerts).
 
-## Transform override property
+## Special overrides
 
-Use the **Transform** override property to transform series values without affecting the values shown in the tooltip, context menu, or legend.
+The following overrides help you further refine a time series visualization.
 
-<!-- add more information about how to access this property -->
+### Transform override property
 
-- **Negative Y transform:** Flip the results to negative values on the Y axis.
-- **Constant:** Show the first value as a constant line.
+Use the **Graph styles > Transform** [override property](#field-overrides) to transform series values without affecting the values shown in the tooltip, context menu, or legend. Choose from the following transform options:
 
-{{< docs/shared lookup="visualizations/multiple-y-axes.md" source="grafana" version="<GRAFANA_VERSION>" leveloffset="+1" >}}
+- **Constant** - Show the first value as a constant line.
+- **Negative Y transform** - Flip the results to negative values on the y-axis.
 
-<!-- update shared filed above to add actual steps for adding this override -->
+### Fill below to override property
 
-## Add the Fill below to override
-
-The **Fill below to** option fills the area between two series. This option is only available as a series/field override.
-
-1. Edit the panel and click **Overrides**.
-1. Select the fields to fill below.
-1. In **Add override property**, select **Fill below to**.
-1. Select the series for which you want the fill to stop.
+The **Graph styles > Fill below to** [override property](#field-overrides) fills the area between two series. When you configure the property, select the series for which you want the fill to stop.
 
 The following example shows three series: Min, Max, and Value. The Min and Max series have **Line width** set to 0. Max has a **Fill below to** override set to Min, which fills the area between Max and Min with the Max line color.
 
 {{< figure src="/static/img/docs/time-series-panel/fill-below-to-7-4.png" max-width="600px" alt="Fill below to example" >}}
 
+{{< docs/shared lookup="visualizations/multiple-y-axes.md" source="grafana" version="<GRAFANA_VERSION>" leveloffset="+2" >}}
+
 ## Configuration options
 
+{{< docs/shared lookup="visualizations/config-options-intro.md" source="grafana" version="<GRAFANA_VERSION>" >}}
+
 ### Panel options
 
 {{< docs/shared lookup="visualizations/panel-options.md" source="grafana" version="<GRAFANA_VERSION>" >}}
@@ -129,30 +131,30 @@ The following example shows three series: Min, Max, and Value. The Min and Max s
 
 ### Axis options
 
-Options under the axis category change how the x- and y-axes are rendered. Some options do not take effect until you click outside of the field option box you are editing. You can also or press `Enter`.
+Options under the **Axis** section control how the x- and y-axes are rendered. Some options don't take effect until you click outside of the field option box you're editing. You can also press `Enter`.
 
-| Option                             | Description                                                                                                                                                                                                                                                                                                                                                                       |
-| ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| Time zone                          | Set the desired time zone(s) to display along the x-axis.                                                                                                                                                                                                                                                                                                                         |
-| [Placement](#placement)            | Select the placement of the y-axis.                                                                                                                                                                                                                                                                                                                                               |
-| Label                              | Set a y-axis text label. If you have more than one y-axis, then you can assign different labels using an override.                                                                                                                                                                                                                                                                |
-| Width                              | Set a fixed width of the axis. By default, Grafana dynamically calculates the width of an axis. By setting the width of the axis, data with different axes types can share the same display proportions. This setting makes it easier for you to compare more than one graph’s worth of data because the axes are not shifted or stretched within visual proximity to each other. |
-| Show grid lines                    | Set the axis grid line visibility.<br>                                                                                                                                                                                                                                                                                                                                            |
-| Color                              | Set the color of the axis.                                                                                                                                                                                                                                                                                                                                                        |
-| Show border                        | Set the axis border visibility.                                                                                                                                                                                                                                                                                                                                                   |
-| Scale                              | Set the y-axis values scale.<br>                                                                                                                                                                                                                                                                                                                                                  |
-| Centered zero                      | Set the y-axis to be centered on zero.                                                                                                                                                                                                                                                                                                                                            |
-| [Soft min](#soft-min-and-soft-max) | Set a soft min to better control the y-axis limits. zero.                                                                                                                                                                                                                                                                                                                         |
-| [Soft max](#soft-min-and-soft-max) | Set a soft max to better control the y-axis limits. zero.                                                                                                                                                                                                                                                                                                                         |
+| Option                             | Description                                                                                                                                                                                                                                                                                                                                                                      |
+| ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| Time zone                          | Set the desired time zones to display along the x-axis.                                                                                                                                                                                                                                                                                                                          |
+| [Placement](#placement)            | Select the placement of the y-axis.                                                                                                                                                                                                                                                                                                                                              |
+| Label                              | Set a y-axis text label. If you have more than one y-axis, then you can assign different labels using an override.                                                                                                                                                                                                                                                               |
+| Width                              | Set a fixed width of the axis. By default, Grafana dynamically calculates the width of an axis. By setting the width of the axis, data with different axes types can share the same display proportions. This setting makes it easier for you to compare more than one graph’s worth of data because the axes aren't shifted or stretched within visual proximity to each other. |
+| Show grid lines                    | Set the axis grid line visibility.<br>                                                                                                                                                                                                                                                                                                                                           |
+| Color                              | Set the color of the axis.                                                                                                                                                                                                                                                                                                                                                       |
+| Show border                        | Set the axis border visibility.                                                                                                                                                                                                                                                                                                                                                  |
+| Scale                              | Set the y-axis values scale.<br>                                                                                                                                                                                                                                                                                                                                                 |
+| Centered zero                      | Set the y-axis so it's centered on zero.                                                                                                                                                                                                                                                                                                                                         |
+| [Soft min](#soft-min-and-soft-max) | Set a soft min to better control the y-axis limits. zero.                                                                                                                                                                                                                                                                                                                        |
+| [Soft max](#soft-min-and-soft-max) | Set a soft max to better control the y-axis limits. zero.                                                                                                                                                                                                                                                                                                                        |
 
 #### Placement
 
-Select the placement of the y-axis.
+Select the placement of the y-axis. Choose from the following:
 
-- **Auto:** Automatically assigns the y-axis to the series. When there are two or more series with different units, Grafana assigns the left axis to the first unit and the right axis to the units that follow.
-- **Left:** Display all y-axes on the left side.
-- **Right:** Display all y-axes on the right side.
-- **Hidden:** Hide all axes. To selectively hide axes, [Add a field override](ref:add-a-field-override) that targets specific fields.
+- **Auto** - Automatically assigns the y-axis to the series. When there are two or more series with different units, Grafana assigns the left axis to the first unit and the right axis to the units that follow.
+- **Left** - Display all y-axes on the left side.
+- **Right** - Display all y-axes on the right side.
+- **Hidden** - Hide all axes. To selectively hide axes, [Add a field override](ref:add-a-field-override) that targets specific fields.
 
 #### Soft min and soft max
 
@@ -166,71 +168,69 @@ To define hard limits of the y-axis, set standard min/max options. For more info
 
 ### Graph styles options
 
+The options under the **Graph styles** section let you control the general appearance of the graph, excluding [color](#standard-options).
+
 | Option                                      | Description                                                                                                                                                                                                                           |
 | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| [Style](#style)                             | Use this option to define how to display your time series data.                                                                                                                                                                       |
-| [Line interpolation](#line-interpolation)   | This option controls how the graph interpolates the series line.                                                                                                                                                                      |
-| [Line width](#line-width)                   | Line width is a slider that controls the thickness for series lines or the outline for bars.                                                                                                                                          |
-| [Fill opacity](#fill-opacity)               | Use opacity to specify the series area fill color.                                                                                                                                                                                    |
-| [Gradient mode](#gradient-mode)             | Gradient mode specifies the gradient fill, which is based on the series color.                                                                                                                                                        |
-| [Line style](#line-style)                   | Set the style of the line.                                                                                                                                                                                                            |
+| [Style](#style)                             | Choose whether to display your time-series data as lines, bars, or points.                                                                                                                                                            |
+| [Line interpolation](#line-interpolation)   | Choose how the graph interpolates the series line.                                                                                                                                                                                    |
+| Line width                                  | Set the thickness of the series lines or the outline for bars using the **Line width** slider.                                                                                                                                        |
+| [Fill opacity](#fill-opacity)               | Set the series area fill color using the **Fill opacity** slider.                                                                                                                                                                     |
+| [Gradient mode](#gradient-mode)             | Choose a gradient mode to control the gradient fill, which is based on the series color.                                                                                                                                              |
+| [Line style](#line-style)                   | Choose a solid, dashed, or dotted line style.                                                                                                                                                                                         |
 | [Connect null values](#connect-null-values) | Choose how null values, which are gaps in the data, appear on the graph.                                                                                                                                                              |
 | [Disconnect values](#disconnect-values)     | Choose whether to set a threshold above which values in the data should be disconnected.                                                                                                                                              |
-| [Show points](#show-points)                 | You can configure your visualization to add points to lines or bars.                                                                                                                                                                  |
+| [Show points](#show-points)                 | Set whether to show data points to lines or bars.                                                                                                                                                                                     |
 | Point size                                  | Set the size of the points, from 1 to 40 pixels in diameter.                                                                                                                                                                          |
-| [Stack series](#stack-series)               | Stacking allows Grafana to display series on top of each other.                                                                                                                                                                       |
+| [Stack series](#stack-series)               | Set whether Grafana displays series on top of each other.                                                                                                                                                                             |
 | [Bar alignment](#bar-alignment)             | Set the position of the bar relative to a data point.                                                                                                                                                                                 |
 | Bar width factor                            | Set the width of the bar relative to minimum space between data points. A factor of 0.5 means that the bars take up half of the available space between data points. A factor of 1.0 means that the bars take up all available space. |
 
 #### Style
 
-Use this option to define how to display your time series data. You can use overrides to combine multiple styles in the same graph.
-
-- Lines
-- Bars
-- Points
+Choose whether to display your time-series data as lines, bars, or points. You can use overrides to combine multiple styles in the same graph. Choose from the following:
 
 ![Style modes](/static/img/docs/time-series-panel/style-modes-v9.png)
 
 #### Line interpolation
 
-This option controls how the graph interpolates the series line.
+Choose how the graph interpolates the series line:
 
-- **Linear:** Points are joined by straight lines.
-- **Smooth:** Points are joined by curved lines that smooths transitions between points.
-- **Step before:** The line is displayed as steps between points. Points are rendered at the end of the step.
-- **Step after:** The line is displayed as steps between points. Points are rendered at the beginning of the step.
+- **Linear** - Points are joined by straight lines.
+- **Smooth** - Points are joined by curved lines that smooths transitions between points.
+- **Step before** - The line is displayed as steps between points. Points are rendered at the end of the step.
+- **Step after** - The line is displayed as steps between points. Points are rendered at the beginning of the step.
 
 #### Line width
 
-Line width is a slider that controls the thickness for series lines or the outline for bars.
+Set the thickness of the series lines or the outline for bars using the **Line width** slider.
 
 #### Fill opacity
 
-Use opacity to specify the series area fill color.
+Set the series area fill color using the **Fill opacity** slider.
 
 ![Fill opacity examples](/static/img/docs/time-series-panel/fill-opacity.png)
 
 #### Gradient mode
 
-Gradient mode specifies the gradient fill, which is based on the series color. To change the color, use the standard color scheme field option. For more information, refer to [Color scheme](ref:color-scheme).
+Choose a gradient mode to control the gradient fill, which is based on the series color. To change the color, use the standard color scheme field option. For more information, refer to [Color scheme](ref:color-scheme).
 
-- **None:** No gradient fill. This is the default setting.
-- **Opacity:** An opacity gradient where the opacity of the fill increases as y-axis values increase.
-- **Hue:** A subtle gradient that is based on the hue of the series color.
-- **Scheme:** A color gradient defined by your [Color scheme](ref:color-scheme). This setting is used for the fill area and line. For more information about scheme, refer to [Scheme gradient mode](#scheme-gradient-mode).
+- **None** - No gradient fill. This is the default setting.
+- **Opacity** - An opacity gradient where the opacity of the fill increases as y-axis values increase.
+- **Hue** - A subtle gradient that's based on the hue of the series color.
+- **Scheme** - A color gradient defined by your [Color scheme](ref:color-scheme). This setting is used for the fill area and line. For more information about scheme, refer to [Scheme gradient mode](#scheme-gradient-mode).
 
-Gradient appearance is influenced by the **Fill opacity** setting. The following image show, the **Fill opacity** is set to 50.
+Gradient appearance is influenced by the **Fill opacity** setting. The following image shows the **Fill opacity** set to 50.
 
 ![Gradient mode examples](/static/img/docs/time-series-panel/gradient-modes-v9.png)
 
 ##### Scheme gradient mode
 
-The **Gradient mode** option located under the **Graph styles** has a mode named **Scheme**. When you enable **Scheme**, the line or bar receives a gradient color defined from the selected **Color scheme**.
+The **Gradient mode** option located under the **Graph styles** section has a mode called **Scheme**. When you enable **Scheme**, the line or bar receives a gradient color defined from the selected **Color scheme**.
 
 ###### From thresholds
 
-If the **Color scheme** is set to **From thresholds (by value)** and **Gradient mode** is set to **Scheme**, then the line or bar color changes as they cross the defined thresholds.
+If the **Color scheme** is set to **From thresholds (by value)** and **Gradient mode** is set to **Scheme**, then the line or bar color changes as it crosses the defined thresholds.
 
 {{< figure src="/static/img/docs/time-series-panel/gradient_mode_scheme_thresholds_line.png" max-width="1200px" alt="Colors scheme: From thresholds" >}}
 
@@ -242,11 +242,11 @@ The following image shows a line chart with the **Green-Yellow-Red (by value)**
 
 #### Line style
 
-Set the style of the line. To change the color, use the standard [color scheme](ref:color-scheme) field option.
+Choose a solid, dashed, or dotted line style:
 
-- **Solid:** Display a solid line. This is the default setting.
-- **Dash:** Display a dashed line. When you choose this option, a list appears for you to select the length and gap (length, gap) for the line dashes. Dash spacing set to 10, 10 (default).
-- **Dots:** Display dotted lines. When you choose this option, a list appears for you to select the gap (length = 0, gap) for the dot spacing. Dot spacing set to 0, 10 (default)
+- **Solid** - Display a solid line. This is the default setting.
+- **Dash** - Display a dashed line. When you choose this option, a list appears for you to select the length and gap (length, gap) for the line dashes. Dash spacing is 10, 10 by default.
+- **Dots** - Display dotted lines. When you choose this option, a list appears for you to select the gap (length = 0, gap) for the dot spacing. Dot spacing is 0, 10 by default.
 
 ![Line styles examples](/static/img/docs/time-series-panel/line-styles-examples-v9.png)
 
@@ -254,21 +254,23 @@ Set the style of the line. To change the color, use the standard [color scheme](
 
 {{< docs/shared lookup="visualizations/disconnect-values.md" source="grafana" version="<GRAFANA_VERSION>" leveloffset="+1" >}}
 
+To change the color, use the standard [color scheme](ref:color-scheme) field option.
+
 #### Show points
 
-You can configure your visualization to add points to lines or bars.
+Set whether to show data points as lines or bars. Choose from the following:
 
-- **Auto:** Grafana determines to show or not to show points based on the density of the data. If the density is low, then points appear.
-- **Always:** Show the points regardless of how dense the data set is.
-- **Never:** Do not show points.
+- **Auto** - Grafana determines a point's visibility based on the density of the data. If the density is low, then points appear.
+- **Always** - Show the points regardless of how dense the data set is.
+- **Never** - Don't show points.
 
 #### Stack series
 
-_Stacking_ allows Grafana to display series on top of each other. Be cautious when using stacking in the visualization as it can easily create misleading graphs. To read more about why stacking might not be the best approach, refer to [The issue with stacking](https://www.data-to-viz.com/caveat/stacking.html).
+Set whether Grafana stacks or displays series on top of each other. Be cautious when using stacking because it can create misleading graphs. To read more about why stacking might not be the best approach, refer to [The issue with stacking](https://www.data-to-viz.com/caveat/stacking.html). Choose from the following:
 
-- **Off:** Turns off series stacking. When **Off**, all series share the same space in the visualization.
-- **Normal:** Stacks series on top of each other.
-- **100%:** Stack by percentage where all series add up to 100%.
+- **Off** - Turns off series stacking. When **Off**, all series share the same space in the visualization.
+- **Normal** - Stacks series on top of each other.
+- **100%** - Stack by percentage where all series add up to 100%.
 
 ##### Stack series in groups
 
@@ -283,7 +285,7 @@ The stacking group option is only available as an override. For more information
 
 #### Bar alignment
 
-Set the position of the bar relative to a data point. In the examples below, **Show points** is set to **Always** which makes it easier to see the difference this setting makes. The points do not change; the bars change in relationship to the points.
+Set the position of the bar relative to a data point. In the examples below, **Show points** is set to **Always** which makes it easier to see the difference this setting makes. The points don't change, but the bars change in relationship to the points. Choose from the following:
 
 - **Before** ![Bar alignment before icon](/static/img/docs/time-series-panel/bar-alignment-before.png)
   The bar is drawn before the point. The point is placed on the trailing corner of the bar.
diff --git a/docs/sources/panels-visualizations/visualizations/xy-chart/index.md b/docs/sources/panels-visualizations/visualizations/xy-chart/index.md
index d28cc0f153e..1e3f4d341dd 100644
--- a/docs/sources/panels-visualizations/visualizations/xy-chart/index.md
+++ b/docs/sources/panels-visualizations/visualizations/xy-chart/index.md
@@ -59,10 +59,6 @@ refs:
 
 # XY chart
 
-{{< admonition type="note">}}
-To use xy charts, enable the `autoMigrateXYChartPanel` [feature toggle](https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/feature-toggles/).
-{{< /admonition >}}
-
 XY charts provide a way to visualize arbitrary x and y values in a graph so that you can easily show the relationship between two variables. XY charts are typically used to create scatter plots. You can also use them to create bubble charts where field values determine the size of each bubble:
 
 ![An xy chart showing height weight distribution](/media/docs/grafana/panels-visualizations/screenshot-xy-charts-v11.0.png)
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 835f7ac2089..a9c8b02cd6f 100644
--- a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md
+++ b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md
@@ -27,6 +27,7 @@ Most [generally available](https://grafana.com/docs/release-life-cycle/#general-
 | `publicDashboards`                     | [Deprecated] Public dashboards are now enabled by default; to disable them, use the configuration setting. This feature toggle will be removed in the next major version.                                                    | Yes                |
 | `featureHighlights`                    | Highlight Grafana Enterprise features                                                                                                                                                                                        |                    |
 | `correlations`                         | Correlations page                                                                                                                                                                                                            | Yes                |
+| `autoMigrateXYChartPanel`              | Migrate old XYChart panel to new XYChart2 model                                                                                                                                                                              | Yes                |
 | `cloudWatchCrossAccountQuerying`       | Enables cross-account querying in CloudWatch datasources                                                                                                                                                                     | Yes                |
 | `nestedFolders`                        | Enable folder nesting                                                                                                                                                                                                        | Yes                |
 | `logsContextDatasourceUi`              | Allow datasource to provide custom UI for context view                                                                                                                                                                       | Yes                |
@@ -80,7 +81,6 @@ Most [generally available](https://grafana.com/docs/release-life-cycle/#general-
 | `autoMigratePiechartPanel`             | Migrate old piechart panel to supported piechart panel - broken out from autoMigrateOldPanels to enable granular tracking                                                                    |
 | `autoMigrateWorldmapPanel`             | Migrate old worldmap panel to supported geomap panel - broken out from autoMigrateOldPanels to enable granular tracking                                                                      |
 | `autoMigrateStatPanel`                 | Migrate old stat panel to supported stat panel - broken out from autoMigrateOldPanels to enable granular tracking                                                                            |
-| `autoMigrateXYChartPanel`              | Migrate old XYChart panel to new XYChart2 model                                                                                                                                              |
 | `disableAngular`                       | Dynamic flag to disable angular at runtime. The preferred method is to set `angular_support_enabled` to `false` in the [security] settings, which allows you to change the state at runtime. |
 | `grpcServer`                           | Run the GRPC server                                                                                                                                                                          |
 | `accessControlOnCall`                  | Access control primitives for OnCall                                                                                                                                                         |
diff --git a/docs/sources/shared/visualizations/config-options-intro.md b/docs/sources/shared/visualizations/config-options-intro.md
new file mode 100644
index 00000000000..94173717f11
--- /dev/null
+++ b/docs/sources/shared/visualizations/config-options-intro.md
@@ -0,0 +1,7 @@
+---
+title: Configuration options intro text
+comments: |
+  This file is used in the following in all visualizations except: alert list, annotiations list, logs, news, text
+---
+
+The following section describes the configuration options available in the panel editor pane for this visualization. These options are, as much as possible, ordered as they appear in Grafana.
diff --git a/docs/sources/shared/visualizations/connect-null-values.md b/docs/sources/shared/visualizations/connect-null-values.md
index d1190a63a92..50660321f93 100644
--- a/docs/sources/shared/visualizations/connect-null-values.md
+++ b/docs/sources/shared/visualizations/connect-null-values.md
@@ -6,6 +6,6 @@ title: Connect null values
 
 Choose how null values, which are gaps in the data, appear on the graph. Null values can be connected to form a continuous line or set to a threshold above which gaps in the data are no longer connected.
 
-- **Never:** Time series data points with gaps in the data are never connected.
-- **Always:** Time series data points with gaps in the data are always connected.
-- **Threshold:** Specify a threshold above which gaps in the data are no longer connected. This can be useful when the connected gaps in the data are of a known size and/or within a known range, and gaps outside this range should no longer be connected.
+- **Never** - Time series data points with gaps in the data are never connected.
+- **Always** - Time series data points with gaps in the data are always connected.
+- **Threshold** - Specify a threshold above which gaps in the data are no longer connected. This can be useful when the connected gaps in the data are of a known size and/or within a known range, and gaps outside this range should no longer be connected.
diff --git a/docs/sources/shared/visualizations/disconnect-values.md b/docs/sources/shared/visualizations/disconnect-values.md
index 72b40153a2d..cba32cfc6fb 100644
--- a/docs/sources/shared/visualizations/disconnect-values.md
+++ b/docs/sources/shared/visualizations/disconnect-values.md
@@ -6,5 +6,5 @@ title: Disconnect values
 
 Choose whether to set a threshold above which values in the data should be disconnected.
 
-- **Never:** Time series data points in the data are never disconnected.
-- **Threshold:** Specify a threshold above which values in the data are disconnected. This can be useful when desired values in the data are of a known size and/or within a known range, and values outside this range should no longer be connected.
+- **Never** - Time series data points in the data are never disconnected.
+- **Threshold** - Specify a threshold above which values in the data are disconnected. This can be useful when desired values in the data are of a known size and/or within a known range, and values outside this range should no longer be connected.
diff --git a/docs/sources/shared/visualizations/legend-options-1.md b/docs/sources/shared/visualizations/legend-options-1.md
index 30123dda0d4..a81d1aa45fc 100644
--- a/docs/sources/shared/visualizations/legend-options-1.md
+++ b/docs/sources/shared/visualizations/legend-options-1.md
@@ -12,6 +12,6 @@ Legend options control the series names and statistics that appear under or to t
 | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
 | Visibility | Toggle the switch to turn the legend on or off.                                                                                                                                                            |
 | Mode       | Use these settings to define how the legend appears in your visualization. **List** displays the legend as a list. This is a default display mode of the legend. **Table** displays the legend as a table. |
-| Placement  | Choose where to display the legend. **Bottom -** Below the graph. **Right -** To the right of the graph.                                                                                                   |
+| Placement  | Choose where to display the legend. **Bottom** places the legend below the graph. **Right** places the legend to the right of the graph.                                                                   |
 | Width      | Control how wide the legend is when placed on the right side of the visualization. This option is only displayed if you set the legend placement to **Right**.                                             |
 | Values     | Choose which of the [standard calculations](../../query-transform-data/calculation-types/) to show in the legend. You can have more than one.                                                              |
diff --git a/docs/sources/shared/visualizations/multiple-y-axes.md b/docs/sources/shared/visualizations/multiple-y-axes.md
index 243f73bda5c..4d74d3b9501 100644
--- a/docs/sources/shared/visualizations/multiple-y-axes.md
+++ b/docs/sources/shared/visualizations/multiple-y-axes.md
@@ -1,9 +1,9 @@
 ---
-title: Display multiple y-axes
+title: Multiple y-axes
 ---
 
-# Display multiple y-axes
+# Multiple y-axes
 
-In some cases, you may want to display multiple y-axes. For example, if you have a dataset showing both temperature and humidity over time, you may want to show two y-axes with different units for these two series.
+In some cases, you might want to display multiple y-axes. For example, if you have a dataset showing both temperature and humidity over time, you might want to show two y-axes with different units for the two series.
 
-You can do this by [adding field overrides]({{< relref "../../panels-visualizations/configure-overrides#add-a-field-override" >}}). Follow the steps as many times as required to add as many y-axes as you need.
+You can configure multiple y-axes and control where they're displayed in the visualization by adding field overrides. [This example of a dataset that includes temperature and humidity](../../configure-overrides/#example-2-format-temperature-and-humidity) describes how you can configure that. Repeat the steps for every y-axis you wish to display.
diff --git a/docs/sources/shared/visualizations/overrides-options.md b/docs/sources/shared/visualizations/overrides-options.md
index 71e7ce8ebcd..21b910af4cb 100644
--- a/docs/sources/shared/visualizations/overrides-options.md
+++ b/docs/sources/shared/visualizations/overrides-options.md
@@ -6,7 +6,7 @@ comments: |
 
 Overrides allow you to customize visualization settings for specific fields or series. When you add an override rule, it targets a particular set of fields and lets you define multiple options for how that field is displayed.
 
-Choose from one the following override options:
+Choose from the following override options:
 
 | Option                         | Description                                                                                                   |
 | ------------------------------ | ------------------------------------------------------------------------------------------------------------- |
diff --git a/docs/sources/shared/visualizations/panel-options.md b/docs/sources/shared/visualizations/panel-options.md
index 5455933bb54..c013457d191 100644
--- a/docs/sources/shared/visualizations/panel-options.md
+++ b/docs/sources/shared/visualizations/panel-options.md
@@ -4,4 +4,4 @@ comments: |
   This file is used in all visualizations pages
 ---
 
-In the **Panel options** section of the panel editor pane, you set basic options like the panel title and description. You can also configure repeating panels in this section. To learn more, refer to [Configure panel options](../../configure-panel-options/).
+In the **Panel options** section of the panel editor pane, set basic options like panel title and description, as well as panel links. To learn more, refer to [Configure panel options](../../configure-panel-options/).
diff --git a/docs/sources/shared/visualizations/standard-options.md b/docs/sources/shared/visualizations/standard-options.md
index f4d84606fd5..db489bd09e3 100644
--- a/docs/sources/shared/visualizations/standard-options.md
+++ b/docs/sources/shared/visualizations/standard-options.md
@@ -6,8 +6,6 @@ comments: |
 
 **Standard options** in the panel editor pane let you change how field data is displayed in your visualizations. When you set a standard option, the change is applied to all fields or series. For more granular control over the display of fields, refer to [Configure overrides](../../configure-overrides/).
 
-You can customize the following standard options:
-
 | Option        | Description                                                                                                                                       |
 | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
 | Unit          | Choose which unit a field should use.                                                                                                             |
diff --git a/docs/sources/shared/visualizations/thresholds-options-1.md b/docs/sources/shared/visualizations/thresholds-options-1.md
index 264e53839ca..3b2fc6b8f6b 100644
--- a/docs/sources/shared/visualizations/thresholds-options-1.md
+++ b/docs/sources/shared/visualizations/thresholds-options-1.md
@@ -8,7 +8,7 @@ comments: |
 
 A threshold is a value or limit you set for a metric that’s reflected visually when it’s met or exceeded. Thresholds are one way you can conditionally style and color your visualizations based on query results.
 
-Set the following options:
+For each threshold, set the following options:
 
 | Option          | Description                                                                          |
 | --------------- | ------------------------------------------------------------------------------------ |
diff --git a/package.json b/package.json
index cd1844afef5..ae06847fb0b 100644
--- a/package.json
+++ b/package.json
@@ -119,7 +119,7 @@
     "@types/lodash": "4.17.7",
     "@types/logfmt": "^1.2.3",
     "@types/lucene": "^2",
-    "@types/node": "20.14.13",
+    "@types/node": "20.14.14",
     "@types/node-forge": "^1",
     "@types/ol-ext": "npm:@siedlerchr/types-ol-ext@3.2.4",
     "@types/pluralize": "^0.0.33",
@@ -172,7 +172,7 @@
     "eslint-config-prettier": "9.1.0",
     "eslint-plugin-import": "^2.26.0",
     "eslint-plugin-jest": "28.6.0",
-    "eslint-plugin-jsdoc": "48.10.2",
+    "eslint-plugin-jsdoc": "48.11.0",
     "eslint-plugin-jsx-a11y": "6.9.0",
     "eslint-plugin-lodash": "7.4.0",
     "eslint-plugin-no-barrel-files": "^1.1.0",
@@ -187,7 +187,7 @@
     "html-loader": "5.1.0",
     "html-webpack-plugin": "5.6.0",
     "http-server": "14.1.1",
-    "i18next-parser": "8.13.0",
+    "i18next-parser": "9.0.1",
     "jest": "29.7.0",
     "jest-canvas-mock": "2.5.2",
     "jest-date-mock": "1.0.10",
@@ -199,7 +199,7 @@
     "knip": "^5.10.0",
     "lerna": "8.1.7",
     "mini-css-extract-plugin": "2.9.0",
-    "msw": "2.3.4",
+    "msw": "2.3.5",
     "mutationobserver-shim": "0.3.7",
     "ngtemplate-loader": "2.1.0",
     "node-notifier": "10.0.1",
diff --git a/packages/grafana-data/package.json b/packages/grafana-data/package.json
index 377150b3e9c..b9e56523c4a 100644
--- a/packages/grafana-data/package.json
+++ b/packages/grafana-data/package.json
@@ -66,7 +66,7 @@
     "@types/dompurify": "^3.0.0",
     "@types/history": "4.7.11",
     "@types/lodash": "4.17.7",
-    "@types/node": "20.14.13",
+    "@types/node": "20.14.14",
     "@types/papaparse": "5.3.14",
     "@types/react": "18.3.3",
     "@types/react-dom": "18.2.25",
diff --git a/packages/grafana-e2e-selectors/package.json b/packages/grafana-e2e-selectors/package.json
index 0192643eee7..f289eb45131 100644
--- a/packages/grafana-e2e-selectors/package.json
+++ b/packages/grafana-e2e-selectors/package.json
@@ -40,7 +40,7 @@
   },
   "devDependencies": {
     "@rollup/plugin-node-resolve": "15.2.3",
-    "@types/node": "20.14.13",
+    "@types/node": "20.14.14",
     "esbuild": "0.20.2",
     "rimraf": "5.0.7",
     "rollup": "2.79.1",
diff --git a/packages/grafana-flamegraph/package.json b/packages/grafana-flamegraph/package.json
index 4bdae15871c..c6bb7ee4bf4 100644
--- a/packages/grafana-flamegraph/package.json
+++ b/packages/grafana-flamegraph/package.json
@@ -68,7 +68,7 @@
     "@types/d3": "^7",
     "@types/jest": "^29.5.4",
     "@types/lodash": "4.17.7",
-    "@types/node": "20.14.13",
+    "@types/node": "20.14.14",
     "@types/react": "18.3.3",
     "@types/react-virtualized-auto-sizer": "1.0.4",
     "@types/tinycolor2": "1.4.6",
diff --git a/packages/grafana-icons/package.json b/packages/grafana-icons/package.json
index 2386ed8e776..a7ea505fbb0 100644
--- a/packages/grafana-icons/package.json
+++ b/packages/grafana-icons/package.json
@@ -45,7 +45,7 @@
     "@svgr/plugin-prettier": "^8.1.0",
     "@svgr/plugin-svgo": "^8.1.0",
     "@types/babel__core": "^7",
-    "@types/node": "20.14.13",
+    "@types/node": "20.14.14",
     "@types/react": "18.3.3",
     "@types/react-dom": "18.2.25",
     "esbuild": "0.20.2",
diff --git a/packages/grafana-o11y-ds-frontend/package.json b/packages/grafana-o11y-ds-frontend/package.json
index c28714bbca2..e9a02d3644e 100644
--- a/packages/grafana-o11y-ds-frontend/package.json
+++ b/packages/grafana-o11y-ds-frontend/package.json
@@ -36,7 +36,7 @@
     "@testing-library/react": "15.0.2",
     "@testing-library/user-event": "14.5.2",
     "@types/jest": "^29.5.4",
-    "@types/node": "20.14.13",
+    "@types/node": "20.14.14",
     "@types/react": "18.3.3",
     "@types/systemjs": "6.13.5",
     "@types/testing-library__jest-dom": "5.14.9",
diff --git a/packages/grafana-prometheus/package.json b/packages/grafana-prometheus/package.json
index 35273842128..d05b669c953 100644
--- a/packages/grafana-prometheus/package.json
+++ b/packages/grafana-prometheus/package.json
@@ -92,7 +92,7 @@
     "@types/jest": "29.5.12",
     "@types/jquery": "3.5.30",
     "@types/lodash": "4.17.7",
-    "@types/node": "20.14.13",
+    "@types/node": "20.14.14",
     "@types/pluralize": "^0.0.33",
     "@types/prismjs": "1.26.4",
     "@types/react": "18.3.3",
@@ -111,7 +111,7 @@
     "eslint-config-prettier": "9.1.0",
     "eslint-plugin-import": "^2.26.0",
     "eslint-plugin-jest": "28.6.0",
-    "eslint-plugin-jsdoc": "48.10.2",
+    "eslint-plugin-jsdoc": "48.11.0",
     "eslint-plugin-jsx-a11y": "6.9.0",
     "eslint-plugin-lodash": "7.4.0",
     "eslint-plugin-react": "7.35.0",
diff --git a/packages/grafana-runtime/src/config.ts b/packages/grafana-runtime/src/config.ts
index 868a3d8a8fb..b2bc145eacf 100644
--- a/packages/grafana-runtime/src/config.ts
+++ b/packages/grafana-runtime/src/config.ts
@@ -182,6 +182,7 @@ export class GrafanaBootConfig implements GrafanaConfig {
   localFileSystemAvailable: boolean | undefined;
   cloudMigrationIsTarget: boolean | undefined;
   cloudMigrationFeedbackURL = '';
+  cloudMigrationPollIntervalMs = 2000;
   reportingStaticContext?: Record<string, string>;
   exploreDefaultTimeOffset = '1h';
 
diff --git a/packages/grafana-sql/package.json b/packages/grafana-sql/package.json
index 8d3c20db50e..5b0b81cf7a9 100644
--- a/packages/grafana-sql/package.json
+++ b/packages/grafana-sql/package.json
@@ -42,7 +42,7 @@
     "@testing-library/user-event": "14.5.2",
     "@types/jest": "^29.5.4",
     "@types/lodash": "4.17.7",
-    "@types/node": "20.14.13",
+    "@types/node": "20.14.14",
     "@types/react": "18.3.3",
     "@types/react-dom": "18.2.25",
     "@types/react-virtualized-auto-sizer": "1.0.4",
diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json
index 98ed90d7b60..691455a85b7 100644
--- a/packages/grafana-ui/package.json
+++ b/packages/grafana-ui/package.json
@@ -145,7 +145,7 @@
     "@types/is-hotkey": "0.1.10",
     "@types/jest": "29.5.12",
     "@types/mock-raf": "1.0.6",
-    "@types/node": "20.14.13",
+    "@types/node": "20.14.14",
     "@types/prismjs": "1.26.4",
     "@types/react": "18.3.3",
     "@types/react-color": "3.0.12",
diff --git a/packages/grafana-ui/src/components/Portal/Portal.tsx b/packages/grafana-ui/src/components/Portal/Portal.tsx
index 867ee890821..1dd8e29b374 100644
--- a/packages/grafana-ui/src/components/Portal/Portal.tsx
+++ b/packages/grafana-ui/src/components/Portal/Portal.tsx
@@ -1,8 +1,11 @@
+import { css, cx } from '@emotion/css';
 import { PropsWithChildren, useLayoutEffect, useRef } from 'react';
 import * as React from 'react';
 import ReactDOM from 'react-dom';
 
-import { useTheme2 } from '../../themes';
+import { GrafanaTheme2 } from '@grafana/data';
+
+import { useStyles2, useTheme2 } from '../../themes';
 
 interface Props {
   className?: string;
@@ -47,9 +50,27 @@ export function getPortalContainer() {
 
 /** @internal */
 export function PortalContainer() {
-  return <div id="grafana-portal-container" />;
+  const styles = useStyles2(getStyles);
+  const isBodyScrolling = window.grafanaBootData?.settings.featureToggles.bodyScrolling;
+  return (
+    <div
+      id="grafana-portal-container"
+      className={cx({
+        [styles.grafanaPortalContainer]: isBodyScrolling,
+      })}
+    />
+  );
 }
 
+const getStyles = (theme: GrafanaTheme2) => ({
+  grafanaPortalContainer: css({
+    position: 'fixed',
+    top: 0,
+    width: '100%',
+    zIndex: theme.zIndex.portal,
+  }),
+});
+
 export const RefForwardingPortal = React.forwardRef<HTMLDivElement, Props>((props, ref) => {
   return <Portal {...props} forwardedRef={ref} />;
 });
diff --git a/pkg/api/dtos/frontend_settings.go b/pkg/api/dtos/frontend_settings.go
index a07a5e4358c..92ce60699b6 100644
--- a/pkg/api/dtos/frontend_settings.go
+++ b/pkg/api/dtos/frontend_settings.go
@@ -257,8 +257,9 @@ type FrontendSettingsDTO struct {
 	PublicDashboardAccessToken string `json:"publicDashboardAccessToken"`
 	PublicDashboardsEnabled    bool   `json:"publicDashboardsEnabled"`
 
-	CloudMigrationIsTarget    bool   `json:"cloudMigrationIsTarget"`
-	CloudMigrationFeedbackURL string `json:"cloudMigrationFeedbackURL"`
+	CloudMigrationIsTarget       bool   `json:"cloudMigrationIsTarget"`
+	CloudMigrationFeedbackURL    string `json:"cloudMigrationFeedbackURL"`
+	CloudMigrationPollIntervalMs int    `json:"cloudMigrationPollIntervalMs"`
 
 	DateFormats setting.DateFormats `json:"dateFormats,omitempty"`
 
diff --git a/pkg/api/folder_bench_test.go b/pkg/api/folder_bench_test.go
index c9f0f300601..02f729ff2b2 100644
--- a/pkg/api/folder_bench_test.go
+++ b/pkg/api/folder_bench_test.go
@@ -25,6 +25,7 @@ import (
 	"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
 	acdb "github.com/grafana/grafana/pkg/services/accesscontrol/database"
 	"github.com/grafana/grafana/pkg/services/accesscontrol/ossaccesscontrol"
+	"github.com/grafana/grafana/pkg/services/accesscontrol/permreg"
 	"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions"
 	"github.com/grafana/grafana/pkg/services/authz/zanzana"
 	"github.com/grafana/grafana/pkg/services/contexthandler/ctxkey"
@@ -463,7 +464,7 @@ func setupServer(b testing.TB, sc benchScenario, features featuremgmt.FeatureTog
 	actionSets := resourcepermissions.NewActionSetService(features)
 	acSvc := acimpl.ProvideOSSService(
 		sc.cfg, acdb.ProvideService(sc.db), actionSets, localcache.ProvideService(),
-		features, tracing.InitializeTracerForTest(), zanzana.NewNoopClient(), sc.db.DB(),
+		features, tracing.InitializeTracerForTest(), zanzana.NewNoopClient(), sc.db.DB(), permreg.ProvidePermissionRegistry(),
 	)
 
 	folderPermissions, err := ossaccesscontrol.ProvideFolderPermissions(
diff --git a/pkg/api/frontendsettings.go b/pkg/api/frontendsettings.go
index 90b3e5317e1..148f916c4ac 100644
--- a/pkg/api/frontendsettings.go
+++ b/pkg/api/frontendsettings.go
@@ -224,6 +224,7 @@ func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.Fro
 		PublicDashboardsEnabled:             hs.Cfg.PublicDashboardsEnabled,
 		CloudMigrationIsTarget:              isCloudMigrationTarget,
 		CloudMigrationFeedbackURL:           hs.Cfg.CloudMigration.FeedbackURL,
+		CloudMigrationPollIntervalMs:        int(hs.Cfg.CloudMigration.FrontendPollInterval.Milliseconds()),
 		SharedWithMeFolderUID:               folder.SharedWithMeFolderUID,
 		RootFolderUID:                       accesscontrol.GeneralFolderUID,
 		LocalFileSystemAvailable:            hs.Cfg.LocalFileSystemAvailable,
diff --git a/pkg/apimachinery/go.mod b/pkg/apimachinery/go.mod
index 086f70b7ece..89344ca3d26 100644
--- a/pkg/apimachinery/go.mod
+++ b/pkg/apimachinery/go.mod
@@ -3,6 +3,7 @@ module github.com/grafana/grafana/pkg/apimachinery
 go 1.21.10
 
 require (
+	github.com/grafana/authlib v0.0.0-20240730122259-a0d13672efb1
 	github.com/stretchr/testify v1.9.0
 	k8s.io/apimachinery v0.29.3
 	k8s.io/apiserver v0.29.2
@@ -12,6 +13,7 @@ require (
 require (
 	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
 	github.com/emicklei/go-restful/v3 v3.11.0 // indirect
+	github.com/go-jose/go-jose/v3 v3.0.3 // indirect
 	github.com/go-logr/logr v1.4.2 // indirect
 	github.com/go-openapi/jsonpointer v0.21.0 // indirect
 	github.com/go-openapi/jsonreference v0.20.4 // indirect
@@ -25,10 +27,15 @@ require (
 	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/patrickmn/go-cache v2.1.0+incompatible // indirect
 	github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
-	github.com/rogpeppe/go-internal v1.12.0 // indirect
+	golang.org/x/crypto v0.24.0 // indirect
 	golang.org/x/net v0.26.0 // indirect
+	golang.org/x/sync v0.7.0 // indirect
+	golang.org/x/sys v0.21.0 // indirect
 	golang.org/x/text v0.16.0 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect
+	google.golang.org/grpc v1.65.0 // indirect
 	google.golang.org/protobuf v1.34.2 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
diff --git a/pkg/apimachinery/go.sum b/pkg/apimachinery/go.sum
index 93d7d4e25d0..9a61a32f216 100644
--- a/pkg/apimachinery/go.sum
+++ b/pkg/apimachinery/go.sum
@@ -1,5 +1,6 @@
 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
 github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
+github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k=
 github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
 github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
 github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU=
@@ -9,6 +10,7 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek
 github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
 github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
 github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
+github.com/grafana/authlib v0.0.0-20240730122259-a0d13672efb1 h1:EiaupmOnt6XF/LPxvagjTofWmByzYaf5VyMIF+w/71M=
 github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
 github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
 github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@@ -16,12 +18,18 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
 github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
 golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
+golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
+golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
 golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA=
+google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
 google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
diff --git a/pkg/apimachinery/identity/requester.go b/pkg/apimachinery/identity/requester.go
index da9609b69a0..9da9d99286e 100644
--- a/pkg/apimachinery/identity/requester.go
+++ b/pkg/apimachinery/identity/requester.go
@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"strconv"
 
+	authnlib "github.com/grafana/authlib/authn"
 	"k8s.io/apiserver/pkg/authentication/user"
 )
 
@@ -77,6 +78,8 @@ type Requester interface {
 	// GetIDToken returns a signed token representing the identity that can be forwarded to plugins and external services.
 	// Will only be set when featuremgmt.FlagIdForwarding is enabled.
 	GetIDToken() string
+	// GetIDClaims returns the claims of the ID token.
+	GetIDClaims() *authnlib.Claims[authnlib.IDTokenClaims]
 }
 
 // IntIdentifier converts a string identifier to an int64.
diff --git a/pkg/apimachinery/identity/static.go b/pkg/apimachinery/identity/static.go
index af4f5fa0565..2fe79aaee8a 100644
--- a/pkg/apimachinery/identity/static.go
+++ b/pkg/apimachinery/identity/static.go
@@ -1,6 +1,10 @@
 package identity
 
-import "fmt"
+import (
+	"fmt"
+
+	authnlib "github.com/grafana/authlib/authn"
+)
 
 var _ Requester = &StaticRequester{}
 
@@ -25,9 +29,10 @@ type StaticRequester struct {
 	AllowedKubernetesNamespace string
 	IsGrafanaAdmin             bool
 	// Permissions grouped by orgID and actions
-	Permissions map[int64]map[string][]string
-	IDToken     string
-	CacheKey    string
+	Permissions   map[int64]map[string][]string
+	IDToken       string
+	IDTokenClaims *authnlib.Claims[authnlib.IDTokenClaims]
+	CacheKey      string
 }
 
 // GetRawIdentifier implements Requester.
@@ -208,3 +213,7 @@ func (u *StaticRequester) GetDisplayName() string {
 func (u *StaticRequester) GetIDToken() string {
 	return u.IDToken
 }
+
+func (u *StaticRequester) GetIDClaims() *authnlib.Claims[authnlib.IDTokenClaims] {
+	return u.IDTokenClaims
+}
diff --git a/pkg/cmd/grafana-cli/commands/conflict_user_command.go b/pkg/cmd/grafana-cli/commands/conflict_user_command.go
index 9ad5fe87611..9d7a534232b 100644
--- a/pkg/cmd/grafana-cli/commands/conflict_user_command.go
+++ b/pkg/cmd/grafana-cli/commands/conflict_user_command.go
@@ -22,6 +22,7 @@ import (
 	"github.com/grafana/grafana/pkg/infra/tracing"
 	"github.com/grafana/grafana/pkg/services/accesscontrol"
 	"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
+	"github.com/grafana/grafana/pkg/services/accesscontrol/permreg"
 	"github.com/grafana/grafana/pkg/services/authz/zanzana"
 	"github.com/grafana/grafana/pkg/services/featuremgmt"
 	"github.com/grafana/grafana/pkg/services/quota/quotaimpl"
@@ -90,7 +91,7 @@ func initializeConflictResolver(cmd *utils.ContextCommandLine, f Formatter, ctx
 	if err != nil {
 		return nil, fmt.Errorf("%v: %w", "failed to initialize tracer service", err)
 	}
-	acService, err := acimpl.ProvideService(cfg, replstore, routing, nil, nil, nil, features, tracer, zanzana.NewNoopClient())
+	acService, err := acimpl.ProvideService(cfg, replstore, routing, nil, nil, nil, features, tracer, zanzana.NewNoopClient(), permreg.ProvidePermissionRegistry())
 	if err != nil {
 		return nil, fmt.Errorf("%v: %w", "failed to get access control", err)
 	}
diff --git a/pkg/server/wire.go b/pkg/server/wire.go
index 6440aab312e..47aa9aedc38 100644
--- a/pkg/server/wire.go
+++ b/pkg/server/wire.go
@@ -39,6 +39,7 @@ import (
 	"github.com/grafana/grafana/pkg/services/accesscontrol"
 	"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
 	"github.com/grafana/grafana/pkg/services/accesscontrol/ossaccesscontrol"
+	"github.com/grafana/grafana/pkg/services/accesscontrol/permreg"
 	"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions"
 	"github.com/grafana/grafana/pkg/services/annotations"
 	"github.com/grafana/grafana/pkg/services/annotations/annotationsimpl"
@@ -345,6 +346,7 @@ var wireBasicSet = wire.NewSet(
 	resourcepermissions.NewActionSetService,
 	wire.Bind(new(accesscontrol.ActionResolver), new(resourcepermissions.ActionSetService)),
 	wire.Bind(new(pluginaccesscontrol.ActionSetRegistry), new(resourcepermissions.ActionSetService)),
+	permreg.ProvidePermissionRegistry,
 	acimpl.ProvideAccessControl,
 	navtreeimpl.ProvideService,
 	wire.Bind(new(accesscontrol.AccessControl), new(*acimpl.AccessControl)),
diff --git a/pkg/services/accesscontrol/acimpl/service.go b/pkg/services/accesscontrol/acimpl/service.go
index 790fc5773fd..5b7b509b245 100644
--- a/pkg/services/accesscontrol/acimpl/service.go
+++ b/pkg/services/accesscontrol/acimpl/service.go
@@ -24,6 +24,7 @@ import (
 	"github.com/grafana/grafana/pkg/services/accesscontrol/api"
 	"github.com/grafana/grafana/pkg/services/accesscontrol/database"
 	"github.com/grafana/grafana/pkg/services/accesscontrol/migrator"
+	"github.com/grafana/grafana/pkg/services/accesscontrol/permreg"
 	"github.com/grafana/grafana/pkg/services/accesscontrol/pluginutils"
 	"github.com/grafana/grafana/pkg/services/authz/zanzana"
 	"github.com/grafana/grafana/pkg/services/dashboards"
@@ -50,9 +51,9 @@ var OSSRolesPrefixes = []string{accesscontrol.ManagedRolePrefix, accesscontrol.E
 func ProvideService(
 	cfg *setting.Cfg, db db.ReplDB, routeRegister routing.RouteRegister, cache *localcache.CacheService,
 	accessControl accesscontrol.AccessControl, actionResolver accesscontrol.ActionResolver,
-	features featuremgmt.FeatureToggles, tracer tracing.Tracer, zclient zanzana.Client,
+	features featuremgmt.FeatureToggles, tracer tracing.Tracer, zclient zanzana.Client, permRegistry permreg.PermissionRegistry,
 ) (*Service, error) {
-	service := ProvideOSSService(cfg, database.ProvideService(db), actionResolver, cache, features, tracer, zclient, db.DB())
+	service := ProvideOSSService(cfg, database.ProvideService(db), actionResolver, cache, features, tracer, zclient, db.DB(), permRegistry)
 
 	api.NewAccessControlAPI(routeRegister, accessControl, service, features).RegisterAPIEndpoints()
 	if err := accesscontrol.DeclareFixedRoles(service, cfg); err != nil {
@@ -73,7 +74,7 @@ func ProvideService(
 func ProvideOSSService(
 	cfg *setting.Cfg, store accesscontrol.Store, actionResolver accesscontrol.ActionResolver,
 	cache *localcache.CacheService, features featuremgmt.FeatureToggles, tracer tracing.Tracer,
-	zclient zanzana.Client, db db.DB,
+	zclient zanzana.Client, db db.DB, permRegistry permreg.PermissionRegistry,
 ) *Service {
 	s := &Service{
 		actionResolver: actionResolver,
@@ -85,6 +86,7 @@ func ProvideOSSService(
 		store:          store,
 		tracer:         tracer,
 		sync:           migrator.NewZanzanaSynchroniser(zclient, db),
+		permRegistry:   permRegistry,
 	}
 
 	return s
@@ -102,6 +104,7 @@ type Service struct {
 	store          accesscontrol.Store
 	tracer         tracing.Tracer
 	sync           *migrator.ZanzanaSynchroniser
+	permRegistry   permreg.PermissionRegistry
 }
 
 func (s *Service) GetUsageStats(_ context.Context) map[string]any {
@@ -406,6 +409,10 @@ func (s *Service) DeclareFixedRoles(registrations ...accesscontrol.RoleRegistrat
 			return err
 		}
 
+		for i := range r.Role.Permissions {
+			s.permRegistry.RegisterPermission(r.Role.Permissions[i].Action, r.Role.Permissions[i].Scope)
+		}
+
 		s.registrations.Append(r)
 	}
 
@@ -458,6 +465,12 @@ func (s *Service) DeclarePluginRoles(ctx context.Context, ID, name string, regs
 			return err
 		}
 
+		for i := range r.Role.Permissions {
+			// Register plugin actions and their possible scopes for permission validation
+			s.permRegistry.RegisterPluginScope(r.Role.Permissions[i].Scope)
+			s.permRegistry.RegisterPermission(r.Role.Permissions[i].Action, r.Role.Permissions[i].Scope)
+		}
+
 		s.log.Debug("Registering plugin role", "role", r.Role.Name)
 		s.registrations.Append(r)
 	}
diff --git a/pkg/services/accesscontrol/acimpl/service_test.go b/pkg/services/accesscontrol/acimpl/service_test.go
index 19245d113f8..e5df3ada30c 100644
--- a/pkg/services/accesscontrol/acimpl/service_test.go
+++ b/pkg/services/accesscontrol/acimpl/service_test.go
@@ -17,6 +17,7 @@ import (
 	"github.com/grafana/grafana/pkg/services/accesscontrol"
 	"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
 	"github.com/grafana/grafana/pkg/services/accesscontrol/database"
+	"github.com/grafana/grafana/pkg/services/accesscontrol/permreg"
 	"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions"
 	"github.com/grafana/grafana/pkg/services/featuremgmt"
 	"github.com/grafana/grafana/pkg/services/licensing"
@@ -42,6 +43,7 @@ func setupTestEnv(t testing.TB) *Service {
 		roles:         accesscontrol.BuildBasicRoleDefinitions(),
 		tracer:        tracing.InitializeTracerForTest(),
 		store:         database.ProvideService(db.InitTestReplDB(t)),
+		permRegistry:  permreg.ProvidePermissionRegistry(),
 	}
 	require.NoError(t, ac.RegisterFixedRoles(context.Background()))
 	return ac
@@ -71,6 +73,7 @@ func TestUsageMetrics(t *testing.T) {
 				tracing.InitializeTracerForTest(),
 				nil,
 				nil,
+				permreg.ProvidePermissionRegistry(),
 			)
 			assert.Equal(t, tt.expectedValue, s.GetUsageStats(context.Background())["stats.oss.accesscontrol.enabled.count"])
 		})
diff --git a/pkg/services/accesscontrol/permreg/permreg.go b/pkg/services/accesscontrol/permreg/permreg.go
new file mode 100644
index 00000000000..ca1b8ba1fd1
--- /dev/null
+++ b/pkg/services/accesscontrol/permreg/permreg.go
@@ -0,0 +1,183 @@
+package permreg
+
+import (
+	"strings"
+
+	"github.com/grafana/grafana/pkg/apimachinery/errutil"
+	"github.com/grafana/grafana/pkg/infra/log"
+)
+
+var (
+	// ErrInvalidScope is returned when the scope is not valid for the action
+	ErrInvalidScopeTplt = "invalid scope: {{.Public.Scope}}, for action: {{.Public.Action}}, expected prefixes are {{.Public.ValidScopesFormat}}"
+	ErrBaseInvalidScope = errutil.BadRequest("permreg.invalid-scope").MustTemplate(ErrInvalidScopeTplt, errutil.WithPublic(ErrInvalidScopeTplt))
+
+	ErrUnknownActionTplt = "unknown action: {{.Public.Action}}, was not found in the list of valid actions"
+	ErrBaseUnknownAction = errutil.BadRequest("permreg.unknown-action").MustTemplate(ErrUnknownActionTplt, errutil.WithPublic(ErrUnknownActionTplt))
+)
+
+func ErrInvalidScope(scope string, action string, validScopePrefixes PrefixSet) error {
+	if len(validScopePrefixes) == 0 {
+		return ErrBaseInvalidScope.Build(errutil.TemplateData{Public: map[string]any{"Scope": scope, "Action": action, "ValidScopesFormat": "[none]"}})
+	}
+	formats := generateValidScopeFormats(validScopePrefixes)
+	return ErrBaseInvalidScope.Build(errutil.TemplateData{Public: map[string]any{"Scope": scope, "Action": action, "ValidScopesFormat": formats}})
+}
+
+func ErrUnknownAction(action string) error {
+	return ErrBaseUnknownAction.Build(errutil.TemplateData{Public: map[string]any{"Action": action}})
+}
+
+func generateValidScopeFormats(acceptedScopePrefixes PrefixSet) []string {
+	if len(acceptedScopePrefixes) == 0 {
+		return []string{}
+	}
+	acceptedPrefixesList := make([]string, 0, 10)
+	acceptedPrefixesList = append(acceptedPrefixesList, "*")
+	for prefix := range acceptedScopePrefixes {
+		parts := strings.Split(prefix, ":")
+		// If the prefix has an attribute part add the intermediate format kind:*
+		if len(parts) > 2 {
+			acceptedPrefixesList = append(acceptedPrefixesList, parts[0]+":*")
+		}
+		// Add the most specific format kind:attribute:*
+		acceptedPrefixesList = append(acceptedPrefixesList, prefix+"*")
+	}
+	return acceptedPrefixesList
+}
+
+type PermissionRegistry interface {
+	RegisterPluginScope(scope string)
+	RegisterPermission(action, scope string)
+	IsPermissionValid(action, scope string) error
+	GetScopePrefixes(action string) (PrefixSet, bool)
+}
+
+type PrefixSet map[string]bool
+
+var _ PermissionRegistry = &permissionRegistry{}
+
+type permissionRegistry struct {
+	actionScopePrefixes map[string]PrefixSet // TODO use thread safe map
+	kindScopePrefix     map[string]string
+	logger              log.Logger
+}
+
+func ProvidePermissionRegistry() PermissionRegistry {
+	return newPermissionRegistry()
+}
+
+func newPermissionRegistry() *permissionRegistry {
+	// defaultKindScopes maps the most specific accepted scope prefix for a given kind (folders, dashboards, etc)
+	defaultKindScopes := map[string]string{
+		"teams":           "teams:id:",
+		"users":           "users:id:",
+		"datasources":     "datasources:uid:",
+		"dashboards":      "dashboards:uid:",
+		"folders":         "folders:uid:",
+		"annotations":     "annotations:type:",
+		"apikeys":         "apikeys:id:",
+		"orgs":            "orgs:id:",
+		"plugins":         "plugins:id:",
+		"provisioners":    "provisioners:",
+		"reports":         "reports:id:",
+		"permissions":     "permissions:type:",
+		"serviceaccounts": "serviceaccounts:id:",
+		"settings":        "settings:",
+		"global.users":    "global.users:id:",
+		"roles":           "roles:uid:",
+		"services":        "services:",
+	}
+	return &permissionRegistry{
+		actionScopePrefixes: make(map[string]PrefixSet, 200),
+		kindScopePrefix:     defaultKindScopes,
+		logger:              log.New("accesscontrol.permreg"),
+	}
+}
+
+func (pr *permissionRegistry) RegisterPluginScope(scope string) {
+	if scope == "" {
+		return
+	}
+
+	scopeParts := strings.Split(scope, ":")
+	// If the scope is already registered, return
+	if _, found := pr.kindScopePrefix[scopeParts[0]]; found {
+		return
+	}
+
+	// If the scope contains an attribute part, register the kind and attribute
+	if len(scopeParts) > 2 {
+		kind, attr := scopeParts[0], scopeParts[1]
+		pr.kindScopePrefix[kind] = kind + ":" + attr + ":"
+		pr.logger.Debug("registered scope prefix", "kind", kind, "scope_prefix", kind+":"+attr+":")
+		return
+	}
+
+	pr.logger.Debug("registered scope prefix", "kind", scopeParts[0], "scope_prefix", scopeParts[0]+":")
+	pr.kindScopePrefix[scopeParts[0]] = scopeParts[0] + ":"
+}
+
+func (pr *permissionRegistry) RegisterPermission(action, scope string) {
+	if _, ok := pr.actionScopePrefixes[action]; !ok {
+		pr.actionScopePrefixes[action] = PrefixSet{}
+	}
+
+	if scope == "" {
+		// scopeless action
+		return
+	}
+
+	kind := strings.Split(scope, ":")[0]
+	scopePrefix, ok := pr.kindScopePrefix[kind]
+	if !ok {
+		pr.logger.Warn("unknown scope prefix", "scope", scope)
+		return
+	}
+
+	// Add a new entry in case the scope is not empty
+	pr.actionScopePrefixes[action][scopePrefix] = true
+}
+
+func (pr *permissionRegistry) IsPermissionValid(action, scope string) error {
+	validScopePrefixes, ok := pr.actionScopePrefixes[action]
+	if !ok {
+		return ErrUnknownAction(action)
+	}
+
+	if ok && len(validScopePrefixes) == 0 {
+		// Expecting action without any scope
+		if scope != "" {
+			return ErrInvalidScope(scope, action, nil)
+		}
+		return nil
+	}
+
+	if !isScopeValid(scope, validScopePrefixes) {
+		return ErrInvalidScope(scope, action, validScopePrefixes)
+	}
+	return nil
+}
+
+func isScopeValid(scope string, validScopePrefixes PrefixSet) bool {
+	// Super wildcard scope
+	if scope == "*" {
+		return true
+	}
+	for scopePrefix := range validScopePrefixes {
+		// Correct scope prefix
+		if strings.HasPrefix(scope, scopePrefix) {
+			return true
+		}
+		// Scope is wildcard of the correct prefix
+		if strings.HasSuffix(scope, ":*") && strings.HasPrefix(scopePrefix, scope[:len(scope)-2]) {
+			return true
+		}
+	}
+	return false
+}
+
+func (pr *permissionRegistry) GetScopePrefixes(action string) (PrefixSet, bool) {
+	set, ok := pr.actionScopePrefixes[action]
+	return set, ok
+}
diff --git a/pkg/services/accesscontrol/permreg/permreg_test.go b/pkg/services/accesscontrol/permreg/permreg_test.go
new file mode 100644
index 00000000000..4d78e0ef9a6
--- /dev/null
+++ b/pkg/services/accesscontrol/permreg/permreg_test.go
@@ -0,0 +1,246 @@
+package permreg
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/require"
+)
+
+func Test_permissionRegistry_RegisterPluginScope(t *testing.T) {
+	tests := []struct {
+		scope     string
+		wantKind  string
+		wantScope string
+	}{
+		{
+			scope:     "folders:uid:AABBCC",
+			wantKind:  "folders",
+			wantScope: "folders:uid:",
+		},
+		{
+			scope:     "plugins:id:test-app",
+			wantKind:  "plugins",
+			wantScope: "plugins:id:",
+		},
+		{
+			scope:     "resource:uid:res",
+			wantKind:  "resource",
+			wantScope: "resource:uid:",
+		},
+		{
+			scope:     "resource:*",
+			wantKind:  "resource",
+			wantScope: "resource:",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.scope, func(t *testing.T) {
+			pr := newPermissionRegistry()
+			pr.RegisterPluginScope(tt.scope)
+			got, ok := pr.kindScopePrefix[tt.wantKind]
+			require.True(t, ok)
+			require.Equal(t, tt.wantScope, got)
+		})
+	}
+}
+
+func Test_permissionRegistry_RegisterPermission(t *testing.T) {
+	tests := []struct {
+		name          string
+		action        string
+		scope         string
+		wantKind      string
+		wantPrefixSet PrefixSet
+		wantSkip      bool
+	}{
+		{
+			name:          "register folders read",
+			action:        "folders:read",
+			scope:         "folders:*",
+			wantKind:      "folders",
+			wantPrefixSet: PrefixSet{"folders:uid:": true},
+		},
+		{
+			name:          "register app plugin settings read",
+			action:        "test-app.settings:read",
+			wantKind:      "settings",
+			wantPrefixSet: PrefixSet{},
+		},
+		{
+			name:          "register an action on an unknown kind",
+			action:        "unknown:action",
+			scope:         "unknown:uid:*",
+			wantPrefixSet: PrefixSet{},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			pr := newPermissionRegistry()
+			pr.RegisterPermission(tt.action, tt.scope)
+			got, ok := pr.actionScopePrefixes[tt.action]
+			require.True(t, ok)
+			for k, v := range got {
+				require.Equal(t, v, tt.wantPrefixSet[k])
+			}
+		})
+	}
+}
+
+func Test_permissionRegistry_IsPermissionValid(t *testing.T) {
+	pr := newPermissionRegistry()
+	pr.RegisterPermission("folders:read", "folders:uid:")
+	pr.RegisterPermission("test-app.settings:read", "")
+
+	tests := []struct {
+		name    string
+		action  string
+		scope   string
+		wantErr bool
+	}{
+		{
+			name:    "valid folders read",
+			action:  "folders:read",
+			scope:   "folders:uid:AABBCC",
+			wantErr: false,
+		},
+		{
+			name:    "valid folders read with wildcard",
+			action:  "folders:read",
+			scope:   "folders:uid:*",
+			wantErr: false,
+		},
+		{
+			name:    "valid folders read with kind level wildcard",
+			action:  "folders:read",
+			scope:   "folders:*",
+			wantErr: false,
+		},
+		{
+			name:    "valid folders read with super wildcard",
+			action:  "folders:read",
+			scope:   "*",
+			wantErr: false,
+		},
+		{
+			name:    "invalid folders read with wrong kind",
+			action:  "folders:read",
+			scope:   "unknown:uid:AABBCC",
+			wantErr: true,
+		},
+		{
+			name:    "invalid folders read with wrong attribute",
+			action:  "folders:read",
+			scope:   "folders:id:3",
+			wantErr: true,
+		},
+		{
+			name:    "valid app plugin settings read",
+			action:  "test-app.settings:read",
+			scope:   "",
+			wantErr: false,
+		},
+		{
+			name:    "app plugin settings read with a scope",
+			action:  "test-app.settings:read",
+			scope:   "folders:uid:*",
+			wantErr: true,
+		},
+		{
+			name:    "unknown action",
+			action:  "unknown:write",
+			scope:   "",
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			err := pr.IsPermissionValid(tt.action, tt.scope)
+			if tt.wantErr {
+				require.Error(t, err)
+				return
+			}
+			require.NoError(t, err)
+		})
+	}
+}
+
+func Test_permissionRegistry_GetScopePrefixes(t *testing.T) {
+	pr := newPermissionRegistry()
+	pr.RegisterPermission("folders:read", "folders:uid:")
+	pr.RegisterPermission("test-app.settings:read", "")
+
+	tests := []struct {
+		name        string
+		action      string
+		want        PrefixSet
+		shouldExist bool
+	}{
+		{
+			name:        "get folders read scope prefixes",
+			action:      "folders:read",
+			want:        PrefixSet{"folders:uid:": true},
+			shouldExist: true,
+		},
+		{
+			name:        "get app plugin settings read scope prefixes",
+			action:      "test-app.settings:read",
+			want:        PrefixSet{},
+			shouldExist: true,
+		},
+		{
+			name:        "get unknown action scope prefixes",
+			action:      "unknown:write",
+			want:        PrefixSet{},
+			shouldExist: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, got1 := pr.GetScopePrefixes(tt.action)
+			if !tt.shouldExist {
+				require.False(t, got1)
+				return
+			}
+			require.True(t, got1)
+			require.Len(t, tt.want, len(got))
+			for k, v := range got {
+				require.Equal(t, v, tt.want[k])
+			}
+		})
+	}
+}
+
+func Test_generateValidScopeFormats(t *testing.T) {
+	tests := []struct {
+		name      string
+		prefixSet PrefixSet
+		want      []string
+	}{
+		{
+			name:      "empty prefix set",
+			prefixSet: PrefixSet{},
+			want:      []string{},
+		},
+		{
+			name:      "short prefix",
+			prefixSet: PrefixSet{"folders:": true},
+			want:      []string{"*", "folders:*"},
+		},
+		{
+			name:      "single prefix",
+			prefixSet: PrefixSet{"folders:uid:": true},
+			want:      []string{"*", "folders:*", "folders:uid:*"},
+		},
+		{
+			name:      "multiple prefixes",
+			prefixSet: PrefixSet{"folders:uid:": true, "dashboards:uid:": true},
+			want:      []string{"*", "folders:*", "folders:uid:*", "dashboards:*", "dashboards:uid:*"},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got := generateValidScopeFormats(tt.prefixSet)
+			require.ElementsMatch(t, tt.want, got)
+		})
+	}
+}
diff --git a/pkg/services/accesscontrol/permreg/test/testreg.go b/pkg/services/accesscontrol/permreg/test/testreg.go
new file mode 100644
index 00000000000..7b5210dd2e6
--- /dev/null
+++ b/pkg/services/accesscontrol/permreg/test/testreg.go
@@ -0,0 +1,22 @@
+package test
+
+import "github.com/grafana/grafana/pkg/services/accesscontrol/permreg"
+
+func ProvidePermissionRegistry() permreg.PermissionRegistry {
+	permReg := permreg.ProvidePermissionRegistry()
+	// Test core permissions
+	permReg.RegisterPermission("datasources:read", "datasources:uid:")
+	permReg.RegisterPermission("dashboards:read", "dashboards:uid:")
+	permReg.RegisterPermission("dashboards:read", "folders:uid:")
+	permReg.RegisterPermission("folders:read", "folders:uid:")
+	// Test plugins permissions
+	permReg.RegisterPermission("plugins.app:access", "plugins:id:")
+	// App
+	permReg.RegisterPermission("test-app:read", "")
+	permReg.RegisterPermission("test-app.settings:read", "")
+	permReg.RegisterPermission("test-app.projects:read", "")
+	// App 1
+	permReg.RegisterPermission("test-app1.catalog:read", "")
+	permReg.RegisterPermission("test-app1.announcements:read", "")
+	return permReg
+}
diff --git a/pkg/services/auth/id.go b/pkg/services/auth/id.go
index 63fa61c05c9..18096eee393 100644
--- a/pkg/services/auth/id.go
+++ b/pkg/services/auth/id.go
@@ -10,7 +10,7 @@ import (
 
 type IDService interface {
 	// SignIdentity signs a id token for provided identity that can be forwarded to plugins and external services
-	SignIdentity(ctx context.Context, identity identity.Requester) (string, error)
+	SignIdentity(ctx context.Context, id identity.Requester) (string, *authnlib.Claims[authnlib.IDTokenClaims], error)
 
 	// RemoveIDToken removes any locally stored id tokens for key
 	RemoveIDToken(ctx context.Context, identity identity.Requester) error
diff --git a/pkg/services/auth/idimpl/service.go b/pkg/services/auth/idimpl/service.go
index d5694c35cfb..f48bf1c700b 100644
--- a/pkg/services/auth/idimpl/service.go
+++ b/pkg/services/auth/idimpl/service.go
@@ -58,21 +58,30 @@ type Service struct {
 	nsMapper request.NamespaceMapper
 }
 
-func (s *Service) SignIdentity(ctx context.Context, id identity.Requester) (string, error) {
+func (s *Service) SignIdentity(ctx context.Context, id identity.Requester) (string, *authnlib.Claims[authnlib.IDTokenClaims], error) {
 	defer func(t time.Time) {
 		s.metrics.tokenSigningDurationHistogram.Observe(time.Since(t).Seconds())
 	}(time.Now())
 
 	cacheKey := prefixCacheKey(id.GetCacheKey())
 
-	result, err, _ := s.si.Do(cacheKey, func() (interface{}, error) {
+	type resultType struct {
+		token    string
+		idClaims *auth.IDClaims
+	}
+	result, err, _ := s.si.Do(cacheKey, func() (any, error) {
 		namespace, identifier := id.GetTypedID()
 
 		cachedToken, err := s.cache.Get(ctx, cacheKey)
 		if err == nil {
 			s.metrics.tokenSigningFromCacheCounter.Inc()
 			s.logger.FromContext(ctx).Debug("Cached token found", "namespace", namespace, "id", identifier)
-			return string(cachedToken), nil
+
+			tokenClaims, err := s.extractTokenClaims(string(cachedToken))
+			if err != nil {
+				return resultType{}, err
+			}
+			return resultType{token: string(cachedToken), idClaims: tokenClaims}, nil
 		}
 
 		s.metrics.tokenSigningCounter.Inc()
@@ -104,21 +113,12 @@ func (s *Service) SignIdentity(ctx context.Context, id identity.Requester) (stri
 		token, err := s.signer.SignIDToken(ctx, claims)
 		if err != nil {
 			s.metrics.failedTokenSigningCounter.Inc()
-			return "", err
+			return resultType{}, nil
 		}
 
-		parsed, err := jwt.ParseSigned(token)
+		extracted, err := s.extractTokenClaims(token)
 		if err != nil {
-			s.metrics.failedTokenSigningCounter.Inc()
-			return "", err
-		}
-
-		extracted := auth.IDClaims{}
-		// We don't need to verify the signature here, we are only interested in checking
-		// when the token expires.
-		if err := parsed.UnsafeClaimsWithoutVerification(&extracted); err != nil {
-			s.metrics.failedTokenSigningCounter.Inc()
-			return "", err
+			return resultType{}, err
 		}
 
 		expires := time.Until(extracted.Expiry.Time())
@@ -126,14 +126,14 @@ func (s *Service) SignIdentity(ctx context.Context, id identity.Requester) (stri
 			s.logger.FromContext(ctx).Error("Failed to add id token to cache", "error", err)
 		}
 
-		return token, nil
+		return resultType{token: token, idClaims: claims}, nil
 	})
 
 	if err != nil {
-		return "", err
+		return "", nil, err
 	}
 
-	return result.(string), nil
+	return result.(resultType).token, result.(resultType).idClaims, nil
 }
 
 func (s *Service) RemoveIDToken(ctx context.Context, id identity.Requester) error {
@@ -142,7 +142,7 @@ func (s *Service) RemoveIDToken(ctx context.Context, id identity.Requester) erro
 
 func (s *Service) hook(ctx context.Context, identity *authn.Identity, _ *authn.Request) error {
 	// FIXME(kalleep): we should probably lazy load this
-	token, err := s.SignIdentity(ctx, identity)
+	token, claims, err := s.SignIdentity(ctx, identity)
 	if err != nil {
 		if shouldLogErr(err) {
 			namespace, id := identity.GetTypedID()
@@ -153,9 +153,28 @@ func (s *Service) hook(ctx context.Context, identity *authn.Identity, _ *authn.R
 	}
 
 	identity.IDToken = token
+	identity.IDTokenClaims = claims
 	return nil
 }
 
+func (s *Service) extractTokenClaims(token string) (*authnlib.Claims[authnlib.IDTokenClaims], error) {
+	parsed, err := jwt.ParseSigned(token)
+	if err != nil {
+		s.metrics.failedTokenSigningCounter.Inc()
+		return nil, err
+	}
+
+	extracted := authnlib.Claims[authnlib.IDTokenClaims]{}
+	// We don't need to verify the signature here, we are only interested in checking
+	// when the token expires.
+	if err := parsed.UnsafeClaimsWithoutVerification(&extracted); err != nil {
+		s.metrics.failedTokenSigningCounter.Inc()
+		return nil, err
+	}
+
+	return &extracted, nil
+}
+
 func getAudience(orgID int64) jwt.Audience {
 	return jwt.Audience{fmt.Sprintf("org:%d", orgID)}
 }
diff --git a/pkg/services/auth/idimpl/service_test.go b/pkg/services/auth/idimpl/service_test.go
index 6b619b5075f..3cb8b36a7b9 100644
--- a/pkg/services/auth/idimpl/service_test.go
+++ b/pkg/services/auth/idimpl/service_test.go
@@ -70,7 +70,7 @@ func TestService_SignIdentity(t *testing.T) {
 			featuremgmt.WithFeatures(featuremgmt.FlagIdForwarding),
 			&authntest.FakeService{}, nil,
 		)
-		token, err := s.SignIdentity(context.Background(), &authn.Identity{ID: identity.MustParseTypedID("user:1")})
+		token, _, err := s.SignIdentity(context.Background(), &authn.Identity{ID: identity.MustParseTypedID("user:1")})
 		require.NoError(t, err)
 		require.NotEmpty(t, token)
 	})
@@ -81,7 +81,7 @@ func TestService_SignIdentity(t *testing.T) {
 			featuremgmt.WithFeatures(featuremgmt.FlagIdForwarding),
 			&authntest.FakeService{}, nil,
 		)
-		token, err := s.SignIdentity(context.Background(), &authn.Identity{
+		token, _, err := s.SignIdentity(context.Background(), &authn.Identity{
 			ID:              identity.MustParseTypedID("user:1"),
 			AuthenticatedBy: login.AzureADAuthModule,
 			Login:           "U1",
@@ -97,4 +97,22 @@ func TestService_SignIdentity(t *testing.T) {
 		assert.Equal(t, "U1", claims.Rest.Username)
 		assert.Equal(t, "user:edpu3nnt61se8e", claims.Rest.UID)
 	})
+
+	t.Run("should sign identity with authenticated by if user is externally authenticated", func(t *testing.T) {
+		s := ProvideService(
+			setting.NewCfg(), signer, remotecache.NewFakeCacheStorage(),
+			featuremgmt.WithFeatures(featuremgmt.FlagIdForwarding),
+			&authntest.FakeService{}, nil,
+		)
+		_, gotClaims, err := s.SignIdentity(context.Background(), &authn.Identity{
+			ID:              identity.MustParseTypedID("user:1"),
+			AuthenticatedBy: login.AzureADAuthModule,
+			Login:           "U1",
+			UID:             identity.NewTypedIDString(identity.TypeUser, "edpu3nnt61se8e")})
+		require.NoError(t, err)
+
+		assert.Equal(t, login.AzureADAuthModule, gotClaims.Rest.AuthenticatedBy)
+		assert.Equal(t, "U1", gotClaims.Rest.Username)
+		assert.Equal(t, "user:edpu3nnt61se8e", gotClaims.Rest.UID)
+	})
 }
diff --git a/pkg/services/auth/idtest/mock.go b/pkg/services/auth/idtest/mock.go
index 2613d6a7690..cd506836d13 100644
--- a/pkg/services/auth/idtest/mock.go
+++ b/pkg/services/auth/idtest/mock.go
@@ -3,6 +3,8 @@ package idtest
 import (
 	"context"
 
+	authnlib "github.com/grafana/authlib/authn"
+
 	"github.com/grafana/grafana/pkg/apimachinery/identity"
 	"github.com/grafana/grafana/pkg/services/auth"
 )
@@ -10,15 +12,15 @@ import (
 var _ auth.IDService = (*MockService)(nil)
 
 type MockService struct {
-	SignIdentityFn  func(ctx context.Context, identity identity.Requester) (string, error)
+	SignIdentityFn  func(ctx context.Context, identity identity.Requester) (string, *authnlib.Claims[authnlib.IDTokenClaims], error)
 	RemoveIDTokenFn func(ctx context.Context, identity identity.Requester) error
 }
 
-func (m *MockService) SignIdentity(ctx context.Context, identity identity.Requester) (string, error) {
+func (m *MockService) SignIdentity(ctx context.Context, identity identity.Requester) (string, *authnlib.Claims[authnlib.IDTokenClaims], error) {
 	if m.SignIdentityFn != nil {
 		return m.SignIdentityFn(ctx, identity)
 	}
-	return "", nil
+	return "", nil, nil
 }
 
 func (m *MockService) RemoveIDToken(ctx context.Context, identity identity.Requester) error {
diff --git a/pkg/services/authn/identity.go b/pkg/services/authn/identity.go
index 51bd72e5156..b41c65c3bba 100644
--- a/pkg/services/authn/identity.go
+++ b/pkg/services/authn/identity.go
@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"time"
 
+	"github.com/grafana/authlib/authn"
 	"golang.org/x/oauth2"
 
 	"github.com/grafana/grafana/pkg/apimachinery/identity"
@@ -69,7 +70,8 @@ type Identity struct {
 	Permissions map[int64]map[string][]string
 	// IDToken is a signed token representing the identity that can be forwarded to plugins and external services.
 	// Will only be set when featuremgmt.FlagIdForwarding is enabled.
-	IDToken string
+	IDToken       string
+	IDTokenClaims *authn.Claims[authn.IDTokenClaims]
 }
 
 // GetRawIdentifier implements Requester.
@@ -156,6 +158,10 @@ func (i *Identity) GetIDToken() string {
 	return i.IDToken
 }
 
+func (i *Identity) GetIDClaims() *authn.Claims[authn.IDTokenClaims] {
+	return i.IDTokenClaims
+}
+
 func (i *Identity) GetIsGrafanaAdmin() bool {
 	return i.IsGrafanaAdmin != nil && *i.IsGrafanaAdmin
 }
diff --git a/pkg/services/featuremgmt/registry.go b/pkg/services/featuremgmt/registry.go
index d0d14abbfbe..4af2dd0aca1 100644
--- a/pkg/services/featuremgmt/registry.go
+++ b/pkg/services/featuremgmt/registry.go
@@ -144,8 +144,9 @@ var (
 		{
 			Name:         "autoMigrateXYChartPanel",
 			Description:  "Migrate old XYChart panel to new XYChart2 model",
-			Stage:        FeatureStagePublicPreview,
+			Stage:        FeatureStageGeneralAvailability,
 			FrontendOnly: true,
+			Expression:   "true", // enabled by default
 			Owner:        grafanaDatavizSquad,
 		},
 		{
diff --git a/pkg/services/featuremgmt/toggles_gen.csv b/pkg/services/featuremgmt/toggles_gen.csv
index 40519b3e7c3..f67a4ed4923 100644
--- a/pkg/services/featuremgmt/toggles_gen.csv
+++ b/pkg/services/featuremgmt/toggles_gen.csv
@@ -16,7 +16,7 @@ autoMigrateTablePanel,preview,@grafana/dataviz-squad,false,false,true
 autoMigratePiechartPanel,preview,@grafana/dataviz-squad,false,false,true
 autoMigrateWorldmapPanel,preview,@grafana/dataviz-squad,false,false,true
 autoMigrateStatPanel,preview,@grafana/dataviz-squad,false,false,true
-autoMigrateXYChartPanel,preview,@grafana/dataviz-squad,false,false,true
+autoMigrateXYChartPanel,GA,@grafana/dataviz-squad,false,false,true
 disableAngular,preview,@grafana/dataviz-squad,false,false,true
 canvasPanelNesting,experimental,@grafana/dataviz-squad,false,false,true
 disableSecretsCompatibility,experimental,@grafana/hosted-grafana-team,false,true,false
diff --git a/pkg/services/featuremgmt/toggles_gen.json b/pkg/services/featuremgmt/toggles_gen.json
index 677764ca6d0..b9318868a78 100644
--- a/pkg/services/featuremgmt/toggles_gen.json
+++ b/pkg/services/featuremgmt/toggles_gen.json
@@ -429,14 +429,18 @@
     {
       "metadata": {
         "name": "autoMigrateXYChartPanel",
-        "resourceVersion": "1718727528075",
-        "creationTimestamp": "2024-03-22T15:44:37Z"
+        "resourceVersion": "1722537244598",
+        "creationTimestamp": "2024-03-22T15:44:37Z",
+        "annotations": {
+          "grafana.app/updatedTimestamp": "2024-08-01 18:34:04.598082 +0000 UTC"
+        }
       },
       "spec": {
         "description": "Migrate old XYChart panel to new XYChart2 model",
-        "stage": "preview",
+        "stage": "GA",
         "codeowner": "@grafana/dataviz-squad",
-        "frontend": true
+        "frontend": true,
+        "expression": "true"
       }
     },
     {
diff --git a/pkg/services/ngalert/ngalert.go b/pkg/services/ngalert/ngalert.go
index aac3a453571..c86a1d00c30 100644
--- a/pkg/services/ngalert/ngalert.go
+++ b/pkg/services/ngalert/ngalert.go
@@ -346,7 +346,7 @@ func (ng *AlertNG) init() error {
 	evalFactory := eval.NewEvaluatorFactory(ng.Cfg.UnifiedAlerting, ng.DataSourceCache, ng.ExpressionService)
 	conditionValidator := eval.NewConditionValidator(ng.DataSourceCache, ng.ExpressionService, ng.pluginsStore)
 
-	recordingWriter, err := createRecordingWriter(ng.FeatureToggles, ng.Cfg.UnifiedAlerting.RecordingRules, ng.httpClientProvider, clk, ng.tracer, ng.Metrics.GetRemoteWriterMetrics())
+	recordingWriter, err := createRecordingWriter(ng.FeatureToggles, ng.Cfg.UnifiedAlerting.RecordingRules, ng.httpClientProvider, clk, ng.Metrics.GetRemoteWriterMetrics())
 	if err != nil {
 		return fmt.Errorf("failed to initialize recording writer: %w", err)
 	}
@@ -663,11 +663,11 @@ func createRemoteAlertmanager(cfg remote.AlertmanagerConfig, kvstore kvstore.KVS
 	return remote.NewAlertmanager(cfg, notifier.NewFileStore(cfg.OrgID, kvstore), decryptFn, autogenFn, m, tracer)
 }
 
-func createRecordingWriter(featureToggles featuremgmt.FeatureToggles, settings setting.RecordingRuleSettings, httpClientProvider httpclient.Provider, clock clock.Clock, tracer tracing.Tracer, m *metrics.RemoteWriter) (schedule.RecordingWriter, error) {
+func createRecordingWriter(featureToggles featuremgmt.FeatureToggles, settings setting.RecordingRuleSettings, httpClientProvider httpclient.Provider, clock clock.Clock, m *metrics.RemoteWriter) (schedule.RecordingWriter, error) {
 	logger := log.New("ngalert.writer")
 
 	if featureToggles.IsEnabledGlobally(featuremgmt.FlagGrafanaManagedRecordingRules) {
-		return writer.NewPrometheusWriter(settings, httpClientProvider, clock, tracer, logger, m)
+		return writer.NewPrometheusWriter(settings, httpClientProvider, clock, logger, m)
 	}
 
 	return writer.NoopWriter{}, nil
diff --git a/pkg/services/ngalert/provisioning/contactpoints.go b/pkg/services/ngalert/provisioning/contactpoints.go
index 78959045adf..539b81ce0cb 100644
--- a/pkg/services/ngalert/provisioning/contactpoints.go
+++ b/pkg/services/ngalert/provisioning/contactpoints.go
@@ -12,6 +12,7 @@ import (
 	"github.com/prometheus/alertmanager/config"
 
 	"github.com/grafana/grafana/pkg/apimachinery/identity"
+	"github.com/grafana/grafana/pkg/components/simplejson"
 	"github.com/grafana/grafana/pkg/infra/log"
 	apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
 	"github.com/grafana/grafana/pkg/services/ngalert/models"
@@ -516,13 +517,39 @@ func RemoveSecretsForContactPoint(e *apimodels.EmbeddedContactPoint) (map[string
 		return nil, err
 	}
 	for _, secretKey := range secretKeys {
-		secretValue := e.Settings.Get(secretKey).MustString()
-		e.Settings.Del(secretKey)
+		foundSecretKey, secretValue, err := getCaseInsensitive(e.Settings, secretKey)
+		if err != nil {
+			return nil, err
+		}
+		e.Settings.Del(foundSecretKey)
 		s[secretKey] = secretValue
 	}
 	return s, nil
 }
 
+// getCaseInsensitive returns the value of the specified key, preferring an exact match but accepting a case-insensitive match.
+// If no key matches, the second return value is an empty string.
+func getCaseInsensitive(jsonObj *simplejson.Json, key string) (string, string, error) {
+	// Check for an exact key match first.
+	if value, ok := jsonObj.CheckGet(key); ok {
+		return key, value.MustString(), nil
+	}
+
+	// If no exact match is found, look for a case-insensitive match.
+	settingsMap, err := jsonObj.Map()
+	if err != nil {
+		return "", "", err
+	}
+
+	for k, v := range settingsMap {
+		if strings.EqualFold(k, key) {
+			return k, v.(string), nil
+		}
+	}
+
+	return key, "", nil
+}
+
 // convertRecSvcErr converts errors from notifier.ReceiverService to errors expected from ContactPointService.
 func convertRecSvcErr(err error) error {
 	if errors.Is(err, store.ErrNoAlertmanagerConfiguration) {
diff --git a/pkg/services/ngalert/provisioning/contactpoints_test.go b/pkg/services/ngalert/provisioning/contactpoints_test.go
index 9ce9af52f93..a502f9c8798 100644
--- a/pkg/services/ngalert/provisioning/contactpoints_test.go
+++ b/pkg/services/ngalert/provisioning/contactpoints_test.go
@@ -40,6 +40,11 @@ func TestContactPointService(t *testing.T) {
 			accesscontrol.ActionAlertingProvisioningRead: nil,
 		},
 	}}
+	decryptedUser := &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{
+		1: {
+			accesscontrol.ActionAlertingProvisioningReadSecrets: nil,
+		},
+	}}
 
 	t.Run("service gets contact points from AM config", func(t *testing.T) {
 		sut := createContactPointServiceSut(t, secretsService)
@@ -265,6 +270,52 @@ func TestContactPointService(t *testing.T) {
 		intercepted := fakeConfigStore.LastSaveCommand
 		require.Equal(t, expectedConcurrencyToken, intercepted.FetchedConfigurationHash)
 	})
+
+	t.Run("secrets are parsed in a case-insensitive way", func(t *testing.T) {
+		// JSON unmarshalling is case-insensitive. This means we can have
+		// a setting named "TOKEN" instead of "token". This test ensures that
+		// we handle such cases correctly and the token value is properly parsed,
+		// even if the setting key does not match the JSON key exactly.
+		tests := []struct {
+			settingsJSON  string
+			expectedValue string
+			name          string
+		}{
+			{
+				settingsJSON:  `{"recipient":"value_recipient","TOKEN":"some-other-token"}`,
+				expectedValue: "some-other-token",
+				name:          "token key is uppercased",
+			},
+
+			// This test checks that if multiple token keys are present in the settings,
+			// the key with the exact matching name is used.
+			{
+				settingsJSON:  `{"recipient":"value_recipient","TOKEN":"some-other-token", "token": "second-token"}`,
+				expectedValue: "second-token",
+				name:          "multiple token keys",
+			},
+		}
+
+		for _, tc := range tests {
+			t.Run(tc.name, func(t *testing.T) {
+				sut := createContactPointServiceSut(t, secretsService)
+
+				newCp := createTestContactPoint()
+				settings, _ := simplejson.NewJson([]byte(tc.settingsJSON))
+				newCp.Settings = settings
+
+				_, err := sut.CreateContactPoint(context.Background(), 1, newCp, models.ProvenanceAPI)
+				require.NoError(t, err)
+
+				q := cpsQueryWithName(1, newCp.Name)
+				q.Decrypt = true
+				cps, err := sut.GetContactPoints(context.Background(), q, decryptedUser)
+				require.NoError(t, err)
+				require.Len(t, cps, 1)
+				require.Equal(t, tc.expectedValue, cps[0].Settings.Get("token").MustString())
+			})
+		}
+	})
 }
 
 func TestContactPointServiceDecryptRedact(t *testing.T) {
diff --git a/pkg/services/ngalert/schedule/recording_rule_test.go b/pkg/services/ngalert/schedule/recording_rule_test.go
index c46144c6d58..8dba179927d 100644
--- a/pkg/services/ngalert/schedule/recording_rule_test.go
+++ b/pkg/services/ngalert/schedule/recording_rule_test.go
@@ -19,7 +19,6 @@ import (
 	"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
 	"github.com/grafana/grafana/pkg/expr"
 	"github.com/grafana/grafana/pkg/infra/log"
-	"github.com/grafana/grafana/pkg/infra/tracing"
 	"github.com/grafana/grafana/pkg/services/featuremgmt"
 	"github.com/grafana/grafana/pkg/services/ngalert/metrics"
 	models "github.com/grafana/grafana/pkg/services/ngalert/models"
@@ -532,7 +531,7 @@ func withQueryForHealth(health string) models.AlertRuleMutator {
 func setupWriter(t *testing.T, target *writer.TestRemoteWriteTarget, reg prometheus.Registerer) *writer.PrometheusWriter {
 	provider := testClientProvider{}
 	m := metrics.NewNGAlert(reg)
-	wr, err := writer.NewPrometheusWriter(target.ClientSettings(), provider, clock.NewMock(), tracing.InitializeTracerForTest(), log.NewNopLogger(), m.GetRemoteWriterMetrics())
+	wr, err := writer.NewPrometheusWriter(target.ClientSettings(), provider, clock.NewMock(), log.NewNopLogger(), m.GetRemoteWriterMetrics())
 	require.NoError(t, err)
 	return wr
 }
diff --git a/pkg/services/ngalert/writer/prom.go b/pkg/services/ngalert/writer/prom.go
index b01baf5197e..ef860a599e7 100644
--- a/pkg/services/ngalert/writer/prom.go
+++ b/pkg/services/ngalert/writer/prom.go
@@ -11,7 +11,6 @@ import (
 	"github.com/benbjohnson/clock"
 	"github.com/grafana/dataplane/sdata/numeric"
 	"github.com/grafana/grafana/pkg/infra/log"
-	"github.com/grafana/grafana/pkg/infra/tracing"
 	"github.com/grafana/grafana/pkg/services/ngalert/metrics"
 	"github.com/grafana/grafana/pkg/services/ngalert/models"
 	"github.com/grafana/grafana/pkg/setting"
@@ -106,7 +105,6 @@ func NewPrometheusWriter(
 	settings setting.RecordingRuleSettings,
 	httpClientProvider HttpClientProvider,
 	clock clock.Clock,
-	tracer tracing.Tracer,
 	l log.Logger,
 	metrics *metrics.RemoteWriter,
 ) (*PrometheusWriter, error) {
@@ -119,14 +117,9 @@ func NewPrometheusWriter(
 		headers.Add(k, v)
 	}
 
-	middlewares := []httpclient.Middleware{
-		httpclient.TracingMiddleware(tracer),
-	}
-
 	cl, err := httpClientProvider.New(httpclient.Options{
-		Middlewares: middlewares,
-		BasicAuth:   createAuthOpts(settings.BasicAuthUsername, settings.BasicAuthPassword),
-		Header:      headers,
+		BasicAuth: createAuthOpts(settings.BasicAuthUsername, settings.BasicAuthPassword),
+		Header:    headers,
 	})
 	if err != nil {
 		return nil, err
diff --git a/pkg/services/serviceaccounts/extsvcaccounts/service_test.go b/pkg/services/serviceaccounts/extsvcaccounts/service_test.go
index 130fbc98fcc..e8f9650ca7c 100644
--- a/pkg/services/serviceaccounts/extsvcaccounts/service_test.go
+++ b/pkg/services/serviceaccounts/extsvcaccounts/service_test.go
@@ -15,6 +15,7 @@ import (
 	ac "github.com/grafana/grafana/pkg/services/accesscontrol"
 	"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
 	"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
+	"github.com/grafana/grafana/pkg/services/accesscontrol/permreg"
 	"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions"
 	"github.com/grafana/grafana/pkg/services/apikey"
 	"github.com/grafana/grafana/pkg/services/extsvcauth"
@@ -48,6 +49,7 @@ func setupTestEnv(t *testing.T) *TestEnv {
 		acSvc: acimpl.ProvideOSSService(
 			cfg, env.AcStore, &resourcepermissions.FakeActionSetSvc{},
 			localcache.New(0, 0), fmgt, tracing.InitializeTracerForTest(), nil, nil,
+			permreg.ProvidePermissionRegistry(),
 		),
 		features: fmgt,
 		logger:   logger,
diff --git a/pkg/services/user/identity.go b/pkg/services/user/identity.go
index b5906276ea5..c05293ae4b5 100644
--- a/pkg/services/user/identity.go
+++ b/pkg/services/user/identity.go
@@ -5,6 +5,8 @@ import (
 	"strconv"
 	"time"
 
+	authnlib "github.com/grafana/authlib/authn"
+
 	"github.com/grafana/grafana/pkg/apimachinery/identity"
 )
 
@@ -40,9 +42,11 @@ type SignedInUser struct {
 	Teams            []int64
 	// Permissions grouped by orgID and actions
 	Permissions map[int64]map[string][]string `json:"-"`
+
 	// IDToken is a signed token representing the identity that can be forwarded to plugins and external services.
 	// Will only be set when featuremgmt.FlagIdForwarding is enabled.
-	IDToken string `json:"-" xorm:"-"`
+	IDToken       string                                   `json:"-" xorm:"-"`
+	IDTokenClaims *authnlib.Claims[authnlib.IDTokenClaims] `json:"-" xorm:"-"`
 
 	// When other settings are not deterministic, this value is used
 	FallbackType identity.IdentityType
@@ -309,3 +313,7 @@ func (u *SignedInUser) GetDisplayName() string {
 func (u *SignedInUser) GetIDToken() string {
 	return u.IDToken
 }
+
+func (u *SignedInUser) GetIDClaims() *authnlib.Claims[authnlib.IDTokenClaims] {
+	return u.IDTokenClaims
+}
diff --git a/pkg/setting/setting_cloud_migration.go b/pkg/setting/setting_cloud_migration.go
index 1efc88089dd..e05eb3b7f42 100644
--- a/pkg/setting/setting_cloud_migration.go
+++ b/pkg/setting/setting_cloud_migration.go
@@ -24,6 +24,7 @@ type CloudMigrationSettings struct {
 	DeleteTokenTimeout          time.Duration
 	TokenExpiresAfter           time.Duration
 	FeedbackURL                 string
+	FrontendPollInterval        time.Duration
 
 	IsDeveloperMode bool
 }
@@ -49,6 +50,7 @@ func (cfg *Cfg) readCloudMigrationSettings() {
 	cfg.CloudMigration.TokenExpiresAfter = cloudMigration.Key("token_expires_after").MustDuration(7 * 24 * time.Hour)
 	cfg.CloudMigration.IsDeveloperMode = cloudMigration.Key("developer_mode").MustBool(false)
 	cfg.CloudMigration.FeedbackURL = cloudMigration.Key("feedback_url").MustString("")
+	cfg.CloudMigration.FrontendPollInterval = cloudMigration.Key("frontend_poll_interval").MustDuration(2 * time.Second)
 
 	if cfg.CloudMigration.SnapshotFolder == "" {
 		cfg.CloudMigration.SnapshotFolder = filepath.Join(cfg.DataPath, "cloud_migration")
diff --git a/pkg/storage/unified/resource/errors.go b/pkg/storage/unified/resource/errors.go
index 088e6683630..7f1d3a3ca56 100644
--- a/pkg/storage/unified/resource/errors.go
+++ b/pkg/storage/unified/resource/errors.go
@@ -12,7 +12,6 @@ import (
 // Package-level errors.
 var (
 	ErrOptimisticLockingFailed = errors.New("optimistic locking failed")
-	ErrUserNotFoundInContext   = errors.New("user not found in context")
 	ErrNotImplementedYet       = errors.New("not implemented yet")
 )
 
diff --git a/pkg/storage/unified/resource/server.go b/pkg/storage/unified/resource/server.go
index c301e37288d..a1190e061fb 100644
--- a/pkg/storage/unified/resource/server.go
+++ b/pkg/storage/unified/resource/server.go
@@ -211,19 +211,15 @@ func (s *server) Stop(ctx context.Context) error {
 }
 
 // Old value indicates an update -- otherwise a create
-func (s *server) newEvent(ctx context.Context, key *ResourceKey, value, oldValue []byte) (*WriteEvent, error) {
-	user, err := identity.GetRequester(ctx)
-	if err != nil {
-		return nil, ErrUserNotFoundInContext
-	}
+func (s *server) newEvent(ctx context.Context, user identity.Requester, key *ResourceKey, value, oldValue []byte) (*WriteEvent, *ErrorResult) {
 	tmp := &unstructured.Unstructured{}
-	err = tmp.UnmarshalJSON(value)
+	err := tmp.UnmarshalJSON(value)
 	if err != nil {
-		return nil, err
+		return nil, AsErrorResult(err)
 	}
 	obj, err := utils.MetaAccessor(tmp)
 	if err != nil {
-		return nil, err
+		return nil, AsErrorResult(err)
 	}
 
 	event := &WriteEvent{
@@ -239,27 +235,27 @@ func (s *server) newEvent(ctx context.Context, key *ResourceKey, value, oldValue
 		temp := &unstructured.Unstructured{}
 		err = temp.UnmarshalJSON(oldValue)
 		if err != nil {
-			return nil, err
+			return nil, AsErrorResult(err)
 		}
 		event.ObjectOld, err = utils.MetaAccessor(temp)
 		if err != nil {
-			return nil, err
+			return nil, AsErrorResult(err)
 		}
 	}
 
 	if key.Namespace != obj.GetNamespace() {
-		return nil, apierrors.NewBadRequest("key/namespace do not match")
+		return nil, NewBadRequestError("key/namespace do not match")
 	}
 
 	gvk := obj.GetGroupVersionKind()
 	if gvk.Kind == "" {
-		return nil, apierrors.NewBadRequest("expecting resources with a kind in the body")
+		return nil, NewBadRequestError("expecting resources with a kind in the body")
 	}
 	if gvk.Version == "" {
-		return nil, apierrors.NewBadRequest("expecting resources with an apiVersion")
+		return nil, NewBadRequestError("expecting resources with an apiVersion")
 	}
 	if gvk.Group != "" && gvk.Group != key.Group {
-		return nil, apierrors.NewBadRequest(
+		return nil, NewBadRequestError(
 			fmt.Sprintf("group in key does not match group in the body (%s != %s)", key.Group, gvk.Group),
 		)
 	}
@@ -267,15 +263,14 @@ func (s *server) newEvent(ctx context.Context, key *ResourceKey, value, oldValue
 	// This needs to be a create function
 	if key.Name == "" {
 		if obj.GetName() == "" {
-			return nil, apierrors.NewBadRequest("missing name")
+			return nil, NewBadRequestError("missing name")
 		}
 		key.Name = obj.GetName()
 	} else if key.Name != obj.GetName() {
-		return nil, apierrors.NewBadRequest(
+		return nil, NewBadRequestError(
 			fmt.Sprintf("key/name do not match (key: %s, name: %s)", key.Name, obj.GetName()))
 	}
-	err = validateName(obj.GetName())
-	if err != nil {
+	if err := validateName(obj.GetName()); err != nil {
 		return nil, err
 	}
 
@@ -283,17 +278,17 @@ func (s *server) newEvent(ctx context.Context, key *ResourceKey, value, oldValue
 	if folder != "" {
 		err = s.access.CanWriteFolder(ctx, user, folder)
 		if err != nil {
-			return nil, err
+			return nil, AsErrorResult(err)
 		}
 	}
 	origin, err := obj.GetOriginInfo()
 	if err != nil {
-		return nil, apierrors.NewBadRequest("invalid origin info")
+		return nil, NewBadRequestError("invalid origin info")
 	}
 	if origin != nil {
 		err = s.access.CanWriteOrigin(ctx, user, origin.Name)
 		if err != nil {
-			return nil, err
+			return nil, AsErrorResult(err)
 		}
 	}
 	return event, nil
@@ -308,6 +303,15 @@ func (s *server) Create(ctx context.Context, req *CreateRequest) (*CreateRespons
 	}
 
 	rsp := &CreateResponse{}
+	user, err := identity.GetRequester(ctx)
+	if err != nil || user == nil {
+		rsp.Error = &ErrorResult{
+			Message: "no user found in context",
+			Code:    http.StatusUnauthorized,
+		}
+		return rsp, nil
+	}
+
 	found := s.backend.ReadResource(ctx, &ReadRequest{Key: req.Key})
 	if found != nil && len(found.Value) > 0 {
 		rsp.Error = &ErrorResult{
@@ -317,9 +321,9 @@ func (s *server) Create(ctx context.Context, req *CreateRequest) (*CreateRespons
 		return rsp, nil
 	}
 
-	event, err := s.newEvent(ctx, req.Key, req.Value, nil)
-	if err != nil {
-		rsp.Error = AsErrorResult(err)
+	event, e := s.newEvent(ctx, user, req.Key, req.Value, nil)
+	if e != nil {
+		rsp.Error = e
 		return rsp, nil
 	}
 
@@ -339,6 +343,14 @@ func (s *server) Update(ctx context.Context, req *UpdateRequest) (*UpdateRespons
 	}
 
 	rsp := &UpdateResponse{}
+	user, err := identity.GetRequester(ctx)
+	if err != nil || user == nil {
+		rsp.Error = &ErrorResult{
+			Message: "no user found in context",
+			Code:    http.StatusUnauthorized,
+		}
+		return rsp, nil
+	}
 	if req.ResourceVersion < 0 {
 		rsp.Error = AsErrorResult(apierrors.NewBadRequest("update must include the previous version"))
 		return rsp, nil
@@ -359,9 +371,9 @@ func (s *server) Update(ctx context.Context, req *UpdateRequest) (*UpdateRespons
 		return nil, ErrOptimisticLockingFailed
 	}
 
-	event, err := s.newEvent(ctx, req.Key, req.Value, latest.Value)
-	if err != nil {
-		rsp.Error = AsErrorResult(err)
+	event, e := s.newEvent(ctx, user, req.Key, req.Value, latest.Value)
+	if e != nil {
+		rsp.Error = e
 		return rsp, err
 	}
 
diff --git a/pkg/storage/unified/resource/validation.go b/pkg/storage/unified/resource/validation.go
index 5ce5362717a..dce25a1b8fe 100644
--- a/pkg/storage/unified/resource/validation.go
+++ b/pkg/storage/unified/resource/validation.go
@@ -1,22 +1,21 @@
 package resource
 
 import (
-	"fmt"
 	"regexp"
 )
 
 var validNameCharPattern = `a-zA-Z0-9\-\_\.`
 var validNamePattern = regexp.MustCompile(`^[` + validNameCharPattern + `]*$`).MatchString
 
-func validateName(name string) error {
+func validateName(name string) *ErrorResult {
 	if len(name) == 0 {
-		return fmt.Errorf("name is too short")
+		return NewBadRequestError("name is too short")
 	}
 	if len(name) > 64 {
-		return fmt.Errorf("name is too long")
+		return NewBadRequestError("name is too long")
 	}
 	if !validNamePattern(name) {
-		return fmt.Errorf("name includes invalid characters")
+		return NewBadRequestError("name includes invalid characters")
 	}
 	// In standard k8s, it must not start with a number
 	// however that would force us to update many many many existing resources
diff --git a/pkg/storage/unified/resource/validation_test.go b/pkg/storage/unified/resource/validation_test.go
index 9b4907d8630..b9f9a51d7b5 100644
--- a/pkg/storage/unified/resource/validation_test.go
+++ b/pkg/storage/unified/resource/validation_test.go
@@ -7,24 +7,24 @@ import (
 )
 
 func TestNameValidation(t *testing.T) {
-	require.Error(t, validateName("")) // too short
-	require.Error(t, validateName(     // too long (max 64)
+	require.NotNil(t, validateName("")) // too short
+	require.NotNil(t, validateName(     // too long (max 64)
 		"0123456789012345678901234567890123456789012345678901234567890123456789",
 	))
 
 	// OK
-	require.NoError(t, validateName("a"))
-	require.NoError(t, validateName("hello-world"))
-	require.NoError(t, validateName("hello.world"))
-	require.NoError(t, validateName("hello_world"))
+	require.Nil(t, validateName("a"))
+	require.Nil(t, validateName("hello-world"))
+	require.Nil(t, validateName("hello.world"))
+	require.Nil(t, validateName("hello_world"))
 
 	// Bad characters
-	require.Error(t, validateName("hello world"))
-	require.Error(t, validateName("hello!"))
-	require.Error(t, validateName("hello~"))
-	require.Error(t, validateName("hello "))
-	require.Error(t, validateName("hello*"))
-	require.Error(t, validateName("hello+"))
-	require.Error(t, validateName("hello="))
-	require.Error(t, validateName("hello%"))
+	require.NotNil(t, validateName("hello world"))
+	require.NotNil(t, validateName("hello!"))
+	require.NotNil(t, validateName("hello~"))
+	require.NotNil(t, validateName("hello "))
+	require.NotNil(t, validateName("hello*"))
+	require.NotNil(t, validateName("hello+"))
+	require.NotNil(t, validateName("hello="))
+	require.NotNil(t, validateName("hello%"))
 }
diff --git a/public/app/core/icons/cached.json b/public/app/core/icons/cached.json
index 4bfb615427e..9d2af6a7ff5 100644
--- a/public/app/core/icons/cached.json
+++ b/public/app/core/icons/cached.json
@@ -25,6 +25,7 @@
   "unicons/bell-slash",
   "unicons/bolt",
   "unicons/book",
+  "unicons/bookmark",
   "unicons/book-open",
   "unicons/brackets-curly",
   "unicons/bug",
@@ -170,5 +171,6 @@
   "mono/heart-break",
   "mono/panel-add",
   "mono/library-panel",
-  "unicons/record-audio"
+  "unicons/record-audio",
+  "solid/bookmark"
 ]
diff --git a/public/app/core/icons/iconBundle.ts b/public/app/core/icons/iconBundle.ts
index f493d0a71c2..b8ed8ae2cbf 100644
--- a/public/app/core/icons/iconBundle.ts
+++ b/public/app/core/icons/iconBundle.ts
@@ -33,152 +33,154 @@ import u1022 from '../../../img/icons/unicons/bell.svg';
 import u1023 from '../../../img/icons/unicons/bell-slash.svg';
 import u1024 from '../../../img/icons/unicons/bolt.svg';
 import u1025 from '../../../img/icons/unicons/book.svg';
-import u1026 from '../../../img/icons/unicons/book-open.svg';
-import u1027 from '../../../img/icons/unicons/brackets-curly.svg';
-import u1028 from '../../../img/icons/unicons/bug.svg';
-import u1029 from '../../../img/icons/unicons/building.svg';
-import u1030 from '../../../img/icons/unicons/calculator-alt.svg';
-import u1031 from '../../../img/icons/unicons/calendar-alt.svg';
-import u1032 from '../../../img/icons/unicons/calendar-slash.svg';
-import u1033 from '../../../img/icons/unicons/camera.svg';
-import u1034 from '../../../img/icons/unicons/channel-add.svg';
-import u1035 from '../../../img/icons/unicons/chart-line.svg';
-import u1036 from '../../../img/icons/unicons/check.svg';
-import u1037 from '../../../img/icons/unicons/check-circle.svg';
-import u1038 from '../../../img/icons/unicons/circle.svg';
-import u1039 from '../../../img/icons/unicons/clipboard-alt.svg';
-import u1040 from '../../../img/icons/unicons/clock-nine.svg';
-import u1041 from '../../../img/icons/unicons/cloud.svg';
-import u1042 from '../../../img/icons/unicons/cloud-download.svg';
-import u1043 from '../../../img/icons/unicons/code-branch.svg';
-import u1044 from '../../../img/icons/unicons/cog.svg';
-import u1045 from '../../../img/icons/unicons/columns.svg';
-import u1046 from '../../../img/icons/unicons/comment-alt.svg';
-import u1047 from '../../../img/icons/unicons/comment-alt-share.svg';
-import u1048 from '../../../img/icons/unicons/comments-alt.svg';
-import u1049 from '../../../img/icons/unicons/compass.svg';
-import u1050 from '../../../img/icons/unicons/copy.svg';
-import u1051 from '../../../img/icons/unicons/corner-down-right-alt.svg';
-import u1052 from '../../../img/icons/unicons/cube.svg';
-import u1053 from '../../../img/icons/unicons/dashboard.svg';
-import u1054 from '../../../img/icons/unicons/database.svg';
-import u1055 from '../../../img/icons/unicons/document-info.svg';
-import u1056 from '../../../img/icons/unicons/download-alt.svg';
-import u1057 from '../../../img/icons/unicons/draggabledots.svg';
-import u1058 from '../../../img/icons/unicons/edit.svg';
-import u1059 from '../../../img/icons/unicons/ellipsis-v.svg';
-import u1060 from '../../../img/icons/unicons/ellipsis-h.svg';
-import u1061 from '../../../img/icons/unicons/envelope.svg';
-import u1062 from '../../../img/icons/unicons/exchange-alt.svg';
-import u1063 from '../../../img/icons/unicons/exclamation-circle.svg';
-import u1064 from '../../../img/icons/unicons/exclamation-triangle.svg';
-import u1065 from '../../../img/icons/unicons/external-link-alt.svg';
-import u1066 from '../../../img/icons/unicons/eye.svg';
-import u1067 from '../../../img/icons/unicons/eye-slash.svg';
-import u1068 from '../../../img/icons/unicons/file-alt.svg';
-import u1069 from '../../../img/icons/unicons/file-blank.svg';
-import u1070 from '../../../img/icons/unicons/filter.svg';
-import u1071 from '../../../img/icons/unicons/folder.svg';
-import u1072 from '../../../img/icons/unicons/folder-open.svg';
-import u1073 from '../../../img/icons/unicons/folder-plus.svg';
-import u1074 from '../../../img/icons/unicons/folder-upload.svg';
-import u1075 from '../../../img/icons/unicons/forward.svg';
-import u1076 from '../../../img/icons/unicons/graph-bar.svg';
-import u1077 from '../../../img/icons/unicons/history.svg';
-import u1078 from '../../../img/icons/unicons/history-alt.svg';
-import u1079 from '../../../img/icons/unicons/home-alt.svg';
-import u1080 from '../../../img/icons/unicons/import.svg';
-import u1081 from '../../../img/icons/unicons/info.svg';
-import u1082 from '../../../img/icons/unicons/info-circle.svg';
-import u1083 from '../../../img/icons/unicons/k6.svg';
-import u1084 from '../../../img/icons/unicons/key-skeleton-alt.svg';
-import u1085 from '../../../img/icons/unicons/keyboard.svg';
-import u1086 from '../../../img/icons/unicons/link.svg';
-import u1087 from '../../../img/icons/unicons/list-ul.svg';
-import u1088 from '../../../img/icons/unicons/lock.svg';
-import u1089 from '../../../img/icons/unicons/minus.svg';
-import u1090 from '../../../img/icons/unicons/minus-circle.svg';
-import u1091 from '../../../img/icons/unicons/mobile-android.svg';
-import u1092 from '../../../img/icons/unicons/monitor.svg';
-import u1093 from '../../../img/icons/unicons/pause.svg';
-import u1094 from '../../../img/icons/unicons/pen.svg';
-import u1095 from '../../../img/icons/unicons/play.svg';
-import u1096 from '../../../img/icons/unicons/plug.svg';
-import u1097 from '../../../img/icons/unicons/plus.svg';
-import u1098 from '../../../img/icons/unicons/plus-circle.svg';
-import u1099 from '../../../img/icons/unicons/power.svg';
-import u1100 from '../../../img/icons/unicons/presentation-play.svg';
-import u1101 from '../../../img/icons/unicons/process.svg';
-import u1102 from '../../../img/icons/unicons/question-circle.svg';
-import u1103 from '../../../img/icons/unicons/repeat.svg';
-import u1104 from '../../../img/icons/unicons/rocket.svg';
-import u1105 from '../../../img/icons/unicons/rss.svg';
-import u1106 from '../../../img/icons/unicons/save.svg';
-import u1107 from '../../../img/icons/unicons/search.svg';
-import u1108 from '../../../img/icons/unicons/search-minus.svg';
-import u1109 from '../../../img/icons/unicons/search-plus.svg';
-import u1110 from '../../../img/icons/unicons/share-alt.svg';
-import u1111 from '../../../img/icons/unicons/shield.svg';
-import u1112 from '../../../img/icons/unicons/signal.svg';
-import u1113 from '../../../img/icons/unicons/signin.svg';
-import u1114 from '../../../img/icons/unicons/signout.svg';
-import u1115 from '../../../img/icons/unicons/sitemap.svg';
-import u1116 from '../../../img/icons/unicons/slack.svg';
-import u1117 from '../../../img/icons/unicons/sliders-v-alt.svg';
-import u1118 from '../../../img/icons/unicons/sort-amount-down.svg';
-import u1119 from '../../../img/icons/unicons/sort-amount-up.svg';
-import u1120 from '../../../img/icons/unicons/square-shape.svg';
-import u1121 from '../../../img/icons/unicons/star.svg';
-import u1122 from '../../../img/icons/unicons/step-backward.svg';
-import u1123 from '../../../img/icons/unicons/sync.svg';
-import u1124 from '../../../img/icons/unicons/stopwatch.svg';
-import u1125 from '../../../img/icons/unicons/table.svg';
-import u1126 from '../../../img/icons/unicons/tag-alt.svg';
-import u1127 from '../../../img/icons/unicons/times.svg';
-import u1128 from '../../../img/icons/unicons/trash-alt.svg';
-import u1129 from '../../../img/icons/unicons/unlock.svg';
-import u1130 from '../../../img/icons/unicons/upload.svg';
-import u1131 from '../../../img/icons/unicons/user.svg';
-import u1132 from '../../../img/icons/unicons/users-alt.svg';
-import u1133 from '../../../img/icons/unicons/wrap-text.svg';
-import u1134 from '../../../img/icons/unicons/cloud-upload.svg';
-import u1135 from '../../../img/icons/unicons/credit-card.svg';
-import u1136 from '../../../img/icons/unicons/file-copy-alt.svg';
-import u1137 from '../../../img/icons/unicons/fire.svg';
-import u1138 from '../../../img/icons/unicons/hourglass.svg';
-import u1139 from '../../../img/icons/unicons/layer-group.svg';
-import u1140 from '../../../img/icons/unicons/layers-alt.svg';
-import u1141 from '../../../img/icons/unicons/line-alt.svg';
-import u1142 from '../../../img/icons/unicons/list-ui-alt.svg';
-import u1143 from '../../../img/icons/unicons/message.svg';
-import u1144 from '../../../img/icons/unicons/palette.svg';
-import u1145 from '../../../img/icons/unicons/percentage.svg';
-import u1146 from '../../../img/icons/unicons/shield-exclamation.svg';
-import u1147 from '../../../img/icons/unicons/plus-square.svg';
-import u1148 from '../../../img/icons/unicons/x.svg';
-import u1149 from '../../../img/icons/unicons/capture.svg';
-import u1150 from '../../../img/icons/custom/gf-grid.svg';
-import u1151 from '../../../img/icons/custom/gf-landscape.svg';
-import u1152 from '../../../img/icons/custom/gf-layout-simple.svg';
-import u1153 from '../../../img/icons/custom/gf-portrait.svg';
-import u1154 from '../../../img/icons/custom/gf-show-context.svg';
-import u1155 from '../../../img/icons/custom/gf-bar-alignment-after.svg';
-import u1156 from '../../../img/icons/custom/gf-bar-alignment-before.svg';
-import u1157 from '../../../img/icons/custom/gf-bar-alignment-center.svg';
-import u1158 from '../../../img/icons/custom/gf-interpolation-linear.svg';
-import u1159 from '../../../img/icons/custom/gf-interpolation-smooth.svg';
-import u1160 from '../../../img/icons/custom/gf-interpolation-step-after.svg';
-import u1161 from '../../../img/icons/custom/gf-interpolation-step-before.svg';
-import u1162 from '../../../img/icons/custom/gf-logs.svg';
-import u1163 from '../../../img/icons/custom/gf-movepane-left.svg';
-import u1164 from '../../../img/icons/custom/gf-movepane-right.svg';
-import u1165 from '../../../img/icons/mono/favorite.svg';
-import u1166 from '../../../img/icons/mono/grafana.svg';
-import u1167 from '../../../img/icons/mono/heart.svg';
-import u1168 from '../../../img/icons/mono/heart-break.svg';
-import u1169 from '../../../img/icons/mono/panel-add.svg';
-import u1170 from '../../../img/icons/mono/library-panel.svg';
-import u1171 from '../../../img/icons/unicons/record-audio.svg';
+import u1026 from '../../../img/icons/unicons/bookmark.svg';
+import u1027 from '../../../img/icons/unicons/book-open.svg';
+import u1028 from '../../../img/icons/unicons/brackets-curly.svg';
+import u1029 from '../../../img/icons/unicons/bug.svg';
+import u1030 from '../../../img/icons/unicons/building.svg';
+import u1031 from '../../../img/icons/unicons/calculator-alt.svg';
+import u1032 from '../../../img/icons/unicons/calendar-alt.svg';
+import u1033 from '../../../img/icons/unicons/calendar-slash.svg';
+import u1034 from '../../../img/icons/unicons/camera.svg';
+import u1035 from '../../../img/icons/unicons/channel-add.svg';
+import u1036 from '../../../img/icons/unicons/chart-line.svg';
+import u1037 from '../../../img/icons/unicons/check.svg';
+import u1038 from '../../../img/icons/unicons/check-circle.svg';
+import u1039 from '../../../img/icons/unicons/circle.svg';
+import u1040 from '../../../img/icons/unicons/clipboard-alt.svg';
+import u1041 from '../../../img/icons/unicons/clock-nine.svg';
+import u1042 from '../../../img/icons/unicons/cloud.svg';
+import u1043 from '../../../img/icons/unicons/cloud-download.svg';
+import u1044 from '../../../img/icons/unicons/code-branch.svg';
+import u1045 from '../../../img/icons/unicons/cog.svg';
+import u1046 from '../../../img/icons/unicons/columns.svg';
+import u1047 from '../../../img/icons/unicons/comment-alt.svg';
+import u1048 from '../../../img/icons/unicons/comment-alt-share.svg';
+import u1049 from '../../../img/icons/unicons/comments-alt.svg';
+import u1050 from '../../../img/icons/unicons/compass.svg';
+import u1051 from '../../../img/icons/unicons/copy.svg';
+import u1052 from '../../../img/icons/unicons/corner-down-right-alt.svg';
+import u1053 from '../../../img/icons/unicons/cube.svg';
+import u1054 from '../../../img/icons/unicons/dashboard.svg';
+import u1055 from '../../../img/icons/unicons/database.svg';
+import u1056 from '../../../img/icons/unicons/document-info.svg';
+import u1057 from '../../../img/icons/unicons/download-alt.svg';
+import u1058 from '../../../img/icons/unicons/draggabledots.svg';
+import u1059 from '../../../img/icons/unicons/edit.svg';
+import u1060 from '../../../img/icons/unicons/ellipsis-v.svg';
+import u1061 from '../../../img/icons/unicons/ellipsis-h.svg';
+import u1062 from '../../../img/icons/unicons/envelope.svg';
+import u1063 from '../../../img/icons/unicons/exchange-alt.svg';
+import u1064 from '../../../img/icons/unicons/exclamation-circle.svg';
+import u1065 from '../../../img/icons/unicons/exclamation-triangle.svg';
+import u1066 from '../../../img/icons/unicons/external-link-alt.svg';
+import u1067 from '../../../img/icons/unicons/eye.svg';
+import u1068 from '../../../img/icons/unicons/eye-slash.svg';
+import u1069 from '../../../img/icons/unicons/file-alt.svg';
+import u1070 from '../../../img/icons/unicons/file-blank.svg';
+import u1071 from '../../../img/icons/unicons/filter.svg';
+import u1072 from '../../../img/icons/unicons/folder.svg';
+import u1073 from '../../../img/icons/unicons/folder-open.svg';
+import u1074 from '../../../img/icons/unicons/folder-plus.svg';
+import u1075 from '../../../img/icons/unicons/folder-upload.svg';
+import u1076 from '../../../img/icons/unicons/forward.svg';
+import u1077 from '../../../img/icons/unicons/graph-bar.svg';
+import u1078 from '../../../img/icons/unicons/history.svg';
+import u1079 from '../../../img/icons/unicons/history-alt.svg';
+import u1080 from '../../../img/icons/unicons/home-alt.svg';
+import u1081 from '../../../img/icons/unicons/import.svg';
+import u1082 from '../../../img/icons/unicons/info.svg';
+import u1083 from '../../../img/icons/unicons/info-circle.svg';
+import u1084 from '../../../img/icons/unicons/k6.svg';
+import u1085 from '../../../img/icons/unicons/key-skeleton-alt.svg';
+import u1086 from '../../../img/icons/unicons/keyboard.svg';
+import u1087 from '../../../img/icons/unicons/link.svg';
+import u1088 from '../../../img/icons/unicons/list-ul.svg';
+import u1089 from '../../../img/icons/unicons/lock.svg';
+import u1090 from '../../../img/icons/unicons/minus.svg';
+import u1091 from '../../../img/icons/unicons/minus-circle.svg';
+import u1092 from '../../../img/icons/unicons/mobile-android.svg';
+import u1093 from '../../../img/icons/unicons/monitor.svg';
+import u1094 from '../../../img/icons/unicons/pause.svg';
+import u1095 from '../../../img/icons/unicons/pen.svg';
+import u1096 from '../../../img/icons/unicons/play.svg';
+import u1097 from '../../../img/icons/unicons/plug.svg';
+import u1098 from '../../../img/icons/unicons/plus.svg';
+import u1099 from '../../../img/icons/unicons/plus-circle.svg';
+import u1100 from '../../../img/icons/unicons/power.svg';
+import u1101 from '../../../img/icons/unicons/presentation-play.svg';
+import u1102 from '../../../img/icons/unicons/process.svg';
+import u1103 from '../../../img/icons/unicons/question-circle.svg';
+import u1104 from '../../../img/icons/unicons/repeat.svg';
+import u1105 from '../../../img/icons/unicons/rocket.svg';
+import u1106 from '../../../img/icons/unicons/rss.svg';
+import u1107 from '../../../img/icons/unicons/save.svg';
+import u1108 from '../../../img/icons/unicons/search.svg';
+import u1109 from '../../../img/icons/unicons/search-minus.svg';
+import u1110 from '../../../img/icons/unicons/search-plus.svg';
+import u1111 from '../../../img/icons/unicons/share-alt.svg';
+import u1112 from '../../../img/icons/unicons/shield.svg';
+import u1113 from '../../../img/icons/unicons/signal.svg';
+import u1114 from '../../../img/icons/unicons/signin.svg';
+import u1115 from '../../../img/icons/unicons/signout.svg';
+import u1116 from '../../../img/icons/unicons/sitemap.svg';
+import u1117 from '../../../img/icons/unicons/slack.svg';
+import u1118 from '../../../img/icons/unicons/sliders-v-alt.svg';
+import u1119 from '../../../img/icons/unicons/sort-amount-down.svg';
+import u1120 from '../../../img/icons/unicons/sort-amount-up.svg';
+import u1121 from '../../../img/icons/unicons/square-shape.svg';
+import u1122 from '../../../img/icons/unicons/star.svg';
+import u1123 from '../../../img/icons/unicons/step-backward.svg';
+import u1124 from '../../../img/icons/unicons/sync.svg';
+import u1125 from '../../../img/icons/unicons/stopwatch.svg';
+import u1126 from '../../../img/icons/unicons/table.svg';
+import u1127 from '../../../img/icons/unicons/tag-alt.svg';
+import u1128 from '../../../img/icons/unicons/times.svg';
+import u1129 from '../../../img/icons/unicons/trash-alt.svg';
+import u1130 from '../../../img/icons/unicons/unlock.svg';
+import u1131 from '../../../img/icons/unicons/upload.svg';
+import u1132 from '../../../img/icons/unicons/user.svg';
+import u1133 from '../../../img/icons/unicons/users-alt.svg';
+import u1134 from '../../../img/icons/unicons/wrap-text.svg';
+import u1135 from '../../../img/icons/unicons/cloud-upload.svg';
+import u1136 from '../../../img/icons/unicons/credit-card.svg';
+import u1137 from '../../../img/icons/unicons/file-copy-alt.svg';
+import u1138 from '../../../img/icons/unicons/fire.svg';
+import u1139 from '../../../img/icons/unicons/hourglass.svg';
+import u1140 from '../../../img/icons/unicons/layer-group.svg';
+import u1141 from '../../../img/icons/unicons/layers-alt.svg';
+import u1142 from '../../../img/icons/unicons/line-alt.svg';
+import u1143 from '../../../img/icons/unicons/list-ui-alt.svg';
+import u1144 from '../../../img/icons/unicons/message.svg';
+import u1145 from '../../../img/icons/unicons/palette.svg';
+import u1146 from '../../../img/icons/unicons/percentage.svg';
+import u1147 from '../../../img/icons/unicons/shield-exclamation.svg';
+import u1148 from '../../../img/icons/unicons/plus-square.svg';
+import u1149 from '../../../img/icons/unicons/x.svg';
+import u1150 from '../../../img/icons/unicons/capture.svg';
+import u1151 from '../../../img/icons/custom/gf-grid.svg';
+import u1152 from '../../../img/icons/custom/gf-landscape.svg';
+import u1153 from '../../../img/icons/custom/gf-layout-simple.svg';
+import u1154 from '../../../img/icons/custom/gf-portrait.svg';
+import u1155 from '../../../img/icons/custom/gf-show-context.svg';
+import u1156 from '../../../img/icons/custom/gf-bar-alignment-after.svg';
+import u1157 from '../../../img/icons/custom/gf-bar-alignment-before.svg';
+import u1158 from '../../../img/icons/custom/gf-bar-alignment-center.svg';
+import u1159 from '../../../img/icons/custom/gf-interpolation-linear.svg';
+import u1160 from '../../../img/icons/custom/gf-interpolation-smooth.svg';
+import u1161 from '../../../img/icons/custom/gf-interpolation-step-after.svg';
+import u1162 from '../../../img/icons/custom/gf-interpolation-step-before.svg';
+import u1163 from '../../../img/icons/custom/gf-logs.svg';
+import u1164 from '../../../img/icons/custom/gf-movepane-left.svg';
+import u1165 from '../../../img/icons/custom/gf-movepane-right.svg';
+import u1166 from '../../../img/icons/mono/favorite.svg';
+import u1167 from '../../../img/icons/mono/grafana.svg';
+import u1168 from '../../../img/icons/mono/heart.svg';
+import u1169 from '../../../img/icons/mono/heart-break.svg';
+import u1170 from '../../../img/icons/mono/panel-add.svg';
+import u1171 from '../../../img/icons/mono/library-panel.svg';
+import u1172 from '../../../img/icons/unicons/record-audio.svg';
+import u1173 from '../../../img/icons/solid/bookmark.svg';
 // do not edit this list directly
 // the list of icons live here: @grafana/ui/components/Icon/cached.json
 
@@ -238,152 +240,154 @@ export function initIconCache() {
   cacheItem(u1023, resolvePath('unicons/bell-slash.svg'));
   cacheItem(u1024, resolvePath('unicons/bolt.svg'));
   cacheItem(u1025, resolvePath('unicons/book.svg'));
-  cacheItem(u1026, resolvePath('unicons/book-open.svg'));
-  cacheItem(u1027, resolvePath('unicons/brackets-curly.svg'));
-  cacheItem(u1028, resolvePath('unicons/bug.svg'));
-  cacheItem(u1029, resolvePath('unicons/building.svg'));
-  cacheItem(u1030, resolvePath('unicons/calculator-alt.svg'));
-  cacheItem(u1031, resolvePath('unicons/calendar-alt.svg'));
-  cacheItem(u1032, resolvePath('unicons/calendar-slash.svg'));
-  cacheItem(u1033, resolvePath('unicons/camera.svg'));
-  cacheItem(u1034, resolvePath('unicons/channel-add.svg'));
-  cacheItem(u1035, resolvePath('unicons/chart-line.svg'));
-  cacheItem(u1036, resolvePath('unicons/check.svg'));
-  cacheItem(u1037, resolvePath('unicons/check-circle.svg'));
-  cacheItem(u1038, resolvePath('unicons/circle.svg'));
-  cacheItem(u1039, resolvePath('unicons/clipboard-alt.svg'));
-  cacheItem(u1040, resolvePath('unicons/clock-nine.svg'));
-  cacheItem(u1041, resolvePath('unicons/cloud.svg'));
-  cacheItem(u1042, resolvePath('unicons/cloud-download.svg'));
-  cacheItem(u1043, resolvePath('unicons/code-branch.svg'));
-  cacheItem(u1044, resolvePath('unicons/cog.svg'));
-  cacheItem(u1045, resolvePath('unicons/columns.svg'));
-  cacheItem(u1046, resolvePath('unicons/comment-alt.svg'));
-  cacheItem(u1047, resolvePath('unicons/comment-alt-share.svg'));
-  cacheItem(u1048, resolvePath('unicons/comments-alt.svg'));
-  cacheItem(u1049, resolvePath('unicons/compass.svg'));
-  cacheItem(u1050, resolvePath('unicons/copy.svg'));
-  cacheItem(u1051, resolvePath('unicons/corner-down-right-alt.svg'));
-  cacheItem(u1052, resolvePath('unicons/cube.svg'));
-  cacheItem(u1053, resolvePath('unicons/dashboard.svg'));
-  cacheItem(u1054, resolvePath('unicons/database.svg'));
-  cacheItem(u1055, resolvePath('unicons/document-info.svg'));
-  cacheItem(u1056, resolvePath('unicons/download-alt.svg'));
-  cacheItem(u1057, resolvePath('unicons/draggabledots.svg'));
-  cacheItem(u1058, resolvePath('unicons/edit.svg'));
-  cacheItem(u1059, resolvePath('unicons/ellipsis-v.svg'));
-  cacheItem(u1060, resolvePath('unicons/ellipsis-h.svg'));
-  cacheItem(u1061, resolvePath('unicons/envelope.svg'));
-  cacheItem(u1062, resolvePath('unicons/exchange-alt.svg'));
-  cacheItem(u1063, resolvePath('unicons/exclamation-circle.svg'));
-  cacheItem(u1064, resolvePath('unicons/exclamation-triangle.svg'));
-  cacheItem(u1065, resolvePath('unicons/external-link-alt.svg'));
-  cacheItem(u1066, resolvePath('unicons/eye.svg'));
-  cacheItem(u1067, resolvePath('unicons/eye-slash.svg'));
-  cacheItem(u1068, resolvePath('unicons/file-alt.svg'));
-  cacheItem(u1069, resolvePath('unicons/file-blank.svg'));
-  cacheItem(u1070, resolvePath('unicons/filter.svg'));
-  cacheItem(u1071, resolvePath('unicons/folder.svg'));
-  cacheItem(u1072, resolvePath('unicons/folder-open.svg'));
-  cacheItem(u1073, resolvePath('unicons/folder-plus.svg'));
-  cacheItem(u1074, resolvePath('unicons/folder-upload.svg'));
-  cacheItem(u1075, resolvePath('unicons/forward.svg'));
-  cacheItem(u1076, resolvePath('unicons/graph-bar.svg'));
-  cacheItem(u1077, resolvePath('unicons/history.svg'));
-  cacheItem(u1078, resolvePath('unicons/history-alt.svg'));
-  cacheItem(u1079, resolvePath('unicons/home-alt.svg'));
-  cacheItem(u1080, resolvePath('unicons/import.svg'));
-  cacheItem(u1081, resolvePath('unicons/info.svg'));
-  cacheItem(u1082, resolvePath('unicons/info-circle.svg'));
-  cacheItem(u1083, resolvePath('unicons/k6.svg'));
-  cacheItem(u1084, resolvePath('unicons/key-skeleton-alt.svg'));
-  cacheItem(u1085, resolvePath('unicons/keyboard.svg'));
-  cacheItem(u1086, resolvePath('unicons/link.svg'));
-  cacheItem(u1087, resolvePath('unicons/list-ul.svg'));
-  cacheItem(u1088, resolvePath('unicons/lock.svg'));
-  cacheItem(u1089, resolvePath('unicons/minus.svg'));
-  cacheItem(u1090, resolvePath('unicons/minus-circle.svg'));
-  cacheItem(u1091, resolvePath('unicons/mobile-android.svg'));
-  cacheItem(u1092, resolvePath('unicons/monitor.svg'));
-  cacheItem(u1093, resolvePath('unicons/pause.svg'));
-  cacheItem(u1094, resolvePath('unicons/pen.svg'));
-  cacheItem(u1095, resolvePath('unicons/play.svg'));
-  cacheItem(u1096, resolvePath('unicons/plug.svg'));
-  cacheItem(u1097, resolvePath('unicons/plus.svg'));
-  cacheItem(u1098, resolvePath('unicons/plus-circle.svg'));
-  cacheItem(u1099, resolvePath('unicons/power.svg'));
-  cacheItem(u1100, resolvePath('unicons/presentation-play.svg'));
-  cacheItem(u1101, resolvePath('unicons/process.svg'));
-  cacheItem(u1102, resolvePath('unicons/question-circle.svg'));
-  cacheItem(u1103, resolvePath('unicons/repeat.svg'));
-  cacheItem(u1104, resolvePath('unicons/rocket.svg'));
-  cacheItem(u1105, resolvePath('unicons/rss.svg'));
-  cacheItem(u1106, resolvePath('unicons/save.svg'));
-  cacheItem(u1107, resolvePath('unicons/search.svg'));
-  cacheItem(u1108, resolvePath('unicons/search-minus.svg'));
-  cacheItem(u1109, resolvePath('unicons/search-plus.svg'));
-  cacheItem(u1110, resolvePath('unicons/share-alt.svg'));
-  cacheItem(u1111, resolvePath('unicons/shield.svg'));
-  cacheItem(u1112, resolvePath('unicons/signal.svg'));
-  cacheItem(u1113, resolvePath('unicons/signin.svg'));
-  cacheItem(u1114, resolvePath('unicons/signout.svg'));
-  cacheItem(u1115, resolvePath('unicons/sitemap.svg'));
-  cacheItem(u1116, resolvePath('unicons/slack.svg'));
-  cacheItem(u1117, resolvePath('unicons/sliders-v-alt.svg'));
-  cacheItem(u1118, resolvePath('unicons/sort-amount-down.svg'));
-  cacheItem(u1119, resolvePath('unicons/sort-amount-up.svg'));
-  cacheItem(u1120, resolvePath('unicons/square-shape.svg'));
-  cacheItem(u1121, resolvePath('unicons/star.svg'));
-  cacheItem(u1122, resolvePath('unicons/step-backward.svg'));
-  cacheItem(u1123, resolvePath('unicons/sync.svg'));
-  cacheItem(u1124, resolvePath('unicons/stopwatch.svg'));
-  cacheItem(u1125, resolvePath('unicons/table.svg'));
-  cacheItem(u1126, resolvePath('unicons/tag-alt.svg'));
-  cacheItem(u1127, resolvePath('unicons/times.svg'));
-  cacheItem(u1128, resolvePath('unicons/trash-alt.svg'));
-  cacheItem(u1129, resolvePath('unicons/unlock.svg'));
-  cacheItem(u1130, resolvePath('unicons/upload.svg'));
-  cacheItem(u1131, resolvePath('unicons/user.svg'));
-  cacheItem(u1132, resolvePath('unicons/users-alt.svg'));
-  cacheItem(u1133, resolvePath('unicons/wrap-text.svg'));
-  cacheItem(u1134, resolvePath('unicons/cloud-upload.svg'));
-  cacheItem(u1135, resolvePath('unicons/credit-card.svg'));
-  cacheItem(u1136, resolvePath('unicons/file-copy-alt.svg'));
-  cacheItem(u1137, resolvePath('unicons/fire.svg'));
-  cacheItem(u1138, resolvePath('unicons/hourglass.svg'));
-  cacheItem(u1139, resolvePath('unicons/layer-group.svg'));
-  cacheItem(u1140, resolvePath('unicons/layers-alt.svg'));
-  cacheItem(u1141, resolvePath('unicons/line-alt.svg'));
-  cacheItem(u1142, resolvePath('unicons/list-ui-alt.svg'));
-  cacheItem(u1143, resolvePath('unicons/message.svg'));
-  cacheItem(u1144, resolvePath('unicons/palette.svg'));
-  cacheItem(u1145, resolvePath('unicons/percentage.svg'));
-  cacheItem(u1146, resolvePath('unicons/shield-exclamation.svg'));
-  cacheItem(u1147, resolvePath('unicons/plus-square.svg'));
-  cacheItem(u1148, resolvePath('unicons/x.svg'));
-  cacheItem(u1149, resolvePath('unicons/capture.svg'));
-  cacheItem(u1150, resolvePath('custom/gf-grid.svg'));
-  cacheItem(u1151, resolvePath('custom/gf-landscape.svg'));
-  cacheItem(u1152, resolvePath('custom/gf-layout-simple.svg'));
-  cacheItem(u1153, resolvePath('custom/gf-portrait.svg'));
-  cacheItem(u1154, resolvePath('custom/gf-show-context.svg'));
-  cacheItem(u1155, resolvePath('custom/gf-bar-alignment-after.svg'));
-  cacheItem(u1156, resolvePath('custom/gf-bar-alignment-before.svg'));
-  cacheItem(u1157, resolvePath('custom/gf-bar-alignment-center.svg'));
-  cacheItem(u1158, resolvePath('custom/gf-interpolation-linear.svg'));
-  cacheItem(u1159, resolvePath('custom/gf-interpolation-smooth.svg'));
-  cacheItem(u1160, resolvePath('custom/gf-interpolation-step-after.svg'));
-  cacheItem(u1161, resolvePath('custom/gf-interpolation-step-before.svg'));
-  cacheItem(u1162, resolvePath('custom/gf-logs.svg'));
-  cacheItem(u1163, resolvePath('custom/gf-movepane-left.svg'));
-  cacheItem(u1164, resolvePath('custom/gf-movepane-right.svg'));
-  cacheItem(u1165, resolvePath('mono/favorite.svg'));
-  cacheItem(u1166, resolvePath('mono/grafana.svg'));
-  cacheItem(u1167, resolvePath('mono/heart.svg'));
-  cacheItem(u1168, resolvePath('mono/heart-break.svg'));
-  cacheItem(u1169, resolvePath('mono/panel-add.svg'));
-  cacheItem(u1170, resolvePath('mono/library-panel.svg'));
-  cacheItem(u1171, resolvePath('unicons/record-audio.svg'));
+  cacheItem(u1026, resolvePath('unicons/bookmark.svg'));
+  cacheItem(u1027, resolvePath('unicons/book-open.svg'));
+  cacheItem(u1028, resolvePath('unicons/brackets-curly.svg'));
+  cacheItem(u1029, resolvePath('unicons/bug.svg'));
+  cacheItem(u1030, resolvePath('unicons/building.svg'));
+  cacheItem(u1031, resolvePath('unicons/calculator-alt.svg'));
+  cacheItem(u1032, resolvePath('unicons/calendar-alt.svg'));
+  cacheItem(u1033, resolvePath('unicons/calendar-slash.svg'));
+  cacheItem(u1034, resolvePath('unicons/camera.svg'));
+  cacheItem(u1035, resolvePath('unicons/channel-add.svg'));
+  cacheItem(u1036, resolvePath('unicons/chart-line.svg'));
+  cacheItem(u1037, resolvePath('unicons/check.svg'));
+  cacheItem(u1038, resolvePath('unicons/check-circle.svg'));
+  cacheItem(u1039, resolvePath('unicons/circle.svg'));
+  cacheItem(u1040, resolvePath('unicons/clipboard-alt.svg'));
+  cacheItem(u1041, resolvePath('unicons/clock-nine.svg'));
+  cacheItem(u1042, resolvePath('unicons/cloud.svg'));
+  cacheItem(u1043, resolvePath('unicons/cloud-download.svg'));
+  cacheItem(u1044, resolvePath('unicons/code-branch.svg'));
+  cacheItem(u1045, resolvePath('unicons/cog.svg'));
+  cacheItem(u1046, resolvePath('unicons/columns.svg'));
+  cacheItem(u1047, resolvePath('unicons/comment-alt.svg'));
+  cacheItem(u1048, resolvePath('unicons/comment-alt-share.svg'));
+  cacheItem(u1049, resolvePath('unicons/comments-alt.svg'));
+  cacheItem(u1050, resolvePath('unicons/compass.svg'));
+  cacheItem(u1051, resolvePath('unicons/copy.svg'));
+  cacheItem(u1052, resolvePath('unicons/corner-down-right-alt.svg'));
+  cacheItem(u1053, resolvePath('unicons/cube.svg'));
+  cacheItem(u1054, resolvePath('unicons/dashboard.svg'));
+  cacheItem(u1055, resolvePath('unicons/database.svg'));
+  cacheItem(u1056, resolvePath('unicons/document-info.svg'));
+  cacheItem(u1057, resolvePath('unicons/download-alt.svg'));
+  cacheItem(u1058, resolvePath('unicons/draggabledots.svg'));
+  cacheItem(u1059, resolvePath('unicons/edit.svg'));
+  cacheItem(u1060, resolvePath('unicons/ellipsis-v.svg'));
+  cacheItem(u1061, resolvePath('unicons/ellipsis-h.svg'));
+  cacheItem(u1062, resolvePath('unicons/envelope.svg'));
+  cacheItem(u1063, resolvePath('unicons/exchange-alt.svg'));
+  cacheItem(u1064, resolvePath('unicons/exclamation-circle.svg'));
+  cacheItem(u1065, resolvePath('unicons/exclamation-triangle.svg'));
+  cacheItem(u1066, resolvePath('unicons/external-link-alt.svg'));
+  cacheItem(u1067, resolvePath('unicons/eye.svg'));
+  cacheItem(u1068, resolvePath('unicons/eye-slash.svg'));
+  cacheItem(u1069, resolvePath('unicons/file-alt.svg'));
+  cacheItem(u1070, resolvePath('unicons/file-blank.svg'));
+  cacheItem(u1071, resolvePath('unicons/filter.svg'));
+  cacheItem(u1072, resolvePath('unicons/folder.svg'));
+  cacheItem(u1073, resolvePath('unicons/folder-open.svg'));
+  cacheItem(u1074, resolvePath('unicons/folder-plus.svg'));
+  cacheItem(u1075, resolvePath('unicons/folder-upload.svg'));
+  cacheItem(u1076, resolvePath('unicons/forward.svg'));
+  cacheItem(u1077, resolvePath('unicons/graph-bar.svg'));
+  cacheItem(u1078, resolvePath('unicons/history.svg'));
+  cacheItem(u1079, resolvePath('unicons/history-alt.svg'));
+  cacheItem(u1080, resolvePath('unicons/home-alt.svg'));
+  cacheItem(u1081, resolvePath('unicons/import.svg'));
+  cacheItem(u1082, resolvePath('unicons/info.svg'));
+  cacheItem(u1083, resolvePath('unicons/info-circle.svg'));
+  cacheItem(u1084, resolvePath('unicons/k6.svg'));
+  cacheItem(u1085, resolvePath('unicons/key-skeleton-alt.svg'));
+  cacheItem(u1086, resolvePath('unicons/keyboard.svg'));
+  cacheItem(u1087, resolvePath('unicons/link.svg'));
+  cacheItem(u1088, resolvePath('unicons/list-ul.svg'));
+  cacheItem(u1089, resolvePath('unicons/lock.svg'));
+  cacheItem(u1090, resolvePath('unicons/minus.svg'));
+  cacheItem(u1091, resolvePath('unicons/minus-circle.svg'));
+  cacheItem(u1092, resolvePath('unicons/mobile-android.svg'));
+  cacheItem(u1093, resolvePath('unicons/monitor.svg'));
+  cacheItem(u1094, resolvePath('unicons/pause.svg'));
+  cacheItem(u1095, resolvePath('unicons/pen.svg'));
+  cacheItem(u1096, resolvePath('unicons/play.svg'));
+  cacheItem(u1097, resolvePath('unicons/plug.svg'));
+  cacheItem(u1098, resolvePath('unicons/plus.svg'));
+  cacheItem(u1099, resolvePath('unicons/plus-circle.svg'));
+  cacheItem(u1100, resolvePath('unicons/power.svg'));
+  cacheItem(u1101, resolvePath('unicons/presentation-play.svg'));
+  cacheItem(u1102, resolvePath('unicons/process.svg'));
+  cacheItem(u1103, resolvePath('unicons/question-circle.svg'));
+  cacheItem(u1104, resolvePath('unicons/repeat.svg'));
+  cacheItem(u1105, resolvePath('unicons/rocket.svg'));
+  cacheItem(u1106, resolvePath('unicons/rss.svg'));
+  cacheItem(u1107, resolvePath('unicons/save.svg'));
+  cacheItem(u1108, resolvePath('unicons/search.svg'));
+  cacheItem(u1109, resolvePath('unicons/search-minus.svg'));
+  cacheItem(u1110, resolvePath('unicons/search-plus.svg'));
+  cacheItem(u1111, resolvePath('unicons/share-alt.svg'));
+  cacheItem(u1112, resolvePath('unicons/shield.svg'));
+  cacheItem(u1113, resolvePath('unicons/signal.svg'));
+  cacheItem(u1114, resolvePath('unicons/signin.svg'));
+  cacheItem(u1115, resolvePath('unicons/signout.svg'));
+  cacheItem(u1116, resolvePath('unicons/sitemap.svg'));
+  cacheItem(u1117, resolvePath('unicons/slack.svg'));
+  cacheItem(u1118, resolvePath('unicons/sliders-v-alt.svg'));
+  cacheItem(u1119, resolvePath('unicons/sort-amount-down.svg'));
+  cacheItem(u1120, resolvePath('unicons/sort-amount-up.svg'));
+  cacheItem(u1121, resolvePath('unicons/square-shape.svg'));
+  cacheItem(u1122, resolvePath('unicons/star.svg'));
+  cacheItem(u1123, resolvePath('unicons/step-backward.svg'));
+  cacheItem(u1124, resolvePath('unicons/sync.svg'));
+  cacheItem(u1125, resolvePath('unicons/stopwatch.svg'));
+  cacheItem(u1126, resolvePath('unicons/table.svg'));
+  cacheItem(u1127, resolvePath('unicons/tag-alt.svg'));
+  cacheItem(u1128, resolvePath('unicons/times.svg'));
+  cacheItem(u1129, resolvePath('unicons/trash-alt.svg'));
+  cacheItem(u1130, resolvePath('unicons/unlock.svg'));
+  cacheItem(u1131, resolvePath('unicons/upload.svg'));
+  cacheItem(u1132, resolvePath('unicons/user.svg'));
+  cacheItem(u1133, resolvePath('unicons/users-alt.svg'));
+  cacheItem(u1134, resolvePath('unicons/wrap-text.svg'));
+  cacheItem(u1135, resolvePath('unicons/cloud-upload.svg'));
+  cacheItem(u1136, resolvePath('unicons/credit-card.svg'));
+  cacheItem(u1137, resolvePath('unicons/file-copy-alt.svg'));
+  cacheItem(u1138, resolvePath('unicons/fire.svg'));
+  cacheItem(u1139, resolvePath('unicons/hourglass.svg'));
+  cacheItem(u1140, resolvePath('unicons/layer-group.svg'));
+  cacheItem(u1141, resolvePath('unicons/layers-alt.svg'));
+  cacheItem(u1142, resolvePath('unicons/line-alt.svg'));
+  cacheItem(u1143, resolvePath('unicons/list-ui-alt.svg'));
+  cacheItem(u1144, resolvePath('unicons/message.svg'));
+  cacheItem(u1145, resolvePath('unicons/palette.svg'));
+  cacheItem(u1146, resolvePath('unicons/percentage.svg'));
+  cacheItem(u1147, resolvePath('unicons/shield-exclamation.svg'));
+  cacheItem(u1148, resolvePath('unicons/plus-square.svg'));
+  cacheItem(u1149, resolvePath('unicons/x.svg'));
+  cacheItem(u1150, resolvePath('unicons/capture.svg'));
+  cacheItem(u1151, resolvePath('custom/gf-grid.svg'));
+  cacheItem(u1152, resolvePath('custom/gf-landscape.svg'));
+  cacheItem(u1153, resolvePath('custom/gf-layout-simple.svg'));
+  cacheItem(u1154, resolvePath('custom/gf-portrait.svg'));
+  cacheItem(u1155, resolvePath('custom/gf-show-context.svg'));
+  cacheItem(u1156, resolvePath('custom/gf-bar-alignment-after.svg'));
+  cacheItem(u1157, resolvePath('custom/gf-bar-alignment-before.svg'));
+  cacheItem(u1158, resolvePath('custom/gf-bar-alignment-center.svg'));
+  cacheItem(u1159, resolvePath('custom/gf-interpolation-linear.svg'));
+  cacheItem(u1160, resolvePath('custom/gf-interpolation-smooth.svg'));
+  cacheItem(u1161, resolvePath('custom/gf-interpolation-step-after.svg'));
+  cacheItem(u1162, resolvePath('custom/gf-interpolation-step-before.svg'));
+  cacheItem(u1163, resolvePath('custom/gf-logs.svg'));
+  cacheItem(u1164, resolvePath('custom/gf-movepane-left.svg'));
+  cacheItem(u1165, resolvePath('custom/gf-movepane-right.svg'));
+  cacheItem(u1166, resolvePath('mono/favorite.svg'));
+  cacheItem(u1167, resolvePath('mono/grafana.svg'));
+  cacheItem(u1168, resolvePath('mono/heart.svg'));
+  cacheItem(u1169, resolvePath('mono/heart-break.svg'));
+  cacheItem(u1170, resolvePath('mono/panel-add.svg'));
+  cacheItem(u1171, resolvePath('mono/library-panel.svg'));
+  cacheItem(u1172, resolvePath('unicons/record-audio.svg'));
+  cacheItem(u1173, resolvePath('solid/bookmark.svg'));
   // do not edit this list directly
   // the list of icons live here: @grafana/ui/components/Icon/cached.json
 }
diff --git a/public/app/core/internationalization/index.tsx b/public/app/core/internationalization/index.tsx
index 895d7c58627..2d31fc1d708 100644
--- a/public/app/core/internationalization/index.tsx
+++ b/public/app/core/internationalization/index.tsx
@@ -1,5 +1,6 @@
 import i18n, { InitOptions, TFunction } from 'i18next';
 import LanguageDetector, { DetectorOptions } from 'i18next-browser-languagedetector';
+import { ReactElement } from 'react';
 import { Trans as I18NextTrans, initReactI18next } from 'react-i18next'; // eslint-disable-line no-restricted-imports
 
 import { DEFAULT_LANGUAGE, NAMESPACES, VALID_LANGUAGES } from './constants';
@@ -56,7 +57,14 @@ export function changeLanguage(locale: string) {
   return i18n.changeLanguage(validLocale);
 }
 
-export const Trans: typeof I18NextTrans = (props) => {
+type I18NextTransType = typeof I18NextTrans;
+type I18NextTransProps = Parameters<I18NextTransType>[0];
+
+interface TransProps extends I18NextTransProps {
+  i18nKey: string;
+}
+
+export const Trans = (props: TransProps): ReactElement => {
   return <I18NextTrans shouldUnescape ns={NAMESPACES} {...props} />;
 };
 
diff --git a/public/app/features/alerting/unified/components/Provisioning.tsx b/public/app/features/alerting/unified/components/Provisioning.tsx
index dd004ce64bf..33f4d866a9d 100644
--- a/public/app/features/alerting/unified/components/Provisioning.tsx
+++ b/public/app/features/alerting/unified/components/Provisioning.tsx
@@ -41,7 +41,7 @@ export const ProvisioningBadge = ({
 
   if (tooltip) {
     const provenanceTooltip = (
-      <Trans i18nKey="alerting.provisioning.badge-tooltip-provenance" provenance={provenance}>
+      <Trans i18nKey="alerting.provisioning.badge-tooltip-provenance" values={{ provenance }}>
         This resource has been provisioned via {{ provenance }} and cannot be edited through the UI
       </Trans>
     );
diff --git a/public/app/features/alerting/unified/components/contact-points/ContactPoint.tsx b/public/app/features/alerting/unified/components/contact-points/ContactPoint.tsx
index 1d671c25c21..f8b353a1059 100644
--- a/public/app/features/alerting/unified/components/contact-points/ContactPoint.tsx
+++ b/public/app/features/alerting/unified/components/contact-points/ContactPoint.tsx
@@ -39,7 +39,7 @@ export const ContactPoint = ({
   const styles = useStyles2(getStyles);
 
   // TODO probably not the best way to figure out if we want to show either only the summary or full metadata for the receivers?
-  const showFullMetadata = receivers.some((receiver) => Boolean(receiver[RECEIVER_STATUS_KEY]));
+  const showFullMetadata = receivers.some((receiver) => Boolean(receiver[RECEIVER_META_KEY]));
 
   return (
     <div className={styles.contactPointWrapper} data-testid="contact-point">
diff --git a/public/app/features/alerting/unified/components/contact-points/useContactPoints.tsx b/public/app/features/alerting/unified/components/contact-points/useContactPoints.tsx
index f5c9dbd14a1..c661ead47f0 100644
--- a/public/app/features/alerting/unified/components/contact-points/useContactPoints.tsx
+++ b/public/app/features/alerting/unified/components/contact-points/useContactPoints.tsx
@@ -11,6 +11,7 @@ import {
   ComGithubGrafanaGrafanaPkgApisAlertingNotificationsV0Alpha1Receiver,
   generatedReceiversApi,
 } from 'app/features/alerting/unified/openapi/receiversApi.gen';
+import { cloudNotifierTypes } from 'app/features/alerting/unified/utils/cloud-alertmanager-notifier-types';
 import { GRAFANA_RULES_SOURCE_NAME } from 'app/features/alerting/unified/utils/datasource';
 import { getNamespace, shouldUseK8sApi } from 'app/features/alerting/unified/utils/k8s/utils';
 
@@ -175,7 +176,7 @@ export function useContactPointsWithStatus() {
       contactPoints: result.data
         ? enhanceContactPointsWithMetadata(
             fetchContactPointsStatus.data,
-            fetchReceiverMetadata.data,
+            isGrafanaAlertmanager ? fetchReceiverMetadata.data : cloudNotifierTypes,
             onCallMetadata,
             result.data.alertmanager_config.receivers ?? [],
             result.data
diff --git a/public/app/features/alerting/unified/components/contact-points/utils.ts b/public/app/features/alerting/unified/components/contact-points/utils.ts
index 7f9d460b606..1fe8c162a20 100644
--- a/public/app/features/alerting/unified/components/contact-points/utils.ts
+++ b/public/app/features/alerting/unified/components/contact-points/utils.ts
@@ -34,13 +34,14 @@ export function getReceiverDescription(receiver: ReceiverConfigWithMetadata): Re
   if (!receiver.settings) {
     return undefined;
   }
+  const { settings } = receiver;
   switch (receiver.type) {
     case 'email': {
-      const hasEmailAddresses = 'addresses' in receiver.settings; // when dealing with alertmanager email_configs we don't normalize the settings
-      return hasEmailAddresses ? summarizeEmailAddresses(receiver.settings['addresses']) : undefined;
+      const addresses = settings.addresses || settings.to; // when dealing with alertmanager email_configs we don't normalize the settings
+      return addresses ? summarizeEmailAddresses(addresses) : undefined;
     }
     case 'slack': {
-      const recipient: string | undefined = receiver.settings['recipient'];
+      const recipient = settings.recipient || settings.channel;
       if (!recipient) {
         return;
       }
@@ -50,12 +51,10 @@ export function getReceiverDescription(receiver: ReceiverConfigWithMetadata): Re
       return `#${channelName}`;
     }
     case 'kafka': {
-      const topicName: string | undefined = receiver.settings['kafkaTopic'];
-      return topicName;
+      return settings.kafkaTopic;
     }
     case 'webhook': {
-      const url: string | undefined = receiver.settings['url'];
-      return url;
+      return settings.url;
     }
     case ReceiverTypes.OnCall: {
       return receiver[RECEIVER_PLUGIN_META_KEY]?.description;
@@ -123,11 +122,7 @@ export function enhanceContactPointsWithMetadata(
   const usedContactPoints = getUsedContactPoints(fullyInheritedTree);
   const usedContactPointsByName = groupBy(usedContactPoints, 'receiver');
 
-  const contactPointsList = alertmanagerConfiguration
-    ? (alertmanagerConfiguration?.alertmanager_config.receivers ?? [])
-    : (contactPoints ?? []);
-
-  const enhanced = contactPointsList.map((contactPoint) => {
+  const enhanced = contactPoints.map((contactPoint) => {
     const receivers = extractReceivers(contactPoint);
     const statusForReceiver = status.find((status) => status.name === contactPoint.name);
 
diff --git a/public/app/features/alerting/unified/components/rule-editor/GrafanaEvaluationBehavior.tsx b/public/app/features/alerting/unified/components/rule-editor/GrafanaEvaluationBehavior.tsx
index 35ad15987c1..5d091aa083d 100644
--- a/public/app/features/alerting/unified/components/rule-editor/GrafanaEvaluationBehavior.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/GrafanaEvaluationBehavior.tsx
@@ -146,7 +146,7 @@ function FolderGroupAndEvaluationInterval({
               <Stack direction="column" gap={1}>
                 {getValues('group') && getValues('evaluateEvery') && (
                   <span>
-                    <Trans i18nKey="alert-rule-form.evaluation-behaviour-group.text" evaluateEvery={evaluateEvery}>
+                    <Trans i18nKey="alert-rule-form.evaluation-behaviour-group.text" values={{ evaluateEvery }}>
                       All rules in the selected group are evaluated every {{ evaluateEvery }}.
                     </Trans>
                     {!isNewGroup && (
diff --git a/public/app/features/alerting/unified/utils/receivers.ts b/public/app/features/alerting/unified/utils/receivers.ts
index d4147cae3d1..9d9c88c960a 100644
--- a/public/app/features/alerting/unified/utils/receivers.ts
+++ b/public/app/features/alerting/unified/utils/receivers.ts
@@ -1,4 +1,4 @@
-import { isEmpty, times } from 'lodash';
+import { isEmpty } from 'lodash';
 
 import { GrafanaManagedReceiverConfig, Receiver } from 'app/plugins/datasource/alertmanager/types';
 
@@ -12,10 +12,14 @@ import { GrafanaManagedReceiverConfig, Receiver } from 'app/plugins/datasource/a
  * We don't normalize the configuration settings and those are blank for vanilla Alertmanager receivers.
  *
  * Example input:
- *  { name: 'my receiver', email_configs: [{ from: "foo@bar.com" }] }
+ *  ```
+ * { name: 'my receiver', email_configs: [{ from: "foo@bar.com" }] }
+ * ```
  *
  * Example output:
- *  { name: 'my receiver', grafana_managed_receiver_configs: [{ type: 'email', settings: {} }] }
+ *  ```
+ * { name: 'my receiver', grafana_managed_receiver_configs: [{ type: 'email', settings: {} }] }
+ * ```
  */
 export function extractReceivers(receiver: Receiver): GrafanaManagedReceiverConfig[] {
   if ('grafana_managed_receiver_configs' in receiver) {
@@ -27,13 +31,14 @@ export function extractReceivers(receiver: Receiver): GrafanaManagedReceiverConf
     .filter(([_, value]) => Array.isArray(value) && !isEmpty(value))
     .reduce((acc: GrafanaManagedReceiverConfig[], [key, value]) => {
       const type = key.replace('_configs', '');
-
-      const configs = times(value.length, () => ({
-        name: receiver.name,
-        type: type,
-        settings: [], // we don't normalize the configuration values
-        disableResolveMessage: false,
-      }));
+      const configs = value.map((settings: unknown) => {
+        return {
+          name: receiver.name,
+          type,
+          settings,
+          disableResolveMessage: false,
+        };
+      });
 
       return acc.concat(configs);
     }, []);
diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/EmptyTransformationsMessage.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/EmptyTransformationsMessage.tsx
index 136e8f17426..d2f6d537559 100644
--- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/EmptyTransformationsMessage.tsx
+++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/EmptyTransformationsMessage.tsx
@@ -10,10 +10,10 @@ export function EmptyTransformationsMessage(props: EmptyTransformationsProps) {
     <Box alignItems="center" padding={4}>
       <Stack direction="column" alignItems="center" gap={2}>
         <Text element="h3" textAlignment="center">
-          <Trans key="transformations.empty.add-transformation-header">Start transforming data</Trans>
+          <Trans i18nKey="transformations.empty.add-transformation-header">Start transforming data</Trans>
         </Text>
         <Text element="p" textAlignment="center" data-testid={selectors.components.Transforms.noTransformationsMessage}>
-          <Trans key="transformations.empty.add-transformation-body">
+          <Trans i18nKey="transformations.empty.add-transformation-body">
             Transformations allow data to be changed in various ways before your visualization is shown.
             <br />
             This includes joining data together, renaming fields, making calculations, formatting data for display, and
diff --git a/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx b/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx
index c40f3e08697..0d44671f1e6 100644
--- a/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx
+++ b/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx
@@ -496,7 +496,6 @@ export function ToolbarActions({ dashboard }: Props) {
         return (
           <Button
             onClick={() => {
-              DashboardInteractions.toolbarSaveClick();
               dashboard.openSaveDrawer({});
             }}
             className={styles.buttonWithExtraMargin}
@@ -516,7 +515,6 @@ export function ToolbarActions({ dashboard }: Props) {
         return (
           <Button
             onClick={() => {
-              DashboardInteractions.toolbarSaveClick();
               dashboard.openSaveDrawer({ saveAsCopy: true });
             }}
             className={styles.buttonWithExtraMargin}
@@ -537,7 +535,6 @@ export function ToolbarActions({ dashboard }: Props) {
             label="Save"
             icon="save"
             onClick={() => {
-              DashboardInteractions.toolbarSaveClick();
               dashboard.openSaveDrawer({});
             }}
           />
@@ -545,7 +542,6 @@ export function ToolbarActions({ dashboard }: Props) {
             label="Save as copy"
             icon="copy"
             onClick={() => {
-              DashboardInteractions.toolbarSaveAsClick();
               dashboard.openSaveDrawer({ saveAsCopy: true });
             }}
           />
@@ -556,7 +552,6 @@ export function ToolbarActions({ dashboard }: Props) {
         <ButtonGroup className={styles.buttonWithExtraMargin} key="save">
           <Button
             onClick={() => {
-              DashboardInteractions.toolbarSaveClick();
               dashboard.openSaveDrawer({});
             }}
             tooltip="Save changes"
diff --git a/public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx b/public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx
index 3a9cea22c9f..c3f2ced3c7e 100644
--- a/public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx
+++ b/public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx
@@ -64,7 +64,6 @@ export function panelMenuBehavior(menu: VizPanelMenu, isRepeat = false) {
         text: t('panel.header-menu.view', `View`),
         iconClassName: 'eye',
         shortcut: 'v',
-        onClick: () => DashboardInteractions.panelMenuItemClicked('view'),
         href: getViewPanelUrl(panel),
       });
     }
@@ -76,7 +75,6 @@ export function panelMenuBehavior(menu: VizPanelMenu, isRepeat = false) {
         text: t('panel.header-menu.edit', `Edit`),
         iconClassName: 'edit',
         shortcut: 'e',
-        onClick: () => DashboardInteractions.panelMenuItemClicked('edit'),
         href: getEditPanelUrl(getPanelIdForVizPanel(panel)),
       });
     }
@@ -111,7 +109,6 @@ export function panelMenuBehavior(menu: VizPanelMenu, isRepeat = false) {
         text: t('panel.header-menu.share', 'Share'),
         iconClassName: 'share-alt',
         onClick: () => {
-          DashboardInteractions.panelMenuItemClicked('share');
           dashboard.showModal(new ShareModal({ panelRef: panel.getRef() }));
         },
         shortcut: 'p s',
@@ -122,7 +119,6 @@ export function panelMenuBehavior(menu: VizPanelMenu, isRepeat = false) {
       moreSubMenu.push({
         text: t('panel.header-menu.duplicate', `Duplicate`),
         onClick: () => {
-          DashboardInteractions.panelMenuItemClicked('duplicate');
           dashboard.duplicatePanel(panel);
         },
         shortcut: 'p d',
@@ -133,7 +129,6 @@ export function panelMenuBehavior(menu: VizPanelMenu, isRepeat = false) {
       moreSubMenu.push({
         text: t('panel.header-menu.copy', `Copy`),
         onClick: () => {
-          DashboardInteractions.panelMenuItemClicked('copy');
           dashboard.copyPanel(panel);
         },
       });
@@ -144,7 +139,6 @@ export function panelMenuBehavior(menu: VizPanelMenu, isRepeat = false) {
         moreSubMenu.push({
           text: t('panel.header-menu.unlink-library-panel', `Unlink library panel`),
           onClick: () => {
-            DashboardInteractions.panelMenuItemClicked('unlinkLibraryPanel');
             dashboard.showModal(
               new UnlinkLibraryPanelModal({
                 panelRef: parent.getRef(),
@@ -156,7 +150,6 @@ export function panelMenuBehavior(menu: VizPanelMenu, isRepeat = false) {
         moreSubMenu.push({
           text: t('panel.header-menu.replace-library-panel', `Replace library panel`),
           onClick: () => {
-            DashboardInteractions.panelMenuItemClicked('replaceLibraryPanel');
             dashboard.onShowAddLibraryPanelDrawer(parent.getRef());
           },
         });
@@ -164,7 +157,6 @@ export function panelMenuBehavior(menu: VizPanelMenu, isRepeat = false) {
         moreSubMenu.push({
           text: t('panel.header-menu.create-library-panel', `Create library panel`),
           onClick: () => {
-            DashboardInteractions.panelMenuItemClicked('createLibraryPanel');
             dashboard.showModal(
               new ShareModal({
                 panelRef: panel.getRef(),
@@ -253,7 +245,6 @@ export function panelMenuBehavior(menu: VizPanelMenu, isRepeat = false) {
         text: t('panel.header-menu.remove', `Remove`),
         iconClassName: 'trash-alt',
         onClick: () => {
-          DashboardInteractions.panelMenuItemClicked('remove');
           onRemovePanel(dashboard, panel);
         },
         shortcut: 'p r',
@@ -278,7 +269,6 @@ async function getExploreMenuItem(panel: VizPanel): Promise<PanelMenuItem | unde
     text: t('panel.header-menu.explore', `Explore`),
     iconClassName: 'compass',
     shortcut: 'p x',
-    onClick: () => DashboardInteractions.panelMenuItemClicked('explore'),
     href: exploreUrl,
   };
 }
@@ -297,7 +287,6 @@ function getInspectMenuItem(
       onClick: (e) => {
         e.preventDefault();
         locationService.partial({ inspect: panel.state.key, inspectTab: InspectTab.Data });
-        DashboardInteractions.panelMenuInspectClicked(InspectTab.Data);
       },
     });
 
@@ -308,7 +297,6 @@ function getInspectMenuItem(
         onClick: (e) => {
           e.preventDefault();
           locationService.partial({ inspect: panel.state.key, inspectTab: InspectTab.Query });
-          DashboardInteractions.panelMenuInspectClicked(InspectTab.Query);
         },
       });
     }
@@ -320,7 +308,6 @@ function getInspectMenuItem(
     onClick: (e) => {
       e.preventDefault();
       locationService.partial({ inspect: panel.state.key, inspectTab: InspectTab.JSON });
-      DashboardInteractions.panelMenuInspectClicked(InspectTab.JSON);
     },
   });
 
@@ -332,7 +319,6 @@ function getInspectMenuItem(
     onClick: (e) => {
       if (!e.isDefaultPrevented()) {
         locationService.partial({ inspect: panel.state.key, inspectTab: InspectTab.Data });
-        DashboardInteractions.panelMenuInspectClicked(InspectTab.Data);
       }
     },
     subMenu: inspectSubMenu.length > 0 ? inspectSubMenu : undefined,
@@ -447,17 +433,12 @@ export function onRemovePanel(dashboard: DashboardScene, panel: VizPanel) {
 }
 
 const onCreateAlert = async (panel: VizPanel) => {
-  DashboardInteractions.panelMenuItemClicked('create-alert');
-
   const formValues = await scenesPanelToRuleFormValues(panel);
   const ruleFormUrl = urlUtil.renderUrl('/alerting/new', {
     defaults: JSON.stringify(formValues),
     returnTo: location.pathname + location.search,
   });
-
   locationService.push(ruleFormUrl);
-
-  DashboardInteractions.panelMenuItemClicked('create-alert');
 };
 
 export function toggleVizPanelLegend(vizPanel: VizPanel): void {
@@ -469,8 +450,6 @@ export function toggleVizPanelLegend(vizPanel: VizPanel): void {
       },
     });
   }
-
-  DashboardInteractions.panelMenuItemClicked('toggleLegend');
 }
 
 function hasLegendOptions(optionsWithLegend: unknown): optionsWithLegend is OptionsWithLegend {
@@ -482,5 +461,4 @@ const onInspectPanel = (vizPanel: VizPanel, tab?: InspectTab) => {
     inspect: vizPanel.state.key,
     inspectTab: tab,
   });
-  DashboardInteractions.panelMenuInspectClicked(tab ?? InspectTab.Data);
 };
diff --git a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts
index 1e11bc51bde..5d45e4a4aa0 100644
--- a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts
+++ b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts
@@ -521,9 +521,6 @@ function registerPanelInteractionsReporter(scene: DashboardScene) {
       case 'panel-cancel-query-clicked':
         DashboardInteractions.panelCancelQueryClicked();
         break;
-      case 'panel-menu-shown':
-        DashboardInteractions.panelMenuShown();
-        break;
     }
   });
 }
diff --git a/public/app/features/dashboard-scene/utils/interactions.ts b/public/app/features/dashboard-scene/utils/interactions.ts
index 3086ec1defb..fef5f346551 100644
--- a/public/app/features/dashboard-scene/utils/interactions.ts
+++ b/public/app/features/dashboard-scene/utils/interactions.ts
@@ -1,5 +1,4 @@
 import { reportInteraction } from '@grafana/runtime';
-import { InspectTab } from 'app/features/inspector/types';
 
 let isScenesContextSet = false;
 
@@ -9,30 +8,6 @@ export const DashboardInteractions = {
     reportDashboardInteraction('init_dashboard_completed', { ...properties });
   },
 
-  // Panel interactions:
-  panelMenuShown: (properties?: Record<string, unknown>) => {
-    reportDashboardInteraction('panelheader_menu', { ...properties, item: 'menu' });
-  },
-  panelMenuItemClicked: (
-    item:
-      | 'view'
-      | 'edit'
-      | 'share'
-      | 'createLibraryPanel'
-      | 'unlinkLibraryPanel'
-      | 'replaceLibraryPanel'
-      | 'duplicate'
-      | 'copy'
-      | 'remove'
-      | 'explore'
-      | 'toggleLegend'
-      | 'create-alert'
-  ) => {
-    reportDashboardInteraction('panelheader_menu', { item });
-  },
-  panelMenuInspectClicked(tab: InspectTab) {
-    reportDashboardInteraction('panelheader_menu', { item: 'inspect', tab });
-  },
   panelLinkClicked: (properties?: Record<string, unknown>) => {
     reportDashboardInteraction('panelheader_datalink_clicked', properties);
   },
@@ -43,6 +18,20 @@ export const DashboardInteractions = {
     reportDashboardInteraction('panelheader_cancelquery_clicked', properties);
   },
 
+  // Dashboard interactions from toolbar
+  toolbarFavoritesClick: () => {
+    reportDashboardInteraction('toolbar_actions_clicked', { item: 'favorites' });
+  },
+  toolbarSettingsClick: () => {
+    reportDashboardInteraction('toolbar_actions_clicked', { item: 'settings' });
+  },
+  toolbarShareClick: () => {
+    reportDashboardInteraction('toolbar_actions_clicked', { item: 'share' });
+  },
+  toolbarAddClick: () => {
+    reportDashboardInteraction('toolbar_actions_clicked', { item: 'add' });
+  },
+
   // Sharing interactions:
   sharingCategoryClicked: (properties?: Record<string, unknown>) => {
     reportDashboardInteraction('sharing_category_clicked', properties);
@@ -111,35 +100,6 @@ export const DashboardInteractions = {
   toolbarAddButtonClicked: (properties?: Record<string, unknown>) => {
     reportDashboardInteraction('toolbar_add_clicked', properties);
   },
-  toolbarFavoritesClick: () => {
-    reportDashboardInteraction('toolbar_actions_clicked', { item: 'favorites' });
-  },
-  toolbarSettingsClick: () => {
-    reportDashboardInteraction('toolbar_actions_clicked', { item: 'settings' });
-  },
-  toolbarRefreshClick: () => {
-    reportDashboardInteraction('toolbar_actions_clicked', { item: 'refresh' });
-  },
-  toolbarTimePickerClick: () => {
-    reportDashboardInteraction('toolbar_actions_clicked', { item: 'time_picker' });
-  },
-  toolbarZoomClick: () => {
-    reportDashboardInteraction('toolbar_actions_clicked', { item: 'zoom_out_time_range' });
-  },
-
-  toolbarShareClick: () => {
-    reportDashboardInteraction('toolbar_actions_clicked', { item: 'share' });
-  },
-  toolbarSaveClick: () => {
-    reportDashboardInteraction('toolbar_actions_clicked', { item: 'save' });
-  },
-  toolbarSaveAsClick: () => {
-    reportDashboardInteraction('toolbar_actions_clicked', { item: 'save_as' });
-  },
-  toolbarAddClick: () => {
-    reportDashboardInteraction('toolbar_actions_clicked', { item: 'add' });
-  },
-
   setScenesContext: () => {
     isScenesContextSet = true;
 
diff --git a/public/app/features/dashboard/components/DashNav/DashNav.tsx b/public/app/features/dashboard/components/DashNav/DashNav.tsx
index 04415bdeb94..b6accdf8c29 100644
--- a/public/app/features/dashboard/components/DashNav/DashNav.tsx
+++ b/public/app/features/dashboard/components/DashNav/DashNav.tsx
@@ -270,14 +270,7 @@ export const DashNav = memo<Props>((props) => {
       return null;
     }
     return (
-      <DashNavTimeControls
-        dashboard={dashboard}
-        onChangeTimeZone={updateTimeZoneForSession}
-        onToolbarRefreshClick={DashboardInteractions.toolbarRefreshClick}
-        onToolbarZoomClick={DashboardInteractions.toolbarZoomClick}
-        onToolbarTimePickerClick={DashboardInteractions.toolbarTimePickerClick}
-        key="time-controls"
-      />
+      <DashNavTimeControls dashboard={dashboard} onChangeTimeZone={updateTimeZoneForSession} key="time-controls" />
     );
   };
 
@@ -315,7 +308,6 @@ export const DashNav = memo<Props>((props) => {
               tooltip={t('dashboard.toolbar.save', 'Save dashboard')}
               icon="save"
               onClick={() => {
-                DashboardInteractions.toolbarSaveClick();
                 showModal(SaveDashboardDrawer, {
                   dashboard,
                   onDismiss: hideModal,
@@ -343,8 +335,8 @@ export const DashNav = memo<Props>((props) => {
     if (canEdit && !isFullscreen) {
       buttons.push(
         <AddPanelButton
-          dashboard={dashboard}
           onToolbarAddMenuOpen={DashboardInteractions.toolbarAddClick}
+          dashboard={dashboard}
           key="panel-add-dropdown"
         />
       );
diff --git a/public/app/features/dashboard/dashgrid/PanelChromeAngular.tsx b/public/app/features/dashboard/dashgrid/PanelChromeAngular.tsx
index c17f5a27bad..4a0eb485f1e 100644
--- a/public/app/features/dashboard/dashgrid/PanelChromeAngular.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelChromeAngular.tsx
@@ -209,7 +209,6 @@ export class PanelChromeAngularUnconnected extends PureComponent<Props, State> {
         hoverHeader={panelChromeProps.hasOverlayHeader()}
         displayMode={transparent ? 'transparent' : 'default'}
         onCancelQuery={panelChromeProps.onCancelQuery}
-        onOpenMenu={panelChromeProps.onOpenMenu}
       >
         {() => <div ref={(element) => (this.element = element)} className="panel-height-helper" />}
       </PanelChrome>
diff --git a/public/app/features/dashboard/dashgrid/PanelStateWrapper.tsx b/public/app/features/dashboard/dashgrid/PanelStateWrapper.tsx
index 7ae7c5a33ae..7d21b626fa3 100644
--- a/public/app/features/dashboard/dashgrid/PanelStateWrapper.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelStateWrapper.tsx
@@ -587,7 +587,6 @@ export class PanelStateWrapper extends PureComponent<Props, State> {
         hoverHeader={panelChromeProps.hasOverlayHeader()}
         displayMode={transparent ? 'transparent' : 'default'}
         onCancelQuery={panelChromeProps.onCancelQuery}
-        onOpenMenu={panelChromeProps.onOpenMenu}
         onFocus={() => this.setPanelAttention()}
         onMouseEnter={() => this.setPanelAttention()}
         onMouseMove={() => this.debouncedSetPanelAttention()}
diff --git a/public/app/features/dashboard/utils/getPanelChromeProps.tsx b/public/app/features/dashboard/utils/getPanelChromeProps.tsx
index f430d744943..52a0e96ec79 100644
--- a/public/app/features/dashboard/utils/getPanelChromeProps.tsx
+++ b/public/app/features/dashboard/utils/getPanelChromeProps.tsx
@@ -113,10 +113,6 @@ export function getPanelChromeProps(props: CommonProps) {
 
   const title = props.panel.getDisplayTitle();
 
-  const onOpenMenu = () => {
-    DashboardInteractions.panelMenuShown();
-  };
-
   return {
     hasOverlayHeader,
     onShowPanelDescription,
@@ -129,6 +125,5 @@ export function getPanelChromeProps(props: CommonProps) {
     dragClass,
     title,
     titleItems,
-    onOpenMenu,
   };
 }
diff --git a/public/app/features/dashboard/utils/getPanelMenu.ts b/public/app/features/dashboard/utils/getPanelMenu.ts
index f1deeff64db..74a6377f2c8 100644
--- a/public/app/features/dashboard/utils/getPanelMenu.ts
+++ b/public/app/features/dashboard/utils/getPanelMenu.ts
@@ -21,7 +21,6 @@ import {
   toggleLegend,
   unlinkLibraryPanel,
 } from 'app/features/dashboard/utils/panel';
-import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions';
 import { InspectTab } from 'app/features/inspector/types';
 import { isPanelModelLibraryPanel } from 'app/features/library-panels/guard';
 import { createExtensionSubMenu } from 'app/features/plugins/extensions/utils';
@@ -43,7 +42,6 @@ export function getPanelMenu(
     locationService.partial({
       viewPanel: panel.id,
     });
-    DashboardInteractions.panelMenuItemClicked('view');
   };
 
   const onEditPanel = (event: React.MouseEvent) => {
@@ -51,26 +49,21 @@ export function getPanelMenu(
     locationService.partial({
       editPanel: panel.id,
     });
-
-    DashboardInteractions.panelMenuItemClicked('edit');
   };
 
   const onSharePanel = (event: React.MouseEvent) => {
     event.preventDefault();
     sharePanel(dashboard, panel);
-    DashboardInteractions.panelMenuItemClicked('share');
   };
 
   const onAddLibraryPanel = (event: React.MouseEvent) => {
     event.preventDefault();
     addLibraryPanel(dashboard, panel);
-    DashboardInteractions.panelMenuItemClicked('createLibraryPanel');
   };
 
   const onUnlinkLibraryPanel = (event: React.MouseEvent) => {
     event.preventDefault();
     unlinkLibraryPanel(panel);
-    DashboardInteractions.panelMenuItemClicked('unlinkLibraryPanel');
   };
 
   const onInspectPanel = (tab?: InspectTab) => {
@@ -78,7 +71,6 @@ export function getPanelMenu(
       inspect: panel.id,
       inspectTab: tab,
     });
-    DashboardInteractions.panelMenuInspectClicked(tab ?? InspectTab.Data);
   };
 
   const onMore = (event: React.MouseEvent) => {
@@ -88,19 +80,16 @@ export function getPanelMenu(
   const onDuplicatePanel = (event: React.MouseEvent) => {
     event.preventDefault();
     duplicatePanel(dashboard, panel);
-    DashboardInteractions.panelMenuItemClicked('duplicate');
   };
 
   const onCopyPanel = (event: React.MouseEvent) => {
     event.preventDefault();
     copyPanel(panel);
-    DashboardInteractions.panelMenuItemClicked('copy');
   };
 
   const onRemovePanel = (event: React.MouseEvent) => {
     event.preventDefault();
     removePanel(dashboard, panel, true);
-    DashboardInteractions.panelMenuItemClicked('remove');
   };
 
   const onNavigateToExplore = (event: React.MouseEvent) => {
@@ -114,13 +103,11 @@ export function getPanelMenu(
         openInNewWindow,
       }) as any
     );
-    DashboardInteractions.panelMenuItemClicked('explore');
   };
 
   const onToggleLegend = (event: React.MouseEvent) => {
     event.preventDefault();
     toggleLegend(panel);
-    DashboardInteractions.panelMenuItemClicked('toggleLegend');
   };
 
   const menu: PanelMenuItem[] = [];
@@ -224,7 +211,6 @@ export function getPanelMenu(
   const onCreateAlert = (event: React.MouseEvent) => {
     event.preventDefault();
     createAlert();
-    DashboardInteractions.panelMenuItemClicked('create-alert');
   };
 
   const subMenu: PanelMenuItem[] = [];
diff --git a/public/app/features/datasources/state/buildCategories.test.ts b/public/app/features/datasources/state/buildCategories.test.ts
index 8d964b29288..ad39fa4908d 100644
--- a/public/app/features/datasources/state/buildCategories.test.ts
+++ b/public/app/features/datasources/state/buildCategories.test.ts
@@ -53,7 +53,7 @@ describe('buildCategories', () => {
   it('should add enterprise phantom plugins', () => {
     const enterprisePluginsCategory = categories[3];
     expect(enterprisePluginsCategory.title).toBe('Enterprise plugins');
-    expect(enterprisePluginsCategory.plugins.length).toBe(23);
+    expect(enterprisePluginsCategory.plugins.length).toBe(24);
     expect(enterprisePluginsCategory.plugins[0].name).toBe('Adobe Analytics');
     expect(enterprisePluginsCategory.plugins[enterprisePluginsCategory.plugins.length - 1].name).toBe('Wavefront');
   });
diff --git a/public/app/features/datasources/state/buildCategories.ts b/public/app/features/datasources/state/buildCategories.ts
index d8288e02aaf..6f59f4da835 100644
--- a/public/app/features/datasources/state/buildCategories.ts
+++ b/public/app/features/datasources/state/buildCategories.ts
@@ -233,6 +233,12 @@ function getEnterprisePhantomPlugins(): DataSourcePluginMeta[] {
       name: 'Cloudflare',
       imgUrl: 'public/img/plugins/cloudflare.jpg',
     }),
+    getPhantomPlugin({
+      id: 'grafana-cockroachdb-datasource',
+      description: 'CockroachDB datasource',
+      name: 'CockroachDB',
+      imgUrl: 'public/img/plugins/cockroachdb.jpg',
+    }),
   ];
 }
 
diff --git a/public/app/features/migrate-to-cloud/onprem/Page.tsx b/public/app/features/migrate-to-cloud/onprem/Page.tsx
index 4da9ea67aa7..213a9ef6449 100644
--- a/public/app/features/migrate-to-cloud/onprem/Page.tsx
+++ b/public/app/features/migrate-to-cloud/onprem/Page.tsx
@@ -1,6 +1,7 @@
 import { skipToken } from '@reduxjs/toolkit/query/react';
 import { useCallback, useEffect, useState } from 'react';
 
+import { config } from '@grafana/runtime';
 import { AlertVariant, Box, Stack, Text } from '@grafana/ui';
 import { Trans, t } from 'app/core/internationalization';
 
@@ -62,8 +63,6 @@ const SNAPSHOT_REBUILD_STATUSES: Array<SnapshotDto['status']> = ['PENDING_UPLOAD
 const SNAPSHOT_BUILDING_STATUSES: Array<SnapshotDto['status']> = ['INITIALIZING', 'CREATING'];
 const SNAPSHOT_UPLOADING_STATUSES: Array<SnapshotDto['status']> = ['UPLOADING', 'PENDING_PROCESSING', 'PROCESSING'];
 
-const STATUS_POLL_INTERVAL = 5 * 1000;
-
 const PAGE_SIZE = 50;
 
 function useGetLatestSnapshot(sessionUid?: string, page = 1) {
@@ -78,7 +77,7 @@ function useGetLatestSnapshot(sessionUid?: string, page = 1) {
       : skipToken;
 
   const snapshotResult = useGetSnapshotQuery(getSnapshotQueryArgs, {
-    pollingInterval: shouldPoll ? STATUS_POLL_INTERVAL : 0,
+    pollingInterval: shouldPoll ? config.cloudMigrationPollIntervalMs : 0,
     skipPollingIfUnfocused: true,
   });
 
diff --git a/public/app/features/trails/ActionTabs/MetricOverviewScene.tsx b/public/app/features/trails/ActionTabs/MetricOverviewScene.tsx
index 7e1b9c141ce..b7894ca6d86 100644
--- a/public/app/features/trails/ActionTabs/MetricOverviewScene.tsx
+++ b/public/app/features/trails/ActionTabs/MetricOverviewScene.tsx
@@ -78,45 +78,39 @@ export class MetricOverviewScene extends SceneObjectBase<MetricOverviewSceneStat
           <>
             <Stack direction="column" gap={0.5}>
               <Text weight={'medium'}>
-                <Trans>Description</Trans>
+                <Trans i18nKey="trails.metric-overview.description-label">Description</Trans>
               </Text>
               <div style={{ maxWidth: 360 }}>
                 {metadata?.help ? (
                   <div>{metadata?.help}</div>
                 ) : (
                   <i>
-                    <Trans>No description available</Trans>
+                    <Trans i18nKey="trails.metric-overview.no-description">No description available</Trans>
                   </i>
                 )}
               </div>
             </Stack>
             <Stack direction="column" gap={0.5}>
               <Text weight={'medium'}>
-                <Trans>Type</Trans>
+                <Trans i18nKey="trails.metric-overview.type-label">Type</Trans>
               </Text>
               {metadata?.type ? (
                 <div>{metadata?.type}</div>
               ) : (
                 <i>
-                  <Trans>Unknown</Trans>
+                  <Trans i18nKey="trails.metric-overview.unknown-type">Unknown</Trans>
                 </i>
               )}
             </Stack>
             <Stack direction="column" gap={0.5}>
               <Text weight={'medium'}>
-                <Trans>Unit</Trans>
+                <Trans i18nKey="trails.metric-overview.unit-label">Unit</Trans>
               </Text>
-              {metadata?.unit ? (
-                <div>{metadata?.unit}</div>
-              ) : (
-                <i>
-                  <Trans>{unit}</Trans>
-                </i>
-              )}
+              {metadata?.unit ? <div>{metadata?.unit}</div> : <i>{unit}</i>}
             </Stack>
             <Stack direction="column" gap={0.5}>
               <Text weight={'medium'}>
-                <Trans>Labels</Trans>
+                <Trans i18nKey="trails.metric-overview.labels-label">Labels</Trans>
               </Text>
               {labelOptions.length === 0 && 'Unable to fetch labels.'}
               {labelOptions.map((l) => (
diff --git a/public/app/plugins/datasource/azuremonitor/package.json b/public/app/plugins/datasource/azuremonitor/package.json
index d9aeb16e710..401db90f6c7 100644
--- a/public/app/plugins/datasource/azuremonitor/package.json
+++ b/public/app/plugins/datasource/azuremonitor/package.json
@@ -32,7 +32,7 @@
     "@testing-library/user-event": "14.5.2",
     "@types/jest": "29.5.12",
     "@types/lodash": "4.17.7",
-    "@types/node": "20.14.13",
+    "@types/node": "20.14.14",
     "@types/prismjs": "1.26.4",
     "@types/react": "18.3.3",
     "@types/react-dom": "18.2.25",
diff --git a/public/app/plugins/datasource/cloud-monitoring/package.json b/public/app/plugins/datasource/cloud-monitoring/package.json
index 6d6882ce46a..6dcdcb8bf2b 100644
--- a/public/app/plugins/datasource/cloud-monitoring/package.json
+++ b/public/app/plugins/datasource/cloud-monitoring/package.json
@@ -34,7 +34,7 @@
     "@types/debounce-promise": "3.1.9",
     "@types/jest": "29.5.12",
     "@types/lodash": "4.17.7",
-    "@types/node": "20.14.13",
+    "@types/node": "20.14.14",
     "@types/prismjs": "1.26.4",
     "@types/react": "18.3.3",
     "@types/react-dom": "18.2.25",
diff --git a/public/app/plugins/datasource/grafana-postgresql-datasource/package.json b/public/app/plugins/datasource/grafana-postgresql-datasource/package.json
index b81bcb2cc38..db09f516cda 100644
--- a/public/app/plugins/datasource/grafana-postgresql-datasource/package.json
+++ b/public/app/plugins/datasource/grafana-postgresql-datasource/package.json
@@ -22,7 +22,7 @@
     "@testing-library/user-event": "14.5.2",
     "@types/jest": "29.5.12",
     "@types/lodash": "4.17.7",
-    "@types/node": "20.14.13",
+    "@types/node": "20.14.14",
     "@types/react": "18.3.3",
     "@types/testing-library__jest-dom": "5.14.9",
     "ts-node": "10.9.2",
diff --git a/public/app/plugins/datasource/grafana-pyroscope-datasource/package.json b/public/app/plugins/datasource/grafana-pyroscope-datasource/package.json
index 81d6c1c6cb2..b5302ae2e7c 100644
--- a/public/app/plugins/datasource/grafana-pyroscope-datasource/package.json
+++ b/public/app/plugins/datasource/grafana-pyroscope-datasource/package.json
@@ -27,7 +27,7 @@
     "@testing-library/user-event": "14.5.2",
     "@types/jest": "29.5.12",
     "@types/lodash": "4.17.7",
-    "@types/node": "20.14.13",
+    "@types/node": "20.14.14",
     "@types/prismjs": "1.26.4",
     "@types/react": "18.3.3",
     "@types/react-dom": "18.2.25",
diff --git a/public/app/plugins/datasource/grafana-testdata-datasource/package.json b/public/app/plugins/datasource/grafana-testdata-datasource/package.json
index 891802c7759..42574cb5b54 100644
--- a/public/app/plugins/datasource/grafana-testdata-datasource/package.json
+++ b/public/app/plugins/datasource/grafana-testdata-datasource/package.json
@@ -30,7 +30,7 @@
     "@types/d3-random": "^3.0.2",
     "@types/jest": "29.5.12",
     "@types/lodash": "4.17.7",
-    "@types/node": "20.14.13",
+    "@types/node": "20.14.14",
     "@types/react": "18.3.3",
     "@types/react-dom": "18.2.25",
     "@types/testing-library__jest-dom": "5.14.9",
diff --git a/public/app/plugins/datasource/jaeger/package.json b/public/app/plugins/datasource/jaeger/package.json
index e4e36419fd4..cf177421244 100644
--- a/public/app/plugins/datasource/jaeger/package.json
+++ b/public/app/plugins/datasource/jaeger/package.json
@@ -31,7 +31,7 @@
     "@types/jest": "29.5.12",
     "@types/lodash": "4.17.7",
     "@types/logfmt": "^1.2.3",
-    "@types/node": "20.14.13",
+    "@types/node": "20.14.14",
     "@types/react": "18.3.3",
     "@types/react-dom": "18.2.25",
     "@types/react-window": "1.8.8",
diff --git a/public/app/plugins/datasource/mysql/package.json b/public/app/plugins/datasource/mysql/package.json
index 423d72f818d..28c38167682 100644
--- a/public/app/plugins/datasource/mysql/package.json
+++ b/public/app/plugins/datasource/mysql/package.json
@@ -22,7 +22,7 @@
     "@testing-library/user-event": "14.5.2",
     "@types/jest": "29.5.12",
     "@types/lodash": "4.17.7",
-    "@types/node": "20.14.13",
+    "@types/node": "20.14.14",
     "@types/react": "18.3.3",
     "@types/testing-library__jest-dom": "5.14.9",
     "ts-node": "10.9.2",
diff --git a/public/app/plugins/datasource/parca/package.json b/public/app/plugins/datasource/parca/package.json
index f5e5714b309..7666e598c06 100644
--- a/public/app/plugins/datasource/parca/package.json
+++ b/public/app/plugins/datasource/parca/package.json
@@ -23,7 +23,7 @@
     "@testing-library/react": "15.0.2",
     "@testing-library/user-event": "14.5.2",
     "@types/lodash": "4.17.7",
-    "@types/node": "20.14.13",
+    "@types/node": "20.14.14",
     "@types/react": "18.3.3",
     "@types/react-dom": "18.2.25",
     "ts-node": "10.9.2",
diff --git a/public/app/plugins/datasource/prometheus/plugin.json b/public/app/plugins/datasource/prometheus/plugin.json
index 356b924dbb0..c11bd2e9809 100644
--- a/public/app/plugins/datasource/prometheus/plugin.json
+++ b/public/app/plugins/datasource/prometheus/plugin.json
@@ -38,31 +38,31 @@
       "method": "GET",
       "path": "/rules",
       "reqRole": "Viewer",
-      "reqAction": "datasources:query"
+      "reqAction": "alert.rules.external:read"
     },
     {
       "method": "POST",
       "path": "/rules",
       "reqRole": "Editor",
-      "reqAction": "datasources:write"
+      "reqAction": "alert.rules.external:write"
     },
     {
       "method": "DELETE",
       "path": "/rules",
       "reqRole": "Editor",
-      "reqAction": "datasources:write"
+      "reqAction": "alert.rules.external:write"
     },
     {
       "method": "DELETE",
       "path": "/config/v1/rules",
       "reqRole": "Editor",
-      "reqAction": "datasources:write"
+      "reqAction": "alert.rules.external:write"
     },
     {
       "method": "POST",
       "path": "/config/v1/rules",
       "reqRole": "Editor",
-      "reqAction": "datasources:write"
+      "reqAction": "alert.rules.external:write"
     }
   ],
   "includes": [
diff --git a/public/app/plugins/datasource/tempo/package.json b/public/app/plugins/datasource/tempo/package.json
index 0616776098d..db9a594992e 100644
--- a/public/app/plugins/datasource/tempo/package.json
+++ b/public/app/plugins/datasource/tempo/package.json
@@ -46,7 +46,7 @@
     "@testing-library/user-event": "14.5.2",
     "@types/jest": "29.5.12",
     "@types/lodash": "4.17.7",
-    "@types/node": "20.14.13",
+    "@types/node": "20.14.14",
     "@types/prismjs": "1.26.4",
     "@types/react": "18.3.3",
     "@types/react-dom": "18.2.25",
diff --git a/public/app/plugins/datasource/zipkin/package.json b/public/app/plugins/datasource/zipkin/package.json
index c8c21ca6d8f..144a401ba39 100644
--- a/public/app/plugins/datasource/zipkin/package.json
+++ b/public/app/plugins/datasource/zipkin/package.json
@@ -25,7 +25,7 @@
     "@testing-library/react": "15.0.2",
     "@types/jest": "29.5.12",
     "@types/lodash": "4.17.7",
-    "@types/node": "20.14.13",
+    "@types/node": "20.14.14",
     "@types/react": "18.3.3",
     "@types/react-dom": "18.2.25",
     "ts-node": "10.9.2",
diff --git a/public/app/plugins/panel/heatmap/utils.ts b/public/app/plugins/panel/heatmap/utils.ts
index 04919f2e809..3618dcdef2d 100644
--- a/public/app/plugins/panel/heatmap/utils.ts
+++ b/public/app/plugins/panel/heatmap/utils.ts
@@ -597,7 +597,7 @@ export function heatmapPathsDense(opts: PathbuilderOpts) {
         );
 
         for (let i = 0; i < dlen; i++) {
-          if (counts[i] > hideLE && counts[i] < hideGE) {
+          if (counts[i] != null && counts[i] > hideLE && counts[i] < hideGE) {
             let cx = cxs[~~(i / yBinQty)];
             let cy = cys[i % yBinQty];
 
@@ -826,7 +826,7 @@ export const boundedMinMax = (
     minValue = Infinity;
 
     for (let i = 0; i < values.length; i++) {
-      if (values[i] > hideLE && values[i] < hideGE) {
+      if (values[i] != null && values[i] > hideLE && values[i] < hideGE) {
         minValue = Math.min(minValue, values[i]);
       }
     }
@@ -836,7 +836,7 @@ export const boundedMinMax = (
     maxValue = -Infinity;
 
     for (let i = 0; i < values.length; i++) {
-      if (values[i] > hideLE && values[i] < hideGE) {
+      if (values[i] != null && values[i] > hideLE && values[i] < hideGE) {
         maxValue = Math.max(maxValue, values[i]);
       }
     }
diff --git a/public/img/plugins/cockroachdb.jpg b/public/img/plugins/cockroachdb.jpg
new file mode 100644
index 00000000000..4edbb1945d4
Binary files /dev/null and b/public/img/plugins/cockroachdb.jpg differ
diff --git a/public/locales/de-DE/grafana.json b/public/locales/de-DE/grafana.json
index 9d8447d1c3c..da660dd7fa8 100644
--- a/public/locales/de-DE/grafana.json
+++ b/public/locales/de-DE/grafana.json
@@ -1,6 +1,5 @@
 {
   "_comment": "",
-  "{unit}": "",
   "access-control": {
     "add-permission": {
       "role-label": "Rolle",
@@ -669,7 +668,6 @@
       "message": "Keine Datenquellen gefunden"
     }
   },
-  "Description": "",
   "explore": {
     "add-to-dashboard": "Zum Dashboard hinzufügen",
     "add-to-library-modal": {
@@ -940,7 +938,6 @@
       "refresh": "Aktualisieren"
     }
   },
-  "Labels": "",
   "library-panel": {
     "add-modal": {
       "cancel": "Abbrechen",
@@ -1541,7 +1538,6 @@
     },
     "title": "Das Neueste aus dem Blog"
   },
-  "No description available": "",
   "notifications": {
     "empty-state": {
       "description": "",
@@ -2233,15 +2229,22 @@
       "select-search-input": "Suchbegriff eingeben (Land, Stadt, Abkürzung)"
     }
   },
+  "trails": {
+    "metric-overview": {
+      "description-label": "",
+      "labels-label": "",
+      "no-description": "",
+      "type-label": "",
+      "unit-label": "",
+      "unknown-type": ""
+    }
+  },
   "transformations": {
     "empty": {
       "add-transformation-body": "Mithilfe von Transformationen können Daten auf verschiedene Arten geändert werden, bevor Ihre Visualisierung angezeigt wird.<1></1>Dies beinhaltet die Verknüpfung von Daten, das Umbenennen von Feldern, die Erstellung von Berechnungen, das Formatieren von Daten für die Anzeige und mehr.",
       "add-transformation-header": "Daten transformieren beginnen"
     }
   },
-  "Type": "",
-  "Unit": "",
-  "Unknown": "",
   "user-orgs": {
     "current-org-button": "Aktuell",
     "name-column": "Name",
diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json
index 10df4dd789a..d1f35a9be67 100644
--- a/public/locales/en-US/grafana.json
+++ b/public/locales/en-US/grafana.json
@@ -1,6 +1,5 @@
 {
   "_comment": "The code is the source of truth for English phrases. They should be updated in the components directly, and additional plurals specified in this file.",
-  "{unit}": "{unit}",
   "access-control": {
     "add-permission": {
       "role-label": "Role",
@@ -669,7 +668,6 @@
       "message": "No data sources found"
     }
   },
-  "Description": "Description",
   "explore": {
     "add-to-dashboard": "Add to dashboard",
     "add-to-library-modal": {
@@ -940,7 +938,6 @@
       "refresh": "Refresh"
     }
   },
-  "Labels": "Labels",
   "library-panel": {
     "add-modal": {
       "cancel": "Cancel",
@@ -1541,7 +1538,6 @@
     },
     "title": "Latest from the blog"
   },
-  "No description available": "No description available",
   "notifications": {
     "empty-state": {
       "description": "Notifications you have received will appear here",
@@ -2233,15 +2229,22 @@
       "select-search-input": "Type to search (country, city, abbreviation)"
     }
   },
+  "trails": {
+    "metric-overview": {
+      "description-label": "Description",
+      "labels-label": "Labels",
+      "no-description": "No description available",
+      "type-label": "Type",
+      "unit-label": "Unit",
+      "unknown-type": "Unknown"
+    }
+  },
   "transformations": {
     "empty": {
       "add-transformation-body": "Transformations allow data to be changed in various ways before your visualization is shown.<1></1>This includes joining data together, renaming fields, making calculations, formatting data for display, and more.",
       "add-transformation-header": "Start transforming data"
     }
   },
-  "Type": "Type",
-  "Unit": "Unit",
-  "Unknown": "Unknown",
   "user-orgs": {
     "current-org-button": "Current",
     "name-column": "Name",
diff --git a/public/locales/es-ES/grafana.json b/public/locales/es-ES/grafana.json
index d65385c3aff..2226877e29b 100644
--- a/public/locales/es-ES/grafana.json
+++ b/public/locales/es-ES/grafana.json
@@ -1,6 +1,5 @@
 {
   "_comment": "",
-  "{unit}": "",
   "access-control": {
     "add-permission": {
       "role-label": "Rol",
@@ -669,7 +668,6 @@
       "message": ""
     }
   },
-  "Description": "",
   "explore": {
     "add-to-dashboard": "Añadir al tablero",
     "add-to-library-modal": {
@@ -940,7 +938,6 @@
       "refresh": "Actualizar"
     }
   },
-  "Labels": "",
   "library-panel": {
     "add-modal": {
       "cancel": "Cancelar",
@@ -1541,7 +1538,6 @@
     },
     "title": "Últimas entradas del blog"
   },
-  "No description available": "",
   "notifications": {
     "empty-state": {
       "description": "",
@@ -2233,15 +2229,22 @@
       "select-search-input": "Escribir para buscar (país, ciudad, abreviatura)"
     }
   },
+  "trails": {
+    "metric-overview": {
+      "description-label": "",
+      "labels-label": "",
+      "no-description": "",
+      "type-label": "",
+      "unit-label": "",
+      "unknown-type": ""
+    }
+  },
   "transformations": {
     "empty": {
       "add-transformation-body": "Las transformaciones permiten cambiar los datos de varias maneras antes de que se muestre su visualización.<1></1>Aquí se incluyen acciones como unir datos, renombrar campos, hacer cálculos, dar formato a los datos para mostrarlos, etc.",
       "add-transformation-header": "Empezar a transformar datos"
     }
   },
-  "Type": "",
-  "Unit": "",
-  "Unknown": "",
   "user-orgs": {
     "current-org-button": "Actual",
     "name-column": "Nombre",
diff --git a/public/locales/fr-FR/grafana.json b/public/locales/fr-FR/grafana.json
index 88c03b2bcca..eb55de35e52 100644
--- a/public/locales/fr-FR/grafana.json
+++ b/public/locales/fr-FR/grafana.json
@@ -1,6 +1,5 @@
 {
   "_comment": "",
-  "{unit}": "",
   "access-control": {
     "add-permission": {
       "role-label": "Rôle",
@@ -669,7 +668,6 @@
       "message": ""
     }
   },
-  "Description": "",
   "explore": {
     "add-to-dashboard": "Ajouter au tableau de bord",
     "add-to-library-modal": {
@@ -940,7 +938,6 @@
       "refresh": "Actualiser"
     }
   },
-  "Labels": "",
   "library-panel": {
     "add-modal": {
       "cancel": "Annuler",
@@ -1541,7 +1538,6 @@
     },
     "title": "Dernières nouvelles sur le blog"
   },
-  "No description available": "",
   "notifications": {
     "empty-state": {
       "description": "",
@@ -2233,15 +2229,22 @@
       "select-search-input": "Tapez pour rechercher (pays, ville, abréviation)"
     }
   },
+  "trails": {
+    "metric-overview": {
+      "description-label": "",
+      "labels-label": "",
+      "no-description": "",
+      "type-label": "",
+      "unit-label": "",
+      "unknown-type": ""
+    }
+  },
   "transformations": {
     "empty": {
       "add-transformation-body": "Les transformations permettent de modifier les données de différentes manières avant l'affichage de votre visualisation.<1></1>Vous pouvez notamment rassembler des données, renommer des champs, faire des calculs, formater les données à afficher, etc.",
       "add-transformation-header": "Commencer la transformation des données"
     }
   },
-  "Type": "",
-  "Unit": "",
-  "Unknown": "",
   "user-orgs": {
     "current-org-button": "Actuel",
     "name-column": "Nom",
diff --git a/public/locales/pseudo-LOCALE/grafana.json b/public/locales/pseudo-LOCALE/grafana.json
index c067310672a..0ca6f638913 100644
--- a/public/locales/pseudo-LOCALE/grafana.json
+++ b/public/locales/pseudo-LOCALE/grafana.json
@@ -1,6 +1,5 @@
 {
   "_comment": "Ŧĥę čőđę įş ŧĥę şőūřčę őƒ ŧřūŧĥ ƒőř Ēʼnģľįşĥ pĥřäşęş. Ŧĥęy şĥőūľđ þę ūpđäŧęđ įʼn ŧĥę čőmpőʼnęʼnŧş đįřęčŧľy, äʼnđ äđđįŧįőʼnäľ pľūřäľş şpęčįƒįęđ įʼn ŧĥįş ƒįľę.",
-  "{unit}": "{ūʼnįŧ}",
   "access-control": {
     "add-permission": {
       "role-label": "Ŗőľę",
@@ -669,7 +668,6 @@
       "message": "Ńő đäŧä şőūřčęş ƒőūʼnđ"
     }
   },
-  "Description": "Đęşčřįpŧįőʼn",
   "explore": {
     "add-to-dashboard": "Åđđ ŧő đäşĥþőäřđ",
     "add-to-library-modal": {
@@ -940,7 +938,6 @@
       "refresh": "Ŗęƒřęşĥ"
     }
   },
-  "Labels": "Ŀäþęľş",
   "library-panel": {
     "add-modal": {
       "cancel": "Cäʼnčęľ",
@@ -1541,7 +1538,6 @@
     },
     "title": "Ŀäŧęşŧ ƒřőm ŧĥę þľőģ"
   },
-  "No description available": "Ńő đęşčřįpŧįőʼn äväįľäþľę",
   "notifications": {
     "empty-state": {
       "description": "Ńőŧįƒįčäŧįőʼnş yőū ĥävę řęčęįvęđ ŵįľľ äppęäř ĥęřę",
@@ -2233,15 +2229,22 @@
       "select-search-input": "Ŧypę ŧő şęäřčĥ (čőūʼnŧřy, čįŧy, äþþřęvįäŧįőʼn)"
     }
   },
+  "trails": {
+    "metric-overview": {
+      "description-label": "Đęşčřįpŧįőʼn",
+      "labels-label": "Ŀäþęľş",
+      "no-description": "Ńő đęşčřįpŧįőʼn äväįľäþľę",
+      "type-label": "Ŧypę",
+      "unit-label": "Ůʼnįŧ",
+      "unknown-type": "Ůʼnĸʼnőŵʼn"
+    }
+  },
   "transformations": {
     "empty": {
       "add-transformation-body": "Ŧřäʼnşƒőřmäŧįőʼnş äľľőŵ đäŧä ŧő þę čĥäʼnģęđ įʼn väřįőūş ŵäyş þęƒőřę yőūř vįşūäľįžäŧįőʼn įş şĥőŵʼn.<1></1>Ŧĥįş įʼnčľūđęş ĵőįʼnįʼnģ đäŧä ŧőģęŧĥęř, řęʼnämįʼnģ ƒįęľđş, mäĸįʼnģ čäľčūľäŧįőʼnş, ƒőřmäŧŧįʼnģ đäŧä ƒőř đįşpľäy, äʼnđ mőřę.",
       "add-transformation-header": "Ŝŧäřŧ ŧřäʼnşƒőřmįʼnģ đäŧä"
     }
   },
-  "Type": "Ŧypę",
-  "Unit": "Ůʼnįŧ",
-  "Unknown": "Ůʼnĸʼnőŵʼn",
   "user-orgs": {
     "current-org-button": "Cūřřęʼnŧ",
     "name-column": "Ńämę",
diff --git a/public/locales/pt-BR/grafana.json b/public/locales/pt-BR/grafana.json
index 945ecd589bc..01d608d7383 100644
--- a/public/locales/pt-BR/grafana.json
+++ b/public/locales/pt-BR/grafana.json
@@ -1,6 +1,5 @@
 {
   "_comment": "",
-  "{unit}": "",
   "access-control": {
     "add-permission": {
       "role-label": "Função",
@@ -669,7 +668,6 @@
       "message": ""
     }
   },
-  "Description": "",
   "explore": {
     "add-to-dashboard": "Adicionar ao painel de controle",
     "add-to-library-modal": {
@@ -940,7 +938,6 @@
       "refresh": "Atualizar"
     }
   },
-  "Labels": "",
   "library-panel": {
     "add-modal": {
       "cancel": "Cancelar",
@@ -1541,7 +1538,6 @@
     },
     "title": "Mais recentes do blog"
   },
-  "No description available": "",
   "notifications": {
     "empty-state": {
       "description": "",
@@ -2233,15 +2229,22 @@
       "select-search-input": "Tipo de busca (país, cidade, abreviação)"
     }
   },
+  "trails": {
+    "metric-overview": {
+      "description-label": "",
+      "labels-label": "",
+      "no-description": "",
+      "type-label": "",
+      "unit-label": "",
+      "unknown-type": ""
+    }
+  },
   "transformations": {
     "empty": {
       "add-transformation-body": "As transformações permitem que os dados sejam alterados de várias maneiras antes de sua visualização ser mostrada. <1></1>Isso inclui juntar dados, renomear campos, fazer cálculos, formatar dados para exibição e muito mais.",
       "add-transformation-header": "Começar a transformar dados"
     }
   },
-  "Type": "",
-  "Unit": "",
-  "Unknown": "",
   "user-orgs": {
     "current-org-button": "Atual",
     "name-column": "Nome",
diff --git a/public/locales/zh-Hans/grafana.json b/public/locales/zh-Hans/grafana.json
index 94502a89b6d..630a7a615ed 100644
--- a/public/locales/zh-Hans/grafana.json
+++ b/public/locales/zh-Hans/grafana.json
@@ -1,6 +1,5 @@
 {
   "_comment": "",
-  "{unit}": "",
   "access-control": {
     "add-permission": {
       "role-label": "角色",
@@ -663,7 +662,6 @@
       "message": ""
     }
   },
-  "Description": "",
   "explore": {
     "add-to-dashboard": "添加到仪表板",
     "add-to-library-modal": {
@@ -934,7 +932,6 @@
       "refresh": "刷新"
     }
   },
-  "Labels": "",
   "library-panel": {
     "add-modal": {
       "cancel": "取消",
@@ -1534,7 +1531,6 @@
     },
     "title": "最新博客"
   },
-  "No description available": "",
   "notifications": {
     "empty-state": {
       "description": "",
@@ -2224,15 +2220,22 @@
       "select-search-input": "输入以搜索(国家、城市、缩写)"
     }
   },
+  "trails": {
+    "metric-overview": {
+      "description-label": "",
+      "labels-label": "",
+      "no-description": "",
+      "type-label": "",
+      "unit-label": "",
+      "unknown-type": ""
+    }
+  },
   "transformations": {
     "empty": {
       "add-transformation-body": "转换允许在显示可视化之前以各种方式更改数据。 <1></1>这包括合并数据、重命名字段、进行计算、格式化数据以便显示等等。",
       "add-transformation-header": "开始转换数据"
     }
   },
-  "Type": "",
-  "Unit": "",
-  "Unknown": "",
   "user-orgs": {
     "current-org-button": "当前",
     "name-column": "姓名",
diff --git a/scripts/webpack/webpack.common.js b/scripts/webpack/webpack.common.js
index 599c4a1fb41..684b2ea1407 100644
--- a/scripts/webpack/webpack.common.js
+++ b/scripts/webpack/webpack.common.js
@@ -106,7 +106,7 @@ module.exports = {
       },
       // for pre-caching SVGs as part of the JS bundles
       {
-        test: /(unicons|mono|custom)[\\/].*\.svg$/,
+        test: /(unicons|mono|custom|solid)[\\/].*\.svg$/,
         type: 'asset/source',
       },
       {
diff --git a/yarn.lock b/yarn.lock
index 44ff43a1731..c5dc42b76e6 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2766,7 +2766,7 @@ __metadata:
     "@testing-library/user-event": "npm:14.5.2"
     "@types/jest": "npm:29.5.12"
     "@types/lodash": "npm:4.17.7"
-    "@types/node": "npm:20.14.13"
+    "@types/node": "npm:20.14.14"
     "@types/prismjs": "npm:1.26.4"
     "@types/react": "npm:18.3.3"
     "@types/react-dom": "npm:18.2.25"
@@ -2808,7 +2808,7 @@ __metadata:
     "@testing-library/user-event": "npm:14.5.2"
     "@types/jest": "npm:29.5.12"
     "@types/lodash": "npm:4.17.7"
-    "@types/node": "npm:20.14.13"
+    "@types/node": "npm:20.14.14"
     "@types/react": "npm:18.3.3"
     "@types/testing-library__jest-dom": "npm:5.14.9"
     lodash: "npm:4.17.21"
@@ -2839,7 +2839,7 @@ __metadata:
     "@testing-library/user-event": "npm:14.5.2"
     "@types/jest": "npm:29.5.12"
     "@types/lodash": "npm:4.17.7"
-    "@types/node": "npm:20.14.13"
+    "@types/node": "npm:20.14.14"
     "@types/prismjs": "npm:1.26.4"
     "@types/react": "npm:18.3.3"
     "@types/react-dom": "npm:18.2.25"
@@ -2882,7 +2882,7 @@ __metadata:
     "@types/d3-random": "npm:^3.0.2"
     "@types/jest": "npm:29.5.12"
     "@types/lodash": "npm:4.17.7"
-    "@types/node": "npm:20.14.13"
+    "@types/node": "npm:20.14.14"
     "@types/react": "npm:18.3.3"
     "@types/react-dom": "npm:18.2.25"
     "@types/testing-library__jest-dom": "npm:5.14.9"
@@ -2924,7 +2924,7 @@ __metadata:
     "@types/jest": "npm:29.5.12"
     "@types/lodash": "npm:4.17.7"
     "@types/logfmt": "npm:^1.2.3"
-    "@types/node": "npm:20.14.13"
+    "@types/node": "npm:20.14.14"
     "@types/react": "npm:18.3.3"
     "@types/react-dom": "npm:18.2.25"
     "@types/react-window": "npm:1.8.8"
@@ -2963,7 +2963,7 @@ __metadata:
     "@testing-library/user-event": "npm:14.5.2"
     "@types/jest": "npm:29.5.12"
     "@types/lodash": "npm:4.17.7"
-    "@types/node": "npm:20.14.13"
+    "@types/node": "npm:20.14.14"
     "@types/react": "npm:18.3.3"
     "@types/testing-library__jest-dom": "npm:5.14.9"
     lodash: "npm:4.17.21"
@@ -2992,7 +2992,7 @@ __metadata:
     "@testing-library/react": "npm:15.0.2"
     "@testing-library/user-event": "npm:14.5.2"
     "@types/lodash": "npm:4.17.7"
-    "@types/node": "npm:20.14.13"
+    "@types/node": "npm:20.14.14"
     "@types/react": "npm:18.3.3"
     "@types/react-dom": "npm:18.2.25"
     lodash: "npm:4.17.21"
@@ -3029,7 +3029,7 @@ __metadata:
     "@types/debounce-promise": "npm:3.1.9"
     "@types/jest": "npm:29.5.12"
     "@types/lodash": "npm:4.17.7"
-    "@types/node": "npm:20.14.13"
+    "@types/node": "npm:20.14.14"
     "@types/prismjs": "npm:1.26.4"
     "@types/react": "npm:18.3.3"
     "@types/react-dom": "npm:18.2.25"
@@ -3085,7 +3085,7 @@ __metadata:
     "@testing-library/user-event": "npm:14.5.2"
     "@types/jest": "npm:29.5.12"
     "@types/lodash": "npm:4.17.7"
-    "@types/node": "npm:20.14.13"
+    "@types/node": "npm:20.14.14"
     "@types/prismjs": "npm:1.26.4"
     "@types/react": "npm:18.3.3"
     "@types/react-dom": "npm:18.2.25"
@@ -3134,7 +3134,7 @@ __metadata:
     "@testing-library/react": "npm:15.0.2"
     "@types/jest": "npm:29.5.12"
     "@types/lodash": "npm:4.17.7"
-    "@types/node": "npm:20.14.13"
+    "@types/node": "npm:20.14.14"
     "@types/react": "npm:18.3.3"
     "@types/react-dom": "npm:18.2.25"
     lodash: "npm:4.17.21"
@@ -3192,7 +3192,7 @@ __metadata:
     "@types/dompurify": "npm:^3.0.0"
     "@types/history": "npm:4.7.11"
     "@types/lodash": "npm:4.17.7"
-    "@types/node": "npm:20.14.13"
+    "@types/node": "npm:20.14.14"
     "@types/papaparse": "npm:5.3.14"
     "@types/react": "npm:18.3.3"
     "@types/react-dom": "npm:18.2.25"
@@ -3239,7 +3239,7 @@ __metadata:
   dependencies:
     "@grafana/tsconfig": "npm:^1.3.0-rc1"
     "@rollup/plugin-node-resolve": "npm:15.2.3"
-    "@types/node": "npm:20.14.13"
+    "@types/node": "npm:20.14.14"
     esbuild: "npm:0.20.2"
     rimraf: "npm:5.0.7"
     rollup: "npm:2.79.1"
@@ -3357,7 +3357,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@grafana/faro-web-sdk@npm:1.9.0, @grafana/faro-web-sdk@npm:^1.3.6, @grafana/faro-web-sdk@npm:^1.8.2":
+"@grafana/faro-web-sdk@npm:1.9.0, @grafana/faro-web-sdk@npm:^1.3.6, @grafana/faro-web-sdk@npm:^1.9.0":
   version: 1.9.0
   resolution: "@grafana/faro-web-sdk@npm:1.9.0"
   dependencies:
@@ -3369,10 +3369,10 @@ __metadata:
   linkType: hard
 
 "@grafana/faro-web-tracing@npm:^1.8.2":
-  version: 1.8.2
-  resolution: "@grafana/faro-web-tracing@npm:1.8.2"
+  version: 1.9.0
+  resolution: "@grafana/faro-web-tracing@npm:1.9.0"
   dependencies:
-    "@grafana/faro-web-sdk": "npm:^1.8.2"
+    "@grafana/faro-web-sdk": "npm:^1.9.0"
     "@opentelemetry/api": "npm:^1.9.0"
     "@opentelemetry/context-zone": "npm:1.21.0"
     "@opentelemetry/core": "npm:^1.25.0"
@@ -3384,7 +3384,7 @@ __metadata:
     "@opentelemetry/resources": "npm:^1.25.0"
     "@opentelemetry/sdk-trace-web": "npm:^1.25.0"
     "@opentelemetry/semantic-conventions": "npm:^1.25.0"
-  checksum: 10/6dd5d07b887de71f37176d01c68602677ebfb9fd9dbc4d6aa2456ec95fd9ceda7556ca71571f4cbaa59b126baebb8424cf34f977c6f3c10cbb3afab1692ebfc4
+  checksum: 10/53aa9105c5bff80025c4d0aca0f4be90338b03143615a11207237a543bbfe14e9573d3617b52ef777dd32826bcdf80ba9dd96db0742caf9d30b0764c6d5781ca
   languageName: node
   linkType: hard
 
@@ -3408,7 +3408,7 @@ __metadata:
     "@types/d3": "npm:^7"
     "@types/jest": "npm:^29.5.4"
     "@types/lodash": "npm:4.17.7"
-    "@types/node": "npm:20.14.13"
+    "@types/node": "npm:20.14.14"
     "@types/react": "npm:18.3.3"
     "@types/react-virtualized-auto-sizer": "npm:1.0.4"
     "@types/tinycolor2": "npm:1.4.6"
@@ -3492,7 +3492,7 @@ __metadata:
     "@testing-library/react": "npm:15.0.2"
     "@testing-library/user-event": "npm:14.5.2"
     "@types/jest": "npm:^29.5.4"
-    "@types/node": "npm:20.14.13"
+    "@types/node": "npm:20.14.14"
     "@types/react": "npm:18.3.3"
     "@types/systemjs": "npm:6.13.5"
     "@types/testing-library__jest-dom": "npm:5.14.9"
@@ -3580,7 +3580,7 @@ __metadata:
     "@types/jest": "npm:29.5.12"
     "@types/jquery": "npm:3.5.30"
     "@types/lodash": "npm:4.17.7"
-    "@types/node": "npm:20.14.13"
+    "@types/node": "npm:20.14.14"
     "@types/pluralize": "npm:^0.0.33"
     "@types/prismjs": "npm:1.26.4"
     "@types/react": "npm:18.3.3"
@@ -3602,7 +3602,7 @@ __metadata:
     eslint-config-prettier: "npm:9.1.0"
     eslint-plugin-import: "npm:^2.26.0"
     eslint-plugin-jest: "npm:28.6.0"
-    eslint-plugin-jsdoc: "npm:48.10.2"
+    eslint-plugin-jsdoc: "npm:48.11.0"
     eslint-plugin-jsx-a11y: "npm:6.9.0"
     eslint-plugin-lodash: "npm:7.4.0"
     eslint-plugin-react: "npm:7.35.0"
@@ -3712,7 +3712,7 @@ __metadata:
     "@svgr/plugin-prettier": "npm:^8.1.0"
     "@svgr/plugin-svgo": "npm:^8.1.0"
     "@types/babel__core": "npm:^7"
-    "@types/node": "npm:20.14.13"
+    "@types/node": "npm:20.14.14"
     "@types/react": "npm:18.3.3"
     "@types/react-dom": "npm:18.2.25"
     esbuild: "npm:0.20.2"
@@ -3790,7 +3790,7 @@ __metadata:
     "@testing-library/user-event": "npm:14.5.2"
     "@types/jest": "npm:^29.5.4"
     "@types/lodash": "npm:4.17.7"
-    "@types/node": "npm:20.14.13"
+    "@types/node": "npm:20.14.14"
     "@types/react": "npm:18.3.3"
     "@types/react-dom": "npm:18.2.25"
     "@types/react-virtualized-auto-sizer": "npm:1.0.4"
@@ -3877,7 +3877,7 @@ __metadata:
     "@types/jquery": "npm:3.5.30"
     "@types/lodash": "npm:4.17.7"
     "@types/mock-raf": "npm:1.0.6"
-    "@types/node": "npm:20.14.13"
+    "@types/node": "npm:20.14.14"
     "@types/prismjs": "npm:1.26.4"
     "@types/react": "npm:18.3.3"
     "@types/react-color": "npm:3.0.12"
@@ -9211,12 +9211,12 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@types/node@npm:*, @types/node@npm:20.14.13, @types/node@npm:>=13.7.0, @types/node@npm:^20.11.16":
-  version: 20.14.13
-  resolution: "@types/node@npm:20.14.13"
+"@types/node@npm:*, @types/node@npm:20.14.14, @types/node@npm:>=13.7.0, @types/node@npm:^20.11.16":
+  version: 20.14.14
+  resolution: "@types/node@npm:20.14.14"
   dependencies:
     undici-types: "npm:~5.26.4"
-  checksum: 10/749160b6bd9866e6169cb1a222e75aaf81da3868af1fda1e1e66d33c7e182be381f98a42b7d231fddf470f6389f2052ee842e776b3fdc677df798b933617866d
+  checksum: 10/035bc347e3de04888d537801e23eb4b4f99522975ca002dbfef978edd853710031b7cd43bf022670d6aba4ed5d4ac75ea1b5ff77ff8f80998bffd943b7bcef48
   languageName: node
   linkType: hard
 
@@ -11889,16 +11889,16 @@ __metadata:
   linkType: hard
 
 "browserslist@npm:^4.0.0, browserslist@npm:^4.21.10, browserslist@npm:^4.21.4, browserslist@npm:^4.22.2, browserslist@npm:^4.23.0, browserslist@npm:^4.23.1":
-  version: 4.23.2
-  resolution: "browserslist@npm:4.23.2"
+  version: 4.23.3
+  resolution: "browserslist@npm:4.23.3"
   dependencies:
-    caniuse-lite: "npm:^1.0.30001640"
-    electron-to-chromium: "npm:^1.4.820"
-    node-releases: "npm:^2.0.14"
+    caniuse-lite: "npm:^1.0.30001646"
+    electron-to-chromium: "npm:^1.5.4"
+    node-releases: "npm:^2.0.18"
     update-browserslist-db: "npm:^1.1.0"
   bin:
     browserslist: cli.js
-  checksum: 10/326a98b1c39bcc9a99b197f15790dc28e122b1aead3257c837421899377ac96239123f26868698085b3d9be916d72540602738e1f857e86a387e810af3fda6e5
+  checksum: 10/e266d18c6c6c5becf9a1a7aa264477677b9796387972e8fce34854bb33dc1666194dc28389780e5dc6566e68a95e87ece2ce222e1c4ca93c2b75b61dfebd5f1c
   languageName: node
   linkType: hard
 
@@ -12141,10 +12141,10 @@ __metadata:
   languageName: node
   linkType: hard
 
-"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001599, caniuse-lite@npm:^1.0.30001640":
-  version: 1.0.30001642
-  resolution: "caniuse-lite@npm:1.0.30001642"
-  checksum: 10/8d80ea82be453ae0fdfea8766d82740a4945c1b99189650f29bfc458d4e235d7e99027a8f8bc5a4228d8c4457ba896315284b0703f300353ad5f09d8e693de10
+"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001599, caniuse-lite@npm:^1.0.30001646":
+  version: 1.0.30001646
+  resolution: "caniuse-lite@npm:1.0.30001646"
+  checksum: 10/6c66a5677b58988c2ee86905b05705b00be552a3e4f768bd0d9a10098cc4ec471de5b204e2c2ab534f34b5f216c059321a9e5cb1395928cf29ded0a4aae4535f
   languageName: node
   linkType: hard
 
@@ -12764,10 +12764,10 @@ __metadata:
   languageName: node
   linkType: hard
 
-"commander@npm:~11.1.0":
-  version: 11.1.0
-  resolution: "commander@npm:11.1.0"
-  checksum: 10/66bd2d8a0547f6cb1d34022efb25f348e433b0e04ad76a65279b1b09da108f59a4d3001ca539c60a7a46ea38bcf399fc17d91adad76a8cf43845d8dcbaf5cda1
+"commander@npm:~12.1.0":
+  version: 12.1.0
+  resolution: "commander@npm:12.1.0"
+  checksum: 10/cdaeb672d979816853a4eed7f1310a9319e8b976172485c2a6b437ed0db0a389a44cfb222bfbde772781efa9f215bdd1b936f80d6b249485b465c6cb906e1f93
   languageName: node
   linkType: hard
 
@@ -14186,13 +14186,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"de-indent@npm:^1.0.2":
-  version: 1.0.2
-  resolution: "de-indent@npm:1.0.2"
-  checksum: 10/30bf43744dca005f9252dbb34ed95dcb3c30dfe52bfed84973b89c29eccff04e27769f222a34c61a93354acf47457785e9032e6184be390ed1d324fb9ab3f427
-  languageName: node
-  linkType: hard
-
 "debounce-promise@npm:3.1.2":
   version: 3.1.2
   resolution: "debounce-promise@npm:3.1.2"
@@ -14907,10 +14900,10 @@ __metadata:
   languageName: node
   linkType: hard
 
-"electron-to-chromium@npm:^1.4.820":
-  version: 1.4.829
-  resolution: "electron-to-chromium@npm:1.4.829"
-  checksum: 10/43279561337582ff47bb3486439efbc7c1f2192455c76ebc7374754fca61334380025af9e5da7646b4d8c007d9dc6c25d8f6059dffb2207dc39d2f79287a296a
+"electron-to-chromium@npm:^1.5.4":
+  version: 1.5.4
+  resolution: "electron-to-chromium@npm:1.5.4"
+  checksum: 10/ce64db25c399d33830e74e58bbc5ab7c06948669e204b6508e98c278ddaead1da1cbb356d15b55eb659f89d4d7bcf00944f08f96e886f1d3d065ba11744c5633
   languageName: node
   linkType: hard
 
@@ -15641,9 +15634,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"eslint-plugin-jsdoc@npm:48.10.2":
-  version: 48.10.2
-  resolution: "eslint-plugin-jsdoc@npm:48.10.2"
+"eslint-plugin-jsdoc@npm:48.11.0":
+  version: 48.11.0
+  resolution: "eslint-plugin-jsdoc@npm:48.11.0"
   dependencies:
     "@es-joy/jsdoccomment": "npm:~0.46.0"
     are-docs-informative: "npm:^0.0.2"
@@ -15658,7 +15651,7 @@ __metadata:
     synckit: "npm:^0.9.1"
   peerDependencies:
     eslint: ^7.0.0 || ^8.0.0 || ^9.0.0
-  checksum: 10/0685131bfdf3a58efbcb37bfccd36ee6251755b2d961d944f5df89e855fdb0264ed107c097b79489a2a2fe34fe80082c3b31f348be6167e68ded6615f768037d
+  checksum: 10/3bc2533656e9ccfdadbcd71a6f7c1ec125b1965c6e399a43c40408b51b4f8c26e44031f077c947b15d68b9cd317e7e8be1e2b222a46fb3c24a25377a2643796b
   languageName: node
   linkType: hard
 
@@ -17565,7 +17558,7 @@ __metadata:
     "@types/lodash": "npm:4.17.7"
     "@types/logfmt": "npm:^1.2.3"
     "@types/lucene": "npm:^2"
-    "@types/node": "npm:20.14.13"
+    "@types/node": "npm:20.14.14"
     "@types/node-forge": "npm:^1"
     "@types/ol-ext": "npm:@siedlerchr/types-ol-ext@3.2.4"
     "@types/pluralize": "npm:^0.0.33"
@@ -17643,7 +17636,7 @@ __metadata:
     eslint-config-prettier: "npm:9.1.0"
     eslint-plugin-import: "npm:^2.26.0"
     eslint-plugin-jest: "npm:28.6.0"
-    eslint-plugin-jsdoc: "npm:48.10.2"
+    eslint-plugin-jsdoc: "npm:48.11.0"
     eslint-plugin-jsx-a11y: "npm:6.9.0"
     eslint-plugin-lodash: "npm:7.4.0"
     eslint-plugin-no-barrel-files: "npm:^1.1.0"
@@ -17664,7 +17657,7 @@ __metadata:
     http-server: "npm:14.1.1"
     i18next: "npm:^23.0.0"
     i18next-browser-languagedetector: "npm:^7.0.2"
-    i18next-parser: "npm:8.13.0"
+    i18next-parser: "npm:9.0.1"
     immer: "npm:10.1.1"
     immutable: "npm:4.3.7"
     jest: "npm:29.7.0"
@@ -17699,7 +17692,7 @@ __metadata:
     moment-timezone: "npm:0.5.45"
     monaco-editor: "npm:0.34.1"
     moveable: "npm:0.53.0"
-    msw: "npm:2.3.4"
+    msw: "npm:2.3.5"
     mutationobserver-shim: "npm:0.3.7"
     nanoid: "npm:^5.0.4"
     ngtemplate-loader: "npm:2.1.0"
@@ -18494,15 +18487,15 @@ __metadata:
   languageName: node
   linkType: hard
 
-"i18next-parser@npm:8.13.0":
-  version: 8.13.0
-  resolution: "i18next-parser@npm:8.13.0"
+"i18next-parser@npm:9.0.1":
+  version: 9.0.1
+  resolution: "i18next-parser@npm:9.0.1"
   dependencies:
     "@babel/runtime": "npm:^7.23.2"
     broccoli-plugin: "npm:^4.0.7"
     cheerio: "npm:^1.0.0-rc.2"
     colors: "npm:1.4.0"
-    commander: "npm:~11.1.0"
+    commander: "npm:~12.1.0"
     eol: "npm:^0.9.1"
     esbuild: "npm:^0.20.1"
     fs-extra: "npm:^11.1.0"
@@ -18515,10 +18508,9 @@ __metadata:
     typescript: "npm:^5.0.4"
     vinyl: "npm:~3.0.0"
     vinyl-fs: "npm:^4.0.0"
-    vue-template-compiler: "npm:^2.6.11"
   bin:
     i18next: bin/cli.js
-  checksum: 10/dcdb34f0418df7c969162f4c58b1f751e0245769a5748d127dcefd3d0986b45622f6b41d598920cf6fbda6972564fc48c8a5e934dc334ed46651294f98835bda
+  checksum: 10/d6f13c6cdc98f853b5cc433fb0853a996e9a88f83e9fe26974b4b6649a01713ec09f567869c57f21e57a7efcb731d50f296373f9647deef7a73d0d76fda63388
   languageName: node
   linkType: hard
 
@@ -22601,9 +22593,9 @@ __metadata:
   languageName: node
   linkType: hard
 
-"msw@npm:2.3.4":
-  version: 2.3.4
-  resolution: "msw@npm:2.3.4"
+"msw@npm:2.3.5":
+  version: 2.3.5
+  resolution: "msw@npm:2.3.5"
   dependencies:
     "@bundled-es-modules/cookie": "npm:^2.0.0"
     "@bundled-es-modules/statuses": "npm:^1.0.1"
@@ -22629,7 +22621,7 @@ __metadata:
       optional: true
   bin:
     msw: cli/index.js
-  checksum: 10/d35f13d2256d336fb808381839b166986d6f9279dd35f32b6fbd9ca3420fb31bbac0fe1d2c0b0d66d2b67489bdb8e09491ac3a797f04114dd550906eb33fb9d6
+  checksum: 10/c7c14f517bf4011de4d8758212f84b355433ac8087840f94a605690a1f41ea8f4a4b6e07161f734f823b2563ba0a8ea168036f59a6ccdfc895817db6eed64418
   languageName: node
   linkType: hard
 
@@ -22901,10 +22893,10 @@ __metadata:
   languageName: node
   linkType: hard
 
-"node-releases@npm:^2.0.14":
-  version: 2.0.14
-  resolution: "node-releases@npm:2.0.14"
-  checksum: 10/0f7607ec7db5ef1dc616899a5f24ae90c869b6a54c2d4f36ff6d84a282ab9343c7ff3ca3670fe4669171bb1e8a9b3e286e1ef1c131f09a83d70554f855d54f24
+"node-releases@npm:^2.0.18":
+  version: 2.0.18
+  resolution: "node-releases@npm:2.0.18"
+  checksum: 10/241e5fa9556f1c12bafb83c6c3e94f8cf3d8f2f8f904906ecef6e10bcaa1d59aa61212d4651bec70052015fc54bd3fdcdbe7fc0f638a17e6685aa586c076ec4e
   languageName: node
   linkType: hard
 
@@ -30526,16 +30518,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"vue-template-compiler@npm:^2.6.11":
-  version: 2.7.10
-  resolution: "vue-template-compiler@npm:2.7.10"
-  dependencies:
-    de-indent: "npm:^1.0.2"
-    he: "npm:^1.2.0"
-  checksum: 10/9990ea1ae1f46648e366dcca6f4f164748f131ebf0588378c7427318eac02e8993780b9e0b03a510236287b02028759cc75e5bd655cb8f3cd86b4ea705f97122
-  languageName: node
-  linkType: hard
-
 "w3c-xmlserializer@npm:^3.0.0":
   version: 3.0.0
   resolution: "w3c-xmlserializer@npm:3.0.0"