diff --git a/.betterer.results b/.betterer.results
index 634b449cdd5..63ec527a0a2 100644
--- a/.betterer.results
+++ b/.betterer.results
@@ -447,9 +447,6 @@ exports[`better eslint`] = {
"packages/grafana-prometheus/src/components/PromQueryField.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
],
- "packages/grafana-prometheus/src/components/PrometheusMetricsBrowser.tsx:5381": [
- [0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"]
- ],
"packages/grafana-prometheus/src/datasource.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
@@ -2907,6 +2904,9 @@ exports[`better eslint`] = {
"public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
],
+ "public/app/features/dashboard-scene/scene/Scopes/ScopesInput.tsx:5381": [
+ [0, 0, 0, "Do not use any type assertions.", "0"]
+ ],
"public/app/features/dashboard-scene/scene/row-actions/RowActions.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with ", "0"],
[0, 0, 0, "No untranslated strings. Wrap text with ", "1"],
@@ -3085,9 +3085,6 @@ exports[`better eslint`] = {
[0, 0, 0, "Do not re-export imported variable (\`./VersionHistoryButtons\`)", "3"],
[0, 0, 0, "Do not re-export imported variable (\`./VersionHistoryComparison\`)", "4"]
],
- "public/app/features/dashboard-scene/sharing/ShareButton/ShareButton.tsx:5381": [
- [0, 0, 0, "No untranslated strings. Wrap text with ", "0"]
- ],
"public/app/features/dashboard-scene/sharing/ShareExportTab.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with ", "0"]
],
@@ -6427,8 +6424,7 @@ exports[`better eslint`] = {
[0, 0, 0, "Styles should be written using objects.", "0"]
],
"public/app/plugins/datasource/graphite/components/GraphiteFunctionEditor.tsx:5381": [
- [0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"],
- [0, 0, 0, "Styles should be written using objects.", "1"]
+ [0, 0, 0, "Styles should be written using objects.", "0"]
],
"public/app/plugins/datasource/graphite/components/GraphiteQueryEditor.tsx:5381": [
[0, 0, 0, "Styles should be written using objects.", "0"],
@@ -6568,9 +6564,6 @@ exports[`better eslint`] = {
[0, 0, 0, "Styles should be written using objects.", "0"],
[0, 0, 0, "Styles should be written using objects.", "1"]
],
- "public/app/plugins/datasource/influxdb/components/editor/query/influxql/code/RawInfluxQLEditor.tsx:5381": [
- [0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"]
- ],
"public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/VisualInfluxQLEditor.tsx:5381": [
[0, 0, 0, "Styles should be written using objects.", "0"]
],
diff --git a/.eslintrc b/.eslintrc
index 71d0b6fbcac..9ad2a337f47 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -1,5 +1,5 @@
{
- "extends": ["@grafana/eslint-config"],
+ "extends": ["@grafana/eslint-config", "plugin:react/jsx-runtime"],
"root": true,
"plugins": ["@emotion", "lodash", "jest", "import", "jsx-a11y", "@grafana", "no-barrel-files"],
"settings": {
diff --git a/.github/workflows/auto-milestone.yml b/.github/workflows/auto-milestone.yml
index 7b38cb0b01d..0697888fba0 100644
--- a/.github/workflows/auto-milestone.yml
+++ b/.github/workflows/auto-milestone.yml
@@ -9,6 +9,7 @@ on:
permissions:
pull-requests: write
+ contents: write
# Note: this action runs with write permissions on GITHUB_TOKEN even from forks
# so it must not run untrusted code (such as checking out the pull request)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d523e856cf8..1a52e0a3bd0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,289 @@
+
+
+# 11.1.0 (2024-06-21)
+
+### Features and enhancements
+
+- **Tracing:** Enable traces to profiles. [#88896](https://github.com/grafana/grafana/issues/88896), [@marefr](https://github.com/marefr)
+- **Auth:** Add org to role mappings support to Google integration. [#88891](https://github.com/grafana/grafana/issues/88891), [@kalleep](https://github.com/kalleep)
+- **Alerting:** Support AWS SNS integration in Grafana. [#88867](https://github.com/grafana/grafana/issues/88867), [@yuri-tceretian](https://github.com/yuri-tceretian)
+- **Auth:** Add org to role mappings support to Okta integration. [#88770](https://github.com/grafana/grafana/issues/88770), [@mgyongyosi](https://github.com/mgyongyosi)
+- **Auth:** Add org to role mappings support to Gitlab integration. [#88751](https://github.com/grafana/grafana/issues/88751), [@kalleep](https://github.com/kalleep)
+- **Cloudwatch:** Use the metric map from grafana-aws-sdk. [#88733](https://github.com/grafana/grafana/issues/88733), [@iwysiu](https://github.com/iwysiu)
+- **Alerting:** Add option to use Redis in cluster mode for Alerting HA. [#88696](https://github.com/grafana/grafana/issues/88696), [@fayzal-g](https://github.com/fayzal-g)
+- **VizTooltip:** Allow setting the `maxWidth` option. [#88652](https://github.com/grafana/grafana/issues/88652), [@adela-almasan](https://github.com/adela-almasan)
+- **Auth:** Add org to role mappings support to GitHub integration . [#88537](https://github.com/grafana/grafana/issues/88537), [@mgyongyosi](https://github.com/mgyongyosi)
+- **CloudWatch:** Handle permissions error and update docs. [#88524](https://github.com/grafana/grafana/issues/88524), [@iwysiu](https://github.com/iwysiu)
+- ** Alerting:** Correctly handle duplicating notification templates. [#88487](https://github.com/grafana/grafana/issues/88487), [@gillesdemey](https://github.com/gillesdemey)
+- **Alerting:** Mute Timing service to prevent changing provenance status to none. [#88462](https://github.com/grafana/grafana/issues/88462), [@yuri-tceretian](https://github.com/yuri-tceretian)
+- **Alerting:** Ensure we fetch AM config before saving new configuration. [#88458](https://github.com/grafana/grafana/issues/88458), [@tomratcliffe](https://github.com/tomratcliffe)
+- **Alerting:** Remove regex reference in silences filter tooltip. [#88455](https://github.com/grafana/grafana/issues/88455), [@tomratcliffe](https://github.com/tomratcliffe)
+- **Cloudwatch:** Update AWS DynamoDB Metrics. [#88418](https://github.com/grafana/grafana/issues/88418), [@LeonardoBoleli](https://github.com/LeonardoBoleli)
+- **Alerting:** Make regex notification routing preview consistent with notification policies implementation. [#88413](https://github.com/grafana/grafana/issues/88413), [@tomratcliffe](https://github.com/tomratcliffe)
+- **DateTimePicker:** Return cleared value in onChange. [#88377](https://github.com/grafana/grafana/issues/88377), [@Clarity-89](https://github.com/Clarity-89)
+- **NodeGraph:** Add msagl and the layered layout code. [#88375](https://github.com/grafana/grafana/issues/88375), [@aocenas](https://github.com/aocenas)
+- **API:** Add in theme support to /render/\* endpoint. [#88304](https://github.com/grafana/grafana/issues/88304), [@timlevett](https://github.com/timlevett)
+- **Alerting:** Add filters for RouteGetRuleStatuses. [#88295](https://github.com/grafana/grafana/issues/88295), [@fayzal-g](https://github.com/fayzal-g)
+- **Plugins:** Update the `plugin.json` schema with UI extensions meta-data. [#88288](https://github.com/grafana/grafana/issues/88288), [@leventebalogh](https://github.com/leventebalogh)
+- **Auth:** Update SAML lib to improve HTTP-Post binding. [#88287](https://github.com/grafana/grafana/issues/88287), [@mgyongyosi](https://github.com/mgyongyosi)
+- **Tempo:** Send current filters when retrieving tags for AdHocFilters. [#88270](https://github.com/grafana/grafana/issues/88270), [@joey-grafana](https://github.com/joey-grafana)
+- **Tempo:** Support standard span convention. [#88268](https://github.com/grafana/grafana/issues/88268), [@fabrizio-grafana](https://github.com/fabrizio-grafana)
+- **ValueFormats:** Add Uruguay peso currency. [#88260](https://github.com/grafana/grafana/issues/88260), [@lfdominguez](https://github.com/lfdominguez)
+- **DateTimePicker:** Add clearable prop. [#88215](https://github.com/grafana/grafana/issues/88215), [@Clarity-89](https://github.com/Clarity-89)
+- **Correlations:** Enable feature toggle by default (on-prem). [#88208](https://github.com/grafana/grafana/issues/88208), [@ifrost](https://github.com/ifrost)
+- **Stat:** Add percent change color modes. [#88205](https://github.com/grafana/grafana/issues/88205), [@drew08t](https://github.com/drew08t)
+- **Logs:** Added multi-line display control to the "wrap lines" option. [#88144](https://github.com/grafana/grafana/issues/88144), [@matyax](https://github.com/matyax)
+- **Tempo:** Update lezer autocomplete (histogram, quantile) and add missing functions. [#88131](https://github.com/grafana/grafana/issues/88131), [@joey-grafana](https://github.com/joey-grafana)
+- **AnnotationsPlugin2:** Implement support for rectangular annotations in Heatmap. [#88107](https://github.com/grafana/grafana/issues/88107), [@adrapereira](https://github.com/adrapereira)
+- **CodeEditor:** Improved styles when the code editor is loading. [#88102](https://github.com/grafana/grafana/issues/88102), [@NWRichmond](https://github.com/NWRichmond)
+- **CloudWatch:** Add additional AWS/KinesisAnalytics metrics . [#88101](https://github.com/grafana/grafana/issues/88101), [@tristanburgess](https://github.com/tristanburgess)
+- **Cloudwatch:** Add AWS/Events Metrics. [#88097](https://github.com/grafana/grafana/issues/88097), [@LeonardoBoleli](https://github.com/LeonardoBoleli)
+- **Azure:** Basic Logs support. [#88025](https://github.com/grafana/grafana/issues/88025), [@aangelisc](https://github.com/aangelisc)
+- **Dashboard:** Make dashboard search faster. [#88019](https://github.com/grafana/grafana/issues/88019), [@knuzhdin](https://github.com/knuzhdin)
+- **Alerting:** Support custom API URL for PagerDuty integration. [#88007](https://github.com/grafana/grafana/issues/88007), [@gaurav1999](https://github.com/gaurav1999)
+- **Alerting:** Add optional metadata via query param to silence GET requests. [#88000](https://github.com/grafana/grafana/issues/88000), [@JacobsonMT](https://github.com/JacobsonMT)
+- **Store:** Enable adding extra middleware. [#87984](https://github.com/grafana/grafana/issues/87984), [@Clarity-89](https://github.com/Clarity-89)
+- **Tempo:** Don't modify the passed time range when using timeShiftEnabled. [#87980](https://github.com/grafana/grafana/issues/87980), [@aocenas](https://github.com/aocenas)
+- **InfluxDB:** Introduce maxDataPoints setting for flux variable query editor. [#87935](https://github.com/grafana/grafana/issues/87935), [@itsmylife](https://github.com/itsmylife)
+- **Alerting:** New list view UI – Part 1. [#87907](https://github.com/grafana/grafana/issues/87907), [@gillesdemey](https://github.com/gillesdemey)
+- **NodeGraph:** Remove msagl lib and layered layout option. [#87905](https://github.com/grafana/grafana/issues/87905), [@aocenas](https://github.com/aocenas)
+- **InfluxDB:** Introduce custom variable support. [#87903](https://github.com/grafana/grafana/issues/87903), [@itsmylife](https://github.com/itsmylife)
+- **Gops:** Add tracking for data source check. [#87886](https://github.com/grafana/grafana/issues/87886), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron)
+- **AzureMonitor:** Prometheus exemplars support . [#87742](https://github.com/grafana/grafana/issues/87742), [@aangelisc](https://github.com/aangelisc)
+- **Feature Management:** Move awsDatasourcesNewFormStyling to GA. [#87696](https://github.com/grafana/grafana/issues/87696), [@idastambuk](https://github.com/idastambuk)
+- **TimeRangePicker:** Announce to screen reader when time range is updated. [#87692](https://github.com/grafana/grafana/issues/87692), [@tskarhed](https://github.com/tskarhed)
+- **Alerting:** Template selector in contact points form. [#87689](https://github.com/grafana/grafana/issues/87689), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron)
+- **Azure:** Load custom clouds from ini file. [#87667](https://github.com/grafana/grafana/issues/87667), [@JonCole](https://github.com/JonCole)
+- **Loki:** Kick start your query now applies templates to the current query. [#87658](https://github.com/grafana/grafana/issues/87658), [@matyax](https://github.com/matyax)
+- **Elasticsearch:** Queries no longer executed while typing. [#87652](https://github.com/grafana/grafana/issues/87652), [@matyax](https://github.com/matyax)
+- **Alerting:** Add options to configure TLS for HA using Redis. [#87567](https://github.com/grafana/grafana/issues/87567), [@fayzal-g](https://github.com/fayzal-g)
+- **VizLegend:** Represent line style in series legend and tooltip. [#87558](https://github.com/grafana/grafana/issues/87558), [@domasx2](https://github.com/domasx2)
+- **FeatureBadge:** Update FeatureBadge to support current release stages. [#87555](https://github.com/grafana/grafana/issues/87555), [@ivanahuckova](https://github.com/ivanahuckova)
+- **Logs:** Infinite scrolling in Explore enabled by default. [#87493](https://github.com/grafana/grafana/issues/87493), [@matyax](https://github.com/matyax)
+- **Plugins:** Improve frontend loader cache. [#87488](https://github.com/grafana/grafana/issues/87488), [@jackw](https://github.com/jackw)
+- **Chore:** Upgrade go from 1.21.0 to 1.21.10. [#87479](https://github.com/grafana/grafana/issues/87479), [@stephaniehingtgen](https://github.com/stephaniehingtgen)
+- **Chore:** Upgrade go to 1.22.3. [#87463](https://github.com/grafana/grafana/issues/87463), [@stephaniehingtgen](https://github.com/stephaniehingtgen)
+- **Team:** Add an endpoint for bulk team membership updates. [#87441](https://github.com/grafana/grafana/issues/87441), [@IevaVasiljeva](https://github.com/IevaVasiljeva)
+- **Flamegraph:** Add collapse and expand group buttons to toolbar. [#87395](https://github.com/grafana/grafana/issues/87395), [@aocenas](https://github.com/aocenas)
+- **OIDC:** Support Generic OAuth org to role mappings. [#87394](https://github.com/grafana/grafana/issues/87394), [@sathieu](https://github.com/sathieu)
+- **Search:** Announce to screen reader when query returns no result. [#87382](https://github.com/grafana/grafana/issues/87382), [@tskarhed](https://github.com/tskarhed)
+- **Logs:** Added support for numeric log levels. [#87366](https://github.com/grafana/grafana/issues/87366), [@nailgun](https://github.com/nailgun)
+- **Prometheus:** Place custom inputs first when using regex filter values in the query builder. [#87360](https://github.com/grafana/grafana/issues/87360), [@NWRichmond](https://github.com/NWRichmond)
+- **Alerting:** Remove requirement for datasource query on rule read. [#87349](https://github.com/grafana/grafana/issues/87349), [@rwwiv](https://github.com/rwwiv)
+- **Alerting:** Add RBAC logic for silences creation. [#87322](https://github.com/grafana/grafana/issues/87322), [@tomratcliffe](https://github.com/tomratcliffe)
+- **Alerting:** Update silences creation to support `__alert_rule_uid__` and move into drawer. [#87320](https://github.com/grafana/grafana/issues/87320), [@tomratcliffe](https://github.com/tomratcliffe)
+- **Flamegraph:** Add diff mode color legend. [#87319](https://github.com/grafana/grafana/issues/87319), [@aocenas](https://github.com/aocenas)
+- **Dashboard:** Keyboard and mouse panel shortcuts improvement. [#87317](https://github.com/grafana/grafana/issues/87317), [@tskarhed](https://github.com/tskarhed)
+- **PanelHeaderCorner:** Remove font-awesome icons. [#87303](https://github.com/grafana/grafana/issues/87303), [@Clarity-89](https://github.com/Clarity-89)
+- **Alerting:** Add OAuth2 to HTTP settings for vanilla Alertmanager / Mimir. [#87272](https://github.com/grafana/grafana/issues/87272), [@gillesdemey](https://github.com/gillesdemey)
+- **Plugins:** Allow apps to expose components. Update the extensions API. [#87236](https://github.com/grafana/grafana/issues/87236), [@leventebalogh](https://github.com/leventebalogh)
+- **Plugins:** Catalog to show all plugins by default. [#87168](https://github.com/grafana/grafana/issues/87168), [@sympatheticmoose](https://github.com/sympatheticmoose)
+- **Prometheus:** Ensure values in metric selector are visible. [#87150](https://github.com/grafana/grafana/issues/87150), [@NWRichmond](https://github.com/NWRichmond)
+- **Select:** Add data-testid to Input. [#87105](https://github.com/grafana/grafana/issues/87105), [@Clarity-89](https://github.com/Clarity-89)
+- **Prometheus:** Add native histogram types metric explorer to allow filter by type. [#87090](https://github.com/grafana/grafana/issues/87090), [@bohandley](https://github.com/bohandley)
+- **Prometheus:** Add hints for native histograms. [#87017](https://github.com/grafana/grafana/issues/87017), [@bohandley](https://github.com/bohandley)
+- **Alerting:** Reduce number of request fetching rules in the dashboard view using rtkq. [#86991](https://github.com/grafana/grafana/issues/86991), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron)
+- **Plugins:** Make grafana-com API URL usage consistent. [#86920](https://github.com/grafana/grafana/issues/86920), [@oshirohugo](https://github.com/oshirohugo)
+- **Stack:** Add size props. [#86900](https://github.com/grafana/grafana/issues/86900), [@Clarity-89](https://github.com/Clarity-89)
+- **Table Panel:** Enable Text Wrapping. [#86895](https://github.com/grafana/grafana/issues/86895), [@codeincarnate](https://github.com/codeincarnate)
+- **Alerting:** Get grafana-managed alert rule by UID. [#86845](https://github.com/grafana/grafana/issues/86845), [@fayzal-g](https://github.com/fayzal-g)
+- **Cloudwatch:** Add Kendra metrics. [#86809](https://github.com/grafana/grafana/issues/86809), [@scottschreckengaust](https://github.com/scottschreckengaust)
+- **Auth:** Added support to filter for parent teams in GitHub connector's team membership filter. [#86754](https://github.com/grafana/grafana/issues/86754), [@wasim-nihal](https://github.com/wasim-nihal)
+- **Alerting:** Hook up GMA silence APIs to new authentication handler. [#86625](https://github.com/grafana/grafana/issues/86625), [@JacobsonMT](https://github.com/JacobsonMT)
+- **GeoMap:** Pan and zoom keyboard support. [#86573](https://github.com/grafana/grafana/issues/86573), [@tskarhed](https://github.com/tskarhed)
+- **Alerting:** Optimize rule status gathering APIs when a limit is applied. [#86568](https://github.com/grafana/grafana/issues/86568), [@stevesg](https://github.com/stevesg)
+- **Plugins:** Add an auto-generated part to the `plugin.json` schema. [#86520](https://github.com/grafana/grafana/issues/86520), [@leventebalogh](https://github.com/leventebalogh)
+- **Loki/Prometheus Query Editor:** Disabled cmd/ctrl+f keybinding within the editor. [#86418](https://github.com/grafana/grafana/issues/86418), [@matyax](https://github.com/matyax)
+- **Grafana packages:** Remove E2E workspace. [#86416](https://github.com/grafana/grafana/issues/86416), [@sunker](https://github.com/sunker)
+- **RefreshPicker:** Change running state to be less distracting . [#86405](https://github.com/grafana/grafana/issues/86405), [@torkelo](https://github.com/torkelo)
+- **Prometheus:** Cancellable label values requests. [#86403](https://github.com/grafana/grafana/issues/86403), [@NWRichmond](https://github.com/NWRichmond)
+- **SQLStore:** Improve recursive CTE support detection. [#86397](https://github.com/grafana/grafana/issues/86397), [@mildwonkey](https://github.com/mildwonkey)
+- **CloudMonitoring:** Ensure variables can be used in all variable queries. [#86377](https://github.com/grafana/grafana/issues/86377), [@aangelisc](https://github.com/aangelisc)
+- **Common labels/displayed fields:** Show label names with values. [#86345](https://github.com/grafana/grafana/issues/86345), [@matyax](https://github.com/matyax)
+- **AuthZ:** Further protect admin endpoints. [#86285](https://github.com/grafana/grafana/issues/86285), [@IevaVasiljeva](https://github.com/IevaVasiljeva)
+- **Explore:** Deprecate local storage singular datasource key. [#86250](https://github.com/grafana/grafana/issues/86250), [@gelicia](https://github.com/gelicia)
+- **Loki:** Add label filters after label_format if present. [#86124](https://github.com/grafana/grafana/issues/86124), [@matyax](https://github.com/matyax)
+- **Alerting:** Immutable plugin rules and alerting plugins extensions. [#86042](https://github.com/grafana/grafana/issues/86042), [@konrad147](https://github.com/konrad147)
+- **Tempo:** Group by template vars. [#86022](https://github.com/grafana/grafana/issues/86022), [@joey-grafana](https://github.com/joey-grafana)
+- **Short Links:** Add setting for changing expiration time. [#86003](https://github.com/grafana/grafana/issues/86003), [@gelicia](https://github.com/gelicia)
+- **Prometheus:** Add native histogram functions. [#86002](https://github.com/grafana/grafana/issues/86002), [@bohandley](https://github.com/bohandley)
+- **Plugins:** Removed feature toggle pluginsDynamicAngularDetectionPatterns. [#85956](https://github.com/grafana/grafana/issues/85956), [@xnyo](https://github.com/xnyo)
+- **Plugins:** Removed feature toggle enablePluginsTracingByDefault. [#85953](https://github.com/grafana/grafana/issues/85953), [@xnyo](https://github.com/xnyo)
+- **Tracing:** Allow otel service name and attributes to be overridden from env. [#85937](https://github.com/grafana/grafana/issues/85937), [@marefr](https://github.com/marefr)
+- **PanelChrome:** Improve accessibility landmark markup. [#85863](https://github.com/grafana/grafana/issues/85863), [@tskarhed](https://github.com/tskarhed)
+- **Gops:** Add configuration tracker on the existing IRM page. [#85838](https://github.com/grafana/grafana/issues/85838), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron)
+- **CloudWatch:** Add additional Glue metrics. [#85798](https://github.com/grafana/grafana/issues/85798), [@tristanburgess](https://github.com/tristanburgess)
+- **CloudWatch:** Add labels for Metric Query type queries. [#85766](https://github.com/grafana/grafana/issues/85766), [@kevinwcyu](https://github.com/kevinwcyu)
+- **Util:** Support parsing and splitting strings enclosed in quotes in util.SplitString. [#85735](https://github.com/grafana/grafana/issues/85735), [@mgyongyosi](https://github.com/mgyongyosi)
+- **Loki:** Handle `X-Scope-OrgID` and tenant IDs. [#85726](https://github.com/grafana/grafana/issues/85726), [@fabrizio-grafana](https://github.com/fabrizio-grafana)
+- **CloudWatch:** Add a Performance Insights and other missing metrics to aws/rds. [#85680](https://github.com/grafana/grafana/issues/85680), [@kgeckhart](https://github.com/kgeckhart)
+- **Prometheus:** Respect dashboard queries when querying ad hoc filter labels. [#85674](https://github.com/grafana/grafana/issues/85674), [@itsmylife](https://github.com/itsmylife)
+- **Pyroscope:** Add adhoc filters support. [#85601](https://github.com/grafana/grafana/issues/85601), [@aocenas](https://github.com/aocenas)
+- **Table Panel:** Update background colors to respect transparency. [#85565](https://github.com/grafana/grafana/issues/85565), [@codeincarnate](https://github.com/codeincarnate)
+- **Canvas:** Add support for line animation. [#85556](https://github.com/grafana/grafana/issues/85556), [@adela-almasan](https://github.com/adela-almasan)
+- **Reducers:** Add in basic Percentile Support. [#85554](https://github.com/grafana/grafana/issues/85554), [@timlevett](https://github.com/timlevett)
+- **Storage:** Watch tests. [#85496](https://github.com/grafana/grafana/issues/85496), [@DanCech](https://github.com/DanCech)
+- **Plugins:** Show update buttons when instance version is different. [#85486](https://github.com/grafana/grafana/issues/85486), [@oshirohugo](https://github.com/oshirohugo)
+- **Tempo:** Always use time range even if timeShiftEnabled is false. [#85477](https://github.com/grafana/grafana/issues/85477), [@ogxd](https://github.com/ogxd)
+- **Alerting:** Gops labels integration. [#85467](https://github.com/grafana/grafana/issues/85467), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron)
+- **Explore:** Set X-Cache-Skip to true for query requests. [#85460](https://github.com/grafana/grafana/issues/85460), [@Elfo404](https://github.com/Elfo404)
+- **Explore:** Make Explore breadcrumb clickable. [#85437](https://github.com/grafana/grafana/issues/85437), [@Elfo404](https://github.com/Elfo404)
+- **Prometheus:** Fuzzy search for metric names in Code Mode. [#85396](https://github.com/grafana/grafana/issues/85396), [@NWRichmond](https://github.com/NWRichmond)
+- **Storage Api:** Adds traces. [#85391](https://github.com/grafana/grafana/issues/85391), [@owensmallwood](https://github.com/owensmallwood)
+- **Storage Api:** Add metrics. [#85316](https://github.com/grafana/grafana/issues/85316), [@owensmallwood](https://github.com/owensmallwood)
+- **Alerting:** Improve paused alert visibility and allow pausing/resuming from alert list view. [#85116](https://github.com/grafana/grafana/issues/85116), [@tomratcliffe](https://github.com/tomratcliffe)
+- **CloudWatch:** Clarify match exact tooltip and docs. [#85095](https://github.com/grafana/grafana/issues/85095), [@iwysiu](https://github.com/iwysiu)
+- **Alerting:** Evaluation quick buttons. [#85010](https://github.com/grafana/grafana/issues/85010), [@gillesdemey](https://github.com/gillesdemey)
+- **Alerting:** Add state history polling interval. [#84837](https://github.com/grafana/grafana/issues/84837), [@gillesdemey](https://github.com/gillesdemey)
+- **CloudWatch:** Improve metric label parsing. [#84835](https://github.com/grafana/grafana/issues/84835), [@iwysiu](https://github.com/iwysiu)
+- **Alerting:** Improve template preview. [#84798](https://github.com/grafana/grafana/issues/84798), [@konrad147](https://github.com/konrad147)
+- **Alerting:** New settings page. [#84501](https://github.com/grafana/grafana/issues/84501), [@gillesdemey](https://github.com/gillesdemey)
+- **Explore:** Move Query History to be screen wide. [#84321](https://github.com/grafana/grafana/issues/84321), [@gelicia](https://github.com/gelicia)
+- **MixedDataSource:** Support multi value data source variable that issues a query to each data source. [#83356](https://github.com/grafana/grafana/issues/83356), [@torkelo](https://github.com/torkelo)
+- **PluginExtensions:** Make the extensions registry reactive. [#83085](https://github.com/grafana/grafana/issues/83085), [@mckn](https://github.com/mckn)
+- **Loki:** Use label/<name>/values API instead of series API for label values discovery. [#83044](https://github.com/grafana/grafana/issues/83044), [@yuri-rs](https://github.com/yuri-rs)
+- **Tempo:** Escape backslash in span name for promsql query. [#83024](https://github.com/grafana/grafana/issues/83024), [@ttshivers](https://github.com/ttshivers)
+- **Alerting:** Export and provisioning rules into subfolders. [#77450](https://github.com/grafana/grafana/issues/77450), [@papagian](https://github.com/papagian)
+- **Notification banner:** Integrate with RBAC. (Enterprise)
+- **Auth:** Assign users using SAML to AutoAssignOrgRole if no role matches. (Enterprise)
+- **Notification banner:** Display preview. (Enterprise)
+- **Auth:** Add None and Viewer roles as options to SAML UI config. (Enterprise)
+- **SAML:** Add nonce to the generated script tag. (Enterprise)
+- **Notification banner:** Add settings page. (Enterprise)
+- **Notification banner:** Add API client. (Enterprise)
+- **Chore:** Upgrade go version to 1.22.3. (Enterprise)
+- **Auditing:** Correctly parse the URL for auditing through Loki. (Enterprise)
+- **Auditlog:** Refactor action to post-action in default auditlogging. (Enterprise)
+- **Plugins:** Make grafana-com API URL usage consistent. (Enterprise)
+- **Plugins:** Make grafana-com API URL usage consistent. (Enterprise)
+- **Caching:** Implement mtls-enabled memcached integration. (Enterprise)
+- **OpenAPI:** Document the datasource caching API. (Enterprise)
+
+### Bug fixes
+
+- **Alerting:** Fix go-swagger extraction and several embedded types from Alertmanager in Swagger docs. [#88879](https://github.com/grafana/grafana/issues/88879), [@alexweav](https://github.com/alexweav)
+- **DashboardScene:** Fixes inspect with transforms issue. [#88843](https://github.com/grafana/grafana/issues/88843), [@torkelo](https://github.com/torkelo)
+- **Elasticsearch:** Fix stripping of trailing slashes in datasource URLs. [#88779](https://github.com/grafana/grafana/issues/88779), [@ivanahuckova](https://github.com/ivanahuckova)
+- **Loki:** Fix editor history in wrong order. [#88666](https://github.com/grafana/grafana/issues/88666), [@svennergr](https://github.com/svennergr)
+- **Cli:** Fix bug where password is hashed twice. [#88589](https://github.com/grafana/grafana/issues/88589), [@kalleep](https://github.com/kalleep)
+- **AzureMonitor:** Fix bug detecting app insights queries. [#88572](https://github.com/grafana/grafana/issues/88572), [@aangelisc](https://github.com/aangelisc)
+- **SSE:** Fix threshold unmarshal to avoid panic. [#88521](https://github.com/grafana/grafana/issues/88521), [@yuri-tceretian](https://github.com/yuri-tceretian)
+- **Dashboard:** Fix Variables query hides fields with non-supported datasources. [#88516](https://github.com/grafana/grafana/issues/88516), [@axelavargas](https://github.com/axelavargas)
+- **Explore:** Align time filters properly to day boundaries in query history. [#88498](https://github.com/grafana/grafana/issues/88498), [@aocenas](https://github.com/aocenas)
+- **Access Control:** Clean up permissions for deprovisioned data sources. [#88483](https://github.com/grafana/grafana/issues/88483), [@IevaVasiljeva](https://github.com/IevaVasiljeva)
+- **Dashboards:** Correctly display Admin access to dashboards in the UI. [#88439](https://github.com/grafana/grafana/issues/88439), [@IevaVasiljeva](https://github.com/IevaVasiljeva)
+- **LibraryPanels/RBAC:** Ignore old folder permission check when deleting/patching lib panel. [#88422](https://github.com/grafana/grafana/issues/88422), [@kaydelaney](https://github.com/kaydelaney)
+- **LogsTable:** Fix default sort by time. [#88398](https://github.com/grafana/grafana/issues/88398), [@svennergr](https://github.com/svennergr)
+- **Dashboards:** Fix regression when deleting folder. [#88311](https://github.com/grafana/grafana/issues/88311), [@papagian](https://github.com/papagian)
+- **Docker:** Fix renderer plugin in custom Dockerfile. [#88223](https://github.com/grafana/grafana/issues/88223), [@AgnesToulet](https://github.com/AgnesToulet)
+- **Alerting:** Fix rules deleting when reordering whilst filtered. [#88221](https://github.com/grafana/grafana/issues/88221), [@tomratcliffe](https://github.com/tomratcliffe)
+- **Alerting:** Fix "copy link" not including full URL. [#88210](https://github.com/grafana/grafana/issues/88210), [@tomratcliffe](https://github.com/tomratcliffe)
+- **Alerting:** Fix typo in JSON response for rule export. [#88028](https://github.com/grafana/grafana/issues/88028), [@yuri-tceretian](https://github.com/yuri-tceretian)
+- **Alerting:** Fix scheduler to sort rules before evaluation. [#88006](https://github.com/grafana/grafana/issues/88006), [@yuri-tceretian](https://github.com/yuri-tceretian)
+- **CloudMonitoring:** Fix query type selection issue. [#87990](https://github.com/grafana/grafana/issues/87990), [@aangelisc](https://github.com/aangelisc)
+- **Alerting:** Assume built-in AM is receiving alerts in case of not having admin config. [#87893](https://github.com/grafana/grafana/issues/87893), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron)
+- **DashboardScene:** Skip panel repeats when values are the same. [#87788](https://github.com/grafana/grafana/issues/87788), [@torkelo](https://github.com/torkelo)
+- **Alerting:** Fix deleting rules when silencing/resuming rule from a panel alert tab. [#87710](https://github.com/grafana/grafana/issues/87710), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron)
+- **Dashboards:** Don't set dashboard creator/updater if the action is done by an API key. [#87704](https://github.com/grafana/grafana/issues/87704), [@IevaVasiljeva](https://github.com/IevaVasiljeva)
+- **Elasticsearch:** Fix setting of default maxConcurrentShardRequests. [#87703](https://github.com/grafana/grafana/issues/87703), [@ivanahuckova](https://github.com/ivanahuckova)
+- **Graphite:** Fix alignment of elements in the query editor. [#87662](https://github.com/grafana/grafana/issues/87662), [@NWRichmond](https://github.com/NWRichmond)
+- **DashboardScene:** Fixing major row repeat issues. [#87539](https://github.com/grafana/grafana/issues/87539), [@torkelo](https://github.com/torkelo)
+- **Alerting:** Do not store series values from past evaluations in state manager for no reason. [#87525](https://github.com/grafana/grafana/issues/87525), [@alexweav](https://github.com/alexweav)
+- **RBAC:** Update role picker in team page, fix a bug with roles being removed upon team setting update. [#87519](https://github.com/grafana/grafana/issues/87519), [@IevaVasiljeva](https://github.com/IevaVasiljeva)
+- **Transformations:** Fix true inner join in `joinByField` transformation. [#87409](https://github.com/grafana/grafana/issues/87409), [@baldm0mma](https://github.com/baldm0mma)
+- **Alerting:** Do not retry rule evaluations with "input data must be a wide series but got type long" style errors. [#87343](https://github.com/grafana/grafana/issues/87343), [@alexweav](https://github.com/alexweav)
+- **Tempo:** Fix sorting for nested tables. [#87214](https://github.com/grafana/grafana/issues/87214), [@fabrizio-grafana](https://github.com/fabrizio-grafana)
+- **Cloudwatch Logs:** Fix bug where we did not return errors to user. [#87190](https://github.com/grafana/grafana/issues/87190), [@sarahzinger](https://github.com/sarahzinger)
+- **CloudWatch:** Fix apostrophes in dimension values not being escaped. [#87182](https://github.com/grafana/grafana/issues/87182), [@kevinwcyu](https://github.com/kevinwcyu)
+- **AnnotationList:** Fix link for annotation with no panel or dashboard. [#87048](https://github.com/grafana/grafana/issues/87048), [@tskarhed](https://github.com/tskarhed)
+- **Graphite:** Fix splitting expressions in tag_value with template variables. [#86958](https://github.com/grafana/grafana/issues/86958), [@EduardZaydler](https://github.com/EduardZaydler)
+- **SQL Query Editor:** Fix label-for IDs, associate "Table" label. [#86944](https://github.com/grafana/grafana/issues/86944), [@timo](https://github.com/timo)
+- **SSO:** Add SSO settings to secrets migrator. [#86913](https://github.com/grafana/grafana/issues/86913), [@dmihai](https://github.com/dmihai)
+- **Plugins:** Preserve trailing slash in plugin proxy. [#86859](https://github.com/grafana/grafana/issues/86859), [@marefr](https://github.com/marefr)
+- **TimeSeries:** Improve keyboard focus and fix spacebar override. [#86848](https://github.com/grafana/grafana/issues/86848), [@tskarhed](https://github.com/tskarhed)
+- **NodeGraph:** Use values from fixedX/fixedY column for layout. [#86643](https://github.com/grafana/grafana/issues/86643), [@timo](https://github.com/timo)
+- **Alerting:** Prevent simplified routing zero duration GroupInterval and RepeatInterval. [#86561](https://github.com/grafana/grafana/issues/86561), [@JacobsonMT](https://github.com/JacobsonMT)
+- **Loki:** Fix setting of tenant ID. [#86433](https://github.com/grafana/grafana/issues/86433), [@fabrizio-grafana](https://github.com/fabrizio-grafana)
+- **DashboardScene:** Fixes checkbox orienation in save forms. [#86408](https://github.com/grafana/grafana/issues/86408), [@torkelo](https://github.com/torkelo)
+- **CloudMonitoring:** Correctly interpolate multi-valued template variables in PromQL queries. [#86391](https://github.com/grafana/grafana/issues/86391), [@aangelisc](https://github.com/aangelisc)
+- **Expressions:** Fix erroneous sorting of metrics and expressions. [#86372](https://github.com/grafana/grafana/issues/86372), [@NWRichmond](https://github.com/NWRichmond)
+- **CloudMonitoring:** Allow a custom group by value. [#86288](https://github.com/grafana/grafana/issues/86288), [@aangelisc](https://github.com/aangelisc)
+- **DataLinks:** Fixes datalinks with onClick and variables in url not being interpolated . [#86253](https://github.com/grafana/grafana/issues/86253), [@gng0](https://github.com/gng0)
+- **I18N:** Fix untranslated descriptions in data source picker. [#86216](https://github.com/grafana/grafana/issues/86216), [@joshhunt](https://github.com/joshhunt)
+- **RBAC:** Fix global role deletion in hosted Grafana. [#85980](https://github.com/grafana/grafana/issues/85980), [@IevaVasiljeva](https://github.com/IevaVasiljeva)
+- **Expression:** Fix a bug of the display name of the threshold expression result. [#85912](https://github.com/grafana/grafana/issues/85912), [@lingyufei](https://github.com/lingyufei)
+- **Alerting:** Fix incorrect display of pending period in alert rule form. [#85893](https://github.com/grafana/grafana/issues/85893), [@tomratcliffe](https://github.com/tomratcliffe)
+- **Alerting:** Fix redirect after saving a notification template. [#85667](https://github.com/grafana/grafana/issues/85667), [@tomratcliffe](https://github.com/tomratcliffe)
+- **Alerting:** Get oncall metada only when we have alert manager configuration data. [#85622](https://github.com/grafana/grafana/issues/85622), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron)
+- **Alerting:** Return better error for invalid time range on alert queries. [#85611](https://github.com/grafana/grafana/issues/85611), [@alexweav](https://github.com/alexweav)
+- **CloudWatch:** Fix SageMaker MBP namespace typo. [#85557](https://github.com/grafana/grafana/issues/85557), [@tristanburgess](https://github.com/tristanburgess)
+- **Alerting:** Only append `/alertmanager` when sending alerts to mimir targets if not already present. [#85543](https://github.com/grafana/grafana/issues/85543), [@alexweav](https://github.com/alexweav)
+- **Alerting:** Set mimir implementation in jsonData by default when creating a new a…. [#85513](https://github.com/grafana/grafana/issues/85513), [@soniaAguilarPeiron](https://github.com/soniaAguilarPeiron)
+- **Alerting:** Persist silence state immediately on Create/Delete . [#84705](https://github.com/grafana/grafana/issues/84705), [@JacobsonMT](https://github.com/JacobsonMT)
+- **NodeGraph:** Fix configuring arc colors with mixed case field names. [#84609](https://github.com/grafana/grafana/issues/84609), [@timo](https://github.com/timo)
+- **Auditing:** Fix Loki URL parsing. (Enterprise)
+- **Provisioning:** Add override option to role provisioning. (Enterprise)
+- **Alerting:** Check pointers before use to prevent segfault. (Enterprise)
+- **Reporting:** Fix UI errors when using linked variables. (Enterprise)
+
+### Breaking changes
+
+Users that provision alert rules into folders whose titles contain slashes from now on they should escape them:
+eg. if an alert group contains:
+`folder: folder_with_/_in_title`
+it should become:
+`folder: folder_with_\/_in_title` Issue [#77450](https://github.com/grafana/grafana/issues/77450)
+
+### Deprecations
+
+The `grafana.explore.richHistory.activeDatasourceOnly` local storage key is deprecated, and will be removed in Grafana 12. You may experience loss of your Explore query history or autocomplete data if you upgrade to Grafana 12 under 2 weeks of Grafana 11.1. Actual risk of data loss depends on your query history retention policy. Issue [#86250](https://github.com/grafana/grafana/issues/86250)
+
+### Plugin development fixes & changes
+
+- **Select:** Change `Select` group headers to always be visible. [#88178](https://github.com/grafana/grafana/issues/88178), [@ashharrison90](https://github.com/ashharrison90)
+- **Select:** Ensure virtualised menu scrolls active option into view when using arrow keys. [#87743](https://github.com/grafana/grafana/issues/87743), [@ashharrison90](https://github.com/ashharrison90)
+- **Switch:** Improve disabled active state. [#87694](https://github.com/grafana/grafana/issues/87694), [@ashharrison90](https://github.com/ashharrison90)
+- **Button:** Allow disabled button to still be focused. [#87516](https://github.com/grafana/grafana/issues/87516), [@JoaoSilvaGrafana](https://github.com/JoaoSilvaGrafana)
+- **GrafanaUI:** Add `tabular` prop to Text component for tabular numbers. [#87440](https://github.com/grafana/grafana/issues/87440), [@JoaoSilvaGrafana](https://github.com/JoaoSilvaGrafana)
+
+
+
+
+# 11.0.1 (2024-06-21)
+
+### Bug fixes
+
+- **Echo:** Suppress errors from frontend-metrics API call failing. [#89493](https://github.com/grafana/grafana/issues/89493), [@joshhunt](https://github.com/joshhunt)
+- **Fix:** Portuguese Brazilian wasn't loading translations. [#89374](https://github.com/grafana/grafana/issues/89374), [@JoaoSilvaGrafana](https://github.com/JoaoSilvaGrafana)
+- **Analytics:** Fix ApplicationInsights integration. [#89300](https://github.com/grafana/grafana/issues/89300), [@ashharrison90](https://github.com/ashharrison90)
+- **DashboardScene:** Fixes issue removing override rule. [#89134](https://github.com/grafana/grafana/issues/89134), [@torkelo](https://github.com/torkelo)
+- **BrowseDashboards:** Prepend subpath to New Browse Dashboard actions. [#89130](https://github.com/grafana/grafana/issues/89130), [@joshhunt](https://github.com/joshhunt)
+- **Alerting:** Fix rule storage to filter by group names using case-sensitive comparison. [#89063](https://github.com/grafana/grafana/issues/89063), [@yuri-tceretian](https://github.com/yuri-tceretian)
+- **RBAC:** List only the folders that the user has access to. [#89015](https://github.com/grafana/grafana/issues/89015), [@IevaVasiljeva](https://github.com/IevaVasiljeva)
+- **DashboardScene:** Fixes lack of re-render when updating field override properties. [#88985](https://github.com/grafana/grafana/issues/88985), [@torkelo](https://github.com/torkelo)
+- **DashboardScene:** Fixes inspect with transforms issue. [#88862](https://github.com/grafana/grafana/issues/88862), [@torkelo](https://github.com/torkelo)
+- **AzureMonitor:** Fix bug detecting app insights queries. [#88787](https://github.com/grafana/grafana/issues/88787), [@aangelisc](https://github.com/aangelisc)
+- **Access Control:** Clean up permissions for deprovisioned data sources. [#88700](https://github.com/grafana/grafana/issues/88700), [@IevaVasiljeva](https://github.com/IevaVasiljeva)
+- **Loki:** Fix editor history in wrong order. [#88669](https://github.com/grafana/grafana/issues/88669), [@svennergr](https://github.com/svennergr)
+- **SSE:** Fix threshold unmarshal to avoid panic. [#88651](https://github.com/grafana/grafana/issues/88651), [@yuri-tceretian](https://github.com/yuri-tceretian)
+- **LibraryPanels/RBAC:** Ignore old folder permission check when deleting/patching lib panel. [#88493](https://github.com/grafana/grafana/issues/88493), [@kaydelaney](https://github.com/kaydelaney)
+- **Dashboards:** Correctly display Admin access to dashboards in the UI. [#88473](https://github.com/grafana/grafana/issues/88473), [@IevaVasiljeva](https://github.com/IevaVasiljeva)
+- **LogsTable:** Fix default sort by time. [#88434](https://github.com/grafana/grafana/issues/88434), [@svennergr](https://github.com/svennergr)
+- **Alerting:** Fix rules deleting when reordering whilst filtered. [#88285](https://github.com/grafana/grafana/issues/88285), [@gillesdemey](https://github.com/gillesdemey)
+- **Alerting:** Fix typo in JSON response for rule export. [#88090](https://github.com/grafana/grafana/issues/88090), [@yuri-tceretian](https://github.com/yuri-tceretian)
+- **CloudMonitoring:** Fix query type selection issue. [#88024](https://github.com/grafana/grafana/issues/88024), [@aangelisc](https://github.com/aangelisc)
+- **Alerting:** Fix scheduler to sort rules before evaluation. [#88021](https://github.com/grafana/grafana/issues/88021), [@yuri-tceretian](https://github.com/yuri-tceretian)
+- **DashboardScene:** Skip panel repeats when values are the same. [#87896](https://github.com/grafana/grafana/issues/87896), [@torkelo](https://github.com/torkelo)
+- **Alerting:** Do not store series values from past evaluations in state manager for no reason. [#87845](https://github.com/grafana/grafana/issues/87845), [@alexweav](https://github.com/alexweav)
+- **DashboardScene:** Fixing major row repeat issues. [#87800](https://github.com/grafana/grafana/issues/87800), [@torkelo](https://github.com/torkelo)
+- **DashboardScene:** Fixes checkbox orienation in save forms. [#86490](https://github.com/grafana/grafana/issues/86490), [@torkelo](https://github.com/torkelo)
+- **Provisioning:** Add override option to role provisioning. (Enterprise)
+
+### Breaking changes
+
+If you had selected your language as "Português Brasileiro" previously, this will be reset. You have to select it again in your Preferences for the fix to be applied and the translations will then be shown. Issue [#89374](https://github.com/grafana/grafana/issues/89374)
+
+
# 11.0.0 (2024-05-14)
@@ -350,6 +636,16 @@ The deprecated `email` field to send a report via `/api/reports/email` endpoint
- **Grafana UI:** Add code variant to Text component. [#82318](https://github.com/grafana/grafana/issues/82318), [@tskarhed](https://github.com/tskarhed)
+
+
+# 10.4.5 (2024-06-21)
+
+### Bug fixes
+
+- **Echo:** Suppress errors from frontend-metrics API call failing. [#89498](https://github.com/grafana/grafana/issues/89498), [@joshhunt](https://github.com/joshhunt)
+- **Azure Monitor:** Add validation for namespace field in AdvancedResourcePicker when entering a forward slash. [#89313](https://github.com/grafana/grafana/issues/89313), [@adamyeats](https://github.com/adamyeats)
+
+
# 10.4.4 (2024-06-13)
diff --git a/conf/defaults.ini b/conf/defaults.ini
index f9e230c580e..aa746872133 100644
--- a/conf/defaults.ini
+++ b/conf/defaults.ini
@@ -1387,6 +1387,12 @@ loki_basic_auth_password =
# Optional max query length for queries sent to Loki. Default is 721h which matches the default Loki value.
loki_max_query_length = 721h
+# For "loki" only.
+# Maximum size in bytes for queries sent to Loki. This limit is applied to user provided filters as well as system defined ones, e.g. applied by access control.
+# If filter exceeds the limit, API returns error with code "alerting.state-history.loki.requestTooLong".
+# Default is 64kb
+loki_max_query_size = 65536
+
[unified_alerting.state_history.external_labels]
# Optional extra labels to attach to outbound state history records or log streams.
# Any number of label key-value-pairs can be provided.
diff --git a/conf/sample.ini b/conf/sample.ini
index 5257c046add..e261822eb57 100644
--- a/conf/sample.ini
+++ b/conf/sample.ini
@@ -1379,6 +1379,12 @@ disabled_labels =
# Optional max query length for queries sent to Loki. Default is 721h which matches the default Loki value.
; loki_max_query_length = 360h
+# For "loki" only.
+# Maximum size in bytes for queries sent to Loki. This limit is applied to user provided filters as well as system defined ones, e.g. applied by access control.
+# If filter exceeds the limit, API returns error with code "alerting.state-history.loki.requestTooLong".
+# Default is 64kb
+;loki_max_query_size = 65536
+
[unified_alerting.state_history.external_labels]
# Optional extra labels to attach to outbound state history records or log streams.
# Any number of label key-value-pairs can be provided.
diff --git a/contribute/style-guides/styling.md b/contribute/style-guides/styling.md
index 73790ce463b..15ed1684ef2 100644
--- a/contribute/style-guides/styling.md
+++ b/contribute/style-guides/styling.md
@@ -13,7 +13,6 @@ To access the theme in your styles, use the `useStyles` hook. It provides basic
> Please remember to put `getStyles` function at the end of the file!
```tsx
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
import { css } from '@emotion/css';
@@ -40,7 +39,6 @@ Let's say you need to style a component that has a different background dependin
```tsx
import { css, cx } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/contribute/style-guides/testing.md b/contribute/style-guides/testing.md
index 7ca50d926b9..18e4c13e248 100644
--- a/contribute/style-guides/testing.md
+++ b/contribute/style-guides/testing.md
@@ -176,7 +176,6 @@ Here's how the test would look like for this [OrgPicker](https://github.com/graf
```tsx
import { screen, render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { OrgPicker } from './OrgPicker';
diff --git a/contribute/style-guides/themes.md b/contribute/style-guides/themes.md
index 5d4a2e0f877..971f63145f9 100644
--- a/contribute/style-guides/themes.md
+++ b/contribute/style-guides/themes.md
@@ -20,7 +20,7 @@ Here's how to use Grafana themes in React components.
`useStyles2` memoizes the function and provides access to the theme.
```tsx
-import React, { FC } from 'react';
+import { FC } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
import { css } from '@emotion/css';
@@ -39,7 +39,7 @@ const getStyles = (theme: GrafanaTheme2) =>
#### Get the theme object
```tsx
-import React, { FC } from 'react';
+import { FC } from 'react';
import { useTheme2 } from '@grafana/ui';
const Foo: FC = () => {
diff --git a/docs/sources/alerting/configure-notifications/manage-contact-points/integrations/configure-oncall.md b/docs/sources/alerting/configure-notifications/manage-contact-points/integrations/configure-oncall.md
index c238f12bf10..e71c6a7ee4f 100644
--- a/docs/sources/alerting/configure-notifications/manage-contact-points/integrations/configure-oncall.md
+++ b/docs/sources/alerting/configure-notifications/manage-contact-points/integrations/configure-oncall.md
@@ -57,9 +57,9 @@ To set up the Grafana OnCall integration using the Grafana Alerting application,
1. Enter a contact point name.
1. From the Integration list, select Grafana OnCall.
- **Note:**
-
- The Grafana OnCall integration is only available for Grafana Alertmanager.
+{{< admonition type="note" >}}
+The Grafana OnCall integration is only available for Grafana Alertmanager.
+{{< /admonition >}}
1. Choose whether to add a new OnCall integration or add an existing one.
diff --git a/docs/sources/alerting/configure-notifications/manage-contact-points/integrations/configure-slack.md b/docs/sources/alerting/configure-notifications/manage-contact-points/integrations/configure-slack.md
index e23b5947e1c..1c4887f9d4c 100644
--- a/docs/sources/alerting/configure-notifications/manage-contact-points/integrations/configure-slack.md
+++ b/docs/sources/alerting/configure-notifications/manage-contact-points/integrations/configure-slack.md
@@ -62,7 +62,7 @@ If you are using a Slack API Token, complete the following steps.
If you are using a Webhook URL, follow steps 1 and 5 in the [Slack API Quickstart](https://api.slack.com/start/quickstart).
{{< admonition type="note" >}}
-Make sure you copy the Slack app Webhook URL. You will need this when setting up your contact point integration in Grafana Alerting.
+Make sure you copy the Slack app Webhook URL. You need this when setting up your contact point integration in Grafana Alerting.
{{< /admonition >}}
## Procedure
diff --git a/docs/sources/alerting/configure-notifications/manage-contact-points/integrations/webhook-notifier.md b/docs/sources/alerting/configure-notifications/manage-contact-points/integrations/webhook-notifier.md
index 13d072a0279..ed4f45b0e97 100644
--- a/docs/sources/alerting/configure-notifications/manage-contact-points/integrations/webhook-notifier.md
+++ b/docs/sources/alerting/configure-notifications/manage-contact-points/integrations/webhook-notifier.md
@@ -144,7 +144,7 @@ Alert rules are not coupled to dashboards anymore therefore the fields related t
## Procedure
-To create your webhook integration in Grafana Alerting, complete the following steps:
+To create your Webhook integration in Grafana Alerting, complete the following steps.
1. Navigate to **Alerts & IRM** -> **Alerting** -> **Contact points**.
1. Click **+ Add contact point**.
diff --git a/docs/sources/alerting/configure-notifications/template-notifications/images-in-notifications.md b/docs/sources/alerting/configure-notifications/template-notifications/images-in-notifications.md
index 3f0a8d7b33b..42c5459825f 100644
--- a/docs/sources/alerting/configure-notifications/template-notifications/images-in-notifications.md
+++ b/docs/sources/alerting/configure-notifications/template-notifications/images-in-notifications.md
@@ -33,7 +33,7 @@ When an alert is fired or resolved Grafana takes a screenshot of the panel assoc
Grafana takes at most two screenshots for each alert: once when the alert fires and again when the alert is resolved. Screenshots are not re-taken over the lifetime of the alert, instead you should open the panel in Grafana to follow the data in real time. In addition, depending on how alerts are grouped in your notification policies, Grafana might send a notification with many screenshots of the same panel. This happens because Grafana does not know how your alerts are grouped at the time a screenshot is taken, and so acts conservatively by taking a screenshot for every alert.
-Once a screenshot has been taken Grafana can either upload it to a cloud storage service such as Amazon S3, Azure Blob Storage or Google Cloud Storage; upload the screenshot to it's internal web server; or upload it to the service that is receiving the notification, such as Slack. Which option you should choose depends on how your Grafana is managed and which integrations you use. More information on this can be found in Requirements.
+After a screenshot has been taken Grafana can either upload it to a cloud storage service such as Amazon S3, Azure Blob Storage or Google Cloud Storage; upload the screenshot to it's internal web server; or upload it to the service that is receiving the notification, such as Slack. Which option you should choose depends on how your Grafana is managed and which integrations you use. More information on this can be found in Requirements.
Refer to the table at the end of this page for a list of contact points and their support for images in notifications.
@@ -41,19 +41,19 @@ Refer to the table at the end of this page for a list of contact points and thei
1. To use images in notifications, Grafana must be set up to use image rendering. You can either install the image rendering plugin or run it as a remote rendering service.
-2. When a screenshot is taken it is saved to the [data][paths] folder, even if Grafana is configured to upload screenshots to a cloud storage service. Grafana must have write-access to this folder otherwise screenshots cannot be saved to disk and an error will be logged for each failed screenshot attempt.
+2. When a screenshot is taken, it is saved to the [data][paths] folder, even if Grafana is configured to upload screenshots to a cloud storage service. Grafana must have write-access to this folder otherwise screenshots cannot be saved to disk and an error is logged for each failed screenshot attempt.
-3. You should use a cloud storage service unless sending alerts to Discord, Email, Pushover, Slack or Telegram. These integrations support either embedding screenshots in the email or attaching screenshots to the notification, while other integrations must link screenshots uploaded to a cloud storage bucket. If a cloud storage service has been configured then integrations that support both will link screenshots from the cloud storage bucket instead of embedding or attaching screenshots to the notification.
+3. You should use a cloud storage service unless sending alerts to Discord, email, Pushover, Slack or Telegram. These integrations support either embedding screenshots in the email or attaching screenshots to the notification, while other integrations must link screenshots uploaded to a cloud storage bucket. If a cloud storage service has been configured then integrations that support both link screenshots from the cloud storage bucket instead of embedding or attaching screenshots to the notification.
-4. If uploading screenshots to a cloud storage service such as Amazon S3, Azure Blob Storage or Google Cloud Storage; and accessing screenshots in the bucket requires authentication, logging into a VPN or corporate network; then image previews might not work in all instant messaging and communication platforms as some services rewrite URLs to use their CDN. If this happens we recommend using [integrations which support uploading images](#supported-contact-points) or [disabling images in notifications](#configuration) altogether.
+4. If uploading screenshots to a cloud storage service such as Amazon S3, Azure Blob Storage or Google Cloud Storage; and accessing screenshots in the bucket requires authentication, logging into a VPN or corporate network; then image previews might not work in all instant messaging and communication platforms as some services rewrite URLs to use their CDN. If this happens, we recommend using [integrations which support uploading images](#supported-contact-points) or [disabling images in notifications](#configuration) altogether.
5. When uploading screenshots to a cloud storage service Grafana uses a random 20 character (30 characters for Azure Blob Storage) filename for each image. This makes URLs hard to guess but not impossible.
6. Grafana does not delete screenshots from cloud storage. We recommend configuring a retention policy with your cloud storage service to delete screenshots older than 1 month.
-7. If Grafana is configured to upload screenshots to its internal web server, and accessing Grafana requires logging into a VPN or corporate network; image previews might not work in all instant messaging and communication platforms as some services rewrite URLs to use their CDN. If this happens we recommend using [integrations which support uploading images](#supported-contact-points) or [disabling images in notifications](#configuration) altogether.
+7. If Grafana is configured to upload screenshots to its internal web server, and accessing Grafana requires logging into a VPN or corporate network; image previews might not work in all instant messaging and communication platforms as some services rewrite URLs to use their CDN. If this happens, we recommend using [integrations which support uploading images](#supported-contact-points) or [disabling images in notifications](#configuration) altogether.
-8. Grafana does not delete screenshots uploaded to its internal web server. To delete screenshots from `static_root_path/images/attachments` after a certain amount of time we recommend setting up a CRON job.
+8. Grafana does not delete screenshots uploaded to its internal web server. To delete screenshots from `static_root_path/images/attachments` after a certain amount of time, we recommend setting up a CRON job.
## Configuration
@@ -72,14 +72,14 @@ If screenshots should be uploaded to cloud storage then `upload_external_image_s
# Uploads screenshots to the local Grafana server or remote storage such as Azure, S3 and GCS. Please
# see [external_image_storage] for further configuration options. If this option is false, screenshots
- # will be persisted to disk for up to temp_data_lifetime.
+ # are persisted to disk for up to temp_data_lifetime.
upload_external_image_storage = false
Restart Grafana for the changes to take effect.
## Advanced configuration
-We recommended that `max_concurrent_screenshots` is less than or equal to `concurrent_render_request_limit`. The default value for both `max_concurrent_screenshots` and `concurrent_render_request_limit` is `5`:
+We recommend that `max_concurrent_screenshots` is less than or equal to `concurrent_render_request_limit`. The default value for both `max_concurrent_screenshots` and `concurrent_render_request_limit` is `5`:
# The maximum number of screenshots that can be taken at the same time. This option is different from
# concurrent_render_request_limit as max_concurrent_screenshots sets the number of concurrent screenshots
@@ -124,9 +124,9 @@ If Grafana has been set up to send images in notifications, however notification
1. Check that images in notifications has been set up as per the instructions.
2. Enable debug logging in Grafana and look for logs with the logger `ngalert.image`.
-3. If the alert is not associated with a dashboard there will be logs for `Cannot take screenshot for alert rule as it is not associated with a dashboard`.
-4. If the alert is associated with a dashboard, but no panel in the dashboard, there will be logs for `Cannot take screenshot for alert rule as it is not associated with a panel`.
-5. If images cannot be taken because of mis-configuration or an issue with image rendering there will be logs for `Failed to take an image` including the Dashboard UID, Panel ID, and the error message.
+3. If the alert is not associated with a dashboard there are logs for `Cannot take screenshot for alert rule as it is not associated with a dashboard`.
+4. If the alert is associated with a dashboard, but no panel in the dashboard, there are logs for `Cannot take screenshot for alert rule as it is not associated with a panel`.
+5. If images cannot be taken because of mis-configuration or an issue with image rendering there are logs for `Failed to take an image` including the Dashboard UID, Panel ID, and the error message.
6. Check that the contact point supports images in notifications and whether it supports uploading images to the receiving service or referencing images that have been uploaded to a cloud storage service.
## Metrics
diff --git a/docs/sources/alerting/configure-notifications/template-notifications/using-go-templating-language.md b/docs/sources/alerting/configure-notifications/template-notifications/using-go-templating-language.md
index e92fd2c4cb6..5999a20001e 100644
--- a/docs/sources/alerting/configure-notifications/template-notifications/using-go-templating-language.md
+++ b/docs/sources/alerting/configure-notifications/template-notifications/using-go-templating-language.md
@@ -256,7 +256,7 @@ You can use indentation, both tabs and spaces, and line breaks, to make template
{{ end }}
```
-However, indentation in the template will also be present in the text. Next we will see how to remove it.
+However, indentation in the template is also present in the text. Next, we look at how to remove it.
## Remove spaces and line breaks
diff --git a/docs/sources/alerting/monitor/_index.md b/docs/sources/alerting/monitor/_index.md
index 104d4e03046..1f807e13c52 100644
--- a/docs/sources/alerting/monitor/_index.md
+++ b/docs/sources/alerting/monitor/_index.md
@@ -68,19 +68,19 @@ This metric is a gauge that shows you the number of alert rules scheduled. An al
#### grafana_alerting_schedule_periodic_duration_seconds_bucket
-This metric is a histogram that shows you the time it takes to process an individual tick in the scheduler that evaluates alert rules. If the scheduler takes longer than 10 seconds to process a tick then pending evaluations will start to accumulate such that alert rules might later than expected.
+This metric is a histogram that shows you the time it takes to process an individual tick in the scheduler that evaluates alert rules. If the scheduler takes longer than 10 seconds to process a tick then pending evaluations start to accumulate such that alert rules might later than expected.
#### grafana_alerting_schedule_query_alert_rules_duration_seconds_bucket
-This metric is a histogram that shows you how long it takes the scheduler to fetch the latest rules from the database. If this metric is elevated then so will `schedule_periodic_duration_seconds`.
+This metric is a histogram that shows you how long it takes the scheduler to fetch the latest rules from the database. If this metric is elevated, `schedule_periodic_duration_seconds` is also evaluated.
#### grafana_alerting_scheduler_behind_seconds
-This metric is a gauge that shows you the number of seconds that the scheduler is behind where it should be. This number will increase if `schedule_periodic_duration_seconds` is longer than 10 seconds, and decrease when it is less than 10 seconds. The smallest possible value of this metric is 0.
+This metric is a gauge that shows you the number of seconds that the scheduler is behind where it should be. This number increases if `schedule_periodic_duration_seconds` is longer than 10 seconds, and decrease when it is less than 10 seconds. The smallest possible value of this metric is 0.
#### grafana_alerting_notification_latency_seconds_bucket
-This metric is a histogram that shows you the number of seconds taken to send notifications for firing and resolved alerts. This metric will let you observe slow or over-utilized integrations, such as an SMTP server that is being given emails faster than it can send them.
+This metric is a histogram that shows you the number of seconds taken to send notifications for firing and resolved alerts. This metric lets you observe slow or over-utilized integrations, such as an SMTP server that is being given emails faster than it can send them.
## Metrics for Mimir-managed alerts
@@ -121,7 +121,7 @@ This metric is a counter that shows you the number of active, suppressed, and un
#### alertmanager_alerts_invalid_total
-This metric is a counter that shows you the number of invalid alerts that were sent to Alertmanager. This counter should not exceed 0, and so in most cases you will want to create an alert that fires if whenever this metric increases.
+This metric is a counter that shows you the number of invalid alerts that were sent to Alertmanager. This counter should not exceed 0, and so in most cases, create an alert that fires if whenever this metric increases.
#### alertmanager_notifications_total
@@ -129,7 +129,7 @@ This metric is a counter that shows you how many notifications have been sent by
#### alertmanager_notifications_failed_total
-This metric is a counter that shows you how many notifications have failed in total. This metric also uses a label "integration" to show the number of failed notifications by integration, such as failed emails. In most cases you will want to use the `rate` function to understand how often notifications are failing to be sent.
+This metric is a counter that shows you how many notifications have failed in total. This metric also uses a label "integration" to show the number of failed notifications by integration, such as failed emails. In most cases, use the `rate` function to understand how often notifications are failing to be sent.
#### alertmanager_notification_latency_seconds_bucket
@@ -157,4 +157,4 @@ This metric is a gauge. It has a constant value `1`, and contains a label called
#### alertmanager_cluster_reconnections_failed_total
-This metric is a counter that shows you the number of failed peer connection attempts. In most cases you will want to use the `rate` function to understand how often reconnections fail as this may be indicative of an issue or instability in your network.
+This metric is a counter that shows you the number of failed peer connection attempts. In most cases you should use the `rate` function to understand how often reconnections fail as this may be indicative of an issue or instability in your network.
diff --git a/docs/sources/dashboards/create-manage-playlists/index.md b/docs/sources/dashboards/create-manage-playlists/index.md
index 20acca7382c..0b916eeb488 100644
--- a/docs/sources/dashboards/create-manage-playlists/index.md
+++ b/docs/sources/dashboards/create-manage-playlists/index.md
@@ -28,34 +28,41 @@ You can access the Playlist feature from Grafana's side menu, in the Dashboards
## Access, share, and control a playlist
-Use the information in this section to access existing playlists. Start and control the display of a playlist using one of the five available modes.
+Use the information in this section to access playlists. Start and control the display of a playlist using one of the six available modes.
### Access a playlist
-1. Click **Dashboards** in the left-side menu.
-1. Click **Playlists** to see a list of existing playlists.
+1. Click **Dashboards** in the main menu.
+1. Click **Playlists** to see a list of playlists.
### Start a playlist
-You can start a playlist in five different view modes. View modes determine how the menus and navigation bar appear on the dashboards.
+You can start a playlist in six different view modes. View modes determine how the menus and navigation bar appear on the dashboards as well as how panels are sized.
-By default, each dashboard is displayed for the amount of time entered in the Interval field, which you set when you create or edit a playlist. After you start a playlist, you can control it with the navbar at the top of the page.
+1. Click **Dashboards** in the main menu.
+1. Click **Playlists**.
+1. Find the desired playlist and click **Start playlist**.
+1. In the dialog box that opens, select one of the [six playlist modes](#playlist-modes) available.
+1. Disable any dashboard controls that you don't want displayed while the list plays; these controls are enabled and visible by default. Select from:
+
+ - **Time and refresh**
+ - **Variables**
+ - **Dashboard links**
-1. Click **Dashboards** in the left-side menu.
-1. Click **Playlists** to see a list of existing playlists.
-1. Find the playlist you want to start, then click **Start playlist**.
-1. In the modal that opens, select one of the five playlist modes available, based on the information in the table below.
1. Click **Start \**.
-The playlist displays each dashboard for the time specified in the **Interval** field, set when creating or editing a playlist. Once a playlist starts, you can [control](#control-a-playlist) it using the navbar at the top of your screen.
+The playlist displays each dashboard for the time specified in the **Interval** field, set when creating or editing a playlist. After a playlist starts, you can [control](#control-a-playlist) it using the navbar at the top of your screen.
-| Mode | Description |
-| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| Normal mode | The side menu remains visible. The navbar, row, and panel controls appear at the top of the screen. |
-| TV mode | The side menu and dashboard submenu (including variable drop-downs and dashboard links) are hidden or removed. The navbar, row, and panel controls appear at the top of the screen. Enabled automatically after one minute of user inactivity. Enable it manually using the `d v` sequence shortcut, or by appending the parameter `?inactive` to the dashboard URL. Disable it with any mouse movement or keyboard action. |
-| TV mode (with auto fit panels) | The side menu and dashboard submenu (including variable drop-downs and dashboard links) are hidden or removed. The navbar, row and panel controls appear at the top of the screen. Dashboard panels automatically adjust to optimize space on screen. |
-| Kiosk mode | The side menu, navbar, ro and panel controls are completely hidden/removed from view. You can enable it manually using the `d v` sequence shortcut after the playlist has started. You can disable it manually with the same shortcut. |
-| Kiosk mode (with auto fit panels) | The side menu, navbar, row, and panel controls are completely hidden/removed from view. Dashboard panels automatically adjust to optimize space on screen. |
+### Playlist modes
+
+| Mode | Description |
+| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| Normal mode | The side menu remains visible. The navbar and dashboard controls appear at the top of the screen. |
+| Normal mode (with auto fit panels) | The side menu remains visible. The navbar and dashboard controls appear at the top of the screen. Dashboard panels automatically adjust to optimize space on screen. |
+| TV mode | The side menu is hidden or removed. The navbar and dashboard controls appear at the top of the screen. Enabled automatically after one minute of user inactivity. Enable it manually using the `d v` sequence shortcut, or by appending the parameter `?inactive` to the dashboard URL. Disable it with any mouse movement or keyboard action. |
+| TV mode (with auto fit panels) | The side menu is hidden or removed. The navbar and dashboard controls appear at the top of the screen. Dashboard panels automatically adjust to optimize space on screen. |
+| Kiosk mode | The side menu is hidden or removed. The navbar and dashboard controls appear at the top of the screen. You can disable or enable it manually using the `d v` sequence shortcut after the playlist has started. |
+| Kiosk mode (with auto fit panels) | The side menu is hidden or removed. The navbar and dashboard controls appear at the top of the screen. You can disable or enable it manually using the `d v` sequence shortcut after the playlist has started. Dashboard panels automatically adjust to optimize space on screen. |
### Control a playlist
@@ -72,79 +79,50 @@ You can control a playlist in **Normal** or **TV** mode after it's started, usin
## Create a playlist
-You can create a playlist to present dashboards in a sequence, with a set order and time interval between dashboards.
+You can create a playlist to present dashboards in a sequence, with a set order and time interval between dashboards. Be sure that all the dashboards you want to appear in your playlist are added before you create the playlist.
+
+1. Click **Dashboards** in the main menu.
+1. Click **Playlists**.
+1. Click **New playlist**.
+1. In the **Name** field, enter a descriptive name.
+1. In the **Interval** field, enter the time interval each dashboard is displayed before moving on to the next dashboard.
+1. In the **Add dashboards** section, add dashboards to the playlist using the **Add by title** and **Add by tag** drop-down options.
+
+ Added dashboards are displayed in a list in the **Dashboards** section of the page, in the order you added them. This is also the play order of the dashboards.
-1. Click **Dashboards** in the left-side menu.
-1. Click **Playlists** to see a list of existing playlists.
-1. Click **New playlist**. The New playlist page opens.
-1. In the **Name** text box, enter a descriptive name.
-1. In the **Interval** text box, enter a time interval. Grafana displays a particular dashboard for the interval of time specified here before moving on to the next dashboard.
-1. In Dashboards, add existing dashboards to the playlist using **Add by title** and **Add by tag** drop-down options. The dashboards you add are listed in a sequential order.
-1. If needed:
- - Search for a dashboard by its name, a regular expression, or a tag.
- - Filter your results by starred status or tags.
-1. If needed, rearrange the order of the dashboard you have added using the up and down arrow icon.
-1. Optionally, remove a dashboard from the playlist by clicking the x icon beside dashboard.
1. Click **Save**.
-## Save a playlist
+## Edit a playlist
-You can save a playlist and add it to your **Playlists** page, where you can start it. Be sure that all the dashboards you want to appear in your playlist are added when creating or editing the playlist before saving it.
+You can edit a playlist including adding, removing, and rearranging the order of dashboards.
+
+1. Click **Dashboards** in the main menu.
+1. Click **Playlists**.
+1. Find the playlist you want to update and click **Edit playlist**. Do one or more of the following:
+
+ - Edit - Update the name and time interval.
+ - Add dashboards - Search for dashboards by title or tag to add them to the playlist.
+ - Rearrange dashboards - Click and drag the dashboards into your desired order.
+ - Remove dashboards - Click the **X** next to the name of the dashboard you want to remove from the playlist.
-1. Click **Dashboards** in the left-side menu.
-1. Click **Playlists** to see a list of existing playlists.
-1. Click on the playlist.
-1. Edit the playlist.
-1. Ensure that your playlist has a **Name**, **Interval**, and at least one **Dashboard** added to it.
1. Click **Save**.
-## Edit or delete a playlist
-
-You can edit a playlist by updating its name, interval time, and by adding, removing, and rearranging the order of dashboards. On the rare occasion when you no longer need a playlist, you can delete it.
-
-### Edit a playlist
-
-1. Click **Dashboards** in the left-side menu.
-1. Click **Playlists** to see a list of existing playlists.
-1. Find the playlist you want to update and click **Edit playlist**.
-1. Update the name and time interval, then add or remove dashboards from the playlist using instructions in [Create a playlist](#create-a-playlist).
-1. Click **Save** to save your changes.
-
-### Delete a playlist
-
-1. Click **Dashboards** in the left-side menu.
-1. Click **Playlists** to see a list of existing playlists.
-1. Find the playlist you want to remove.
-1. Click **Delete playlist**.
-
-### Rearrange dashboard order
-
-1. Click **Dashboards** in the left-side menu.
-1. Click **Playlists** to see a list of existing playlists.
-1. Find the playlist you want to update and click **Edit playlist**.
-1. Click and drag the dashboards into your desired order.
-1. Click **Save** to save your changes.
-
-### Remove a dashboard
-
-1. Click **Dashboards** in the left-side menu.
-1. Click **Playlists** to see a list of existing playlists.
-1. Find the playlist you want to update and click **Edit playlist**.
-1. Click **\[x\]** on the name of the dashboard you want to remove from the playlist.
-1. Click **Save** to save your changes.
-
## Share a playlist in a view mode
You can share a playlist by copying the link address on the view mode you prefer, and pasting the URL to your destination.
-1. Click **Dashboards** in the left-side menu.
-1. Click **Playlists** to see a list of existing playlists.
+1. Click **Dashboards** in the main menu.
+1. Click **Playlists**.
1. Click the share icon of the playlist you want to share.
1. Select the view mode you prefer.
-1. Click **Copy** next to the Link URL to copy it to your clipboard.
-
- For example, the URL for the first playlist on the Grafana Play site in Kiosk mode will look like this:
-
- [https://play.grafana.org/playlists/play/1?kiosk](https://play.grafana.org/playlists/play/1?kiosk).
-
+1. Click **Copy** next to the **Link URL** to copy it to your clipboard.
1. Paste the URL to your destination.
+
+## Delete a playlist
+
+When you no longer need a playlist, follow these steps to delete it:
+
+1. Click **Dashboards** in the main menu.
+1. Click **Playlists**.
+1. Find the playlist you want to remove.
+1. Click **Delete playlist**.
diff --git a/docs/sources/upgrade-guide/upgrade-v11.1/index.md b/docs/sources/upgrade-guide/upgrade-v11.1/index.md
new file mode 100644
index 00000000000..4e7178ee2b8
--- /dev/null
+++ b/docs/sources/upgrade-guide/upgrade-v11.1/index.md
@@ -0,0 +1,22 @@
+---
+description: Guide for upgrading to Grafana v11.1
+keywords:
+ - grafana
+ - configuration
+ - documentation
+ - upgrade
+ - '11.1'
+title: Upgrade to Grafana v11.1
+menuTitle: Upgrade to v11.1
+weight: 1100
+---
+
+# Upgrade to Grafana v11.1
+
+{{< docs/shared lookup="upgrade/intro.md" source="grafana" version="" >}}
+
+{{< docs/shared lookup="back-up/back-up-grafana.md" source="grafana" version="" leveloffset="+1" >}}
+
+{{< docs/shared lookup="upgrade/upgrade-common-tasks.md" source="grafana" version="" >}}
+
+## Technical notes
diff --git a/docs/sources/whatsnew/_index.md b/docs/sources/whatsnew/_index.md
index d7211700cdf..0058e464ba9 100644
--- a/docs/sources/whatsnew/_index.md
+++ b/docs/sources/whatsnew/_index.md
@@ -76,6 +76,7 @@ For a complete list of every change, with links to pull requests and related iss
## Grafana 11
+- [What's new in 11.1](https://grafana.com/docs/grafana//whatsnew/whats-new-in-v11-1/)
- [What's new in 11.0](https://grafana.com/docs/grafana//whatsnew/whats-new-in-v11-0/)
## Grafana 10
diff --git a/docs/sources/whatsnew/whats-new-in-v11-1.md b/docs/sources/whatsnew/whats-new-in-v11-1.md
new file mode 100644
index 00000000000..15e28cc5287
--- /dev/null
+++ b/docs/sources/whatsnew/whats-new-in-v11-1.md
@@ -0,0 +1,191 @@
+---
+description: Feature and improvement highlights for Grafana v11.1
+keywords:
+ - grafana
+ - new
+ - documentation
+ - '11.1'
+ - release notes
+labels:
+products:
+ - cloud
+ - enterprise
+ - oss
+title: What's new in Grafana v11.1
+weight: -43
+---
+
+
+
+
+# What’s new in Grafana v11.1
+
+Welcome to Grafana 11.1! This release contains some minor improvements following on the big announcements in Grafana 11.0. We've adding cell text wrapping to table visualizations, a much-requested feature. We've also redesigned the Alerting settings page and made it easier to set rule-specific silences. A number of accessibility improvements are included in this release, making Grafana easier to use for everyone. And lastly, the XY chart is now generally available.
+
+{{< youtube id="gjQX9-7Hsfs" >}}
+
+For even more detail about all the changes in this release, refer to the [changelog](https://github.com/grafana/grafana/blob/main/CHANGELOG.md). For the specific steps we recommend when you upgrade to v11.1, check out our [Upgrade Guide](https://grafana.com/docs/grafana//upgrade-guide/upgrade-v11.1/).
+
+
+
+## Dashboards and visualizations
+
+### Visualization ease of use improvements
+
+
+
+We’ve made a number of small improvements to the data visualization experience in Grafana.
+
+#### Table cell text wrapping
+
+_Available in public preview in all editions of Grafana_
+
+A longstanding feature request for the table visualization is to allow wrapping of text within cells. In Grafana 11.1 we've added this capability! By default, the column with the longest text is selected for wrapping. You can also configure wrapping manually using field overrides.
+
+Learn more about the table panel in our [table panel documentation](https://grafana.com/docs/grafana//panels-visualizations/visualizations/table/).
+
+
+
+#### Stat visualization percent change color mode options
+
+_Generally available in all editions of Grafana_
+
+Sometimes less is more! The **Standard** behavior for percent change in the [stat visualization](https://grafana.com/docs/grafana//panels-visualizations/visualizations/stat/#show-percent-change) is to color positive percent changes green and negative percent changes red. Depending on your use case however, you may want to customize how percent change color is set. We've added the options to have percent change color mode **Inverted** (with positive red and negative green) or match the **Same as value**.
+
+
+
+### XY chart is GA
+
+
+
+_Generally available in all editions of Grafana_
+
+We’re promoting XY chart out of public preview and into general availability.
+
+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:
+
+
+
+Over the past several months we’ve introduced multiple enhancements to the visualizations like auto mode, which now handles most scenarios that previously required manual configuration. Additionally, we've added better control over point styling and further improved performance. We’re excited to include XY chart as a first class citizen in the core Grafana visualization library. To learn more about the panel, refer to [the documentation](https://grafana.com/docs/grafana//panels-visualizations/visualizations/xy-chart/).
+
+To use the new XY chart visualization, you must first enable the `autoMigrateXYChartPanel` [feature toggle](https://grafana.com/docs/grafana//setup-grafana/configure-grafana/feature-toggles/).
+
+## Alerting
+
+### Re-designed settings page for Alerting
+
+
+
+_Generally available in all editions of Grafana_
+
+The new settings page provides you with a holistic view of where Grafana-managed alert instances are forwarded.
+
+- Manage which Alertmanagers receive alert instances from Grafana-managed rules without navigating and editing data sources.
+- Manage version snapshots for the built-in Alertmanager, which allows administrators to roll back unintentional changes or mistakes in the Alertmanager configuration.
+- There is also a visual diff that compares the historical snapshot with the latest configuration to see which changes were made.
+
+{{< figure src="/media/docs/alerting/alert-settings.png" alt="Alert settings page" >}}
+
+Learn more in the [Alertmanager configuration documentation](https://grafana.com/docs/grafana//alerting/set-up/configure-alertmanager/).
+
+### Alerting template selector
+
+
+
+_Generally available in all editions of Grafana_
+
+Enables you to easily choose which templates you want to use in your alert notification messages by adding a template selector in the Contact Points form.
+
+Select from existing templates or enter a custom one for your specific needs. You can switch between the two tabs to access the list of available templates and copy them across to the customized version.
+
+Learn more in the [documentation](https://grafana.com/docs/grafana//alerting/configure-notifications/manage-contact-points/).
+
+### Add OAuth2 to HTTP settings for vanilla Alertmanager / Mimir
+
+
+
+_Generally available in all editions of Grafana_
+
+Configure OAuth2 authentication for any Alertmanager or Mimir receiver (called Contact Points in Grafana) through the user interface. Learn more about alerting contact points in [supported contact point integrations](https://grafana.com/docs/grafana-cloud/alerting-and-irm/alerting/configure-notifications/manage-contact-points/#list-of-supported-integrations) and find the reference for Oauth2 fields in the [Prometheus Alertmanager docs for Oauth2](https://prometheus.io/docs/alerting/latest/configuration/#oauth2).
+
+Note that OAuth2 is not yet implemented for the Grafana built-in Alertmanager.
+
+### Improved paused alert visibility
+
+
+
+_Generally available in all editions of Grafana_
+
+Pause and resume alert rule evaluation directly from the Alert rules list and details view. This helps Improve visibility of when alert rules have been paused by displaying “Paused” as the alert rule state.
+
+Learn more in the [alert rules documentation](https://grafana.com/docs/grafana//alerting/manage-notifications/view-alert-rules/).
+
+### Removes requirement of datasources:query permission for reading rules
+
+
+
+_Generally available in Grafana Enterprise and Cloud_
+
+Fetching a rule group no longer requires the **datasources:query** permission for every data source used by the rules within that group. Now, the only requirements are **alert.rules:read** and **folders:read** for the folder the group is contained in.
+
+Note: **datasources:query** is still required to preview an alert rule, regardless of alert rules and folders permissions.
+
+Learn more in the [RBAC configuration documentation](https://grafana.com/docs/grafana-cloud/alerting-and-irm/alerting/set-up/configure-rbac/).
+
+### Rule-specific silences with permissions
+
+
+
+_Generally available in all editions of Grafana_
+
+More easily create silences directly from the Alert rule list view or detail page.
+
+These rule-specific silences are guaranteed to only apply to a single rule and permissions to read, create, update or delete are tied to a user’s permissions for that rule.
+
+### Rule-specific silences with RBAC
+
+
+
+_Generally available in Grafana Enterprise and Cloud_
+
+Manage silences through Role-Based Access Control (RBAC). In addition to the Grafana open source functionality in **Rule-specific silences with permissions**, you can choose who can create, edit, and read silences using the following permissions:
+
+- Users with the **alert.silences:create permission**, scoped within a folder, are able to create silences for rules contained within that folder and its subfolders
+- Users with the **alert.silences:read permission**, scoped within a folder, are able to read silences for rules contained within that folder and its subfolders, and general silences
+- Users with the **alert.silences:write permission**, scoped within a folder, are able to expire and recreate silences for rules contained within that folder and its subfolders
+
+Learn more about [managing access using roles](https://grafana.com/docs/grafana-cloud/alerting-and-irm/alerting/set-up/configure-rbac/access-roles/).
+
+### Support for AWS SNS integration in Grafana-managed alerts
+
+
+
+_Generally available in all editions of Grafana_
+
+Send alerts notifications to AWS simple notifications service.
+
+## Recent accessibility improvements
+
+
+
+_Generally available in all editions of Grafana_
+
+### GeoMap keyboard support
+
+The GeoMap panel can now be used with a keyboard! Focus the map area, move around with the arrows keys and zoom in and out using + and -.
+
+### Panel shortcut keyboard support
+
+We have [panel shortcuts](https://grafana.com/docs/grafana//dashboards/use-dashboards/#keyboard-shortcuts), which previously only worked on whichever panel you hovered over. It now also takes into account the keyboard focus.
+
+{{< video-embed src="/media/docs/grafana/2024-06-10-Keyboard-Improvements-Enablement-Video.mp4" >}}
+
+### Heading improvements
+
+The majority of screen reader users [find things on a web page using headings](https://webaim.org/projects/screenreadersurvey10/#finding). Recently, we have added missing headings and corrected heading levels in some places, most notably panel titles.
+
+### Reduced motion support
+
+Users who are affected by a lot of animations on a web site have the possibility to configure [reduced motion settings](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion). Grafana now supports this, either by making animations simpler or removing them altogether. We have [implemented a rule](https://github.com/grafana/grafana/tree/main/packages/grafana-eslint-rules#no-unreduced-motion), which prohibits unhandled transitions and animations, ensuring that we can continuously support reduced motion.
diff --git a/e2e/scenes/various-suite/keybinds.spec.ts b/e2e/scenes/various-suite/keybinds.spec.ts
index 02a45a6f42e..88e256b5576 100644
--- a/e2e/scenes/various-suite/keybinds.spec.ts
+++ b/e2e/scenes/various-suite/keybinds.spec.ts
@@ -52,16 +52,20 @@ describe.skip('Keyboard shortcuts', () => {
zone: 'Browser',
});
e2e.components.RefreshPicker.runButtonV2().should('have.text', 'Run query');
+ let expectedRange = `Time range selected: 2024-06-05 10:05:00 to 2024-06-05 10:06:00`;
+ e2e.components.TimePicker.openButton().should('have.attr', 'aria-label', expectedRange);
cy.log('Trying one shift-left');
cy.get('body').type('t{leftarrow}');
e2e.components.RefreshPicker.runButtonV2().should('have.text', 'Run query');
- let expectedRange = `Time range selected: 2024-06-05 10:04:00 to 2024-06-05 10:05:00`; // 1 min back
+ expectedRange = `Time range selected: 2024-06-05 10:04:00 to 2024-06-05 10:05:00`; // 1 min back
e2e.components.TimePicker.openButton().should('have.attr', 'aria-label', expectedRange);
cy.log('Trying two shift-lefts');
cy.get('body').type('t{leftarrow}');
e2e.components.RefreshPicker.runButtonV2().should('have.text', 'Run query');
+ expectedRange = `Time range selected: 2024-06-05 10:03:00 to 2024-06-05 10:04:00`; // 1 min back
+ e2e.components.TimePicker.openButton().should('have.attr', 'aria-label', expectedRange);
cy.get('body').type('t{leftarrow}');
e2e.components.RefreshPicker.runButtonV2().should('have.text', 'Run query');
expectedRange = `Time range selected: 2024-06-05 10:02:00 to 2024-06-05 10:03:00`; // 2 mins back
@@ -70,11 +74,15 @@ describe.skip('Keyboard shortcuts', () => {
cy.log('Trying two shift-lefts and a shift-right');
cy.get('body').type('t{leftarrow}');
e2e.components.RefreshPicker.runButtonV2().should('have.text', 'Run query');
+ expectedRange = `Time range selected: 2024-06-05 10:01:00 to 2024-06-05 10:02:00`; // 1 min back
+ e2e.components.TimePicker.openButton().should('have.attr', 'aria-label', expectedRange);
cy.get('body').type('t{leftarrow}');
e2e.components.RefreshPicker.runButtonV2().should('have.text', 'Run query');
+ expectedRange = `Time range selected: 2024-06-05 10:00:00 to 2024-06-05 10:01:00`; // 2 mins back
+ e2e.components.TimePicker.openButton().should('have.attr', 'aria-label', expectedRange);
cy.get('body').type('t{rightarrow}');
e2e.components.RefreshPicker.runButtonV2().should('have.text', 'Run query');
- expectedRange = `Time range selected: 2024-06-05 10:01:00 to 2024-06-05 10:02:00`; // 2 mins back, 1 min forward (1 min back total)
+ expectedRange = `Time range selected: 2024-06-05 10:01:00 to 2024-06-05 10:02:00`; // 1 min forward (1 min back total)
e2e.components.TimePicker.openButton().should('have.attr', 'aria-label', expectedRange);
});
});
diff --git a/e2e/various-suite/keybinds.spec.ts b/e2e/various-suite/keybinds.spec.ts
index 07635c4df74..37f3c8da9c0 100644
--- a/e2e/various-suite/keybinds.spec.ts
+++ b/e2e/various-suite/keybinds.spec.ts
@@ -65,6 +65,8 @@ describe('Keyboard shortcuts', () => {
cy.log('Trying two shift-lefts');
cy.get('body').type('t{leftarrow}');
e2e.components.RefreshPicker.runButtonV2().should('have.text', 'Run query');
+ expectedRange = `Time range selected: 2024-06-05 10:03:00 to 2024-06-05 10:04:00`; // 1 min back
+ e2e.components.TimePicker.openButton().should('have.attr', 'aria-label', expectedRange);
cy.get('body').type('t{leftarrow}');
e2e.components.RefreshPicker.runButtonV2().should('have.text', 'Run query');
expectedRange = `Time range selected: 2024-06-05 10:02:00 to 2024-06-05 10:03:00`; // 2 mins back
@@ -73,11 +75,15 @@ describe('Keyboard shortcuts', () => {
cy.log('Trying two shift-lefts and a shift-right');
cy.get('body').type('t{leftarrow}');
e2e.components.RefreshPicker.runButtonV2().should('have.text', 'Run query');
+ expectedRange = `Time range selected: 2024-06-05 10:01:00 to 2024-06-05 10:02:00`; // 1 min back
+ e2e.components.TimePicker.openButton().should('have.attr', 'aria-label', expectedRange);
cy.get('body').type('t{leftarrow}');
e2e.components.RefreshPicker.runButtonV2().should('have.text', 'Run query');
+ expectedRange = `Time range selected: 2024-06-05 10:00:00 to 2024-06-05 10:01:00`; // 2 mins back
+ e2e.components.TimePicker.openButton().should('have.attr', 'aria-label', expectedRange);
cy.get('body').type('t{rightarrow}');
e2e.components.RefreshPicker.runButtonV2().should('have.text', 'Run query');
- expectedRange = `Time range selected: 2024-06-05 10:01:00 to 2024-06-05 10:02:00`; // 2 mins back, 1 min forward (1 min back total)
+ expectedRange = `Time range selected: 2024-06-05 10:01:00 to 2024-06-05 10:02:00`; // 1 min forward (1 min back total)
e2e.components.TimePicker.openButton().should('have.attr', 'aria-label', expectedRange);
});
});
diff --git a/go.mod b/go.mod
index b121c40ae80..be519c7bd83 100644
--- a/go.mod
+++ b/go.mod
@@ -30,6 +30,7 @@ require (
github.com/Masterminds/semver v1.5.0 // @grafana/grafana-backend-group
github.com/Masterminds/semver/v3 v3.2.0 // @grafana/grafana-release-guild
github.com/Masterminds/sprig/v3 v3.2.3 // @grafana/grafana-backend-group
+ github.com/Masterminds/squirrel v1.5.4 // @grafana/identity-access-team
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // @grafana/plugins-platform-backend
github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f // @grafana/grafana-backend-group
github.com/alicebob/miniredis/v2 v2.30.1 // @grafana/alerting-backend
@@ -129,6 +130,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // @grafana/alerting-backend
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // @grafana/alerting-backend
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // @grafana/grafana-operator-experience-squad
+ github.com/oklog/ulid/v2 v2.1.0 // @grafana/identity-access-team
github.com/olekukonko/tablewriter v0.0.5 // @grafana/grafana-backend-group
github.com/openfga/api/proto v0.0.0-20240529184453-5b0b4941f3e0 // @grafana/identity-access-team
github.com/openfga/openfga v1.5.4 // @grafana/identity-access-team
@@ -299,7 +301,7 @@ require (
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
- github.com/grafana/grafana/pkg/storage/unified/resource v0.0.0-20240620152449-c88de7f4d073 // @grafana/grafana-search-and-storage
+ github.com/grafana/grafana/pkg/storage/unified/resource v0.0.0-20240624122844-a89deaeb7365 // @grafana/grafana-search-and-storage
github.com/grafana/regexp v0.0.0-20221123153739-15dc172cd2db // indirect
github.com/grafana/sqlds/v3 v3.2.0 // indirect
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect; @grafana/plugins-platform-backend
@@ -436,9 +438,11 @@ require (
)
require (
- github.com/Masterminds/squirrel v1.5.4 // indirect
+ github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
github.com/envoyproxy/protoc-gen-validate v1.0.4 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
+ github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
+ github.com/hashicorp/go-retryablehttp v0.7.5 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect
@@ -451,7 +455,7 @@ require (
github.com/mfridman/interpolate v0.0.2 // indirect
github.com/natefinch/wrap v0.2.0 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
- github.com/oklog/ulid/v2 v2.1.0 // indirect
+ github.com/openfga/language/pkg/go v0.0.0-20240409225820-a53ea2892d6d // indirect
github.com/pelletier/go-toml/v2 v2.1.1 // indirect
github.com/pressly/goose/v3 v3.20.0 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
diff --git a/go.sum b/go.sum
index 2c66d93841d..d6616ff8998 100644
--- a/go.sum
+++ b/go.sum
@@ -2334,8 +2334,8 @@ github.com/grafana/grafana/pkg/apiserver v0.0.0-20240226124929-648abdbd0ea4 h1:t
github.com/grafana/grafana/pkg/apiserver v0.0.0-20240226124929-648abdbd0ea4/go.mod h1:vpYI6DHvFO595rpQGooUjcyicjt9rOevldDdW79peV0=
github.com/grafana/grafana/pkg/promlib v0.0.6 h1:FuRyHMIgVVXkLuJnCflNfk3gqJflmyiI+/ZuJ9MoAfY=
github.com/grafana/grafana/pkg/promlib v0.0.6/go.mod h1:shFkrG1fQ/PPNRGhxAPNMLp0SAeG/jhqaLoG6n2191M=
-github.com/grafana/grafana/pkg/storage/unified/resource v0.0.0-20240620152449-c88de7f4d073 h1:Au8+1QORZnMVo52+19dgkP4zzIlXyJ7x/d9ysSGQHOk=
-github.com/grafana/grafana/pkg/storage/unified/resource v0.0.0-20240620152449-c88de7f4d073/go.mod h1:zOInHv2y6bsgm9bIMsCVDaz1XylqIVX9r4amH4iuWPE=
+github.com/grafana/grafana/pkg/storage/unified/resource v0.0.0-20240624122844-a89deaeb7365 h1:XRHqYGxjN2+/4QHPoOtr7kYTL9p2P5UxTXfnbiaO/NI=
+github.com/grafana/grafana/pkg/storage/unified/resource v0.0.0-20240624122844-a89deaeb7365/go.mod h1:X4dwV2eQI8z8G2aHXvhZZXu/y/rb3psQXuaZa66WZfA=
github.com/grafana/grafana/pkg/util/xorm v0.0.1 h1:72QZjxWIWpSeOF8ob4aMV058kfgZyeetkAB8dmeti2o=
github.com/grafana/grafana/pkg/util/xorm v0.0.1/go.mod h1:eNfbB9f2jM8o9RfwqwjY8SYm5tvowJ8Ly+iE4P9rXII=
github.com/grafana/otel-profiling-go v0.5.1 h1:stVPKAFZSa7eGiqbYuG25VcqYksR6iWvF3YH66t4qL8=
diff --git a/go.work.sum b/go.work.sum
index 84c674a4f2d..7eec5551ec7 100644
--- a/go.work.sum
+++ b/go.work.sum
@@ -958,6 +958,7 @@ github.com/grafana/grafana-plugin-sdk-go v0.231.1-0.20240523124942-62dae9836284/
github.com/grafana/grafana-plugin-sdk-go v0.234.0/go.mod h1:FlXjmBESxaD6Hoi8ojWLkH007nyjtJM3XC8SpwzF/YE=
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20240613114114-5e2f08de316d/go.mod h1:adT8O7k6ZSzUKjAC4WS6VfWlCE4G1VavPwSXVhvScCs=
github.com/grafana/grafana/pkg/promlib v0.0.3/go.mod h1:3El4NlsfALz8QQCbEGHGFvJUG+538QLMuALRhZ3pcoo=
+github.com/grafana/grafana/pkg/storage/unified/resource v0.0.0-20240620152449-c88de7f4d073/go.mod h1:zOInHv2y6bsgm9bIMsCVDaz1XylqIVX9r4amH4iuWPE=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
diff --git a/packages/grafana-data/src/context/plugins/DataSourcePluginContextProvider.tsx b/packages/grafana-data/src/context/plugins/DataSourcePluginContextProvider.tsx
index ec61e62713e..8747615a7cf 100644
--- a/packages/grafana-data/src/context/plugins/DataSourcePluginContextProvider.tsx
+++ b/packages/grafana-data/src/context/plugins/DataSourcePluginContextProvider.tsx
@@ -1,4 +1,4 @@
-import React, { PropsWithChildren, ReactElement, useMemo } from 'react';
+import { PropsWithChildren, ReactElement, useMemo } from 'react';
import { DataSourceInstanceSettings } from '../../types';
diff --git a/packages/grafana-data/src/context/plugins/PluginContextProvider.tsx b/packages/grafana-data/src/context/plugins/PluginContextProvider.tsx
index 282db933825..f60381c5aaa 100644
--- a/packages/grafana-data/src/context/plugins/PluginContextProvider.tsx
+++ b/packages/grafana-data/src/context/plugins/PluginContextProvider.tsx
@@ -1,4 +1,4 @@
-import React, { PropsWithChildren, ReactElement } from 'react';
+import { PropsWithChildren, ReactElement } from 'react';
import { PluginMeta } from '../../types/plugin';
diff --git a/packages/grafana-data/src/panel/PanelPlugin.test.tsx b/packages/grafana-data/src/panel/PanelPlugin.test.tsx
index e4451b73244..35ef52186ab 100644
--- a/packages/grafana-data/src/panel/PanelPlugin.test.tsx
+++ b/packages/grafana-data/src/panel/PanelPlugin.test.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PanelOptionsEditorBuilder } from '..';
import {
identityOverrideProcessor,
diff --git a/packages/grafana-data/src/themes/context.tsx b/packages/grafana-data/src/themes/context.tsx
index dc87729e9fb..e3536450c27 100644
--- a/packages/grafana-data/src/themes/context.tsx
+++ b/packages/grafana-data/src/themes/context.tsx
@@ -1,8 +1,8 @@
-import React from 'react';
+import { createContext } from 'react';
import { createTheme } from './createTheme';
/** @public */
-export const ThemeContext = React.createContext(createTheme());
+export const ThemeContext = createContext(createTheme());
ThemeContext.displayName = 'ThemeContext';
diff --git a/packages/grafana-data/src/transformations/standardTransformersRegistry.ts b/packages/grafana-data/src/transformations/standardTransformersRegistry.ts
index 3abc4de896b..e04950873be 100644
--- a/packages/grafana-data/src/transformations/standardTransformersRegistry.ts
+++ b/packages/grafana-data/src/transformations/standardTransformersRegistry.ts
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { DataFrame, DataTransformerInfo } from '../types';
import { Registry, RegistryItem } from '../utils/Registry';
diff --git a/packages/grafana-data/src/types/pluginExtensions.ts b/packages/grafana-data/src/types/pluginExtensions.ts
index d0c78553630..00594fad001 100644
--- a/packages/grafana-data/src/types/pluginExtensions.ts
+++ b/packages/grafana-data/src/types/pluginExtensions.ts
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { DataQuery, DataSourceJsonData } from '@grafana/schema';
diff --git a/packages/grafana-data/src/utils/LocalStorageValueProvider.tsx b/packages/grafana-data/src/utils/LocalStorageValueProvider.tsx
index f8491c8dece..fb6d8137315 100644
--- a/packages/grafana-data/src/utils/LocalStorageValueProvider.tsx
+++ b/packages/grafana-data/src/utils/LocalStorageValueProvider.tsx
@@ -1,4 +1,5 @@
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
+import * as React from 'react';
import { store } from './store';
diff --git a/packages/grafana-data/tsconfig.json b/packages/grafana-data/tsconfig.json
index fcc5100b8f8..d6da863dda3 100644
--- a/packages/grafana-data/tsconfig.json
+++ b/packages/grafana-data/tsconfig.json
@@ -1,5 +1,6 @@
{
"compilerOptions": {
+ "jsx": "react-jsx",
"declarationDir": "./compiled",
"emitDeclarationOnly": true,
"isolatedModules": true,
diff --git a/packages/grafana-flamegraph/src/FlameGraph/FlameGraph.test.tsx b/packages/grafana-flamegraph/src/FlameGraph/FlameGraph.test.tsx
index 3fb3f0585f5..64dc10da72e 100644
--- a/packages/grafana-flamegraph/src/FlameGraph/FlameGraph.test.tsx
+++ b/packages/grafana-flamegraph/src/FlameGraph/FlameGraph.test.tsx
@@ -1,5 +1,5 @@
import { fireEvent, render, screen } from '@testing-library/react';
-import React from 'react';
+import * as React from 'react';
import { createDataFrame } from '@grafana/data';
diff --git a/packages/grafana-flamegraph/src/FlameGraph/FlameGraph.tsx b/packages/grafana-flamegraph/src/FlameGraph/FlameGraph.tsx
index c05f2227c2f..ffd8c88d4f9 100644
--- a/packages/grafana-flamegraph/src/FlameGraph/FlameGraph.tsx
+++ b/packages/grafana-flamegraph/src/FlameGraph/FlameGraph.tsx
@@ -17,7 +17,8 @@
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
// THIS SOFTWARE.
import { css, cx } from '@emotion/css';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
+import * as React from 'react';
import { Icon } from '@grafana/ui';
diff --git a/packages/grafana-flamegraph/src/FlameGraph/FlameGraphCanvas.tsx b/packages/grafana-flamegraph/src/FlameGraph/FlameGraphCanvas.tsx
index df4131317ab..aae1d69276e 100644
--- a/packages/grafana-flamegraph/src/FlameGraph/FlameGraphCanvas.tsx
+++ b/packages/grafana-flamegraph/src/FlameGraph/FlameGraphCanvas.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { MouseEvent as ReactMouseEvent, useCallback, useEffect, useRef, useState } from 'react';
+import { MouseEvent as ReactMouseEvent, useCallback, useEffect, useRef, useState } from 'react';
+import * as React from 'react';
import { useMeasure } from 'react-use';
import { PIXELS_PER_LEVEL } from '../constants';
diff --git a/packages/grafana-flamegraph/src/FlameGraph/FlameGraphContextMenu.tsx b/packages/grafana-flamegraph/src/FlameGraph/FlameGraphContextMenu.tsx
index c84d4810f42..a4570305a34 100644
--- a/packages/grafana-flamegraph/src/FlameGraph/FlameGraphContextMenu.tsx
+++ b/packages/grafana-flamegraph/src/FlameGraph/FlameGraphContextMenu.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { DataFrame } from '@grafana/data';
import { MenuItem, MenuGroup, ContextMenu, IconName } from '@grafana/ui';
diff --git a/packages/grafana-flamegraph/src/FlameGraph/FlameGraphMetadata.test.tsx b/packages/grafana-flamegraph/src/FlameGraph/FlameGraphMetadata.test.tsx
index 5779255ce9c..379224d4761 100644
--- a/packages/grafana-flamegraph/src/FlameGraph/FlameGraphMetadata.test.tsx
+++ b/packages/grafana-flamegraph/src/FlameGraph/FlameGraphMetadata.test.tsx
@@ -1,6 +1,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
+import * as React from 'react';
import FlameGraphMetadata from './FlameGraphMetadata';
import { textToDataContainer } from './testHelpers';
diff --git a/packages/grafana-flamegraph/src/FlameGraph/FlameGraphMetadata.tsx b/packages/grafana-flamegraph/src/FlameGraph/FlameGraphMetadata.tsx
index a24b96f7f19..488b48965b3 100644
--- a/packages/grafana-flamegraph/src/FlameGraph/FlameGraphMetadata.tsx
+++ b/packages/grafana-flamegraph/src/FlameGraph/FlameGraphMetadata.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { ReactNode } from 'react';
+import { memo, ReactNode } from 'react';
import { getValueFormat, GrafanaTheme2 } from '@grafana/data';
import { Icon, IconButton, useStyles2 } from '@grafana/ui';
@@ -17,7 +17,7 @@ type Props = {
sandwichedLabel?: string;
};
-const FlameGraphMetadata = React.memo(
+const FlameGraphMetadata = memo(
({ data, focusedItem, totalTicks, sandwichedLabel, onFocusPillClick, onSandwichPillClick }: Props) => {
const styles = useStyles2(getStyles);
const parts: ReactNode[] = [];
diff --git a/packages/grafana-flamegraph/src/FlameGraph/FlameGraphTooltip.tsx b/packages/grafana-flamegraph/src/FlameGraph/FlameGraphTooltip.tsx
index 62f4a53343a..b9dca5a3a94 100644
--- a/packages/grafana-flamegraph/src/FlameGraph/FlameGraphTooltip.tsx
+++ b/packages/grafana-flamegraph/src/FlameGraph/FlameGraphTooltip.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { DisplayValue, getValueFormat, GrafanaTheme2 } from '@grafana/data';
import { InteractiveTable, Portal, useStyles2, VizTooltipContainer } from '@grafana/ui';
diff --git a/packages/grafana-flamegraph/src/FlameGraphContainer.test.tsx b/packages/grafana-flamegraph/src/FlameGraphContainer.test.tsx
index 12e1423f448..00d9e019e71 100644
--- a/packages/grafana-flamegraph/src/FlameGraphContainer.test.tsx
+++ b/packages/grafana-flamegraph/src/FlameGraphContainer.test.tsx
@@ -1,6 +1,6 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { useCallback } from 'react';
+import { useRef, useCallback } from 'react';
import { createDataFrame, createTheme } from '@grafana/data';
@@ -10,7 +10,7 @@ import { MIN_WIDTH_TO_SHOW_BOTH_TOPTABLE_AND_FLAMEGRAPH } from './constants';
jest.mock('react-use', () => ({
useMeasure: () => {
- const ref = React.useRef();
+ const ref = useRef();
return [ref, { width: 1600 }];
},
}));
diff --git a/packages/grafana-flamegraph/src/FlameGraphContainer.tsx b/packages/grafana-flamegraph/src/FlameGraphContainer.tsx
index e42fab741e4..d1ff3652e45 100644
--- a/packages/grafana-flamegraph/src/FlameGraphContainer.tsx
+++ b/packages/grafana-flamegraph/src/FlameGraphContainer.tsx
@@ -1,6 +1,7 @@
import { css } from '@emotion/css';
import uFuzzy from '@leeoniya/ufuzzy';
-import React, { useCallback, useEffect, useMemo, useState } from 'react';
+import { useCallback, useEffect, useMemo, useState } from 'react';
+import * as React from 'react';
import { useMeasure } from 'react-use';
import { DataFrame, GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-flamegraph/src/FlameGraphHeader.test.tsx b/packages/grafana-flamegraph/src/FlameGraphHeader.test.tsx
index 24da2445064..546450dad2b 100644
--- a/packages/grafana-flamegraph/src/FlameGraphHeader.test.tsx
+++ b/packages/grafana-flamegraph/src/FlameGraphHeader.test.tsx
@@ -1,7 +1,7 @@
import '@testing-library/jest-dom';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
+import * as React from 'react';
import { CollapsedMap } from './FlameGraph/dataTransform';
import FlameGraphHeader from './FlameGraphHeader';
diff --git a/packages/grafana-flamegraph/src/FlameGraphHeader.tsx b/packages/grafana-flamegraph/src/FlameGraphHeader.tsx
index a5f4f4c084b..8024dd68d8c 100644
--- a/packages/grafana-flamegraph/src/FlameGraphHeader.tsx
+++ b/packages/grafana-flamegraph/src/FlameGraphHeader.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
+import * as React from 'react';
import useDebounce from 'react-use/lib/useDebounce';
import usePrevious from 'react-use/lib/usePrevious';
diff --git a/packages/grafana-flamegraph/src/TopTable/FlameGraphTopTableContainer.test.tsx b/packages/grafana-flamegraph/src/TopTable/FlameGraphTopTableContainer.test.tsx
index 03d4ddb153b..0396e536535 100644
--- a/packages/grafana-flamegraph/src/TopTable/FlameGraphTopTableContainer.test.tsx
+++ b/packages/grafana-flamegraph/src/TopTable/FlameGraphTopTableContainer.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvents from '@testing-library/user-event';
-import React from 'react';
import { createDataFrame } from '@grafana/data';
diff --git a/packages/grafana-flamegraph/src/TopTable/FlameGraphTopTableContainer.tsx b/packages/grafana-flamegraph/src/TopTable/FlameGraphTopTableContainer.tsx
index 491230334f1..1ee3f172fa4 100644
--- a/packages/grafana-flamegraph/src/TopTable/FlameGraphTopTableContainer.tsx
+++ b/packages/grafana-flamegraph/src/TopTable/FlameGraphTopTableContainer.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo, useState } from 'react';
+import { memo, useMemo, useState } from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
import {
@@ -41,7 +41,7 @@ type Props = {
colorScheme: ColorScheme | ColorSchemeDiff;
};
-const FlameGraphTopTableContainer = React.memo(
+const FlameGraphTopTableContainer = memo(
({
data,
onSymbolClick,
diff --git a/packages/grafana-flamegraph/tsconfig.json b/packages/grafana-flamegraph/tsconfig.json
index 03aa83f469f..0092e86ac62 100644
--- a/packages/grafana-flamegraph/tsconfig.json
+++ b/packages/grafana-flamegraph/tsconfig.json
@@ -1,5 +1,6 @@
{
"compilerOptions": {
+ "jsx": "react-jsx",
"baseUrl": "./",
"declarationDir": "./compiled",
"emitDeclarationOnly": true,
diff --git a/packages/grafana-icons/src/IconBase.tsx b/packages/grafana-icons/src/IconBase.tsx
index 5c3983f0442..51b2d432d6c 100644
--- a/packages/grafana-icons/src/IconBase.tsx
+++ b/packages/grafana-icons/src/IconBase.tsx
@@ -1,4 +1,4 @@
-import React, { SVGProps } from 'react';
+import { SVGProps } from 'react';
export type IconSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl' | 'xxxl';
diff --git a/packages/grafana-icons/templates/icon.cjs b/packages/grafana-icons/templates/icon.cjs
index ec784905a7b..5fd12b10508 100644
--- a/packages/grafana-icons/templates/icon.cjs
+++ b/packages/grafana-icons/templates/icon.cjs
@@ -26,7 +26,7 @@ const comments = `
// Run "yarn generate" to update.
`;
const imports = `
-import React, { memo } from 'react';
+import { memo } from 'react';
import { IconBase, IconProps } from '../IconBase';
`;
diff --git a/packages/grafana-icons/tsconfig.json b/packages/grafana-icons/tsconfig.json
index 06210e1a227..bf218cdd730 100644
--- a/packages/grafana-icons/tsconfig.json
+++ b/packages/grafana-icons/tsconfig.json
@@ -1,5 +1,6 @@
{
"compilerOptions": {
+ "jsx": "react-jsx",
"baseUrl": "./",
"declarationDir": "./compiled",
"emitDeclarationOnly": true,
@@ -9,5 +10,5 @@
},
"exclude": ["dist/**/*"],
"extends": "@grafana/tsconfig",
- "include": ["src/**/*.ts"]
+ "include": ["src/**/*.tsx"]
}
diff --git a/packages/grafana-o11y-ds-frontend/src/IntervalInput/IntervalInput.test.tsx b/packages/grafana-o11y-ds-frontend/src/IntervalInput/IntervalInput.test.tsx
index ed3464bfd6d..e5d45c8449c 100644
--- a/packages/grafana-o11y-ds-frontend/src/IntervalInput/IntervalInput.test.tsx
+++ b/packages/grafana-o11y-ds-frontend/src/IntervalInput/IntervalInput.test.tsx
@@ -1,6 +1,6 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { invalidTimeShiftError } from '../TraceToLogs/TraceToLogsSettings';
diff --git a/packages/grafana-o11y-ds-frontend/src/IntervalInput/IntervalInput.tsx b/packages/grafana-o11y-ds-frontend/src/IntervalInput/IntervalInput.tsx
index 692845a3cdd..2b29cbea1de 100644
--- a/packages/grafana-o11y-ds-frontend/src/IntervalInput/IntervalInput.tsx
+++ b/packages/grafana-o11y-ds-frontend/src/IntervalInput/IntervalInput.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { useDebounce } from 'react-use';
import { InlineField, Input } from '@grafana/ui';
diff --git a/packages/grafana-o11y-ds-frontend/src/NodeGraph/NodeGraphSettings.tsx b/packages/grafana-o11y-ds-frontend/src/NodeGraph/NodeGraphSettings.tsx
index 6544b333869..8b6f3c5f4b6 100644
--- a/packages/grafana-o11y-ds-frontend/src/NodeGraph/NodeGraphSettings.tsx
+++ b/packages/grafana-o11y-ds-frontend/src/NodeGraph/NodeGraphSettings.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import {
DataSourceJsonData,
diff --git a/packages/grafana-o11y-ds-frontend/src/SpanBar/SpanBarSettings.tsx b/packages/grafana-o11y-ds-frontend/src/SpanBar/SpanBarSettings.tsx
index 81780446edd..a612dee380d 100644
--- a/packages/grafana-o11y-ds-frontend/src/SpanBar/SpanBarSettings.tsx
+++ b/packages/grafana-o11y-ds-frontend/src/SpanBar/SpanBarSettings.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import {
DataSourceJsonData,
diff --git a/packages/grafana-o11y-ds-frontend/src/TemporaryAlert.test.tsx b/packages/grafana-o11y-ds-frontend/src/TemporaryAlert.test.tsx
index c8ae7b1c1a4..62446153546 100644
--- a/packages/grafana-o11y-ds-frontend/src/TemporaryAlert.test.tsx
+++ b/packages/grafana-o11y-ds-frontend/src/TemporaryAlert.test.tsx
@@ -1,5 +1,4 @@
import { act, render, screen } from '@testing-library/react';
-import React from 'react';
import { TemporaryAlert } from './TemporaryAlert';
diff --git a/packages/grafana-o11y-ds-frontend/src/TemporaryAlert.tsx b/packages/grafana-o11y-ds-frontend/src/TemporaryAlert.tsx
index 8a7003a576c..a63acc9a2a8 100644
--- a/packages/grafana-o11y-ds-frontend/src/TemporaryAlert.tsx
+++ b/packages/grafana-o11y-ds-frontend/src/TemporaryAlert.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Alert, AlertVariant, useTheme2 } from '@grafana/ui';
diff --git a/packages/grafana-o11y-ds-frontend/src/TraceToLogs/TagMappingInput.tsx b/packages/grafana-o11y-ds-frontend/src/TraceToLogs/TagMappingInput.tsx
index d263682a92f..355f8085a37 100644
--- a/packages/grafana-o11y-ds-frontend/src/TraceToLogs/TagMappingInput.tsx
+++ b/packages/grafana-o11y-ds-frontend/src/TraceToLogs/TagMappingInput.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { InlineLabel, SegmentInput, ToolbarButton, useStyles2 } from '@grafana/ui';
diff --git a/packages/grafana-o11y-ds-frontend/src/TraceToLogs/TraceToLogsSettings.test.tsx b/packages/grafana-o11y-ds-frontend/src/TraceToLogs/TraceToLogsSettings.test.tsx
index d3b5fb8254d..3297f2571bf 100644
--- a/packages/grafana-o11y-ds-frontend/src/TraceToLogs/TraceToLogsSettings.test.tsx
+++ b/packages/grafana-o11y-ds-frontend/src/TraceToLogs/TraceToLogsSettings.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { DataSourceInstanceSettings, DataSourceSettings } from '@grafana/data';
import { DataSourceSrv, setDataSourceSrv } from '@grafana/runtime';
diff --git a/packages/grafana-o11y-ds-frontend/src/TraceToLogs/TraceToLogsSettings.tsx b/packages/grafana-o11y-ds-frontend/src/TraceToLogs/TraceToLogsSettings.tsx
index bc290883d65..9af49fd9ae5 100644
--- a/packages/grafana-o11y-ds-frontend/src/TraceToLogs/TraceToLogsSettings.tsx
+++ b/packages/grafana-o11y-ds-frontend/src/TraceToLogs/TraceToLogsSettings.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useCallback, useMemo } from 'react';
+import { useCallback, useMemo } from 'react';
+import * as React from 'react';
import { DataSourceJsonData, DataSourceInstanceSettings, DataSourcePluginOptionsEditorProps } from '@grafana/data';
import { ConfigDescriptionLink, ConfigSection } from '@grafana/experimental';
diff --git a/packages/grafana-o11y-ds-frontend/src/TraceToMetrics/TraceToMetricsSettings.tsx b/packages/grafana-o11y-ds-frontend/src/TraceToMetrics/TraceToMetricsSettings.tsx
index 90249d4dd3f..26359c41cba 100644
--- a/packages/grafana-o11y-ds-frontend/src/TraceToMetrics/TraceToMetricsSettings.tsx
+++ b/packages/grafana-o11y-ds-frontend/src/TraceToMetrics/TraceToMetricsSettings.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import {
DataSourceInstanceSettings,
diff --git a/packages/grafana-o11y-ds-frontend/src/TraceToProfiles/TraceToProfilesSettings.test.tsx b/packages/grafana-o11y-ds-frontend/src/TraceToProfiles/TraceToProfilesSettings.test.tsx
index 0cf648def33..2956ae12393 100644
--- a/packages/grafana-o11y-ds-frontend/src/TraceToProfiles/TraceToProfilesSettings.test.tsx
+++ b/packages/grafana-o11y-ds-frontend/src/TraceToProfiles/TraceToProfilesSettings.test.tsx
@@ -1,5 +1,4 @@
import { render, screen, waitFor } from '@testing-library/react';
-import React from 'react';
import { DataSourceInstanceSettings, DataSourceSettings } from '@grafana/data';
import { DataSourceSrv, setDataSourceSrv } from '@grafana/runtime';
diff --git a/packages/grafana-o11y-ds-frontend/src/TraceToProfiles/TraceToProfilesSettings.tsx b/packages/grafana-o11y-ds-frontend/src/TraceToProfiles/TraceToProfilesSettings.tsx
index ebabc60dd01..ef51352916b 100644
--- a/packages/grafana-o11y-ds-frontend/src/TraceToProfiles/TraceToProfilesSettings.tsx
+++ b/packages/grafana-o11y-ds-frontend/src/TraceToProfiles/TraceToProfilesSettings.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useEffect, useMemo, useState } from 'react';
+import { useEffect, useMemo, useState } from 'react';
+import * as React from 'react';
import { useAsync } from 'react-use';
import {
diff --git a/packages/grafana-o11y-ds-frontend/src/pyroscope/ProfileTypesCascader.tsx b/packages/grafana-o11y-ds-frontend/src/pyroscope/ProfileTypesCascader.tsx
index da34d4c1919..b95b24abae7 100644
--- a/packages/grafana-o11y-ds-frontend/src/pyroscope/ProfileTypesCascader.tsx
+++ b/packages/grafana-o11y-ds-frontend/src/pyroscope/ProfileTypesCascader.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useMemo, useState } from 'react';
+import { useEffect, useMemo, useState } from 'react';
import { Cascader, CascaderOption } from '@grafana/ui';
diff --git a/packages/grafana-o11y-ds-frontend/tsconfig.json b/packages/grafana-o11y-ds-frontend/tsconfig.json
index 03aa83f469f..0092e86ac62 100644
--- a/packages/grafana-o11y-ds-frontend/tsconfig.json
+++ b/packages/grafana-o11y-ds-frontend/tsconfig.json
@@ -1,5 +1,6 @@
{
"compilerOptions": {
+ "jsx": "react-jsx",
"baseUrl": "./",
"declarationDir": "./compiled",
"emitDeclarationOnly": true,
diff --git a/packages/grafana-plugin-configs/tsconfig.json b/packages/grafana-plugin-configs/tsconfig.json
index 5fa5336e958..81e50af6c47 100644
--- a/packages/grafana-plugin-configs/tsconfig.json
+++ b/packages/grafana-plugin-configs/tsconfig.json
@@ -1,5 +1,6 @@
{
"compilerOptions": {
+ "jsx": "react-jsx",
"alwaysStrict": true,
"declaration": false,
"resolveJsonModule": true
diff --git a/packages/grafana-plugin-configs/webpack.config.ts b/packages/grafana-plugin-configs/webpack.config.ts
index 0f851707350..e3b5bd097bb 100644
--- a/packages/grafana-plugin-configs/webpack.config.ts
+++ b/packages/grafana-plugin-configs/webpack.config.ts
@@ -100,6 +100,11 @@ const config = async (env: Record): Promise => {
decorators: false,
dynamicImport: true,
},
+ transform: {
+ react: {
+ runtime: 'automatic',
+ },
+ },
},
},
},
diff --git a/packages/grafana-prometheus/src/components/AnnotationQueryEditor.tsx b/packages/grafana-prometheus/src/components/AnnotationQueryEditor.tsx
index 2c22905e99e..04a50e72f10 100644
--- a/packages/grafana-prometheus/src/components/AnnotationQueryEditor.tsx
+++ b/packages/grafana-prometheus/src/components/AnnotationQueryEditor.tsx
@@ -1,6 +1,4 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/AnnotationQueryEditor.tsx
-import React from 'react';
-
import { AnnotationQuery } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { EditorField, EditorRow, EditorRows, EditorSwitch } from '@grafana/experimental';
diff --git a/packages/grafana-prometheus/src/components/PromCheatSheet.tsx b/packages/grafana-prometheus/src/components/PromCheatSheet.tsx
index 4e452244cce..eafa5a3b61a 100644
--- a/packages/grafana-prometheus/src/components/PromCheatSheet.tsx
+++ b/packages/grafana-prometheus/src/components/PromCheatSheet.tsx
@@ -1,6 +1,5 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/PromCheatSheet.tsx
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2, QueryEditorHelpProps } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/packages/grafana-prometheus/src/components/PromExemplarField.tsx b/packages/grafana-prometheus/src/components/PromExemplarField.tsx
index 2431d37cf63..2e1f0272965 100644
--- a/packages/grafana-prometheus/src/components/PromExemplarField.tsx
+++ b/packages/grafana-prometheus/src/components/PromExemplarField.tsx
@@ -1,6 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/PromExemplarField.tsx
import { css, cx } from '@emotion/css';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { usePrevious } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-prometheus/src/components/PromExploreExtraField.test.tsx b/packages/grafana-prometheus/src/components/PromExploreExtraField.test.tsx
index 75cc778f7f0..b02e9b7f0e3 100644
--- a/packages/grafana-prometheus/src/components/PromExploreExtraField.test.tsx
+++ b/packages/grafana-prometheus/src/components/PromExploreExtraField.test.tsx
@@ -1,6 +1,5 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/PromExploreExtraField.test.tsx
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { PrometheusDatasource } from '../datasource';
import { PromQuery } from '../types';
diff --git a/packages/grafana-prometheus/src/components/PromExploreExtraField.tsx b/packages/grafana-prometheus/src/components/PromExploreExtraField.tsx
index bbff06629c5..02ef6d4d461 100644
--- a/packages/grafana-prometheus/src/components/PromExploreExtraField.tsx
+++ b/packages/grafana-prometheus/src/components/PromExploreExtraField.tsx
@@ -1,7 +1,8 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/PromExploreExtraField.tsx
import { css, cx } from '@emotion/css';
import { isEqual } from 'lodash';
-import React, { memo, useCallback } from 'react';
+import { memo, useCallback } from 'react';
+import * as React from 'react';
import { usePrevious } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-prometheus/src/components/PromQueryEditorByApp.test.tsx b/packages/grafana-prometheus/src/components/PromQueryEditorByApp.test.tsx
index 6626eaccbab..798bf833421 100644
--- a/packages/grafana-prometheus/src/components/PromQueryEditorByApp.test.tsx
+++ b/packages/grafana-prometheus/src/components/PromQueryEditorByApp.test.tsx
@@ -1,7 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/PromQueryEditorByApp.test.tsx
import { render, screen } from '@testing-library/react';
import { noop } from 'lodash';
-import React from 'react';
import { CoreApp } from '@grafana/data';
diff --git a/packages/grafana-prometheus/src/components/PromQueryEditorByApp.tsx b/packages/grafana-prometheus/src/components/PromQueryEditorByApp.tsx
index 82b095322bf..471f8dd4eb3 100644
--- a/packages/grafana-prometheus/src/components/PromQueryEditorByApp.tsx
+++ b/packages/grafana-prometheus/src/components/PromQueryEditorByApp.tsx
@@ -1,5 +1,5 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/PromQueryEditorByApp.tsx
-import React, { memo } from 'react';
+import { memo } from 'react';
import { CoreApp } from '@grafana/data';
diff --git a/packages/grafana-prometheus/src/components/PromQueryEditorForAlerting.tsx b/packages/grafana-prometheus/src/components/PromQueryEditorForAlerting.tsx
index 5f5f2da7bfc..df7f0b9b946 100644
--- a/packages/grafana-prometheus/src/components/PromQueryEditorForAlerting.tsx
+++ b/packages/grafana-prometheus/src/components/PromQueryEditorForAlerting.tsx
@@ -1,6 +1,4 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/PromQueryEditorForAlerting.tsx
-import React from 'react';
-
import { PromQueryField } from './PromQueryField';
import { PromQueryEditorProps } from './types';
diff --git a/packages/grafana-prometheus/src/components/PromQueryField.test.tsx b/packages/grafana-prometheus/src/components/PromQueryField.test.tsx
index 46c56efc381..36ffb5556e6 100644
--- a/packages/grafana-prometheus/src/components/PromQueryField.test.tsx
+++ b/packages/grafana-prometheus/src/components/PromQueryField.test.tsx
@@ -2,7 +2,6 @@
import { getByTestId, render, screen, waitFor } from '@testing-library/react';
// @ts-ignore
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { CoreApp, DataFrame, LoadingState, PanelData } from '@grafana/data';
diff --git a/packages/grafana-prometheus/src/components/PromQueryField.tsx b/packages/grafana-prometheus/src/components/PromQueryField.tsx
index e4a83498aad..de9ec25c83d 100644
--- a/packages/grafana-prometheus/src/components/PromQueryField.tsx
+++ b/packages/grafana-prometheus/src/components/PromQueryField.tsx
@@ -1,6 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/PromQueryField.tsx
import { css, cx } from '@emotion/css';
-import React, { ReactNode } from 'react';
+import { PureComponent, ReactNode } from 'react';
import { isDataFrame, QueryEditorProps, QueryHint, TimeRange, toLegacyResponseData } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
@@ -49,7 +49,7 @@ interface PromQueryFieldState {
hint: QueryHint | null;
}
-class PromQueryFieldClass extends React.PureComponent {
+class PromQueryFieldClass extends PureComponent {
declare languageProviderInitializationPromise: CancelablePromise;
constructor(props: PromQueryFieldProps) {
diff --git a/packages/grafana-prometheus/src/components/PrometheusMetricsBrowser.test.tsx b/packages/grafana-prometheus/src/components/PrometheusMetricsBrowser.test.tsx
index 393a15b3d00..58efb0e28f0 100644
--- a/packages/grafana-prometheus/src/components/PrometheusMetricsBrowser.test.tsx
+++ b/packages/grafana-prometheus/src/components/PrometheusMetricsBrowser.test.tsx
@@ -1,7 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/PrometheusMetricsBrowser.test.tsx
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { createTheme } from '@grafana/data';
diff --git a/packages/grafana-prometheus/src/components/PrometheusMetricsBrowser.tsx b/packages/grafana-prometheus/src/components/PrometheusMetricsBrowser.tsx
index 6d19dfbbe86..924e1067544 100644
--- a/packages/grafana-prometheus/src/components/PrometheusMetricsBrowser.tsx
+++ b/packages/grafana-prometheus/src/components/PrometheusMetricsBrowser.tsx
@@ -1,6 +1,7 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/PrometheusMetricsBrowser.tsx
import { css, cx } from '@emotion/css';
-import React, { ChangeEvent } from 'react';
+import { ChangeEvent } from 'react';
+import * as React from 'react';
import { FixedSizeList } from 'react-window';
import { GrafanaTheme2, TimeRange } from '@grafana/data';
@@ -8,7 +9,7 @@ import { selectors } from '@grafana/e2e-selectors';
import {
BrowserLabel as PromLabel,
Button,
- HorizontalGroup,
+ Stack,
Input,
Label,
LoadingPlaceholder,
@@ -488,7 +489,7 @@ export class UnthemedPrometheusMetricsBrowser extends React.Component
-
+
1. Select a metric
@@ -631,7 +632,7 @@ export class UnthemedPrometheusMetricsBrowser extends React.Component
-
+
4. Resulting selector
@@ -639,7 +640,7 @@ export class UnthemedPrometheusMetricsBrowser extends React.Component
{validationStatus && {validationStatus}
}
-
+
{error || status}
-
+
);
diff --git a/packages/grafana-prometheus/src/components/VariableQueryEditor.test.tsx b/packages/grafana-prometheus/src/components/VariableQueryEditor.test.tsx
index 70fc36a5173..749416c5e14 100644
--- a/packages/grafana-prometheus/src/components/VariableQueryEditor.test.tsx
+++ b/packages/grafana-prometheus/src/components/VariableQueryEditor.test.tsx
@@ -1,7 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/VariableQueryEditor.test.tsx
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { dateTime, TimeRange } from '@grafana/data';
diff --git a/packages/grafana-prometheus/src/components/VariableQueryEditor.tsx b/packages/grafana-prometheus/src/components/VariableQueryEditor.tsx
index b89590eabcd..ad6a2c5386b 100644
--- a/packages/grafana-prometheus/src/components/VariableQueryEditor.tsx
+++ b/packages/grafana-prometheus/src/components/VariableQueryEditor.tsx
@@ -1,5 +1,5 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/VariableQueryEditor.tsx
-import React, { FormEvent, useCallback, useEffect, useState } from 'react';
+import { FormEvent, useCallback, useEffect, useState } from 'react';
import { QueryEditorProps, SelectableValue } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryField.tsx b/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryField.tsx
index 123b668edcc..5115c6880d1 100644
--- a/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryField.tsx
+++ b/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryField.tsx
@@ -3,7 +3,7 @@ import { css } from '@emotion/css';
import { parser } from '@prometheus-io/lezer-promql';
import { debounce } from 'lodash';
import { promLanguageDefinition } from 'monaco-promql';
-import React, { useEffect, useRef } from 'react';
+import { useEffect, useRef } from 'react';
import { useLatest } from 'react-use';
import { v4 as uuidv4 } from 'uuid';
diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryFieldLazy.tsx b/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryFieldLazy.tsx
index ea2fb3576e9..53aad0b3047 100644
--- a/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryFieldLazy.tsx
+++ b/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryFieldLazy.tsx
@@ -1,5 +1,5 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/monaco-query-field/MonacoQueryFieldLazy.tsx
-import React, { Suspense } from 'react';
+import { Suspense } from 'react';
import MonacoQueryField from './MonacoQueryField';
import { Props } from './MonacoQueryFieldProps';
diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryFieldWrapper.tsx b/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryFieldWrapper.tsx
index 2fafe41a1cc..c95e8341b92 100644
--- a/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryFieldWrapper.tsx
+++ b/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryFieldWrapper.tsx
@@ -1,5 +1,5 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/monaco-query-field/MonacoQueryFieldWrapper.tsx
-import React, { useRef } from 'react';
+import { useRef } from 'react';
import { MonacoQueryFieldLazy } from './MonacoQueryFieldLazy';
import { Props as MonacoProps } from './MonacoQueryFieldProps';
diff --git a/packages/grafana-prometheus/src/configuration/AlertingSettingsOverhaul.tsx b/packages/grafana-prometheus/src/configuration/AlertingSettingsOverhaul.tsx
index 4cd5a13b85a..feea1322c69 100644
--- a/packages/grafana-prometheus/src/configuration/AlertingSettingsOverhaul.tsx
+++ b/packages/grafana-prometheus/src/configuration/AlertingSettingsOverhaul.tsx
@@ -1,6 +1,5 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/configuration/AlertingSettingsOverhaul.tsx
import { cx } from '@emotion/css';
-import React from 'react';
import { DataSourceJsonData, DataSourcePluginOptionsEditorProps } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-prometheus/src/configuration/ConfigEditor.test.tsx b/packages/grafana-prometheus/src/configuration/ConfigEditor.test.tsx
index 12878c69435..ed3c92afe4e 100644
--- a/packages/grafana-prometheus/src/configuration/ConfigEditor.test.tsx
+++ b/packages/grafana-prometheus/src/configuration/ConfigEditor.test.tsx
@@ -1,6 +1,4 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/configuration/ConfigEditor.test.tsx
-import React from 'react';
-
import { FieldValidationMessage } from '@grafana/ui';
import { validateInput } from './ConfigEditor';
diff --git a/packages/grafana-prometheus/src/configuration/ConfigEditor.tsx b/packages/grafana-prometheus/src/configuration/ConfigEditor.tsx
index b5818b34b12..534db5f1e2d 100644
--- a/packages/grafana-prometheus/src/configuration/ConfigEditor.tsx
+++ b/packages/grafana-prometheus/src/configuration/ConfigEditor.tsx
@@ -1,6 +1,5 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/configuration/ConfigEditor.tsx
import { css } from '@emotion/css';
-import React from 'react';
import { DataSourcePluginOptionsEditorProps, GrafanaTheme2 } from '@grafana/data';
import { ConfigSection, DataSourceDescription, AdvancedHttpSettings } from '@grafana/experimental';
diff --git a/packages/grafana-prometheus/src/configuration/DataSourceHttpSettingsOverhaul.tsx b/packages/grafana-prometheus/src/configuration/DataSourceHttpSettingsOverhaul.tsx
index 035e513c6a3..04c77dfe854 100644
--- a/packages/grafana-prometheus/src/configuration/DataSourceHttpSettingsOverhaul.tsx
+++ b/packages/grafana-prometheus/src/configuration/DataSourceHttpSettingsOverhaul.tsx
@@ -1,6 +1,4 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/configuration/DataSourceHttpSettingsOverhaul.tsx
-import React from 'react';
-
import { DataSourceSettings } from '@grafana/data';
import { Auth, AuthMethod, ConnectionSettings, convertLegacyAuthProps } from '@grafana/experimental';
import { SecureSocksProxySettings, useTheme2 } from '@grafana/ui';
diff --git a/packages/grafana-prometheus/src/configuration/ExemplarSetting.tsx b/packages/grafana-prometheus/src/configuration/ExemplarSetting.tsx
index cc2f94b1251..1323077dd6f 100644
--- a/packages/grafana-prometheus/src/configuration/ExemplarSetting.tsx
+++ b/packages/grafana-prometheus/src/configuration/ExemplarSetting.tsx
@@ -1,5 +1,5 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/configuration/ExemplarSetting.tsx
-import React, { useState } from 'react';
+import { useState } from 'react';
import { DataSourceInstanceSettings } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-prometheus/src/configuration/ExemplarsSettings.tsx b/packages/grafana-prometheus/src/configuration/ExemplarsSettings.tsx
index b0868370695..dc82d80984f 100644
--- a/packages/grafana-prometheus/src/configuration/ExemplarsSettings.tsx
+++ b/packages/grafana-prometheus/src/configuration/ExemplarsSettings.tsx
@@ -1,6 +1,5 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/configuration/ExemplarsSettings.tsx
import { css } from '@emotion/css';
-import React from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { ConfigSubSection } from '@grafana/experimental';
diff --git a/packages/grafana-prometheus/src/configuration/PromSettings.test.tsx b/packages/grafana-prometheus/src/configuration/PromSettings.test.tsx
index 2deae5f94dd..8d90f39084f 100644
--- a/packages/grafana-prometheus/src/configuration/PromSettings.test.tsx
+++ b/packages/grafana-prometheus/src/configuration/PromSettings.test.tsx
@@ -1,6 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/configuration/PromSettings.test.tsx
import { render, screen, fireEvent } from '@testing-library/react';
-import React, { SyntheticEvent } from 'react';
+import { SyntheticEvent } from 'react';
import { SelectableValue } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-prometheus/src/configuration/PromSettings.tsx b/packages/grafana-prometheus/src/configuration/PromSettings.tsx
index 5e41aaac5e9..c08273b4ff7 100644
--- a/packages/grafana-prometheus/src/configuration/PromSettings.tsx
+++ b/packages/grafana-prometheus/src/configuration/PromSettings.tsx
@@ -1,5 +1,5 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/configuration/PromSettings.tsx
-import React, { SyntheticEvent, useState } from 'react';
+import { SyntheticEvent, useState } from 'react';
import {
DataSourcePluginOptionsEditorProps,
diff --git a/packages/grafana-prometheus/src/gcopypaste/app/core/components/LocalStorageValueProvider/LocalStorageValueProvider.tsx b/packages/grafana-prometheus/src/gcopypaste/app/core/components/LocalStorageValueProvider/LocalStorageValueProvider.tsx
index c71e11ec749..903a6b94b53 100644
--- a/packages/grafana-prometheus/src/gcopypaste/app/core/components/LocalStorageValueProvider/LocalStorageValueProvider.tsx
+++ b/packages/grafana-prometheus/src/gcopypaste/app/core/components/LocalStorageValueProvider/LocalStorageValueProvider.tsx
@@ -1,5 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/core/components/LocalStorageValueProvider/LocalStorageValueProvider.tsx
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
+import * as React from 'react';
import store from '../../store';
diff --git a/packages/grafana-prometheus/src/gcopypaste/packages/grafana-ui/src/components/Select/SelectBase.tsx b/packages/grafana-prometheus/src/gcopypaste/packages/grafana-ui/src/components/Select/SelectBase.tsx
index 06ae7ee04fb..8ee9578e5c2 100644
--- a/packages/grafana-prometheus/src/gcopypaste/packages/grafana-ui/src/components/Select/SelectBase.tsx
+++ b/packages/grafana-prometheus/src/gcopypaste/packages/grafana-ui/src/components/Select/SelectBase.tsx
@@ -1,7 +1,8 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/packages/grafana-ui/src/components/Select/SelectBase.tsx
import { cx } from '@emotion/css';
import { max } from 'lodash';
-import React, { RefCallback } from 'react';
+import { RefCallback } from 'react';
+import * as React from 'react';
import { MenuListProps } from 'react-select';
import { FixedSizeList as List } from 'react-window';
diff --git a/packages/grafana-prometheus/src/querybuilder/QueryPattern.tsx b/packages/grafana-prometheus/src/querybuilder/QueryPattern.tsx
index 5f4507f1cd4..e1381b2d554 100644
--- a/packages/grafana-prometheus/src/querybuilder/QueryPattern.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/QueryPattern.tsx
@@ -1,6 +1,5 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/QueryPattern.tsx
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Button, Card, useStyles2 } from '@grafana/ui';
diff --git a/packages/grafana-prometheus/src/querybuilder/QueryPatternsModal.test.tsx b/packages/grafana-prometheus/src/querybuilder/QueryPatternsModal.test.tsx
index 8cc19b9cbe9..1e3a8dec1fc 100644
--- a/packages/grafana-prometheus/src/querybuilder/QueryPatternsModal.test.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/QueryPatternsModal.test.tsx
@@ -1,7 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/QueryPatternsModal.test.tsx
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { promQueryModeller } from './PromQueryModeller';
import { QueryPatternsModal } from './QueryPatternsModal';
diff --git a/packages/grafana-prometheus/src/querybuilder/QueryPatternsModal.tsx b/packages/grafana-prometheus/src/querybuilder/QueryPatternsModal.tsx
index ce54fb149df..1fb721fdfad 100644
--- a/packages/grafana-prometheus/src/querybuilder/QueryPatternsModal.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/QueryPatternsModal.tsx
@@ -1,7 +1,7 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/QueryPatternsModal.tsx
import { css } from '@emotion/css';
import { capitalize } from 'lodash';
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
import { CoreApp, DataQuery, GrafanaTheme2 } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/LabelFilterItem.tsx b/packages/grafana-prometheus/src/querybuilder/components/LabelFilterItem.tsx
index b5ef8a62848..cd8bcb54cb4 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/LabelFilterItem.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/LabelFilterItem.tsx
@@ -1,6 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/LabelFilterItem.tsx
import debounce from 'debounce-promise';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { SelectableValue, toOption } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/LabelFilters.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/LabelFilters.test.tsx
index b94a1b04b0a..55151ae2800 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/LabelFilters.test.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/LabelFilters.test.tsx
@@ -1,7 +1,7 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/LabelFilters.test.tsx
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { ComponentProps } from 'react';
+import { ComponentProps } from 'react';
import { selectOptionInTest } from '../../gcopypaste/test/helpers/selectOptionInTest';
import { getLabelSelects } from '../testUtils';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/LabelFilters.tsx b/packages/grafana-prometheus/src/querybuilder/components/LabelFilters.tsx
index 1bb5e393593..45b0b9866eb 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/LabelFilters.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/LabelFilters.tsx
@@ -1,7 +1,7 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/LabelFilters.tsx
import { css, cx } from '@emotion/css';
import { isEqual } from 'lodash';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { SelectableValue } from '@grafana/data';
import { EditorField, EditorFieldGroup, EditorList } from '@grafana/experimental';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/LabelParamEditor.tsx b/packages/grafana-prometheus/src/querybuilder/components/LabelParamEditor.tsx
index 0c1c4a8e35c..e1049d18752 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/LabelParamEditor.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/LabelParamEditor.tsx
@@ -1,5 +1,5 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/LabelParamEditor.tsx
-import React, { useState } from 'react';
+import { useState } from 'react';
import { DataSourceApi, SelectableValue, toOption } from '@grafana/data';
import { Select } from '@grafana/ui';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/MetricSelect.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/MetricSelect.test.tsx
index d21e7ce27f1..e6e9c5e9946 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/MetricSelect.test.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/MetricSelect.test.tsx
@@ -1,7 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/MetricSelect.test.tsx
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { DataSourceInstanceSettings, MetricFindValue } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/MetricSelect.tsx b/packages/grafana-prometheus/src/querybuilder/components/MetricSelect.tsx
index 244c935c06d..95301e8075f 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/MetricSelect.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/MetricSelect.tsx
@@ -1,7 +1,8 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/MetricSelect.tsx
import { css } from '@emotion/css';
import debounce from 'debounce-promise';
-import React, { RefCallback, useCallback, useState } from 'react';
+import { RefCallback, useCallback, useState } from 'react';
+import * as React from 'react';
import Highlighter from 'react-highlight-words';
import { GrafanaTheme2, SelectableValue, toOption } from '@grafana/data';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/MetricsLabelsSection.tsx b/packages/grafana-prometheus/src/querybuilder/components/MetricsLabelsSection.tsx
index 6d25c74377d..ce91d04bbdb 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/MetricsLabelsSection.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/MetricsLabelsSection.tsx
@@ -1,5 +1,5 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/MetricsLabelsSection.tsx
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { SelectableValue } from '@grafana/data';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/NestedQuery.tsx b/packages/grafana-prometheus/src/querybuilder/components/NestedQuery.tsx
index efdffc73023..6c27f0fa1e3 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/NestedQuery.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/NestedQuery.tsx
@@ -1,6 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/NestedQuery.tsx
import { css } from '@emotion/css';
-import React from 'react';
+import { memo } from 'react';
import { GrafanaTheme2, toOption } from '@grafana/data';
import { EditorRows, FlexItem } from '@grafana/experimental';
@@ -22,7 +22,7 @@ export interface NestedQueryProps {
showExplain: boolean;
}
-export const NestedQuery = React.memo((props) => {
+export const NestedQuery = memo((props) => {
const { nestedQuery, index, datasource, onChange, onRemove, onRunQuery, showExplain } = props;
const styles = useStyles2(getStyles);
diff --git a/packages/grafana-prometheus/src/querybuilder/components/NestedQueryList.tsx b/packages/grafana-prometheus/src/querybuilder/components/NestedQueryList.tsx
index 7d36bec9919..f0aca4ae1fd 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/NestedQueryList.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/NestedQueryList.tsx
@@ -1,6 +1,4 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/NestedQueryList.tsx
-import React from 'react';
-
import { Stack } from '@grafana/ui';
import { PrometheusDatasource } from '../../datasource';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilder.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilder.test.tsx
index d5da0babb73..db74ff98655 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilder.test.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilder.test.tsx
@@ -1,7 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilder.test.tsx
import { getByText, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import {
DataSourceInstanceSettings,
diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilder.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilder.tsx
index f2c1abb531d..a1d450b2452 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilder.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilder.tsx
@@ -1,6 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilder.tsx
import { css } from '@emotion/css';
-import React, { useEffect, useState } from 'react';
+import { memo, useEffect, useState } from 'react';
import { DataSourceApi, PanelData } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
@@ -37,7 +37,7 @@ export interface PromQueryBuilderProps {
showExplain: boolean;
}
-export const PromQueryBuilder = React.memo((props) => {
+export const PromQueryBuilder = memo((props) => {
const { datasource, query, onChange, onRunQuery, data, showExplain } = props;
const [highlightedOp, setHighlightedOp] = useState();
const [showDrawer, setShowDrawer] = useState(false);
diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderContainer.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderContainer.test.tsx
index 34012591019..efe436a4f2c 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderContainer.test.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderContainer.test.tsx
@@ -1,7 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderContainer.test.tsx
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { DataSourceInstanceSettings, DataSourcePluginMeta } from '@grafana/data';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderContainer.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderContainer.tsx
index a960fc3a58e..2b1c05e52a0 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderContainer.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderContainer.tsx
@@ -1,6 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderContainer.tsx
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
-import React, { useEffect, useReducer } from 'react';
+import { useEffect, useReducer } from 'react';
import { PanelData } from '@grafana/data';
import { config } from '@grafana/runtime';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderExplained.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderExplained.tsx
index c3de6c3808e..4fa9503c34e 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderExplained.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderExplained.tsx
@@ -1,5 +1,5 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderExplained.tsx
-import React from 'react';
+import { memo } from 'react';
import { Stack } from '@grafana/ui';
@@ -17,7 +17,7 @@ export interface PromQueryBuilderExplainedProps {
query: string;
}
-export const PromQueryBuilderExplained = React.memo(({ query }) => {
+export const PromQueryBuilderExplained = memo(({ query }) => {
const visQuery = buildVisualQueryFromString(query || '').query;
const lang = { grammar: promqlGrammar, name: 'promql' };
diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderOptions.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderOptions.test.tsx
index 9b9531a28ed..b6654dadafb 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderOptions.test.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderOptions.test.tsx
@@ -1,7 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderOptions.test.tsx
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { CoreApp } from '@grafana/data';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderOptions.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderOptions.tsx
index 7a554d9be45..60c73709c68 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderOptions.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderOptions.tsx
@@ -1,5 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderOptions.tsx
-import React, { SyntheticEvent } from 'react';
+import { SyntheticEvent } from 'react';
+import * as React from 'react';
import { CoreApp, SelectableValue } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryCodeEditor.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryCodeEditor.test.tsx
index c907e604576..5aa9ba645dc 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryCodeEditor.test.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryCodeEditor.test.tsx
@@ -1,6 +1,5 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryCodeEditor.test.tsx
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { DataSourceInstanceSettings, DataSourcePluginMeta } from '@grafana/data';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryCodeEditor.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryCodeEditor.tsx
index a972a2e435c..0942b93ff88 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryCodeEditor.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryCodeEditor.tsx
@@ -1,6 +1,5 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryCodeEditor.tsx
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryCodeEditorAutocompleteInfo.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryCodeEditorAutocompleteInfo.test.tsx
index 2cc33275317..42ae5cb2284 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryCodeEditorAutocompleteInfo.test.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryCodeEditorAutocompleteInfo.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, fireEvent, createEvent } from '@testing-library/react';
import { cloneDeep, defaultsDeep } from 'lodash';
-import React from 'react';
import { PluginMeta, PluginType } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryCodeEditorAutocompleteInfo.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryCodeEditorAutocompleteInfo.tsx
index d64c77c946e..fb0707a3dfa 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryCodeEditorAutocompleteInfo.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryCodeEditorAutocompleteInfo.tsx
@@ -1,4 +1,4 @@
-import React, { useState, useEffect, useCallback } from 'react';
+import { useState, useEffect, useCallback } from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { config } from '@grafana/runtime';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryEditorSelector.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryEditorSelector.test.tsx
index e3f15b0e66b..dcba07eb367 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryEditorSelector.test.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryEditorSelector.test.tsx
@@ -2,7 +2,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { cloneDeep, defaultsDeep } from 'lodash';
-import React from 'react';
import { CoreApp, PluginMeta, PluginType } from '@grafana/data';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryEditorSelector.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryEditorSelector.tsx
index 30c5502bacb..cfb5d06a951 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryEditorSelector.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryEditorSelector.tsx
@@ -1,6 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryEditorSelector.tsx
import { isEqual, map } from 'lodash';
-import React, { SyntheticEvent, useCallback, useEffect, useState } from 'react';
+import { memo, SyntheticEvent, useCallback, useEffect, useState } from 'react';
import { CoreApp, LoadingState, SelectableValue } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
@@ -37,7 +37,7 @@ export const INTERVAL_FACTOR_OPTIONS: Array> = map([1, 2
type Props = PromQueryEditorProps;
-export const PromQueryEditorSelector = React.memo((props) => {
+export const PromQueryEditorSelector = memo((props) => {
const {
onChange,
onRunQuery,
diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryLegendEditor.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryLegendEditor.tsx
index 5be07dee6be..e06af3c98c2 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryLegendEditor.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryLegendEditor.tsx
@@ -1,5 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryLegendEditor.tsx
-import React, { useRef } from 'react';
+import { useRef } from 'react';
+import * as React from 'react';
import { SelectableValue } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/QueryPreview.tsx b/packages/grafana-prometheus/src/querybuilder/components/QueryPreview.tsx
index 2bd0e252672..0f974b7df42 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/QueryPreview.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/QueryPreview.tsx
@@ -1,6 +1,4 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/QueryPreview.tsx
-import React from 'react';
-
import { EditorFieldGroup, EditorRow } from '@grafana/experimental';
import promqlGrammar from '../../promql';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/AdditionalSettings.tsx b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/AdditionalSettings.tsx
index f9af4e62125..65949f65e3f 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/AdditionalSettings.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/AdditionalSettings.tsx
@@ -1,6 +1,5 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/metrics-modal/AdditionalSettings.tsx
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Icon, Switch, Tooltip, useTheme2 } from '@grafana/ui';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/FeedbackLink.tsx b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/FeedbackLink.tsx
index 954efbd61e1..7e64ad06673 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/FeedbackLink.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/FeedbackLink.tsx
@@ -1,6 +1,5 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/metrics-modal/FeedbackLink.tsx
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Icon, useStyles2, Stack } from '@grafana/ui';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.test.tsx
index d314a7b6d70..5f9928fa450 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.test.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.test.tsx
@@ -1,7 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/metrics-modal/MetricsModal.test.tsx
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { DataSourceInstanceSettings, DataSourcePluginMeta } from '@grafana/data';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.tsx b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.tsx
index 4d6aab8dc0d..ae7eae785b6 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.tsx
@@ -2,7 +2,7 @@
import { cx } from '@emotion/css';
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
import debounce from 'debounce-promise';
-import React, { useCallback, useEffect, useMemo, useReducer } from 'react';
+import { useCallback, useEffect, useMemo, useReducer } from 'react';
import { SelectableValue } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/ResultsTable.tsx b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/ResultsTable.tsx
index a9529e01a14..54c2c9ecc18 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/ResultsTable.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/ResultsTable.tsx
@@ -1,6 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/metrics-modal/ResultsTable.tsx
import { css } from '@emotion/css';
-import React, { ReactElement } from 'react';
+import { ReactElement } from 'react';
import Highlighter from 'react-highlight-words';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/promQail/PromQail.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/promQail/PromQail.test.tsx
index 0874258cc87..2f95975f5c4 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/promQail/PromQail.test.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/promQail/PromQail.test.tsx
@@ -1,7 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/promQail/PromQail.test.tsx
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { DataSourceInstanceSettings, DataSourcePluginMeta } from '@grafana/data';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/promQail/PromQail.tsx b/packages/grafana-prometheus/src/querybuilder/components/promQail/PromQail.tsx
index 638d3f53b93..7c9304f8fc7 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/promQail/PromQail.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/promQail/PromQail.tsx
@@ -1,7 +1,7 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/promQail/PromQail.tsx
import { css, cx } from '@emotion/css';
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
-import React, { useEffect, useReducer, useRef, useState } from 'react';
+import { useEffect, useReducer, useRef, useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/promQail/QueryAssistantButton.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/promQail/QueryAssistantButton.test.tsx
index 3bfabc4bf60..8d1bf6971d4 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/promQail/QueryAssistantButton.test.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/promQail/QueryAssistantButton.test.tsx
@@ -1,7 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/promQail/QueryAssistantButton.test.tsx
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { QueryAssistantButton } from './QueryAssistantButton';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/promQail/QueryAssistantButton.tsx b/packages/grafana-prometheus/src/querybuilder/components/promQail/QueryAssistantButton.tsx
index 577d330691e..2324f60e402 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/promQail/QueryAssistantButton.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/promQail/QueryAssistantButton.tsx
@@ -1,6 +1,4 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/promQail/QueryAssistantButton.tsx
-import React from 'react';
-
import { selectors } from '@grafana/e2e-selectors';
import { reportInteraction } from '@grafana/runtime';
import { Button, Tooltip, useTheme2 } from '@grafana/ui';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/promQail/QuerySuggestionContainer.tsx b/packages/grafana-prometheus/src/querybuilder/components/promQail/QuerySuggestionContainer.tsx
index 469811e72e2..ac51393edac 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/promQail/QuerySuggestionContainer.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/promQail/QuerySuggestionContainer.tsx
@@ -1,6 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/promQail/QuerySuggestionContainer.tsx
import { cx } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { Button, useTheme2 } from '@grafana/ui';
diff --git a/packages/grafana-prometheus/src/querybuilder/components/promQail/QuerySuggestionItem.tsx b/packages/grafana-prometheus/src/querybuilder/components/promQail/QuerySuggestionItem.tsx
index ab776ca515c..a173c8c4efb 100644
--- a/packages/grafana-prometheus/src/querybuilder/components/promQail/QuerySuggestionItem.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/components/promQail/QuerySuggestionItem.tsx
@@ -1,6 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/promQail/QuerySuggestionItem.tsx
import { cx } from '@emotion/css';
-import React, { FormEvent, useState } from 'react';
+import { FormEvent, useState } from 'react';
import { SelectableValue } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime';
diff --git a/packages/grafana-prometheus/src/querybuilder/shared/OperationEditor.tsx b/packages/grafana-prometheus/src/querybuilder/shared/OperationEditor.tsx
index a2d23aacdc9..3a6c8780f69 100644
--- a/packages/grafana-prometheus/src/querybuilder/shared/OperationEditor.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/shared/OperationEditor.tsx
@@ -1,6 +1,7 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationEditor.tsx
import { css, cx } from '@emotion/css';
-import React, { useEffect, useId, useState } from 'react';
+import { useEffect, useId, useState } from 'react';
+import * as React from 'react';
import { Draggable } from 'react-beautiful-dnd';
import { DataSourceApi, GrafanaTheme2, TimeRange } from '@grafana/data';
diff --git a/packages/grafana-prometheus/src/querybuilder/shared/OperationExplainedBox.tsx b/packages/grafana-prometheus/src/querybuilder/shared/OperationExplainedBox.tsx
index d5e5f753997..4546f3cd427 100644
--- a/packages/grafana-prometheus/src/querybuilder/shared/OperationExplainedBox.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/shared/OperationExplainedBox.tsx
@@ -1,6 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationExplainedBox.tsx
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2, renderMarkdown } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/packages/grafana-prometheus/src/querybuilder/shared/OperationHeader.tsx b/packages/grafana-prometheus/src/querybuilder/shared/OperationHeader.tsx
index 757befe40ec..421c01e41c1 100644
--- a/packages/grafana-prometheus/src/querybuilder/shared/OperationHeader.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/shared/OperationHeader.tsx
@@ -1,6 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationHeader.tsx
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { memo, useState } from 'react';
import { DraggableProvided } from 'react-beautiful-dnd';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
@@ -25,7 +25,7 @@ interface State {
alternatives?: Array>;
}
-export const OperationHeader = React.memo(
+export const OperationHeader = memo(
({ operation, def, index, onChange, onRemove, queryModeller, dragHandleProps }) => {
const styles = useStyles2(getStyles);
const [state, setState] = useState({});
diff --git a/packages/grafana-prometheus/src/querybuilder/shared/OperationInfoButton.tsx b/packages/grafana-prometheus/src/querybuilder/shared/OperationInfoButton.tsx
index c5149c16ef9..d95e308d817 100644
--- a/packages/grafana-prometheus/src/querybuilder/shared/OperationInfoButton.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/shared/OperationInfoButton.tsx
@@ -10,7 +10,7 @@ import {
useFloating,
useInteractions,
} from '@floating-ui/react';
-import React, { useState } from 'react';
+import { memo, useState } from 'react';
import { GrafanaTheme2, renderMarkdown } from '@grafana/data';
import { FlexItem } from '@grafana/experimental';
@@ -23,7 +23,7 @@ export interface Props {
def: QueryBuilderOperationDef;
}
-export const OperationInfoButton = React.memo(({ def, operation }) => {
+export const OperationInfoButton = memo(({ def, operation }) => {
const styles = useStyles2(getStyles);
const [show, setShow] = useState(false);
diff --git a/packages/grafana-prometheus/src/querybuilder/shared/OperationList.test.tsx b/packages/grafana-prometheus/src/querybuilder/shared/OperationList.test.tsx
index 298901d39fe..871d8621e59 100644
--- a/packages/grafana-prometheus/src/querybuilder/shared/OperationList.test.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/shared/OperationList.test.tsx
@@ -1,7 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationList.test.tsx
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { DataSourceApi, DataSourceInstanceSettings } from '@grafana/data';
diff --git a/packages/grafana-prometheus/src/querybuilder/shared/OperationList.tsx b/packages/grafana-prometheus/src/querybuilder/shared/OperationList.tsx
index 875eb166730..d3091559642 100644
--- a/packages/grafana-prometheus/src/querybuilder/shared/OperationList.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/shared/OperationList.tsx
@@ -1,6 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationList.tsx
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd';
import { useMountedState, usePrevious } from 'react-use';
diff --git a/packages/grafana-prometheus/src/querybuilder/shared/OperationListExplained.tsx b/packages/grafana-prometheus/src/querybuilder/shared/OperationListExplained.tsx
index bde7203584c..580109a0999 100644
--- a/packages/grafana-prometheus/src/querybuilder/shared/OperationListExplained.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/shared/OperationListExplained.tsx
@@ -1,6 +1,5 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationListExplained.tsx
import { Grammar } from 'prismjs';
-import React from 'react';
import { OperationExplainedBox } from './OperationExplainedBox';
import { RawQuery } from './RawQuery';
diff --git a/packages/grafana-prometheus/src/querybuilder/shared/OperationParamEditor.tsx b/packages/grafana-prometheus/src/querybuilder/shared/OperationParamEditor.tsx
index d4f8694c4a6..6a1d6717879 100644
--- a/packages/grafana-prometheus/src/querybuilder/shared/OperationParamEditor.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/shared/OperationParamEditor.tsx
@@ -1,6 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationParamEditor.tsx
import { css } from '@emotion/css';
-import React, { ComponentType } from 'react';
+import { ComponentType } from 'react';
import { GrafanaTheme2, SelectableValue, toOption } from '@grafana/data';
import { AutoSizeInput, Button, Checkbox, Select, useStyles2, Stack } from '@grafana/ui';
diff --git a/packages/grafana-prometheus/src/querybuilder/shared/OperationsEditorRow.tsx b/packages/grafana-prometheus/src/querybuilder/shared/OperationsEditorRow.tsx
index 696d034b5a9..891f85e0414 100644
--- a/packages/grafana-prometheus/src/querybuilder/shared/OperationsEditorRow.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/shared/OperationsEditorRow.tsx
@@ -1,6 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationsEditorRow.tsx
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2, Stack } from '@grafana/ui';
diff --git a/packages/grafana-prometheus/src/querybuilder/shared/QueryBuilderHints.tsx b/packages/grafana-prometheus/src/querybuilder/shared/QueryBuilderHints.tsx
index 2024bff7753..df2c9fa048d 100644
--- a/packages/grafana-prometheus/src/querybuilder/shared/QueryBuilderHints.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/shared/QueryBuilderHints.tsx
@@ -1,6 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/QueryBuilderHints.tsx
import { css } from '@emotion/css';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { GrafanaTheme2, PanelData, QueryHint } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime';
diff --git a/packages/grafana-prometheus/src/querybuilder/shared/QueryEditorModeToggle.tsx b/packages/grafana-prometheus/src/querybuilder/shared/QueryEditorModeToggle.tsx
index f5541dde1c8..0b0951cac5a 100644
--- a/packages/grafana-prometheus/src/querybuilder/shared/QueryEditorModeToggle.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/shared/QueryEditorModeToggle.tsx
@@ -1,6 +1,4 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/QueryEditorModeToggle.tsx
-import React from 'react';
-
import { RadioButtonGroup } from '@grafana/ui';
import { QueryEditorMode } from './types';
diff --git a/packages/grafana-prometheus/src/querybuilder/shared/QueryHeaderSwitch.tsx b/packages/grafana-prometheus/src/querybuilder/shared/QueryHeaderSwitch.tsx
index f92f2accd44..a5b484dd01e 100644
--- a/packages/grafana-prometheus/src/querybuilder/shared/QueryHeaderSwitch.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/shared/QueryHeaderSwitch.tsx
@@ -1,7 +1,7 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/QueryHeaderSwitch.tsx
import { css } from '@emotion/css';
import { uniqueId } from 'lodash';
-import React, { HTMLProps, useRef } from 'react';
+import { HTMLProps, useRef } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Switch, useStyles2, Stack } from '@grafana/ui';
diff --git a/packages/grafana-prometheus/src/querybuilder/shared/QueryOptionGroup.tsx b/packages/grafana-prometheus/src/querybuilder/shared/QueryOptionGroup.tsx
index 7d8df70545b..066e0f805ed 100644
--- a/packages/grafana-prometheus/src/querybuilder/shared/QueryOptionGroup.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/shared/QueryOptionGroup.tsx
@@ -1,6 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/QueryOptionGroup.tsx
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { useToggle } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-prometheus/src/querybuilder/shared/RawQuery.tsx b/packages/grafana-prometheus/src/querybuilder/shared/RawQuery.tsx
index da7ec8c0f79..ddaffbc3b87 100644
--- a/packages/grafana-prometheus/src/querybuilder/shared/RawQuery.tsx
+++ b/packages/grafana-prometheus/src/querybuilder/shared/RawQuery.tsx
@@ -1,7 +1,6 @@
// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/RawQuery.tsx
import { css, cx } from '@emotion/css';
import Prism, { Grammar } from 'prismjs';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useTheme2 } from '@grafana/ui';
diff --git a/packages/grafana-prometheus/tsconfig.json b/packages/grafana-prometheus/tsconfig.json
index 16a6f15ea71..403dfb14d23 100644
--- a/packages/grafana-prometheus/tsconfig.json
+++ b/packages/grafana-prometheus/tsconfig.json
@@ -1,5 +1,6 @@
{
"compilerOptions": {
+ "jsx": "react-jsx",
"alwaysStrict": true,
"declarationDir": "./compiled",
"emitDeclarationOnly": true,
diff --git a/packages/grafana-runtime/src/analytics/plugins/usePluginInteractionReporter.test.tsx b/packages/grafana-runtime/src/analytics/plugins/usePluginInteractionReporter.test.tsx
index 40c2a65bdc9..0a3c7669489 100644
--- a/packages/grafana-runtime/src/analytics/plugins/usePluginInteractionReporter.test.tsx
+++ b/packages/grafana-runtime/src/analytics/plugins/usePluginInteractionReporter.test.tsx
@@ -1,5 +1,5 @@
import { renderHook } from '@testing-library/react';
-import React from 'react';
+import * as React from 'react';
import {
DataSourceInstanceSettings,
diff --git a/packages/grafana-runtime/src/components/DataSourcePicker.test.tsx b/packages/grafana-runtime/src/components/DataSourcePicker.test.tsx
index bdd44487e7b..6480a2644dc 100644
--- a/packages/grafana-runtime/src/components/DataSourcePicker.test.tsx
+++ b/packages/grafana-runtime/src/components/DataSourcePicker.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { DataSourcePicker } from './DataSourcePicker';
diff --git a/packages/grafana-runtime/src/components/DataSourcePicker.tsx b/packages/grafana-runtime/src/components/DataSourcePicker.tsx
index 442bb2ad45d..337366827bc 100644
--- a/packages/grafana-runtime/src/components/DataSourcePicker.tsx
+++ b/packages/grafana-runtime/src/components/DataSourcePicker.tsx
@@ -1,5 +1,5 @@
// Libraries
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
// Components
import {
diff --git a/packages/grafana-runtime/src/components/EmbeddedDashboard.tsx b/packages/grafana-runtime/src/components/EmbeddedDashboard.tsx
index 92a78e5d4ea..e78d3ae7a8b 100644
--- a/packages/grafana-runtime/src/components/EmbeddedDashboard.tsx
+++ b/packages/grafana-runtime/src/components/EmbeddedDashboard.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
export interface EmbeddedDashboardProps {
uid?: string;
diff --git a/packages/grafana-runtime/src/components/PanelDataErrorView.tsx b/packages/grafana-runtime/src/components/PanelDataErrorView.tsx
index 05902a3348a..53a716a4d8f 100644
--- a/packages/grafana-runtime/src/components/PanelDataErrorView.tsx
+++ b/packages/grafana-runtime/src/components/PanelDataErrorView.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { FieldConfigSource, PanelData, VisualizationSuggestion } from '@grafana/data';
diff --git a/packages/grafana-runtime/src/components/PanelRenderer.tsx b/packages/grafana-runtime/src/components/PanelRenderer.tsx
index 027db5d8ad3..b015377068f 100644
--- a/packages/grafana-runtime/src/components/PanelRenderer.tsx
+++ b/packages/grafana-runtime/src/components/PanelRenderer.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { AbsoluteTimeRange, FieldConfigSource, PanelData } from '@grafana/data';
diff --git a/packages/grafana-runtime/src/components/PluginPage.tsx b/packages/grafana-runtime/src/components/PluginPage.tsx
index de886f12e8e..b14db4abefa 100644
--- a/packages/grafana-runtime/src/components/PluginPage.tsx
+++ b/packages/grafana-runtime/src/components/PluginPage.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { NavModelItem, PageLayoutType } from '@grafana/data';
diff --git a/packages/grafana-runtime/tsconfig.json b/packages/grafana-runtime/tsconfig.json
index f157cf99c3f..8dc5fe6ffb8 100644
--- a/packages/grafana-runtime/tsconfig.json
+++ b/packages/grafana-runtime/tsconfig.json
@@ -1,5 +1,6 @@
{
"compilerOptions": {
+ "jsx": "react-jsx",
"baseUrl": "./",
"declarationDir": "./compiled",
"emitDeclarationOnly": true,
diff --git a/packages/grafana-schema/tsconfig.json b/packages/grafana-schema/tsconfig.json
index 99cbc657b72..a7e415a1cea 100644
--- a/packages/grafana-schema/tsconfig.json
+++ b/packages/grafana-schema/tsconfig.json
@@ -1,5 +1,6 @@
{
"compilerOptions": {
+ "jsx": "react-jsx",
"declarationDir": "./dist/esm",
"emitDeclarationOnly": true,
"isolatedModules": true,
diff --git a/packages/grafana-sql/src/components/ConfirmModal.tsx b/packages/grafana-sql/src/components/ConfirmModal.tsx
index 0bf1e1b67d5..52090012b79 100644
--- a/packages/grafana-sql/src/components/ConfirmModal.tsx
+++ b/packages/grafana-sql/src/components/ConfirmModal.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useRef, useEffect } from 'react';
+import { useRef, useEffect } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Button, Icon, Modal, useStyles2 } from '@grafana/ui';
diff --git a/packages/grafana-sql/src/components/DatasetSelector.tsx b/packages/grafana-sql/src/components/DatasetSelector.tsx
index bed91f5f5ca..2e0cf47f014 100644
--- a/packages/grafana-sql/src/components/DatasetSelector.tsx
+++ b/packages/grafana-sql/src/components/DatasetSelector.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import { useAsync } from 'react-use';
import { SelectableValue } from '@grafana/data';
diff --git a/packages/grafana-sql/src/components/ErrorBoundary.tsx b/packages/grafana-sql/src/components/ErrorBoundary.tsx
index 4102bfbf932..d46ad205602 100644
--- a/packages/grafana-sql/src/components/ErrorBoundary.tsx
+++ b/packages/grafana-sql/src/components/ErrorBoundary.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
type Props = {
fallBackComponent?: React.ReactNode;
diff --git a/packages/grafana-sql/src/components/QueryEditor.tsx b/packages/grafana-sql/src/components/QueryEditor.tsx
index cfefaf37935..3adffb79efb 100644
--- a/packages/grafana-sql/src/components/QueryEditor.tsx
+++ b/packages/grafana-sql/src/components/QueryEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
import { useAsync } from 'react-use';
import { QueryEditorProps } from '@grafana/data';
diff --git a/packages/grafana-sql/src/components/QueryHeader.tsx b/packages/grafana-sql/src/components/QueryHeader.tsx
index c52fdaafaf8..f1bede6cb4f 100644
--- a/packages/grafana-sql/src/components/QueryHeader.tsx
+++ b/packages/grafana-sql/src/components/QueryHeader.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useId, useState } from 'react';
+import { useCallback, useId, useState } from 'react';
import { useCopyToClipboard } from 'react-use';
import { SelectableValue } from '@grafana/data';
diff --git a/packages/grafana-sql/src/components/SqlComponents.test.tsx b/packages/grafana-sql/src/components/SqlComponents.test.tsx
index 9cfd8b59565..efe5bd85bd7 100644
--- a/packages/grafana-sql/src/components/SqlComponents.test.tsx
+++ b/packages/grafana-sql/src/components/SqlComponents.test.tsx
@@ -1,5 +1,4 @@
import { render, waitFor } from '@testing-library/react';
-import React from 'react';
import { config } from '@grafana/runtime';
diff --git a/packages/grafana-sql/src/components/TableSelector.tsx b/packages/grafana-sql/src/components/TableSelector.tsx
index d1dff4d0b78..9801f98d12c 100644
--- a/packages/grafana-sql/src/components/TableSelector.tsx
+++ b/packages/grafana-sql/src/components/TableSelector.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useAsync } from 'react-use';
import { SelectableValue, toOption } from '@grafana/data';
diff --git a/packages/grafana-sql/src/components/configuration/ConnectionLimits.tsx b/packages/grafana-sql/src/components/configuration/ConnectionLimits.tsx
index 667bc7fe5cb..17218d5188a 100644
--- a/packages/grafana-sql/src/components/configuration/ConnectionLimits.tsx
+++ b/packages/grafana-sql/src/components/configuration/ConnectionLimits.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { DataSourceSettings } from '@grafana/data';
import { ConfigSubSection, Stack } from '@grafana/experimental';
import { config } from '@grafana/runtime';
diff --git a/packages/grafana-sql/src/components/configuration/Divider.tsx b/packages/grafana-sql/src/components/configuration/Divider.tsx
index c6582eb725f..6eff752c64c 100644
--- a/packages/grafana-sql/src/components/configuration/Divider.tsx
+++ b/packages/grafana-sql/src/components/configuration/Divider.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/packages/grafana-sql/src/components/configuration/NumberInput.tsx b/packages/grafana-sql/src/components/configuration/NumberInput.tsx
index 875dc921116..e71ce679311 100644
--- a/packages/grafana-sql/src/components/configuration/NumberInput.tsx
+++ b/packages/grafana-sql/src/components/configuration/NumberInput.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import { useState } from 'react';
import { Input } from '@grafana/ui/src/components/Input/Input';
@@ -10,7 +10,7 @@ type NumberInputProps = {
};
export function NumberInput({ value, defaultValue, onChange, width }: NumberInputProps) {
- const [isEmpty, setIsEmpty] = React.useState(false);
+ const [isEmpty, setIsEmpty] = useState(false);
return (
{
+export const EllipsisAnimated = memo(() => {
const styles = useStyles2(getStyles);
return (
diff --git a/packages/grafana-ui/src/components/Badge/Badge.story.tsx b/packages/grafana-ui/src/components/Badge/Badge.story.tsx
index 247f7774790..442daa3a379 100644
--- a/packages/grafana-ui/src/components/Badge/Badge.story.tsx
+++ b/packages/grafana-ui/src/components/Badge/Badge.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { Badge } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/Badge/Badge.tsx b/packages/grafana-ui/src/components/Badge/Badge.tsx
index 969c6ebfb10..9238c8a648c 100644
--- a/packages/grafana-ui/src/components/Badge/Badge.tsx
+++ b/packages/grafana-ui/src/components/Badge/Badge.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { HTMLAttributes } from 'react';
+import { HTMLAttributes } from 'react';
+import * as React from 'react';
import Skeleton from 'react-loading-skeleton';
import tinycolor from 'tinycolor2';
diff --git a/packages/grafana-ui/src/components/BarGauge/BarGauge.story.tsx b/packages/grafana-ui/src/components/BarGauge/BarGauge.story.tsx
index 8905e958f1e..be5fe58381f 100644
--- a/packages/grafana-ui/src/components/BarGauge/BarGauge.story.tsx
+++ b/packages/grafana-ui/src/components/BarGauge/BarGauge.story.tsx
@@ -1,5 +1,4 @@
import { StoryFn, Meta } from '@storybook/react';
-import React from 'react';
import { VizOrientation, ThresholdsMode, Field, FieldType, getDisplayProcessor } from '@grafana/data';
import { BarGauge, BarGaugeDisplayMode } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/BarGauge/BarGauge.test.tsx b/packages/grafana-ui/src/components/BarGauge/BarGauge.test.tsx
index 3982a31931b..c8b76542ba5 100644
--- a/packages/grafana-ui/src/components/BarGauge/BarGauge.test.tsx
+++ b/packages/grafana-ui/src/components/BarGauge/BarGauge.test.tsx
@@ -1,5 +1,4 @@
import { render } from '@testing-library/react';
-import React from 'react';
import {
DisplayValue,
diff --git a/packages/grafana-ui/src/components/BarGauge/BarGauge.tsx b/packages/grafana-ui/src/components/BarGauge/BarGauge.tsx
index db2ff91f09b..2624bc9f794 100644
--- a/packages/grafana-ui/src/components/BarGauge/BarGauge.tsx
+++ b/packages/grafana-ui/src/components/BarGauge/BarGauge.tsx
@@ -1,6 +1,7 @@
// Library
import { cx } from '@emotion/css';
-import React, { CSSProperties, PureComponent, ReactNode } from 'react';
+import { CSSProperties, PureComponent, ReactNode } from 'react';
+import * as React from 'react';
import tinycolor from 'tinycolor2';
import {
diff --git a/packages/grafana-ui/src/components/BigValue/BigValue.story.tsx b/packages/grafana-ui/src/components/BigValue/BigValue.story.tsx
index 58005a08989..a7a4ea9d6e1 100644
--- a/packages/grafana-ui/src/components/BigValue/BigValue.story.tsx
+++ b/packages/grafana-ui/src/components/BigValue/BigValue.story.tsx
@@ -1,5 +1,4 @@
import { StoryFn, Meta } from '@storybook/react';
-import React from 'react';
import { FieldSparkline, FieldType } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/BigValue/BigValue.test.tsx b/packages/grafana-ui/src/components/BigValue/BigValue.test.tsx
index a5e6fa46e1e..ff682372578 100644
--- a/packages/grafana-ui/src/components/BigValue/BigValue.test.tsx
+++ b/packages/grafana-ui/src/components/BigValue/BigValue.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { createTheme } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/BigValue/BigValue.tsx b/packages/grafana-ui/src/components/BigValue/BigValue.tsx
index 0b89924d885..220799ee37f 100644
--- a/packages/grafana-ui/src/components/BigValue/BigValue.tsx
+++ b/packages/grafana-ui/src/components/BigValue/BigValue.tsx
@@ -1,5 +1,6 @@
import { cx } from '@emotion/css';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
+import * as React from 'react';
import { DisplayValue, DisplayValueAlignmentFactors, FieldSparkline } from '@grafana/data';
import { PercentChangeColorMode, VizTextDisplayOptions } from '@grafana/schema';
diff --git a/packages/grafana-ui/src/components/BigValue/BigValueLayout.tsx b/packages/grafana-ui/src/components/BigValue/BigValueLayout.tsx
index 5535847e978..23b32b90ad1 100644
--- a/packages/grafana-ui/src/components/BigValue/BigValueLayout.tsx
+++ b/packages/grafana-ui/src/components/BigValue/BigValueLayout.tsx
@@ -1,4 +1,5 @@
-import React, { CSSProperties } from 'react';
+import { CSSProperties } from 'react';
+import * as React from 'react';
import tinycolor from 'tinycolor2';
import { formattedValueToString, DisplayValue, FieldConfig, FieldType, ThemeVisualizationColors } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/BigValue/PercentChange.tsx b/packages/grafana-ui/src/components/BigValue/PercentChange.tsx
index b492dfb6398..222cccf13b6 100644
--- a/packages/grafana-ui/src/components/BigValue/PercentChange.tsx
+++ b/packages/grafana-ui/src/components/BigValue/PercentChange.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Icon } from '../Icon/Icon';
import { PercentChangeStyles } from './BigValueLayout';
diff --git a/packages/grafana-ui/src/components/BrowserLabel/Label.tsx b/packages/grafana-ui/src/components/BrowserLabel/Label.tsx
index 69d09b4aafd..9ce9289575e 100644
--- a/packages/grafana-ui/src/components/BrowserLabel/Label.tsx
+++ b/packages/grafana-ui/src/components/BrowserLabel/Label.tsx
@@ -1,5 +1,6 @@
import { cx, css } from '@emotion/css';
-import React, { forwardRef, HTMLAttributes, useCallback } from 'react';
+import { forwardRef, HTMLAttributes, useCallback } from 'react';
+import * as React from 'react';
import Highlighter from 'react-highlight-words';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Button/Button.story.tsx b/packages/grafana-ui/src/components/Button/Button.story.tsx
index d1372d63dc5..706215637af 100644
--- a/packages/grafana-ui/src/components/Button/Button.story.tsx
+++ b/packages/grafana-ui/src/components/Button/Button.story.tsx
@@ -1,6 +1,5 @@
import { action } from '@storybook/addon-actions';
import { StoryFn } from '@storybook/react';
-import React from 'react';
import { ComponentSize } from '../../types';
import { Card } from '../Card/Card';
diff --git a/packages/grafana-ui/src/components/Button/Button.tsx b/packages/grafana-ui/src/components/Button/Button.tsx
index 991bf3ad454..3f8e1b6f642 100644
--- a/packages/grafana-ui/src/components/Button/Button.tsx
+++ b/packages/grafana-ui/src/components/Button/Button.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { AnchorHTMLAttributes, ButtonHTMLAttributes } from 'react';
+import { AnchorHTMLAttributes, ButtonHTMLAttributes } from 'react';
+import * as React from 'react';
import { GrafanaTheme2, ThemeRichColor } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Button/ButtonGroup.tsx b/packages/grafana-ui/src/components/Button/ButtonGroup.tsx
index 49340d5f933..f7cdb009fe7 100644
--- a/packages/grafana-ui/src/components/Button/ButtonGroup.tsx
+++ b/packages/grafana-ui/src/components/Button/ButtonGroup.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { forwardRef, HTMLAttributes } from 'react';
+import { forwardRef, HTMLAttributes } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Button/FullWidthButtonContainer.tsx b/packages/grafana-ui/src/components/Button/FullWidthButtonContainer.tsx
index 9c3fcfa7ca7..1e4ee66c10d 100644
--- a/packages/grafana-ui/src/components/Button/FullWidthButtonContainer.tsx
+++ b/packages/grafana-ui/src/components/Button/FullWidthButtonContainer.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { useStyles2 } from '../../themes';
diff --git a/packages/grafana-ui/src/components/ButtonCascader/ButtonCascader.story.tsx b/packages/grafana-ui/src/components/ButtonCascader/ButtonCascader.story.tsx
index 4a80c5a4390..7ae5ad2bae8 100644
--- a/packages/grafana-ui/src/components/ButtonCascader/ButtonCascader.story.tsx
+++ b/packages/grafana-ui/src/components/ButtonCascader/ButtonCascader.story.tsx
@@ -1,5 +1,4 @@
import { StoryFn, Meta } from '@storybook/react';
-import React from 'react';
import { ButtonCascader } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/ButtonCascader/ButtonCascader.tsx b/packages/grafana-ui/src/components/ButtonCascader/ButtonCascader.tsx
index 947f921a460..cc09b8d840a 100644
--- a/packages/grafana-ui/src/components/ButtonCascader/ButtonCascader.tsx
+++ b/packages/grafana-ui/src/components/ButtonCascader/ButtonCascader.tsx
@@ -1,6 +1,6 @@
import { css, cx } from '@emotion/css';
import RCCascader, { BaseOptionType } from 'rc-cascader';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/CallToActionCard/CallToActionCard.internal.story.tsx b/packages/grafana-ui/src/components/CallToActionCard/CallToActionCard.internal.story.tsx
index 6272ef29152..5d42373e1cc 100644
--- a/packages/grafana-ui/src/components/CallToActionCard/CallToActionCard.internal.story.tsx
+++ b/packages/grafana-ui/src/components/CallToActionCard/CallToActionCard.internal.story.tsx
@@ -1,6 +1,5 @@
import { action } from '@storybook/addon-actions';
import { StoryFn, Meta } from '@storybook/react';
-import React from 'react';
import { Button } from '../Button/Button';
diff --git a/packages/grafana-ui/src/components/CallToActionCard/CallToActionCard.test.tsx b/packages/grafana-ui/src/components/CallToActionCard/CallToActionCard.test.tsx
index 70828c81a6e..2e2391da18a 100644
--- a/packages/grafana-ui/src/components/CallToActionCard/CallToActionCard.test.tsx
+++ b/packages/grafana-ui/src/components/CallToActionCard/CallToActionCard.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { CallToActionCard } from './CallToActionCard';
diff --git a/packages/grafana-ui/src/components/CallToActionCard/CallToActionCard.tsx b/packages/grafana-ui/src/components/CallToActionCard/CallToActionCard.tsx
index e0be02a5e67..e71c688f3e7 100644
--- a/packages/grafana-ui/src/components/CallToActionCard/CallToActionCard.tsx
+++ b/packages/grafana-ui/src/components/CallToActionCard/CallToActionCard.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Card/Card.story.tsx b/packages/grafana-ui/src/components/Card/Card.story.tsx
index c53e01798b0..fb040abb520 100644
--- a/packages/grafana-ui/src/components/Card/Card.story.tsx
+++ b/packages/grafana-ui/src/components/Card/Card.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { Button } from '../Button';
import { IconButton } from '../IconButton/IconButton';
diff --git a/packages/grafana-ui/src/components/Card/Card.test.tsx b/packages/grafana-ui/src/components/Card/Card.test.tsx
index ec7c673faa0..86e81c784aa 100644
--- a/packages/grafana-ui/src/components/Card/Card.test.tsx
+++ b/packages/grafana-ui/src/components/Card/Card.test.tsx
@@ -1,5 +1,4 @@
import { render, screen, fireEvent } from '@testing-library/react';
-import React from 'react';
import { Button } from '../Button';
import { IconButton } from '../IconButton/IconButton';
diff --git a/packages/grafana-ui/src/components/Card/Card.tsx b/packages/grafana-ui/src/components/Card/Card.tsx
index 08f363dda25..2b433485a1d 100644
--- a/packages/grafana-ui/src/components/Card/Card.tsx
+++ b/packages/grafana-ui/src/components/Card/Card.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { memo, cloneElement, FC, useMemo, useContext, ReactNode } from 'react';
+import { memo, cloneElement, FC, useMemo, useContext, ReactNode } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Card/CardContainer.tsx b/packages/grafana-ui/src/components/Card/CardContainer.tsx
index 15ba01c9651..2d461dabf6f 100644
--- a/packages/grafana-ui/src/components/Card/CardContainer.tsx
+++ b/packages/grafana-ui/src/components/Card/CardContainer.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { HTMLAttributes } from 'react';
+import { HTMLAttributes } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Cascader/Cascader.story.tsx b/packages/grafana-ui/src/components/Cascader/Cascader.story.tsx
index 9abfda616a3..9135ec928ae 100644
--- a/packages/grafana-ui/src/components/Cascader/Cascader.story.tsx
+++ b/packages/grafana-ui/src/components/Cascader/Cascader.story.tsx
@@ -1,5 +1,5 @@
import { StoryFn, Meta } from '@storybook/react';
-import React from 'react';
+import { useState } from 'react';
import { Cascader } from '@grafana/ui';
@@ -87,7 +87,7 @@ WithDisplayAllSelectedLevels.args = {
};
export const WithOptionsStateUpdate = () => {
- const [updatedOptions, setOptions] = React.useState
([
+ const [updatedOptions, setOptions] = useState([
{
label: 'Initial state option',
value: 'initial',
diff --git a/packages/grafana-ui/src/components/Cascader/Cascader.test.tsx b/packages/grafana-ui/src/components/Cascader/Cascader.test.tsx
index e33b21bab0c..231bd8e6ff8 100644
--- a/packages/grafana-ui/src/components/Cascader/Cascader.test.tsx
+++ b/packages/grafana-ui/src/components/Cascader/Cascader.test.tsx
@@ -1,6 +1,6 @@
import { act, render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
+import { useState } from 'react';
import { Field } from '../Forms/Field';
@@ -32,7 +32,7 @@ const options = [
];
const CascaderWithOptionsStateUpdate = (props: Omit) => {
- const [updatedOptions, setOptions] = React.useState([
+ const [updatedOptions, setOptions] = useState([
{
label: 'Initial state option',
value: 'initial',
diff --git a/packages/grafana-ui/src/components/Cascader/Cascader.tsx b/packages/grafana-ui/src/components/Cascader/Cascader.tsx
index 8d3622e6d5e..f3b2114b613 100644
--- a/packages/grafana-ui/src/components/Cascader/Cascader.tsx
+++ b/packages/grafana-ui/src/components/Cascader/Cascader.tsx
@@ -1,7 +1,8 @@
import { css } from '@emotion/css';
import memoize from 'micro-memoize';
import RCCascader from 'rc-cascader';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
+import * as React from 'react';
import { SelectableValue } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/ClickOutsideWrapper/ClickOutsideWrapper.story.tsx b/packages/grafana-ui/src/components/ClickOutsideWrapper/ClickOutsideWrapper.story.tsx
index ec5273dae33..c2fc4d41a24 100644
--- a/packages/grafana-ui/src/components/ClickOutsideWrapper/ClickOutsideWrapper.story.tsx
+++ b/packages/grafana-ui/src/components/ClickOutsideWrapper/ClickOutsideWrapper.story.tsx
@@ -1,6 +1,5 @@
import { action } from '@storybook/addon-actions';
import { Meta } from '@storybook/react';
-import React from 'react';
import { ClickOutsideWrapper } from './ClickOutsideWrapper';
import mdx from './ClickOutsideWrapper.mdx';
diff --git a/packages/grafana-ui/src/components/ClickOutsideWrapper/ClickOutsideWrapper.tsx b/packages/grafana-ui/src/components/ClickOutsideWrapper/ClickOutsideWrapper.tsx
index 2effdc87463..015aada0881 100644
--- a/packages/grafana-ui/src/components/ClickOutsideWrapper/ClickOutsideWrapper.tsx
+++ b/packages/grafana-ui/src/components/ClickOutsideWrapper/ClickOutsideWrapper.tsx
@@ -1,4 +1,5 @@
-import React, { PureComponent, createRef } from 'react';
+import { PureComponent, createRef } from 'react';
+import * as React from 'react';
export interface Props {
/**
diff --git a/packages/grafana-ui/src/components/ClipboardButton/ClipboardButton.internal.story.tsx b/packages/grafana-ui/src/components/ClipboardButton/ClipboardButton.internal.story.tsx
index 2f9fa9cc0e6..5089786ae97 100644
--- a/packages/grafana-ui/src/components/ClipboardButton/ClipboardButton.internal.story.tsx
+++ b/packages/grafana-ui/src/components/ClipboardButton/ClipboardButton.internal.story.tsx
@@ -1,5 +1,4 @@
import { StoryFn, Meta } from '@storybook/react';
-import React from 'react';
import { Field } from '../Forms/Field';
import { Input } from '../Input/Input';
diff --git a/packages/grafana-ui/src/components/ClipboardButton/ClipboardButton.tsx b/packages/grafana-ui/src/components/ClipboardButton/ClipboardButton.tsx
index 4151461307e..8f56a9a36a0 100644
--- a/packages/grafana-ui/src/components/ClipboardButton/ClipboardButton.tsx
+++ b/packages/grafana-ui/src/components/ClipboardButton/ClipboardButton.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { useCallback, useRef, useState, useEffect } from 'react';
+import { useCallback, useRef, useState, useEffect } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Collapse/CollapsableSection.story.tsx b/packages/grafana-ui/src/components/Collapse/CollapsableSection.story.tsx
index f545207945a..4053b6d1e24 100644
--- a/packages/grafana-ui/src/components/Collapse/CollapsableSection.story.tsx
+++ b/packages/grafana-ui/src/components/Collapse/CollapsableSection.story.tsx
@@ -1,7 +1,6 @@
import { action } from '@storybook/addon-actions';
import { useArgs } from '@storybook/preview-api';
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { CollapsableSection, Props } from './CollapsableSection';
import mdx from './CollapsableSection.mdx';
diff --git a/packages/grafana-ui/src/components/Collapse/CollapsableSection.tsx b/packages/grafana-ui/src/components/Collapse/CollapsableSection.tsx
index 8c166852039..34e0f95db20 100644
--- a/packages/grafana-ui/src/components/Collapse/CollapsableSection.tsx
+++ b/packages/grafana-ui/src/components/Collapse/CollapsableSection.tsx
@@ -1,6 +1,7 @@
import { css, cx } from '@emotion/css';
import { uniqueId } from 'lodash';
-import React, { ReactNode, useRef, useState } from 'react';
+import { ReactNode, useRef, useState } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Collapse/Collapse.story.tsx b/packages/grafana-ui/src/components/Collapse/Collapse.story.tsx
index d3f74c3cb15..002a6f00093 100644
--- a/packages/grafana-ui/src/components/Collapse/Collapse.story.tsx
+++ b/packages/grafana-ui/src/components/Collapse/Collapse.story.tsx
@@ -1,7 +1,6 @@
import { action } from '@storybook/addon-actions';
import { useArgs } from '@storybook/preview-api';
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { Collapse, ControlledCollapse } from './Collapse';
import mdx from './Collapse.mdx';
diff --git a/packages/grafana-ui/src/components/Collapse/Collapse.tsx b/packages/grafana-ui/src/components/Collapse/Collapse.tsx
index d934ee52285..97e0389aa8a 100644
--- a/packages/grafana-ui/src/components/Collapse/Collapse.tsx
+++ b/packages/grafana-ui/src/components/Collapse/Collapse.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/ColorPicker/ColorInput.tsx b/packages/grafana-ui/src/components/ColorPicker/ColorInput.tsx
index d8891939c66..1e55e1ac481 100644
--- a/packages/grafana-ui/src/components/ColorPicker/ColorInput.tsx
+++ b/packages/grafana-ui/src/components/ColorPicker/ColorInput.tsx
@@ -1,6 +1,7 @@
import { cx, css } from '@emotion/css';
import { debounce } from 'lodash';
-import React, { forwardRef, useState, useEffect, useMemo } from 'react';
+import { forwardRef, useState, useEffect, useMemo } from 'react';
+import * as React from 'react';
import tinycolor from 'tinycolor2';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/ColorPicker/ColorPicker.story.tsx b/packages/grafana-ui/src/components/ColorPicker/ColorPicker.story.tsx
index 1d7cc0439c1..b239587710e 100644
--- a/packages/grafana-ui/src/components/ColorPicker/ColorPicker.story.tsx
+++ b/packages/grafana-ui/src/components/ColorPicker/ColorPicker.story.tsx
@@ -1,7 +1,6 @@
import { action } from '@storybook/addon-actions';
import { useArgs } from '@storybook/preview-api';
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { SeriesColorPicker, ColorPicker, clearButtonStyles, useStyles2, ColorPickerInput } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/ColorPicker/ColorPicker.test.tsx b/packages/grafana-ui/src/components/ColorPicker/ColorPicker.test.tsx
index d3cf04a4b71..68cf98b1c2c 100644
--- a/packages/grafana-ui/src/components/ColorPicker/ColorPicker.test.tsx
+++ b/packages/grafana-ui/src/components/ColorPicker/ColorPicker.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import renderer from 'react-test-renderer';
import { ColorPicker } from './ColorPicker';
diff --git a/packages/grafana-ui/src/components/ColorPicker/ColorPicker.tsx b/packages/grafana-ui/src/components/ColorPicker/ColorPicker.tsx
index 57fc7cfe6ce..0f2221e497e 100644
--- a/packages/grafana-ui/src/components/ColorPicker/ColorPicker.tsx
+++ b/packages/grafana-ui/src/components/ColorPicker/ColorPicker.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { Component, createRef } from 'react';
+import { Component, createRef } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/ColorPicker/ColorPickerInput.test.tsx b/packages/grafana-ui/src/components/ColorPicker/ColorPickerInput.test.tsx
index 86f2b00a5e2..8b81be33bf0 100644
--- a/packages/grafana-ui/src/components/ColorPicker/ColorPickerInput.test.tsx
+++ b/packages/grafana-ui/src/components/ColorPicker/ColorPickerInput.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { ColorPickerInput } from './ColorPickerInput';
diff --git a/packages/grafana-ui/src/components/ColorPicker/ColorPickerInput.tsx b/packages/grafana-ui/src/components/ColorPicker/ColorPickerInput.tsx
index dc1d83d67a0..add799af11c 100644
--- a/packages/grafana-ui/src/components/ColorPicker/ColorPickerInput.tsx
+++ b/packages/grafana-ui/src/components/ColorPicker/ColorPickerInput.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { useState, forwardRef } from 'react';
+import { useState, forwardRef } from 'react';
import { RgbaStringColorPicker } from 'react-colorful';
import { useThrottleFn } from 'react-use';
diff --git a/packages/grafana-ui/src/components/ColorPicker/ColorPickerPopover.story.tsx b/packages/grafana-ui/src/components/ColorPicker/ColorPickerPopover.story.tsx
index 2a2b6fbba99..80974cf1b57 100644
--- a/packages/grafana-ui/src/components/ColorPicker/ColorPickerPopover.story.tsx
+++ b/packages/grafana-ui/src/components/ColorPicker/ColorPickerPopover.story.tsx
@@ -1,5 +1,5 @@
import { Meta } from '@storybook/react';
-import React from 'react';
+import { useState } from 'react';
import { useTheme2 } from '../../themes';
@@ -32,7 +32,7 @@ export const Basic = () => {
export const SeriesColorPickerPopoverExample = () => {
const theme = useTheme2();
- const [yAxis, setYAxis] = React.useState(0);
+ const [yAxis, setYAxis] = useState(0);
return (
diff --git a/packages/grafana-ui/src/components/ColorPicker/ColorPickerPopover.test.tsx b/packages/grafana-ui/src/components/ColorPicker/ColorPickerPopover.test.tsx
index 2be5a39d981..71379860992 100644
--- a/packages/grafana-ui/src/components/ColorPicker/ColorPickerPopover.test.tsx
+++ b/packages/grafana-ui/src/components/ColorPicker/ColorPickerPopover.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { createTheme } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/ColorPicker/ColorPickerPopover.tsx b/packages/grafana-ui/src/components/ColorPicker/ColorPickerPopover.tsx
index e6037228b56..a21122c5a08 100644
--- a/packages/grafana-ui/src/components/ColorPicker/ColorPickerPopover.tsx
+++ b/packages/grafana-ui/src/components/ColorPicker/ColorPickerPopover.tsx
@@ -1,6 +1,7 @@
import { css } from '@emotion/css';
import { FocusScope } from '@react-aria/focus';
-import React, { Component } from 'react';
+import { Component } from 'react';
+import * as React from 'react';
import { GrafanaTheme2, colorManipulator } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/ColorPicker/ColorSwatch.tsx b/packages/grafana-ui/src/components/ColorPicker/ColorSwatch.tsx
index 97cdabdc1c1..01a96edb421 100644
--- a/packages/grafana-ui/src/components/ColorPicker/ColorSwatch.tsx
+++ b/packages/grafana-ui/src/components/ColorPicker/ColorSwatch.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { useFocusRing } from '@react-aria/focus';
-import React from 'react';
+import * as React from 'react';
import tinycolor from 'tinycolor2';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/ColorPicker/NamedColorsGroup.tsx b/packages/grafana-ui/src/components/ColorPicker/NamedColorsGroup.tsx
index 5ea91f413ae..47500ac910d 100644
--- a/packages/grafana-ui/src/components/ColorPicker/NamedColorsGroup.tsx
+++ b/packages/grafana-ui/src/components/ColorPicker/NamedColorsGroup.tsx
@@ -1,7 +1,6 @@
import { css } from '@emotion/css';
import { Property } from 'csstype';
import { upperFirst } from 'lodash';
-import React from 'react';
import { GrafanaTheme2, ThemeVizHue } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/ColorPicker/NamedColorsPalette.test.tsx b/packages/grafana-ui/src/components/ColorPicker/NamedColorsPalette.test.tsx
index 51809087d90..d9b645dba2b 100644
--- a/packages/grafana-ui/src/components/ColorPicker/NamedColorsPalette.test.tsx
+++ b/packages/grafana-ui/src/components/ColorPicker/NamedColorsPalette.test.tsx
@@ -1,5 +1,4 @@
import { screen, render } from '@testing-library/react';
-import React from 'react';
import { createTheme } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/ColorPicker/NamedColorsPalette.tsx b/packages/grafana-ui/src/components/ColorPicker/NamedColorsPalette.tsx
index fa7c9ab02f3..521500db77d 100644
--- a/packages/grafana-ui/src/components/ColorPicker/NamedColorsPalette.tsx
+++ b/packages/grafana-ui/src/components/ColorPicker/NamedColorsPalette.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/ColorPicker/Palettes.story.tsx b/packages/grafana-ui/src/components/ColorPicker/Palettes.story.tsx
index 50a076c9513..06042a9a30d 100644
--- a/packages/grafana-ui/src/components/ColorPicker/Palettes.story.tsx
+++ b/packages/grafana-ui/src/components/ColorPicker/Palettes.story.tsx
@@ -1,7 +1,7 @@
import { action } from '@storybook/addon-actions';
import { useArgs } from '@storybook/preview-api';
import { Meta, StoryFn } from '@storybook/react';
-import React, { useState } from 'react';
+import { useState } from 'react';
import mdx from './ColorPicker.mdx';
import { NamedColorsPalette } from './NamedColorsPalette';
diff --git a/packages/grafana-ui/src/components/ColorPicker/SeriesColorPickerPopover.tsx b/packages/grafana-ui/src/components/ColorPicker/SeriesColorPickerPopover.tsx
index 90f5e80f605..542d8a67d26 100644
--- a/packages/grafana-ui/src/components/ColorPicker/SeriesColorPickerPopover.tsx
+++ b/packages/grafana-ui/src/components/ColorPicker/SeriesColorPickerPopover.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { withTheme2 } from '../../themes';
import { InlineField } from '../Forms/InlineField';
import { InlineSwitch } from '../Switch/Switch';
diff --git a/packages/grafana-ui/src/components/ColorPicker/SpectrumPalette.tsx b/packages/grafana-ui/src/components/ColorPicker/SpectrumPalette.tsx
index 825b59dbd1c..589b90375d5 100644
--- a/packages/grafana-ui/src/components/ColorPicker/SpectrumPalette.tsx
+++ b/packages/grafana-ui/src/components/ColorPicker/SpectrumPalette.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
import { RgbaStringColorPicker } from 'react-colorful';
import { useThrottleFn } from 'react-use';
import tinycolor from 'tinycolor2';
diff --git a/packages/grafana-ui/src/components/Combobox/Combobox.internal.story.tsx b/packages/grafana-ui/src/components/Combobox/Combobox.internal.story.tsx
index cf373415761..120e333e76d 100644
--- a/packages/grafana-ui/src/components/Combobox/Combobox.internal.story.tsx
+++ b/packages/grafana-ui/src/components/Combobox/Combobox.internal.story.tsx
@@ -1,7 +1,7 @@
import { action } from '@storybook/addon-actions';
import { Meta, StoryFn, StoryObj } from '@storybook/react';
import { Chance } from 'chance';
-import React, { ComponentProps, useMemo, useState } from 'react';
+import { ComponentProps, useMemo, useState } from 'react';
import { Combobox, Option, Value } from './Combobox';
diff --git a/packages/grafana-ui/src/components/Combobox/Combobox.tsx b/packages/grafana-ui/src/components/Combobox/Combobox.tsx
index 17e782a4b36..af247f7bae1 100644
--- a/packages/grafana-ui/src/components/Combobox/Combobox.tsx
+++ b/packages/grafana-ui/src/components/Combobox/Combobox.tsx
@@ -1,7 +1,7 @@
import { css } from '@emotion/css';
import { useVirtualizer } from '@tanstack/react-virtual';
import { useCombobox } from 'downshift';
-import React, { useMemo, useRef, useState } from 'react';
+import { useMemo, useRef, useState } from 'react';
import { useStyles2 } from '../../themes';
import { Icon } from '../Icon/Icon';
diff --git a/packages/grafana-ui/src/components/ConfirmButton/ConfirmButton.story.tsx b/packages/grafana-ui/src/components/ConfirmButton/ConfirmButton.story.tsx
index bf28ecc1be4..e8b577fe32b 100644
--- a/packages/grafana-ui/src/components/ConfirmButton/ConfirmButton.story.tsx
+++ b/packages/grafana-ui/src/components/ConfirmButton/ConfirmButton.story.tsx
@@ -1,6 +1,5 @@
import { action } from '@storybook/addon-actions';
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { ConfirmButton } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/ConfirmButton/ConfirmButton.test.tsx b/packages/grafana-ui/src/components/ConfirmButton/ConfirmButton.test.tsx
index 223ec38b780..98b0707a9c7 100644
--- a/packages/grafana-ui/src/components/ConfirmButton/ConfirmButton.test.tsx
+++ b/packages/grafana-ui/src/components/ConfirmButton/ConfirmButton.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { ConfirmButton } from './ConfirmButton';
diff --git a/packages/grafana-ui/src/components/ConfirmButton/ConfirmButton.tsx b/packages/grafana-ui/src/components/ConfirmButton/ConfirmButton.tsx
index d8c539fc43c..d045576bf1f 100644
--- a/packages/grafana-ui/src/components/ConfirmButton/ConfirmButton.tsx
+++ b/packages/grafana-ui/src/components/ConfirmButton/ConfirmButton.tsx
@@ -1,5 +1,6 @@
import { cx, css } from '@emotion/css';
-import React, { ReactElement, useEffect, useRef, useState } from 'react';
+import { ReactElement, useEffect, useRef, useState } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/ConfirmButton/DeleteButton.tsx b/packages/grafana-ui/src/components/ConfirmButton/DeleteButton.tsx
index d09ecaa46e2..81ca3c12a1c 100644
--- a/packages/grafana-ui/src/components/ConfirmButton/DeleteButton.tsx
+++ b/packages/grafana-ui/src/components/ConfirmButton/DeleteButton.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { ComponentSize } from '../../types/size';
import { Button } from '../Button';
diff --git a/packages/grafana-ui/src/components/ConfirmModal/ConfirmContent.tsx b/packages/grafana-ui/src/components/ConfirmModal/ConfirmContent.tsx
index 016df971c2b..b63f2ffe7ad 100644
--- a/packages/grafana-ui/src/components/ConfirmModal/ConfirmContent.tsx
+++ b/packages/grafana-ui/src/components/ConfirmModal/ConfirmContent.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useEffect, useRef, useState } from 'react';
+import { useEffect, useRef, useState } from 'react';
+import * as React from 'react';
import { useForm } from 'react-hook-form';
import { GrafanaTheme2 } from '@grafana/data';
@@ -7,8 +8,8 @@ import { selectors } from '@grafana/e2e-selectors';
import { useStyles2 } from '../../themes';
import { Button, ButtonVariant } from '../Button';
+import { Field } from '../Forms/Field';
import { Input } from '../Input/Input';
-import { Box } from '../Layout/Box/Box';
import { Stack } from '../Layout/Stack/Stack';
import { JustifyContent } from '../Layout/types';
import { ResponsiveProp } from '../Layout/utils/responsiveness';
@@ -40,6 +41,8 @@ export interface ConfirmContentProps {
onDismiss(): void;
/** Alternative action callback */
onAlternative?(): void;
+ /** Disable the confirm button and the confirm text input if needed */
+ disabled?: boolean;
}
export const ConfirmContent = ({
@@ -55,13 +58,14 @@ export const ConfirmContent = ({
alternativeButtonLabel,
description,
justifyButtons = 'flex-end',
+ disabled,
}: ConfirmContentProps) => {
- const [disabled, setDisabled] = useState(Boolean(confirmPromptText));
+ const [isDisabled, setIsDisabled] = useState(disabled);
const styles = useStyles2(getStyles);
const buttonRef = useRef
(null);
const onConfirmationTextChange = (event: React.FormEvent) => {
- setDisabled(confirmPromptText?.toLowerCase().localeCompare(event.currentTarget.value.toLowerCase()) !== 0);
+ setIsDisabled(confirmPromptText?.toLowerCase().localeCompare(event.currentTarget.value.toLowerCase()) !== 0);
};
useEffect(() => {
@@ -69,15 +73,15 @@ export const ConfirmContent = ({
}, []);
useEffect(() => {
- setDisabled(Boolean(confirmPromptText));
- }, [confirmPromptText]);
+ setIsDisabled(disabled ? true : Boolean(confirmPromptText));
+ }, [confirmPromptText, disabled]);
const onConfirmClick = async () => {
- setDisabled(true);
+ setIsDisabled(true);
try {
await onConfirm();
} finally {
- setDisabled(false);
+ setIsDisabled(false);
}
};
@@ -91,9 +95,9 @@ export const ConfirmContent = ({
{confirmPromptText ? (
-
+
-
+
) : null}
@@ -106,7 +110,7 @@ export const ConfirmContent = ({
diff --git a/packages/grafana-ui/src/components/ConfirmModal/ConfirmModal.story.tsx b/packages/grafana-ui/src/components/ConfirmModal/ConfirmModal.story.tsx
index a44d142a2d8..25ef06ffb2b 100644
--- a/packages/grafana-ui/src/components/ConfirmModal/ConfirmModal.story.tsx
+++ b/packages/grafana-ui/src/components/ConfirmModal/ConfirmModal.story.tsx
@@ -1,6 +1,5 @@
import { action } from '@storybook/addon-actions';
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { ConfirmModal } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/ConfirmModal/ConfirmModal.test.tsx b/packages/grafana-ui/src/components/ConfirmModal/ConfirmModal.test.tsx
index 0ffeb63acd1..53ac68e20ad 100644
--- a/packages/grafana-ui/src/components/ConfirmModal/ConfirmModal.test.tsx
+++ b/packages/grafana-ui/src/components/ConfirmModal/ConfirmModal.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { ConfirmModal } from './ConfirmModal';
diff --git a/packages/grafana-ui/src/components/ConfirmModal/ConfirmModal.tsx b/packages/grafana-ui/src/components/ConfirmModal/ConfirmModal.tsx
index 070c9db9d75..ae478db3ad5 100644
--- a/packages/grafana-ui/src/components/ConfirmModal/ConfirmModal.tsx
+++ b/packages/grafana-ui/src/components/ConfirmModal/ConfirmModal.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { IconName } from '@grafana/data';
@@ -44,6 +44,8 @@ export interface ConfirmModalProps {
onDismiss(): void;
/** Alternative action callback */
onAlternative?(): void;
+ /** Disable the confirm button and the confirm text input if needed */
+ disabled?: boolean;
}
export const ConfirmModal = ({
@@ -63,6 +65,7 @@ export const ConfirmModal = ({
onDismiss,
onAlternative,
confirmButtonVariant = 'destructive',
+ disabled,
}: ConfirmModalProps): JSX.Element => {
const styles = useStyles2(getStyles);
@@ -80,6 +83,7 @@ export const ConfirmModal = ({
onConfirm={onConfirm}
onDismiss={onDismiss}
onAlternative={onAlternative}
+ disabled={disabled}
/>
);
diff --git a/packages/grafana-ui/src/components/ContextMenu/ContextMenu.story.tsx b/packages/grafana-ui/src/components/ContextMenu/ContextMenu.story.tsx
index 19888e4b5bf..3834bccbedf 100644
--- a/packages/grafana-ui/src/components/ContextMenu/ContextMenu.story.tsx
+++ b/packages/grafana-ui/src/components/ContextMenu/ContextMenu.story.tsx
@@ -1,6 +1,6 @@
import { action } from '@storybook/addon-actions';
import { StoryFn, Meta } from '@storybook/react';
-import React from 'react';
+import * as React from 'react';
import { IconButton } from '../IconButton/IconButton';
diff --git a/packages/grafana-ui/src/components/ContextMenu/ContextMenu.tsx b/packages/grafana-ui/src/components/ContextMenu/ContextMenu.tsx
index a6a90a6ed35..86802d58743 100644
--- a/packages/grafana-ui/src/components/ContextMenu/ContextMenu.tsx
+++ b/packages/grafana-ui/src/components/ContextMenu/ContextMenu.tsx
@@ -1,4 +1,5 @@
-import React, { useRef, useState, useLayoutEffect } from 'react';
+import { useRef, useState, useLayoutEffect } from 'react';
+import * as React from 'react';
import { useClickAway } from 'react-use';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-ui/src/components/ContextMenu/ContextMenuStoryHelper.tsx b/packages/grafana-ui/src/components/ContextMenu/ContextMenuStoryHelper.tsx
index 66b905a0239..be4613d25a1 100644
--- a/packages/grafana-ui/src/components/ContextMenu/ContextMenuStoryHelper.tsx
+++ b/packages/grafana-ui/src/components/ContextMenu/ContextMenuStoryHelper.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { MenuGroup } from '../Menu/MenuGroup';
import { MenuItem } from '../Menu/MenuItem';
diff --git a/packages/grafana-ui/src/components/ContextMenu/WithContextMenu.tsx b/packages/grafana-ui/src/components/ContextMenu/WithContextMenu.tsx
index a3fa1f9c452..f02aba48c1f 100644
--- a/packages/grafana-ui/src/components/ContextMenu/WithContextMenu.tsx
+++ b/packages/grafana-ui/src/components/ContextMenu/WithContextMenu.tsx
@@ -1,4 +1,5 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
+import * as React from 'react';
import { ContextMenu } from '../ContextMenu/ContextMenu';
diff --git a/packages/grafana-ui/src/components/CustomScrollbar/CustomScrollbar.test.tsx b/packages/grafana-ui/src/components/CustomScrollbar/CustomScrollbar.test.tsx
index 0c8c84a229d..003d5721d9d 100644
--- a/packages/grafana-ui/src/components/CustomScrollbar/CustomScrollbar.test.tsx
+++ b/packages/grafana-ui/src/components/CustomScrollbar/CustomScrollbar.test.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import renderer from 'react-test-renderer';
import { CustomScrollbar } from './CustomScrollbar';
diff --git a/packages/grafana-ui/src/components/CustomScrollbar/CustomScrollbar.tsx b/packages/grafana-ui/src/components/CustomScrollbar/CustomScrollbar.tsx
index ab949ebc99e..6da36b9b03d 100644
--- a/packages/grafana-ui/src/components/CustomScrollbar/CustomScrollbar.tsx
+++ b/packages/grafana-ui/src/components/CustomScrollbar/CustomScrollbar.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { RefCallback, useCallback, useEffect, useRef } from 'react';
+import { RefCallback, useCallback, useEffect, useRef } from 'react';
+import * as React from 'react';
import Scrollbars, { positionValues } from 'react-custom-scrollbars-2';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/CustomScrollbar/ScrollIndicators.tsx b/packages/grafana-ui/src/components/CustomScrollbar/ScrollIndicators.tsx
index ef80d3df6a1..0572e8cd66d 100644
--- a/packages/grafana-ui/src/components/CustomScrollbar/ScrollIndicators.tsx
+++ b/packages/grafana-ui/src/components/CustomScrollbar/ScrollIndicators.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { useEffect, useRef, useState } from 'react';
+import { useEffect, useRef, useState } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/DataLinks/DataLinkButton.tsx b/packages/grafana-ui/src/components/DataLinks/DataLinkButton.tsx
index a2d327167ba..47ddfc7f493 100644
--- a/packages/grafana-ui/src/components/DataLinks/DataLinkButton.tsx
+++ b/packages/grafana-ui/src/components/DataLinks/DataLinkButton.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Field, LinkModel } from '@grafana/data';
import { ButtonProps, Button } from '../Button';
diff --git a/packages/grafana-ui/src/components/DataLinks/DataLinkEditor.tsx b/packages/grafana-ui/src/components/DataLinks/DataLinkEditor.tsx
index 115b1b93674..f671f98d21f 100644
--- a/packages/grafana-ui/src/components/DataLinks/DataLinkEditor.tsx
+++ b/packages/grafana-ui/src/components/DataLinks/DataLinkEditor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { ChangeEvent } from 'react';
+import { memo, ChangeEvent } from 'react';
import { VariableSuggestion, GrafanaTheme2, DataLink } from '@grafana/data';
@@ -30,7 +30,7 @@ const getStyles = (theme: GrafanaTheme2) => ({
}),
});
-export const DataLinkEditor = React.memo(({ index, value, onChange, suggestions, isLast }: DataLinkEditorProps) => {
+export const DataLinkEditor = memo(({ index, value, onChange, suggestions, isLast }: DataLinkEditorProps) => {
const styles = useStyles2(getStyles);
const onUrlChange = (url: string, callback?: () => void) => {
diff --git a/packages/grafana-ui/src/components/DataLinks/DataLinkInput.tsx b/packages/grafana-ui/src/components/DataLinks/DataLinkInput.tsx
index ecc981cf3a2..81f03efc4f4 100644
--- a/packages/grafana-ui/src/components/DataLinks/DataLinkInput.tsx
+++ b/packages/grafana-ui/src/components/DataLinks/DataLinkInput.tsx
@@ -1,7 +1,8 @@
import { css, cx } from '@emotion/css';
import { autoUpdate, flip, offset, shift, useFloating } from '@floating-ui/react';
import Prism, { Grammar, LanguageMap } from 'prismjs';
-import React, { memo, useEffect, useRef, useState } from 'react';
+import { memo, useEffect, useRef, useState } from 'react';
+import * as React from 'react';
import usePrevious from 'react-use/lib/usePrevious';
import { Value } from 'slate';
import Plain from 'slate-plain-serializer';
diff --git a/packages/grafana-ui/src/components/DataLinks/DataLinkSuggestions.tsx b/packages/grafana-ui/src/components/DataLinks/DataLinkSuggestions.tsx
index 472d69eee7e..2e6ca8d215a 100644
--- a/packages/grafana-ui/src/components/DataLinks/DataLinkSuggestions.tsx
+++ b/packages/grafana-ui/src/components/DataLinks/DataLinkSuggestions.tsx
@@ -1,6 +1,7 @@
import { css, cx } from '@emotion/css';
import { groupBy, capitalize } from 'lodash';
-import React, { useRef, useMemo } from 'react';
+import { useRef, useMemo } from 'react';
+import * as React from 'react';
import useClickAway from 'react-use/lib/useClickAway';
import { VariableSuggestion, GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/DataLinks/DataLinksContextMenu.test.tsx b/packages/grafana-ui/src/components/DataLinks/DataLinksContextMenu.test.tsx
index 34c826a03f9..64d7049d8d4 100644
--- a/packages/grafana-ui/src/components/DataLinks/DataLinksContextMenu.test.tsx
+++ b/packages/grafana-ui/src/components/DataLinks/DataLinksContextMenu.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-ui/src/components/DataLinks/DataLinksContextMenu.tsx b/packages/grafana-ui/src/components/DataLinks/DataLinksContextMenu.tsx
index 64e11a28288..afd3c8855b5 100644
--- a/packages/grafana-ui/src/components/DataLinks/DataLinksContextMenu.tsx
+++ b/packages/grafana-ui/src/components/DataLinks/DataLinksContextMenu.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { CSSProperties } from 'react';
+import { CSSProperties } from 'react';
+import * as React from 'react';
import { LinkModel } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-ui/src/components/DataLinks/DataLinksInlineEditor/DataLinkEditorModalContent.tsx b/packages/grafana-ui/src/components/DataLinks/DataLinksInlineEditor/DataLinkEditorModalContent.tsx
index 4b2cebf7adf..0a9e94e5f63 100644
--- a/packages/grafana-ui/src/components/DataLinks/DataLinksInlineEditor/DataLinkEditorModalContent.tsx
+++ b/packages/grafana-ui/src/components/DataLinks/DataLinksInlineEditor/DataLinkEditorModalContent.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { DataFrame, DataLink, VariableSuggestion } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/DataLinks/DataLinksInlineEditor/DataLinksInlineEditor.tsx b/packages/grafana-ui/src/components/DataLinks/DataLinksInlineEditor/DataLinksInlineEditor.tsx
index 99914a5a4c3..509c65d1dc2 100644
--- a/packages/grafana-ui/src/components/DataLinks/DataLinksInlineEditor/DataLinksInlineEditor.tsx
+++ b/packages/grafana-ui/src/components/DataLinks/DataLinksInlineEditor/DataLinksInlineEditor.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { cloneDeep } from 'lodash';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { DataFrame, DataLink, GrafanaTheme2, VariableSuggestion } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/DataLinks/DataLinksInlineEditor/DataLinksListItem.test.tsx b/packages/grafana-ui/src/components/DataLinks/DataLinksInlineEditor/DataLinksListItem.test.tsx
index 90df2a95099..bca3ab2f072 100644
--- a/packages/grafana-ui/src/components/DataLinks/DataLinksInlineEditor/DataLinksListItem.test.tsx
+++ b/packages/grafana-ui/src/components/DataLinks/DataLinksInlineEditor/DataLinksListItem.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { DataLinksListItem, DataLinksListItemProps } from './DataLinksListItem';
diff --git a/packages/grafana-ui/src/components/DataLinks/DataLinksInlineEditor/DataLinksListItem.tsx b/packages/grafana-ui/src/components/DataLinks/DataLinksInlineEditor/DataLinksListItem.tsx
index 97a23834fe7..705347567a6 100644
--- a/packages/grafana-ui/src/components/DataLinks/DataLinksInlineEditor/DataLinksListItem.tsx
+++ b/packages/grafana-ui/src/components/DataLinks/DataLinksInlineEditor/DataLinksListItem.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { DataFrame, DataLink, GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/DataLinks/FieldLinkList.tsx b/packages/grafana-ui/src/components/DataLinks/FieldLinkList.tsx
index 2ca9ac59f95..2712c5b7af1 100644
--- a/packages/grafana-ui/src/components/DataLinks/FieldLinkList.tsx
+++ b/packages/grafana-ui/src/components/DataLinks/FieldLinkList.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { Field, GrafanaTheme2, LinkModel } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/DataSourceSettings/AlertingSettings.test.tsx b/packages/grafana-ui/src/components/DataSourceSettings/AlertingSettings.test.tsx
index e860f0ade63..82c0c782fd3 100644
--- a/packages/grafana-ui/src/components/DataSourceSettings/AlertingSettings.test.tsx
+++ b/packages/grafana-ui/src/components/DataSourceSettings/AlertingSettings.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { AlertingSettings } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/DataSourceSettings/AlertingSettings.tsx b/packages/grafana-ui/src/components/DataSourceSettings/AlertingSettings.tsx
index e02c7954daf..0cab20711c7 100644
--- a/packages/grafana-ui/src/components/DataSourceSettings/AlertingSettings.tsx
+++ b/packages/grafana-ui/src/components/DataSourceSettings/AlertingSettings.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { DataSourceJsonData, DataSourcePluginOptionsEditorProps } from '@grafana/data';
import { InlineSwitch } from '../../components/Switch/Switch';
diff --git a/packages/grafana-ui/src/components/DataSourceSettings/BasicAuthSettings.tsx b/packages/grafana-ui/src/components/DataSourceSettings/BasicAuthSettings.tsx
index 7086c9b7148..36f13215210 100644
--- a/packages/grafana-ui/src/components/DataSourceSettings/BasicAuthSettings.tsx
+++ b/packages/grafana-ui/src/components/DataSourceSettings/BasicAuthSettings.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { InlineField } from '../../components/Forms/InlineField';
import { FormField } from '../FormField/FormField';
diff --git a/packages/grafana-ui/src/components/DataSourceSettings/CertificationKey.tsx b/packages/grafana-ui/src/components/DataSourceSettings/CertificationKey.tsx
index 6355ba9440b..8b574aeb4fd 100644
--- a/packages/grafana-ui/src/components/DataSourceSettings/CertificationKey.tsx
+++ b/packages/grafana-ui/src/components/DataSourceSettings/CertificationKey.tsx
@@ -1,4 +1,4 @@
-import React, { ChangeEvent, MouseEvent } from 'react';
+import { ChangeEvent, MouseEvent } from 'react';
import { Button } from '../Button';
import { InlineField } from '../Forms/InlineField';
diff --git a/packages/grafana-ui/src/components/DataSourceSettings/CustomHeadersSettings.test.tsx b/packages/grafana-ui/src/components/DataSourceSettings/CustomHeadersSettings.test.tsx
index a5cc5172898..007d74cbce6 100644
--- a/packages/grafana-ui/src/components/DataSourceSettings/CustomHeadersSettings.test.tsx
+++ b/packages/grafana-ui/src/components/DataSourceSettings/CustomHeadersSettings.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { CustomHeadersSettings, Props } from './CustomHeadersSettings';
diff --git a/packages/grafana-ui/src/components/DataSourceSettings/CustomHeadersSettings.tsx b/packages/grafana-ui/src/components/DataSourceSettings/CustomHeadersSettings.tsx
index 0751890d5a0..fe7f9d9d1b7 100644
--- a/packages/grafana-ui/src/components/DataSourceSettings/CustomHeadersSettings.tsx
+++ b/packages/grafana-ui/src/components/DataSourceSettings/CustomHeadersSettings.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { uniqueId } from 'lodash';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { DataSourceSettings } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/DataSourceSettings/DataSourceHttpSettings.story.tsx b/packages/grafana-ui/src/components/DataSourceSettings/DataSourceHttpSettings.story.tsx
index 3541c6e5f59..a1b51c6e78a 100644
--- a/packages/grafana-ui/src/components/DataSourceSettings/DataSourceHttpSettings.story.tsx
+++ b/packages/grafana-ui/src/components/DataSourceSettings/DataSourceHttpSettings.story.tsx
@@ -1,7 +1,6 @@
import { action } from '@storybook/addon-actions';
import { useArgs } from '@storybook/preview-api';
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { DataSourceHttpSettings } from './DataSourceHttpSettings';
import mdx from './DataSourceHttpSettings.mdx';
diff --git a/packages/grafana-ui/src/components/DataSourceSettings/DataSourceHttpSettings.test.tsx b/packages/grafana-ui/src/components/DataSourceSettings/DataSourceHttpSettings.test.tsx
index 2daebd46a92..61ce7d881ff 100644
--- a/packages/grafana-ui/src/components/DataSourceSettings/DataSourceHttpSettings.test.tsx
+++ b/packages/grafana-ui/src/components/DataSourceSettings/DataSourceHttpSettings.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { DataSourceHttpSettings } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/DataSourceSettings/DataSourceHttpSettings.tsx b/packages/grafana-ui/src/components/DataSourceSettings/DataSourceHttpSettings.tsx
index d9d9d8df1fb..ad412649e7e 100644
--- a/packages/grafana-ui/src/components/DataSourceSettings/DataSourceHttpSettings.tsx
+++ b/packages/grafana-ui/src/components/DataSourceSettings/DataSourceHttpSettings.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { useState, useCallback, useId } from 'react';
+import { useState, useCallback, useId } from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-ui/src/components/DataSourceSettings/HttpProxySettings.tsx b/packages/grafana-ui/src/components/DataSourceSettings/HttpProxySettings.tsx
index 33b6cc0b7fd..66335368f8b 100644
--- a/packages/grafana-ui/src/components/DataSourceSettings/HttpProxySettings.tsx
+++ b/packages/grafana-ui/src/components/DataSourceSettings/HttpProxySettings.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { InlineField } from '../Forms/InlineField';
import { InlineSwitch } from '../Switch/Switch';
diff --git a/packages/grafana-ui/src/components/DataSourceSettings/SecureSocksProxySettings.tsx b/packages/grafana-ui/src/components/DataSourceSettings/SecureSocksProxySettings.tsx
index 79e244a99b3..df2d0fe2078 100644
--- a/packages/grafana-ui/src/components/DataSourceSettings/SecureSocksProxySettings.tsx
+++ b/packages/grafana-ui/src/components/DataSourceSettings/SecureSocksProxySettings.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { DataSourceJsonData, DataSourcePluginOptionsEditorProps } from '@grafana/data';
import { InlineSwitch } from '../../components/Switch/Switch';
diff --git a/packages/grafana-ui/src/components/DataSourceSettings/TLSAuthSettings.tsx b/packages/grafana-ui/src/components/DataSourceSettings/TLSAuthSettings.tsx
index 41614c1c587..acaa314e0e4 100644
--- a/packages/grafana-ui/src/components/DataSourceSettings/TLSAuthSettings.tsx
+++ b/packages/grafana-ui/src/components/DataSourceSettings/TLSAuthSettings.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { KeyValue } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/DataSourceSettings/types.ts b/packages/grafana-ui/src/components/DataSourceSettings/types.ts
index 7fe44bd7862..567d32fcf86 100644
--- a/packages/grafana-ui/src/components/DataSourceSettings/types.ts
+++ b/packages/grafana-ui/src/components/DataSourceSettings/types.ts
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { DataSourceJsonData, DataSourceSettings } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/DatePicker/DatePicker.mdx b/packages/grafana-ui/src/components/DateTimePickers/DatePicker/DatePicker.mdx
index 6a4fded7636..43ebf3f22ad 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/DatePicker/DatePicker.mdx
+++ b/packages/grafana-ui/src/components/DateTimePickers/DatePicker/DatePicker.mdx
@@ -8,7 +8,7 @@ A component with a calendar view for selecting a date.
### Usage
```tsx
-import React, { useState } from 'react';
+import { useState } from 'react';
import { DatePicker, Button } from '@grafana/ui';
const [date, setDate] = useState(new Date());
diff --git a/packages/grafana-ui/src/components/DateTimePickers/DatePicker/DatePicker.story.tsx b/packages/grafana-ui/src/components/DateTimePickers/DatePicker/DatePicker.story.tsx
index da8d485f776..29b10d03148 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/DatePicker/DatePicker.story.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/DatePicker/DatePicker.story.tsx
@@ -1,5 +1,5 @@
import { Meta } from '@storybook/react';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { Button } from '../../Button/Button';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/DatePicker/DatePicker.test.tsx b/packages/grafana-ui/src/components/DateTimePickers/DatePicker/DatePicker.test.tsx
index 7ee7671bcc8..b0aeabb0e2e 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/DatePicker/DatePicker.test.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/DatePicker/DatePicker.test.tsx
@@ -1,5 +1,4 @@
import { fireEvent, render, screen } from '@testing-library/react';
-import React from 'react';
import { DatePicker } from './DatePicker';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/DatePicker/DatePicker.tsx b/packages/grafana-ui/src/components/DateTimePickers/DatePicker/DatePicker.tsx
index 358d985a169..e48656b38fc 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/DatePicker/DatePicker.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/DatePicker/DatePicker.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { memo } from 'react';
+import { memo } from 'react';
import Calendar from 'react-calendar';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/DatePickerWithInput/DatePickerWithInput.mdx b/packages/grafana-ui/src/components/DateTimePickers/DatePickerWithInput/DatePickerWithInput.mdx
index 608c3662ccc..2a67e9cc9f9 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/DatePickerWithInput/DatePickerWithInput.mdx
+++ b/packages/grafana-ui/src/components/DateTimePickers/DatePickerWithInput/DatePickerWithInput.mdx
@@ -8,7 +8,7 @@ An input with a calendar view, used to select a date.
### Usage
```tsx
-import React, { useState } from 'react';
+import { useState } from 'react';
import { DatePickerWithInput } from '@grafana/ui';
const [date, setDate] = useState(new Date());
diff --git a/packages/grafana-ui/src/components/DateTimePickers/DatePickerWithInput/DatePickerWithInput.story.tsx b/packages/grafana-ui/src/components/DateTimePickers/DatePickerWithInput/DatePickerWithInput.story.tsx
index daa8cf2916c..66b067846dd 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/DatePickerWithInput/DatePickerWithInput.story.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/DatePickerWithInput/DatePickerWithInput.story.tsx
@@ -1,7 +1,6 @@
import { action } from '@storybook/addon-actions';
import { useArgs } from '@storybook/preview-api';
import { StoryFn, Meta } from '@storybook/react';
-import React from 'react';
import { DatePickerWithInput } from './DatePickerWithInput';
import mdx from './DatePickerWithInput.mdx';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/DatePickerWithInput/DatePickerWithInput.test.tsx b/packages/grafana-ui/src/components/DateTimePickers/DatePickerWithInput/DatePickerWithInput.test.tsx
index f67bedfd45c..11c27cff02e 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/DatePickerWithInput/DatePickerWithInput.test.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/DatePickerWithInput/DatePickerWithInput.test.tsx
@@ -1,5 +1,4 @@
import { fireEvent, render, screen } from '@testing-library/react';
-import React from 'react';
import { dateTimeFormat } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/DatePickerWithInput/DatePickerWithInput.tsx b/packages/grafana-ui/src/components/DateTimePickers/DatePickerWithInput/DatePickerWithInput.tsx
index 515160fceed..c1f151beded 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/DatePickerWithInput/DatePickerWithInput.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/DatePickerWithInput/DatePickerWithInput.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { autoUpdate, flip, shift, useClick, useDismiss, useFloating, useInteractions } from '@floating-ui/react';
-import React, { ChangeEvent, useState } from 'react';
+import { ChangeEvent, useState } from 'react';
import { GrafanaTheme2, dateTime } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/DateTimePicker/DateTimePicker.mdx b/packages/grafana-ui/src/components/DateTimePickers/DateTimePicker/DateTimePicker.mdx
index 356f3f4ab54..773bcfa997c 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/DateTimePicker/DateTimePicker.mdx
+++ b/packages/grafana-ui/src/components/DateTimePickers/DateTimePicker/DateTimePicker.mdx
@@ -8,7 +8,7 @@ A component for selecting a date _and_ time.
### Usage
```tsx
-import React, { useState } from 'react';
+import { useState } from 'react';
import { DateTime, dateTime } from '@grafana/data';
import { DateTimePicker } from '@grafana/ui';
@@ -19,7 +19,7 @@ return ;
### With disabled hours, minutes or seconds
```tsx
-import React, { useState } from 'react';
+import { useState } from 'react';
import { DateTime, dateTime } from '@grafana/data';
import { DateTimePicker } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/DateTimePicker/DateTimePicker.story.tsx b/packages/grafana-ui/src/components/DateTimePickers/DateTimePicker/DateTimePicker.story.tsx
index 4fe4573db69..a7a8d87961f 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/DateTimePicker/DateTimePicker.story.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/DateTimePicker/DateTimePicker.story.tsx
@@ -1,6 +1,6 @@
import { action } from '@storybook/addon-actions';
import { StoryFn, Meta } from '@storybook/react';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { dateTime, DateTime } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/DateTimePicker/DateTimePicker.test.tsx b/packages/grafana-ui/src/components/DateTimePickers/DateTimePicker/DateTimePicker.test.tsx
index 5258ee22ad0..187366e6b47 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/DateTimePicker/DateTimePicker.test.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/DateTimePicker/DateTimePicker.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { dateTime, dateTimeAsMoment, dateTimeForTimeZone, getTimeZone, setTimeZoneResolver } from '@grafana/data';
import { Components } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/DateTimePicker/DateTimePicker.tsx b/packages/grafana-ui/src/components/DateTimePickers/DateTimePicker/DateTimePicker.tsx
index 4a0b12cf330..9124d4636d0 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/DateTimePicker/DateTimePicker.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/DateTimePicker/DateTimePicker.tsx
@@ -3,7 +3,8 @@ import { autoUpdate, flip, shift, useFloating } from '@floating-ui/react';
import { useDialog } from '@react-aria/dialog';
import { FocusScope } from '@react-aria/focus';
import { useOverlay } from '@react-aria/overlays';
-import React, { FormEvent, ReactNode, useCallback, useEffect, useRef, useState } from 'react';
+import { FormEvent, ReactNode, useCallback, useEffect, useRef, useState } from 'react';
+import * as React from 'react';
import Calendar from 'react-calendar';
import { useMedia } from 'react-use';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/RelativeTimeRangePicker/RelativeTimeRangePicker.story.tsx b/packages/grafana-ui/src/components/DateTimePickers/RelativeTimeRangePicker/RelativeTimeRangePicker.story.tsx
index 6b52e886c3b..a6a0813e210 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/RelativeTimeRangePicker/RelativeTimeRangePicker.story.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/RelativeTimeRangePicker/RelativeTimeRangePicker.story.tsx
@@ -1,7 +1,6 @@
import { action } from '@storybook/addon-actions';
import { useArgs } from '@storybook/preview-api';
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { RelativeTimeRangePicker } from './RelativeTimeRangePicker';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/RelativeTimeRangePicker/RelativeTimeRangePicker.test.tsx b/packages/grafana-ui/src/components/DateTimePickers/RelativeTimeRangePicker/RelativeTimeRangePicker.test.tsx
index d4b3b0c6226..9d6a45c6f29 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/RelativeTimeRangePicker/RelativeTimeRangePicker.test.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/RelativeTimeRangePicker/RelativeTimeRangePicker.test.tsx
@@ -1,6 +1,6 @@
import { render, RenderResult } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { RelativeTimeRange } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/RelativeTimeRangePicker/RelativeTimeRangePicker.tsx b/packages/grafana-ui/src/components/DateTimePickers/RelativeTimeRangePicker/RelativeTimeRangePicker.tsx
index b7f5b76bda3..25abe7efe25 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/RelativeTimeRangePicker/RelativeTimeRangePicker.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/RelativeTimeRangePicker/RelativeTimeRangePicker.tsx
@@ -3,7 +3,7 @@ import { autoUpdate, flip, shift, useClick, useDismiss, useFloating, useInteract
import { useDialog } from '@react-aria/dialog';
import { FocusScope } from '@react-aria/focus';
import { useOverlay } from '@react-aria/overlays';
-import React, { FormEvent, useCallback, useRef, useState } from 'react';
+import { FormEvent, useCallback, useRef, useState } from 'react';
import { RelativeTimeRange, GrafanaTheme2, TimeOption } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeOfDayPicker.story.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeOfDayPicker.story.tsx
index cd72d21e1dc..bde38d03457 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/TimeOfDayPicker.story.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/TimeOfDayPicker.story.tsx
@@ -1,7 +1,6 @@
import { action } from '@storybook/addon-actions';
import { useArgs } from '@storybook/preview-api';
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { dateTime } from '@grafana/data';
import { TimeOfDayPicker } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeOfDayPicker.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeOfDayPicker.tsx
index f6e64fb279a..23e6e2d2870 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/TimeOfDayPicker.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/TimeOfDayPicker.tsx
@@ -1,6 +1,5 @@
import { css, cx } from '@emotion/css';
import RcTimePicker from 'rc-time-picker';
-import React from 'react';
import { dateTime, DateTime, dateTimeAsMoment, GrafanaTheme2, isDateTimeInput } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeRangeInput.story.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeRangeInput.story.tsx
index bb4e248190c..db5c56a8816 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/TimeRangeInput.story.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/TimeRangeInput.story.tsx
@@ -1,7 +1,6 @@
import { action } from '@storybook/addon-actions';
import { useArgs } from '@storybook/preview-api';
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { dateTime, DefaultTimeZone, isDateTime, TimeRange } from '@grafana/data';
import { TimeRangeInput } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeRangeInput.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeRangeInput.tsx
index 03b48a4d7ff..12e910661a2 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/TimeRangeInput.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/TimeRangeInput.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { FormEvent, MouseEvent, useState } from 'react';
+import { FormEvent, MouseEvent, useState } from 'react';
import { dateTime, getDefaultTimeRange, GrafanaTheme2, TimeRange, TimeZone } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
@@ -11,6 +11,7 @@ import { getInputStyles } from '../Input/Input';
import { TimePickerContent } from './TimeRangePicker/TimePickerContent';
import { TimeRangeLabel } from './TimeRangePicker/TimeRangeLabel';
+import { WeekStart } from './WeekStartPicker';
import { quickOptions } from './options';
import { isValidTimeRange } from './utils';
@@ -28,6 +29,8 @@ export interface TimeRangeInputProps {
hideQuickRanges?: boolean;
disabled?: boolean;
showIcon?: boolean;
+ /** Which day of the week the calendar should start on. Possible values: "saturday", "sunday" or "monday" */
+ weekStart?: WeekStart;
}
const noop = () => {};
@@ -37,6 +40,7 @@ export const TimeRangeInput = ({
onChange,
onChangeTimeZone = noop,
clearable,
+ weekStart,
hideTimeZone = true,
timeZone = 'browser',
placeholder = 'Select time range',
@@ -106,6 +110,7 @@ export const TimeRangeInput = ({
hideTimeZone={hideTimeZone}
isReversed={isReversed}
hideQuickRanges={hideQuickRanges}
+ weekStart={weekStart}
/>
)}
diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker.story.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker.story.tsx
index e756cb293bb..47ad36a6c6d 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker.story.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker.story.tsx
@@ -1,7 +1,6 @@
import { action } from '@storybook/addon-actions';
import { useArgs } from '@storybook/preview-api';
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { dateTime, DefaultTimeZone } from '@grafana/data';
import { TimeRangePicker } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker.test.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker.test.tsx
index 13b46255d37..b0dfaa27ede 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker.test.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { dateTime, TimeRange } from '@grafana/data';
import { selectors as e2eSelectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker.tsx
index d76cd7ac5fd..e83357196f5 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker.tsx
@@ -2,7 +2,7 @@ import { css, cx } from '@emotion/css';
import { useDialog } from '@react-aria/dialog';
import { FocusScope } from '@react-aria/focus';
import { useOverlay } from '@react-aria/overlays';
-import React, { memo, createRef, useState, useEffect } from 'react';
+import { memo, createRef, useState, useEffect } from 'react';
import {
rangeUtil,
@@ -23,6 +23,7 @@ import { ToolbarButton } from '../ToolbarButton';
import { Tooltip } from '../Tooltip/Tooltip';
import { TimePickerContent } from './TimeRangePicker/TimePickerContent';
+import { WeekStart } from './WeekStartPicker';
import { quickOptions } from './options';
/** @public */
@@ -45,6 +46,8 @@ export interface TimeRangePickerProps {
widthOverride?: number;
isOnCanvas?: boolean;
onToolbarTimePickerClick?: () => void;
+ /** Which day of the week the calendar should start on. Possible values: "saturday", "sunday" or "monday" */
+ weekStart?: WeekStart;
}
export interface State {
@@ -71,6 +74,7 @@ export function TimeRangePicker(props: TimeRangePickerProps) {
widthOverride,
isOnCanvas,
onToolbarTimePickerClick,
+ weekStart,
} = props;
const onChange = (timeRange: TimeRange) => {
@@ -168,6 +172,7 @@ export function TimeRangePicker(props: TimeRangePickerProps) {
onChangeFiscalYearStartMonth={onChangeFiscalYearStartMonth}
hideQuickRanges={hideQuickRanges}
onError={onError}
+ weekStart={weekStart}
/>
diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/CalendarBody.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/CalendarBody.tsx
index 652c223a0eb..a3f988cb3a4 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/CalendarBody.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/CalendarBody.tsx
@@ -1,17 +1,25 @@
import { css } from '@emotion/css';
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import Calendar from 'react-calendar';
+import { CalendarType } from 'react-calendar/dist/cjs/shared/types';
import { GrafanaTheme2, dateTimeParse, DateTime, TimeZone } from '@grafana/data';
import { useStyles2 } from '../../../themes';
import { t } from '../../../utils/i18n';
import { Icon } from '../../Icon/Icon';
+import { WeekStart } from '../WeekStartPicker';
import { adjustDateForReactCalendar } from '../utils/adjustDateForReactCalendar';
import { TimePickerCalendarProps } from './TimePickerCalendar';
-export function Body({ onChange, from, to, timeZone }: TimePickerCalendarProps) {
+const weekStartMap: Record = {
+ saturday: 'islamic',
+ sunday: 'gregory',
+ monday: 'iso8601',
+};
+
+export function Body({ onChange, from, to, timeZone, weekStart = 'monday' }: TimePickerCalendarProps) {
const value = inputToValue(from, to, new Date(), timeZone);
const onCalendarChange = useOnCalendarChange(onChange, timeZone);
const styles = useStyles2(getBodyStyles);
@@ -30,6 +38,7 @@ export function Body({ onChange, from, to, timeZone }: TimePickerCalendarProps)
prevAriaLabel={t('time-picker.calendar.previous-month', 'Previous month')}
onChange={onCalendarChange}
locale="en"
+ calendarType={weekStartMap[weekStart]}
/>
);
}
diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/CalendarFooter.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/CalendarFooter.tsx
index 1f5ab28cff4..58d0e317fc6 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/CalendarFooter.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/CalendarFooter.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Trans } from '../../../utils/i18n';
import { Button } from '../../Button';
import { Stack } from '../../Layout/Stack/Stack';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/CalendarHeader.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/CalendarHeader.tsx
index c09d39d198a..8c02a21cee4 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/CalendarHeader.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/CalendarHeader.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { selectors } from '@grafana/e2e-selectors';
import { Trans, t } from '../../../utils/i18n';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimePickerCalendar.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimePickerCalendar.tsx
index 9b39f55f4af..d2ac66f7ba2 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimePickerCalendar.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimePickerCalendar.tsx
@@ -2,13 +2,14 @@ import { css } from '@emotion/css';
import { useDialog } from '@react-aria/dialog';
import { FocusScope } from '@react-aria/focus';
import { OverlayContainer, useOverlay } from '@react-aria/overlays';
-import React, { FormEvent, memo } from 'react';
+import { createRef, FormEvent, memo } from 'react';
import { DateTime, GrafanaTheme2, TimeZone } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { useStyles2, useTheme2 } from '../../../themes';
import { getModalStyles } from '../../Modal/getModalStyles';
+import { WeekStart } from '../WeekStartPicker';
import { Body } from './CalendarBody';
import { Footer } from './CalendarFooter';
@@ -58,6 +59,7 @@ export interface TimePickerCalendarProps {
onClose: () => void;
onApply: (e: FormEvent) => void;
onChange: (from: DateTime, to: DateTime) => void;
+ weekStart?: WeekStart;
/**
* When true, the calendar is rendered as a floating "tooltip" next to the input.
@@ -73,7 +75,7 @@ function TimePickerCalendar(props: TimePickerCalendarProps) {
const { modalBackdrop } = useStyles2(getModalStyles);
const styles = getStyles(theme, props.isReversed);
const { isOpen, isFullscreen: isFullscreenProp, onClose } = props;
- const ref = React.createRef();
+ const ref = createRef();
const { dialogProps } = useDialog(
{
'aria-label': selectors.components.TimePicker.calendar.label,
diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimePickerContent.test.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimePickerContent.test.tsx
index ba9c9a4f011..18fa0cf2f24 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimePickerContent.test.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimePickerContent.test.tsx
@@ -1,5 +1,4 @@
import { render, RenderResult, screen } from '@testing-library/react';
-import React from 'react';
import { dateTime, TimeRange } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimePickerContent.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimePickerContent.tsx
index f8d9b847cf1..6b8a47d5932 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimePickerContent.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimePickerContent.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { memo, useMemo, useState } from 'react';
+import { memo, useMemo, useState } from 'react';
import { GrafanaTheme2, isDateTime, rangeUtil, RawTimeRange, TimeOption, TimeRange, TimeZone } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
@@ -9,6 +9,7 @@ import { getFocusStyles } from '../../../themes/mixins';
import { t, Trans } from '../../../utils/i18n';
import { FilterInput } from '../../FilterInput/FilterInput';
import { Icon } from '../../Icon/Icon';
+import { WeekStart } from '../WeekStartPicker';
import { TimePickerFooter } from './TimePickerFooter';
import { TimePickerTitle } from './TimePickerTitle';
@@ -33,6 +34,7 @@ interface Props {
isReversed?: boolean;
hideQuickRanges?: boolean;
widthOverride?: number;
+ weekStart?: WeekStart;
}
export interface PropsWithScreenSize extends Props {
@@ -121,7 +123,7 @@ export const TimePickerContent = (props: Props) => {
};
const NarrowScreenForm = (props: FormProps) => {
- const { value, hideQuickRanges, onChange, timeZone, historyOptions = [], showHistory, onError } = props;
+ const { value, hideQuickRanges, onChange, timeZone, historyOptions = [], showHistory, onError, weekStart } = props;
const styles = useStyles2(getNarrowScreenStyles);
const isAbsolute = isDateTime(value.raw.from) || isDateTime(value.raw.to);
const [collapsedFlag, setCollapsedFlag] = useState(!isAbsolute);
@@ -161,6 +163,7 @@ const NarrowScreenForm = (props: FormProps) => {
timeZone={timeZone}
isFullscreen={false}
onError={onError}
+ weekStart={weekStart}
/>
{showHistory && (
@@ -178,7 +181,7 @@ const NarrowScreenForm = (props: FormProps) => {
};
const FullScreenForm = (props: FormProps) => {
- const { onChange, value, timeZone, fiscalYearStartMonth, isReversed, historyOptions, onError } = props;
+ const { onChange, value, timeZone, fiscalYearStartMonth, isReversed, historyOptions, onError, weekStart } = props;
const styles = useStyles2(getFullScreenStyles, props.hideQuickRanges);
const onChangeTimeOption = (timeOption: TimeOption) => {
return onChange(mapOptionToTimeRange(timeOption, timeZone));
@@ -200,6 +203,7 @@ const FullScreenForm = (props: FormProps) => {
isFullscreen={true}
isReversed={isReversed}
onError={onError}
+ weekStart={weekStart}
/>
{props.showHistory && (
diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimePickerFooter.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimePickerFooter.tsx
index 34f24ae49dc..28b328ed5c3 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimePickerFooter.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimePickerFooter.tsx
@@ -1,6 +1,7 @@
import { css, cx } from '@emotion/css';
import { isString } from 'lodash';
-import React, { useCallback, useId, useState } from 'react';
+import { useCallback, useId, useState } from 'react';
+import * as React from 'react';
import { getTimeZoneInfo, GrafanaTheme2, TimeZone } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimePickerTitle.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimePickerTitle.tsx
index 1df35b9a364..e65201002bb 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimePickerTitle.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimePickerTitle.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { memo, PropsWithChildren } from 'react';
+import { memo, PropsWithChildren } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimeRangeContent.test.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimeRangeContent.test.tsx
index 40a1964b224..d6a7aa1c35e 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimeRangeContent.test.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimeRangeContent.test.tsx
@@ -1,6 +1,5 @@
import { fireEvent, render, RenderResult } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { dateTimeParse, TimeRange } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimeRangeContent.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimeRangeContent.tsx
index d5a53aa10f3..87f5572c586 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimeRangeContent.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimeRangeContent.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { FormEvent, useCallback, useEffect, useId, useState } from 'react';
+import { FormEvent, useCallback, useEffect, useId, useState } from 'react';
+import * as React from 'react';
import {
DateTime,
@@ -21,6 +22,7 @@ import { Field } from '../../Forms/Field';
import { Icon } from '../../Icon/Icon';
import { Input } from '../../Input/Input';
import { Tooltip } from '../../Tooltip/Tooltip';
+import { WeekStart } from '../WeekStartPicker';
import { isValid } from '../utils';
import TimePickerCalendar from './TimePickerCalendar';
@@ -34,6 +36,7 @@ interface Props {
roundup?: boolean;
isReversed?: boolean;
onError?: (error?: string) => void;
+ weekStart?: WeekStart;
}
interface InputState {
@@ -56,6 +59,7 @@ export const TimeRangeContent = (props: Props) => {
isReversed,
fiscalYearStartMonth,
onError,
+ weekStart,
} = props;
const [fromValue, toValue] = valueToState(value.raw.from, value.raw.to, timeZone);
const style = useStyles2(getStyles);
@@ -223,6 +227,7 @@ export const TimeRangeContent = (props: Props) => {
onChange={onChange}
timeZone={timeZone}
isReversed={isReversed}
+ weekStart={weekStart}
/>
);
diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimeRangeLabel.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimeRangeLabel.tsx
index d3c7d5cc2f4..4cd7392aa37 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimeRangeLabel.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimeRangeLabel.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { memo } from 'react';
+import { memo } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimeRangeList.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimeRangeList.tsx
index 76676a5bba6..cfc070c51c7 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimeRangeList.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimeRangeList.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { ReactNode } from 'react';
+import { useRef, ReactNode } from 'react';
import { TimeOption } from '@grafana/data';
@@ -45,7 +45,7 @@ export const TimeRangeList = (props: Props) => {
const Options = ({ options, value, onChange, title }: Props) => {
const styles = useStyles2(getOptionsStyles);
- const localRef = React.useRef(null);
+ const localRef = useRef(null);
const [handleKeys] = useListFocus({ localRef, options });
return (
diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimeRangeOption.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimeRangeOption.tsx
index 4df76628dcb..a85a11f948a 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimeRangeOption.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimeRangeOption.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { memo } from 'react';
+import { memo } from 'react';
import { v4 as uuidv4 } from 'uuid';
import { GrafanaTheme2, TimeOption } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/hooks.test.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/hooks.test.tsx
index 9da5a28e468..38fe7529625 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/hooks.test.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/hooks.test.tsx
@@ -1,5 +1,5 @@
import { act, fireEvent, render, renderHook, screen } from '@testing-library/react';
-import React, { createRef, KeyboardEvent, RefObject } from 'react';
+import { createRef, KeyboardEvent, RefObject } from 'react';
import { useListFocus } from './hooks';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker.story.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker.story.tsx
index 28e2458d888..a609ee8daa8 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker.story.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker.story.tsx
@@ -1,7 +1,6 @@
import { action } from '@storybook/addon-actions';
import { useArgs } from '@storybook/preview-api';
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { TimeZonePicker } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker.tsx
index 03cd1495315..7e0f1495e0b 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker.tsx
@@ -1,5 +1,5 @@
import { toLower, isEmpty, isString } from 'lodash';
-import React, { useMemo, useCallback } from 'react';
+import { useMemo, useCallback } from 'react';
import {
SelectableValue,
diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneDescription.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneDescription.tsx
index beee071996b..12594c31b65 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneDescription.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneDescription.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { GrafanaTheme2, TimeZoneInfo } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneGroup.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneGroup.tsx
index 407dc82d65d..c5e2c0bba14 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneGroup.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneGroup.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneOffset.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneOffset.tsx
index e9e269d2c15..03c1d50b816 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneOffset.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneOffset.tsx
@@ -1,6 +1,5 @@
import { css, cx } from '@emotion/css';
import { isString } from 'lodash';
-import React from 'react';
import { GrafanaTheme2, TimeZone, dateTimeFormat } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneOption.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneOption.tsx
index 090f04b01de..3ce0a3cd17a 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneOption.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneOption.tsx
@@ -1,6 +1,7 @@
import { css, cx } from '@emotion/css';
import { isString } from 'lodash';
-import React, { PropsWithChildren, RefCallback } from 'react';
+import { PropsWithChildren, RefCallback } from 'react';
+import * as React from 'react';
import { GrafanaTheme2, SelectableValue, getTimeZoneInfo } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneTitle.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneTitle.tsx
index 6d1239bdd4d..25d25e28f75 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneTitle.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneTitle.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { ReactNode } from 'react';
+import { ReactNode } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/WeekStartPicker.story.tsx b/packages/grafana-ui/src/components/DateTimePickers/WeekStartPicker.story.tsx
index b5c902d92a2..9054e9b53fd 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/WeekStartPicker.story.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/WeekStartPicker.story.tsx
@@ -1,7 +1,6 @@
import { action } from '@storybook/addon-actions';
import { useArgs } from '@storybook/preview-api';
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { WeekStartPicker } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/DateTimePickers/WeekStartPicker.tsx b/packages/grafana-ui/src/components/DateTimePickers/WeekStartPicker.tsx
index 59dd368280a..e5f3b6397a3 100644
--- a/packages/grafana-ui/src/components/DateTimePickers/WeekStartPicker.tsx
+++ b/packages/grafana-ui/src/components/DateTimePickers/WeekStartPicker.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { SelectableValue } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
@@ -15,7 +15,8 @@ export interface Props {
inputId?: string;
}
-const weekStarts: Array> = [
+export type WeekStart = 'saturday' | 'sunday' | 'monday';
+const weekStarts: Array> = [
{ value: '', label: 'Default' },
{ value: 'saturday', label: 'Saturday' },
{ value: 'sunday', label: 'Sunday' },
diff --git a/packages/grafana-ui/src/components/Divider/Divider.story.tsx b/packages/grafana-ui/src/components/Divider/Divider.story.tsx
index e48091dabca..f7757d80d4f 100644
--- a/packages/grafana-ui/src/components/Divider/Divider.story.tsx
+++ b/packages/grafana-ui/src/components/Divider/Divider.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { Divider } from './Divider';
import mdx from './Divider.mdx';
diff --git a/packages/grafana-ui/src/components/Divider/Divider.tsx b/packages/grafana-ui/src/components/Divider/Divider.tsx
index ad0da71d3de..0ffd0c032cf 100644
--- a/packages/grafana-ui/src/components/Divider/Divider.tsx
+++ b/packages/grafana-ui/src/components/Divider/Divider.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2, ThemeSpacingTokens } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Drawer/Drawer.story.tsx b/packages/grafana-ui/src/components/Drawer/Drawer.story.tsx
index 06e4c96f94d..9c99056f00b 100644
--- a/packages/grafana-ui/src/components/Drawer/Drawer.story.tsx
+++ b/packages/grafana-ui/src/components/Drawer/Drawer.story.tsx
@@ -1,5 +1,5 @@
import { Meta, StoryFn } from '@storybook/react';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { Button, Drawer, Tab, TabsBar } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/Drawer/Drawer.tsx b/packages/grafana-ui/src/components/Drawer/Drawer.tsx
index 3d600cd1f19..f3b17f2511f 100644
--- a/packages/grafana-ui/src/components/Drawer/Drawer.tsx
+++ b/packages/grafana-ui/src/components/Drawer/Drawer.tsx
@@ -3,7 +3,8 @@ import { useDialog } from '@react-aria/dialog';
import { FocusScope } from '@react-aria/focus';
import { useOverlay } from '@react-aria/overlays';
import RcDrawer from 'rc-drawer';
-import React, { ReactNode, useCallback, useEffect, useState } from 'react';
+import { ReactNode, useCallback, useEffect, useState } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-ui/src/components/Dropdown/ButtonSelect.internal.story.tsx b/packages/grafana-ui/src/components/Dropdown/ButtonSelect.internal.story.tsx
index f21e6bfccb2..edc03ecf4a4 100644
--- a/packages/grafana-ui/src/components/Dropdown/ButtonSelect.internal.story.tsx
+++ b/packages/grafana-ui/src/components/Dropdown/ButtonSelect.internal.story.tsx
@@ -1,7 +1,6 @@
import { action } from '@storybook/addon-actions';
import { useArgs } from '@storybook/preview-api';
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { ButtonSelect } from './ButtonSelect';
diff --git a/packages/grafana-ui/src/components/Dropdown/ButtonSelect.test.tsx b/packages/grafana-ui/src/components/Dropdown/ButtonSelect.test.tsx
index f1c5c63a055..3cdc4ad1544 100644
--- a/packages/grafana-ui/src/components/Dropdown/ButtonSelect.test.tsx
+++ b/packages/grafana-ui/src/components/Dropdown/ButtonSelect.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { SelectableValue } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Dropdown/ButtonSelect.tsx b/packages/grafana-ui/src/components/Dropdown/ButtonSelect.tsx
index 2fb0bb2f98b..719a32bcb38 100644
--- a/packages/grafana-ui/src/components/Dropdown/ButtonSelect.tsx
+++ b/packages/grafana-ui/src/components/Dropdown/ButtonSelect.tsx
@@ -10,7 +10,7 @@ import {
useInteractions,
} from '@floating-ui/react';
import { FocusScope } from '@react-aria/focus';
-import React, { HTMLAttributes, useState } from 'react';
+import { memo, HTMLAttributes, useState } from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
@@ -118,7 +118,7 @@ ButtonSelectComponent.displayName = 'ButtonSelect';
// needed to properly forward the generic type through React.memo
// see https://github.com/DefinitelyTyped/DefinitelyTyped/issues/37087#issuecomment-656596623
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
-export const ButtonSelect = React.memo(ButtonSelectComponent) as typeof ButtonSelectComponent;
+export const ButtonSelect = memo(ButtonSelectComponent) as typeof ButtonSelectComponent;
const getStyles = (theme: GrafanaTheme2) => {
return {
diff --git a/packages/grafana-ui/src/components/Dropdown/Dropdown.story.tsx b/packages/grafana-ui/src/components/Dropdown/Dropdown.story.tsx
index fbcef7c6c8d..40253bb2157 100644
--- a/packages/grafana-ui/src/components/Dropdown/Dropdown.story.tsx
+++ b/packages/grafana-ui/src/components/Dropdown/Dropdown.story.tsx
@@ -1,5 +1,4 @@
import { Meta } from '@storybook/react';
-import React from 'react';
import { StoryExample } from '../../utils/storybook/StoryExample';
import { Button } from '../Button';
diff --git a/packages/grafana-ui/src/components/Dropdown/Dropdown.test.tsx b/packages/grafana-ui/src/components/Dropdown/Dropdown.test.tsx
index 94ef9b20e72..a4a0151eafc 100644
--- a/packages/grafana-ui/src/components/Dropdown/Dropdown.test.tsx
+++ b/packages/grafana-ui/src/components/Dropdown/Dropdown.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { Button } from '../Button';
import { Menu } from '../Menu/Menu';
diff --git a/packages/grafana-ui/src/components/Dropdown/Dropdown.tsx b/packages/grafana-ui/src/components/Dropdown/Dropdown.tsx
index 568933aeb21..1cd35603df6 100644
--- a/packages/grafana-ui/src/components/Dropdown/Dropdown.tsx
+++ b/packages/grafana-ui/src/components/Dropdown/Dropdown.tsx
@@ -10,7 +10,8 @@ import {
useFloating,
useInteractions,
} from '@floating-ui/react';
-import React, { useCallback, useRef, useState } from 'react';
+import { useCallback, useRef, useState } from 'react';
+import * as React from 'react';
import { CSSTransition } from 'react-transition-group';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/EmptySearchResult/EmptySearchResult.story.tsx b/packages/grafana-ui/src/components/EmptySearchResult/EmptySearchResult.story.tsx
index 108592394b5..c44444597e0 100644
--- a/packages/grafana-ui/src/components/EmptySearchResult/EmptySearchResult.story.tsx
+++ b/packages/grafana-ui/src/components/EmptySearchResult/EmptySearchResult.story.tsx
@@ -1,5 +1,4 @@
import { Meta } from '@storybook/react';
-import React from 'react';
import { EmptySearchResult } from './EmptySearchResult';
import mdx from './EmptySearchResult.mdx';
diff --git a/packages/grafana-ui/src/components/EmptySearchResult/EmptySearchResult.tsx b/packages/grafana-ui/src/components/EmptySearchResult/EmptySearchResult.tsx
index 7f8fb1f67ea..e46007e0017 100644
--- a/packages/grafana-ui/src/components/EmptySearchResult/EmptySearchResult.tsx
+++ b/packages/grafana-ui/src/components/EmptySearchResult/EmptySearchResult.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/EmptyState/EmptyState.story.tsx b/packages/grafana-ui/src/components/EmptyState/EmptyState.story.tsx
index 9e81d2e234e..d7d3b790c1b 100644
--- a/packages/grafana-ui/src/components/EmptyState/EmptyState.story.tsx
+++ b/packages/grafana-ui/src/components/EmptyState/EmptyState.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { Button } from '../Button';
diff --git a/packages/grafana-ui/src/components/EmptyState/EmptyState.tsx b/packages/grafana-ui/src/components/EmptyState/EmptyState.tsx
index 338f6771a06..6e92a5d5ce7 100644
--- a/packages/grafana-ui/src/components/EmptyState/EmptyState.tsx
+++ b/packages/grafana-ui/src/components/EmptyState/EmptyState.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { AriaRole, ReactNode } from 'react';
+import { AriaRole, ReactNode } from 'react';
+import * as React from 'react';
import SVG from 'react-inlinesvg';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/EmptyState/GrotCTA/GrotCTA.tsx b/packages/grafana-ui/src/components/EmptyState/GrotCTA/GrotCTA.tsx
index ce7d363fb6f..9350e1dfc18 100644
--- a/packages/grafana-ui/src/components/EmptyState/GrotCTA/GrotCTA.tsx
+++ b/packages/grafana-ui/src/components/EmptyState/GrotCTA/GrotCTA.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { SVGProps } from 'react';
+import { SVGProps } from 'react';
import SVG from 'react-inlinesvg';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/EmptyState/GrotNotFound/GrotNotFound.tsx b/packages/grafana-ui/src/components/EmptyState/GrotNotFound/GrotNotFound.tsx
index 4a288f886d1..8df37510eaa 100644
--- a/packages/grafana-ui/src/components/EmptyState/GrotNotFound/GrotNotFound.tsx
+++ b/packages/grafana-ui/src/components/EmptyState/GrotNotFound/GrotNotFound.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { SVGProps, useEffect, useRef } from 'react';
+import { SVGProps, useEffect, useRef } from 'react';
import SVG from 'react-inlinesvg';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/ErrorBoundary/ErrorBoundary.story.tsx b/packages/grafana-ui/src/components/ErrorBoundary/ErrorBoundary.story.tsx
index 8b20cffae36..c659719a893 100644
--- a/packages/grafana-ui/src/components/ErrorBoundary/ErrorBoundary.story.tsx
+++ b/packages/grafana-ui/src/components/ErrorBoundary/ErrorBoundary.story.tsx
@@ -1,5 +1,5 @@
import { Meta } from '@storybook/react';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { Alert } from '../Alert/Alert';
import { Button } from '../Button';
diff --git a/packages/grafana-ui/src/components/ErrorBoundary/ErrorBoundary.test.tsx b/packages/grafana-ui/src/components/ErrorBoundary/ErrorBoundary.test.tsx
index d2af63af611..d14867aef54 100644
--- a/packages/grafana-ui/src/components/ErrorBoundary/ErrorBoundary.test.tsx
+++ b/packages/grafana-ui/src/components/ErrorBoundary/ErrorBoundary.test.tsx
@@ -1,5 +1,5 @@
import { render, screen } from '@testing-library/react';
-import React, { FC } from 'react';
+import { FC } from 'react';
import { faro } from '@grafana/faro-web-sdk';
diff --git a/packages/grafana-ui/src/components/ErrorBoundary/ErrorBoundary.tsx b/packages/grafana-ui/src/components/ErrorBoundary/ErrorBoundary.tsx
index 4c5760a377e..312d6e76029 100644
--- a/packages/grafana-ui/src/components/ErrorBoundary/ErrorBoundary.tsx
+++ b/packages/grafana-ui/src/components/ErrorBoundary/ErrorBoundary.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent, ReactNode, ComponentType, ErrorInfo } from 'react';
+import { PureComponent, ReactNode, ComponentType, ErrorInfo } from 'react';
import { faro } from '@grafana/faro-web-sdk';
diff --git a/packages/grafana-ui/src/components/ErrorBoundary/ErrorWithStack.tsx b/packages/grafana-ui/src/components/ErrorBoundary/ErrorWithStack.tsx
index f5d2395e834..40594795c97 100644
--- a/packages/grafana-ui/src/components/ErrorBoundary/ErrorWithStack.tsx
+++ b/packages/grafana-ui/src/components/ErrorBoundary/ErrorWithStack.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { useStyles2 } from '../../themes';
diff --git a/packages/grafana-ui/src/components/FeatureBadge/FeatureBadge.story.tsx b/packages/grafana-ui/src/components/FeatureBadge/FeatureBadge.story.tsx
index 273ea948dd8..bac8577fbf4 100644
--- a/packages/grafana-ui/src/components/FeatureBadge/FeatureBadge.story.tsx
+++ b/packages/grafana-ui/src/components/FeatureBadge/FeatureBadge.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { FeatureState } from '@grafana/data';
import { FeatureBadge } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/FeatureBadge/FeatureBadge.tsx b/packages/grafana-ui/src/components/FeatureBadge/FeatureBadge.tsx
index f4e99ee5c94..87f79ff05bc 100644
--- a/packages/grafana-ui/src/components/FeatureBadge/FeatureBadge.tsx
+++ b/packages/grafana-ui/src/components/FeatureBadge/FeatureBadge.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { FeatureState } from '@grafana/data';
import { Badge, BadgeProps } from '../Badge/Badge';
diff --git a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.story.tsx b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.story.tsx
index 644155da2a8..c3cb4d216cb 100644
--- a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.story.tsx
+++ b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { FileDropzone } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.test.tsx b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.test.tsx
index c115abbf6c6..23d965f6f10 100644
--- a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.test.tsx
+++ b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.test.tsx
@@ -1,5 +1,4 @@
import { fireEvent, render, screen } from '@testing-library/react';
-import React from 'react';
import { FileDropzone } from './FileDropzone';
import { REMOVE_FILE } from './FileListItem';
diff --git a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx
index ce4746c24ba..fe9ae54045a 100644
--- a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx
+++ b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx
@@ -1,6 +1,6 @@
import { css, cx } from '@emotion/css';
import { isString, uniqueId } from 'lodash';
-import React, { ReactNode, useCallback, useState } from 'react';
+import { ReactNode, useCallback, useState } from 'react';
import { Accept, DropEvent, DropzoneOptions, FileError, FileRejection, useDropzone, ErrorCode } from 'react-dropzone';
import { formattedValueToString, getValueFormat, GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/FileDropzone/FileListItem.story.tsx b/packages/grafana-ui/src/components/FileDropzone/FileListItem.story.tsx
index 88640fca2ce..3e10caf11f4 100644
--- a/packages/grafana-ui/src/components/FileDropzone/FileListItem.story.tsx
+++ b/packages/grafana-ui/src/components/FileDropzone/FileListItem.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { FileListItem as FileListItemComponent, FileListItemProps } from './FileListItem';
import mdx from './FileListItem.mdx';
diff --git a/packages/grafana-ui/src/components/FileDropzone/FileListItem.test.tsx b/packages/grafana-ui/src/components/FileDropzone/FileListItem.test.tsx
index 021a4c1ac48..587756b25b9 100644
--- a/packages/grafana-ui/src/components/FileDropzone/FileListItem.test.tsx
+++ b/packages/grafana-ui/src/components/FileDropzone/FileListItem.test.tsx
@@ -1,5 +1,4 @@
import { fireEvent, render, screen } from '@testing-library/react';
-import React from 'react';
import { FileListItem, REMOVE_FILE } from './FileListItem';
diff --git a/packages/grafana-ui/src/components/FileDropzone/FileListItem.tsx b/packages/grafana-ui/src/components/FileDropzone/FileListItem.tsx
index 36477c6fbfa..977debdfb46 100644
--- a/packages/grafana-ui/src/components/FileDropzone/FileListItem.tsx
+++ b/packages/grafana-ui/src/components/FileDropzone/FileListItem.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { formattedValueToString, getValueFormat, GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/FileUpload/FileUpload.story.tsx b/packages/grafana-ui/src/components/FileUpload/FileUpload.story.tsx
index 40a8ad73b07..ac49c175392 100644
--- a/packages/grafana-ui/src/components/FileUpload/FileUpload.story.tsx
+++ b/packages/grafana-ui/src/components/FileUpload/FileUpload.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { FileUpload } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/FileUpload/FileUpload.test.tsx b/packages/grafana-ui/src/components/FileUpload/FileUpload.test.tsx
index 833734fad02..8b76e4ab435 100644
--- a/packages/grafana-ui/src/components/FileUpload/FileUpload.test.tsx
+++ b/packages/grafana-ui/src/components/FileUpload/FileUpload.test.tsx
@@ -1,6 +1,5 @@
import { render, waitFor, fireEvent, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-ui/src/components/FileUpload/FileUpload.tsx b/packages/grafana-ui/src/components/FileUpload/FileUpload.tsx
index c4d7baf95a5..23db2b8c134 100644
--- a/packages/grafana-ui/src/components/FileUpload/FileUpload.tsx
+++ b/packages/grafana-ui/src/components/FileUpload/FileUpload.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { FormEvent, useCallback, useState } from 'react';
+import { FormEvent, useCallback, useState } from 'react';
+import * as React from 'react';
import { v4 as uuidv4 } from 'uuid';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/FilterInput/FilterInput.tsx b/packages/grafana-ui/src/components/FilterInput/FilterInput.tsx
index 403df7146c6..d026b88b466 100644
--- a/packages/grafana-ui/src/components/FilterInput/FilterInput.tsx
+++ b/packages/grafana-ui/src/components/FilterInput/FilterInput.tsx
@@ -1,4 +1,4 @@
-import React, { HTMLProps } from 'react';
+import { forwardRef, useRef, HTMLProps } from 'react';
import { escapeStringForRegex, unEscapeStringFromRegex } from '@grafana/data';
@@ -14,9 +14,9 @@ export interface Props extends Omit, 'onChange'> {
escapeRegex?: boolean;
}
-export const FilterInput = React.forwardRef(
+export const FilterInput = forwardRef(
({ value, width, onChange, escapeRegex = true, ...restProps }, ref) => {
- const innerRef = React.useRef(null);
+ const innerRef = useRef(null);
const combinedRef = useCombinedRefs(ref, innerRef);
const suffix =
diff --git a/packages/grafana-ui/src/components/FilterPill/FilterPill.story.tsx b/packages/grafana-ui/src/components/FilterPill/FilterPill.story.tsx
index 40590ae4011..bbc85b2c90c 100644
--- a/packages/grafana-ui/src/components/FilterPill/FilterPill.story.tsx
+++ b/packages/grafana-ui/src/components/FilterPill/FilterPill.story.tsx
@@ -1,5 +1,5 @@
import { Meta, StoryFn } from '@storybook/react';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { getAvailableIcons } from '../../types';
import { Stack } from '../Layout/Stack/Stack';
diff --git a/packages/grafana-ui/src/components/FilterPill/FilterPill.tsx b/packages/grafana-ui/src/components/FilterPill/FilterPill.tsx
index 1612747b533..653a9688939 100644
--- a/packages/grafana-ui/src/components/FilterPill/FilterPill.tsx
+++ b/packages/grafana-ui/src/components/FilterPill/FilterPill.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/FormField/FormField.internal.story.tsx b/packages/grafana-ui/src/components/FormField/FormField.internal.story.tsx
index df7bd6c1bfb..efddb8d7f3c 100644
--- a/packages/grafana-ui/src/components/FormField/FormField.internal.story.tsx
+++ b/packages/grafana-ui/src/components/FormField/FormField.internal.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { FormField } from './FormField';
diff --git a/packages/grafana-ui/src/components/FormField/FormField.test.tsx b/packages/grafana-ui/src/components/FormField/FormField.test.tsx
index c64baf0c568..598dcd8a8be 100644
--- a/packages/grafana-ui/src/components/FormField/FormField.test.tsx
+++ b/packages/grafana-ui/src/components/FormField/FormField.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { FormField, Props } from './FormField';
diff --git a/packages/grafana-ui/src/components/FormField/FormField.tsx b/packages/grafana-ui/src/components/FormField/FormField.tsx
index a872ff27461..4de155dcfb2 100644
--- a/packages/grafana-ui/src/components/FormField/FormField.tsx
+++ b/packages/grafana-ui/src/components/FormField/FormField.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { InputHTMLAttributes } from 'react';
+import { InputHTMLAttributes } from 'react';
+import * as React from 'react';
import { InlineFormLabel } from '../FormLabel/FormLabel';
import { Field } from '../Forms/Field';
diff --git a/packages/grafana-ui/src/components/FormLabel/FormLabel.tsx b/packages/grafana-ui/src/components/FormLabel/FormLabel.tsx
index bd5e24fdc6c..654521ba606 100644
--- a/packages/grafana-ui/src/components/FormLabel/FormLabel.tsx
+++ b/packages/grafana-ui/src/components/FormLabel/FormLabel.tsx
@@ -1,5 +1,5 @@
import classNames from 'classnames';
-import React, { ReactNode } from 'react';
+import { ReactNode } from 'react';
import { Icon } from '../Icon/Icon';
import { Tooltip, PopoverContent } from '../Tooltip';
diff --git a/packages/grafana-ui/src/components/FormattedValueDisplay/FormattedValueDisplay.story.tsx b/packages/grafana-ui/src/components/FormattedValueDisplay/FormattedValueDisplay.story.tsx
index 60f322cc4da..3358a90f179 100644
--- a/packages/grafana-ui/src/components/FormattedValueDisplay/FormattedValueDisplay.story.tsx
+++ b/packages/grafana-ui/src/components/FormattedValueDisplay/FormattedValueDisplay.story.tsx
@@ -1,5 +1,4 @@
import { Meta } from '@storybook/react';
-import React from 'react';
import { FormattedValueDisplay } from './FormattedValueDisplay';
import mdx from './FormattedValueDisplay.mdx';
diff --git a/packages/grafana-ui/src/components/FormattedValueDisplay/FormattedValueDisplay.tsx b/packages/grafana-ui/src/components/FormattedValueDisplay/FormattedValueDisplay.tsx
index effd3060c02..603dbe0b499 100644
--- a/packages/grafana-ui/src/components/FormattedValueDisplay/FormattedValueDisplay.tsx
+++ b/packages/grafana-ui/src/components/FormattedValueDisplay/FormattedValueDisplay.tsx
@@ -1,4 +1,4 @@
-import React, { CSSProperties, HTMLProps } from 'react';
+import { CSSProperties, HTMLProps } from 'react';
import { FormattedValue } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Forms/Checkbox.story.tsx b/packages/grafana-ui/src/components/Forms/Checkbox.story.tsx
index 6ce2c1907bf..8cdf3daa56d 100644
--- a/packages/grafana-ui/src/components/Forms/Checkbox.story.tsx
+++ b/packages/grafana-ui/src/components/Forms/Checkbox.story.tsx
@@ -1,5 +1,6 @@
import { Meta, StoryFn } from '@storybook/react';
-import React, { useState, useCallback } from 'react';
+import { useState, useCallback } from 'react';
+import * as React from 'react';
import { Stack } from '../Layout/Stack/Stack';
diff --git a/packages/grafana-ui/src/components/Forms/Checkbox.tsx b/packages/grafana-ui/src/components/Forms/Checkbox.tsx
index 74716ec57d5..f5250844fff 100644
--- a/packages/grafana-ui/src/components/Forms/Checkbox.tsx
+++ b/packages/grafana-ui/src/components/Forms/Checkbox.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { HTMLProps, useCallback } from 'react';
+import { HTMLProps, useCallback } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Forms/Field.story.tsx b/packages/grafana-ui/src/components/Forms/Field.story.tsx
index 974035e0f18..3d38e8af6e4 100644
--- a/packages/grafana-ui/src/components/Forms/Field.story.tsx
+++ b/packages/grafana-ui/src/components/Forms/Field.story.tsx
@@ -1,5 +1,6 @@
import { Meta, StoryFn } from '@storybook/react';
-import React, { useState, useCallback } from 'react';
+import { useState, useCallback } from 'react';
+import * as React from 'react';
import { Input, Switch } from '..';
diff --git a/packages/grafana-ui/src/components/Forms/Field.test.tsx b/packages/grafana-ui/src/components/Forms/Field.test.tsx
index 861b23fe78c..768bc3095cf 100644
--- a/packages/grafana-ui/src/components/Forms/Field.test.tsx
+++ b/packages/grafana-ui/src/components/Forms/Field.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { Input } from '../Input/Input';
import { Select } from '../Select/Select';
diff --git a/packages/grafana-ui/src/components/Forms/Field.tsx b/packages/grafana-ui/src/components/Forms/Field.tsx
index 9b6e6ef5a7c..10db5c83bfc 100644
--- a/packages/grafana-ui/src/components/Forms/Field.tsx
+++ b/packages/grafana-ui/src/components/Forms/Field.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { HTMLAttributes } from 'react';
+import { HTMLAttributes } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Forms/FieldArray.story.tsx b/packages/grafana-ui/src/components/Forms/FieldArray.story.tsx
index e1bf660d902..3bec83bf20e 100644
--- a/packages/grafana-ui/src/components/Forms/FieldArray.story.tsx
+++ b/packages/grafana-ui/src/components/Forms/FieldArray.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { FieldValues } from 'react-hook-form';
import { Form, Input, Button, HorizontalGroup } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/Forms/FieldSet.story.tsx b/packages/grafana-ui/src/components/Forms/FieldSet.story.tsx
index 716b4206d3c..8d2e5de1344 100644
--- a/packages/grafana-ui/src/components/Forms/FieldSet.story.tsx
+++ b/packages/grafana-ui/src/components/Forms/FieldSet.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { Input, Form, FieldSet, Field } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/Forms/FieldSet.tsx b/packages/grafana-ui/src/components/Forms/FieldSet.tsx
index 3d3c0986092..1823d5d456e 100644
--- a/packages/grafana-ui/src/components/Forms/FieldSet.tsx
+++ b/packages/grafana-ui/src/components/Forms/FieldSet.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { HTMLProps } from 'react';
+import { HTMLProps } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Forms/FieldValidationMessage.story.tsx b/packages/grafana-ui/src/components/Forms/FieldValidationMessage.story.tsx
index 5d5d5e23004..56010bedf03 100644
--- a/packages/grafana-ui/src/components/Forms/FieldValidationMessage.story.tsx
+++ b/packages/grafana-ui/src/components/Forms/FieldValidationMessage.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { FieldValidationMessage } from './FieldValidationMessage';
import mdx from './FieldValidationMessage.mdx';
diff --git a/packages/grafana-ui/src/components/Forms/FieldValidationMessage.tsx b/packages/grafana-ui/src/components/Forms/FieldValidationMessage.tsx
index 8d8dc832b66..14f9c235c89 100644
--- a/packages/grafana-ui/src/components/Forms/FieldValidationMessage.tsx
+++ b/packages/grafana-ui/src/components/Forms/FieldValidationMessage.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Forms/Form.story.tsx b/packages/grafana-ui/src/components/Forms/Form.story.tsx
index 3d2972a9d6a..b7322cbbc77 100644
--- a/packages/grafana-ui/src/components/Forms/Form.story.tsx
+++ b/packages/grafana-ui/src/components/Forms/Form.story.tsx
@@ -1,5 +1,4 @@
import { StoryFn } from '@storybook/react';
-import React from 'react';
import { ValidateResult } from 'react-hook-form';
import {
diff --git a/packages/grafana-ui/src/components/Forms/Form.tsx b/packages/grafana-ui/src/components/Forms/Form.tsx
index 065dab5c794..a56393f95c7 100644
--- a/packages/grafana-ui/src/components/Forms/Form.tsx
+++ b/packages/grafana-ui/src/components/Forms/Form.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { HTMLProps, useEffect } from 'react';
+import { HTMLProps, useEffect } from 'react';
+import * as React from 'react';
import { useForm, Mode, DefaultValues, SubmitHandler, FieldValues } from 'react-hook-form';
import { FormAPI } from '../../types';
diff --git a/packages/grafana-ui/src/components/Forms/InlineField.story.tsx b/packages/grafana-ui/src/components/Forms/InlineField.story.tsx
index bc86285a18e..384e5aa98de 100644
--- a/packages/grafana-ui/src/components/Forms/InlineField.story.tsx
+++ b/packages/grafana-ui/src/components/Forms/InlineField.story.tsx
@@ -1,6 +1,5 @@
import { action } from '@storybook/addon-actions';
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { Input } from '../Input/Input';
import { Select } from '../Select/Select';
diff --git a/packages/grafana-ui/src/components/Forms/InlineField.test.tsx b/packages/grafana-ui/src/components/Forms/InlineField.test.tsx
index 8b86dd9fec5..657c11875c6 100644
--- a/packages/grafana-ui/src/components/Forms/InlineField.test.tsx
+++ b/packages/grafana-ui/src/components/Forms/InlineField.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { Input } from '../Input/Input';
import { Select } from '../Select/Select';
diff --git a/packages/grafana-ui/src/components/Forms/InlineField.tsx b/packages/grafana-ui/src/components/Forms/InlineField.tsx
index 37f2551c9b7..8750e300122 100644
--- a/packages/grafana-ui/src/components/Forms/InlineField.tsx
+++ b/packages/grafana-ui/src/components/Forms/InlineField.tsx
@@ -1,5 +1,5 @@
import { cx, css } from '@emotion/css';
-import React from 'react';
+import { cloneElement } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
@@ -70,7 +70,7 @@ export const InlineField = ({
{labelElement}
- {React.cloneElement(children, { invalid, disabled, loading })}
+ {cloneElement(children, { invalid, disabled, loading })}
{invalid && error && (
{error}
diff --git a/packages/grafana-ui/src/components/Forms/InlineFieldRow.story.tsx b/packages/grafana-ui/src/components/Forms/InlineFieldRow.story.tsx
index 2173c5dace6..b9a74b6f345 100644
--- a/packages/grafana-ui/src/components/Forms/InlineFieldRow.story.tsx
+++ b/packages/grafana-ui/src/components/Forms/InlineFieldRow.story.tsx
@@ -1,5 +1,4 @@
import { Meta } from '@storybook/react';
-import React from 'react';
import { Input } from '../Input/Input';
diff --git a/packages/grafana-ui/src/components/Forms/InlineFieldRow.tsx b/packages/grafana-ui/src/components/Forms/InlineFieldRow.tsx
index d7eb138b640..f77222a04d3 100644
--- a/packages/grafana-ui/src/components/Forms/InlineFieldRow.tsx
+++ b/packages/grafana-ui/src/components/Forms/InlineFieldRow.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { HTMLProps, ReactNode } from 'react';
+import { HTMLProps, ReactNode } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Forms/InlineLabel.story.tsx b/packages/grafana-ui/src/components/Forms/InlineLabel.story.tsx
index a68c3049914..1aac70c7134 100644
--- a/packages/grafana-ui/src/components/Forms/InlineLabel.story.tsx
+++ b/packages/grafana-ui/src/components/Forms/InlineLabel.story.tsx
@@ -1,5 +1,4 @@
import { Meta } from '@storybook/react';
-import React from 'react';
import { InlineLabel, Props } from './InlineLabel';
import mdx from './InlineLabel.mdx';
diff --git a/packages/grafana-ui/src/components/Forms/InlineLabel.tsx b/packages/grafana-ui/src/components/Forms/InlineLabel.tsx
index b433dc5a46d..d930f89247b 100644
--- a/packages/grafana-ui/src/components/Forms/InlineLabel.tsx
+++ b/packages/grafana-ui/src/components/Forms/InlineLabel.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Forms/InlineSegmentGroup.tsx b/packages/grafana-ui/src/components/Forms/InlineSegmentGroup.tsx
index 8d94fd87856..2dee14a5c9c 100644
--- a/packages/grafana-ui/src/components/Forms/InlineSegmentGroup.tsx
+++ b/packages/grafana-ui/src/components/Forms/InlineSegmentGroup.tsx
@@ -1,5 +1,5 @@
import { cx, css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Forms/Label.story.tsx b/packages/grafana-ui/src/components/Forms/Label.story.tsx
index d2039480e71..7923bd27af6 100644
--- a/packages/grafana-ui/src/components/Forms/Label.story.tsx
+++ b/packages/grafana-ui/src/components/Forms/Label.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { Label } from './Label';
import mdx from './Label.mdx';
diff --git a/packages/grafana-ui/src/components/Forms/Label.tsx b/packages/grafana-ui/src/components/Forms/Label.tsx
index 6abadee2fd9..ddc9df7902a 100644
--- a/packages/grafana-ui/src/components/Forms/Label.tsx
+++ b/packages/grafana-ui/src/components/Forms/Label.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Forms/Legacy/Input/Input.internal.story.tsx b/packages/grafana-ui/src/components/Forms/Legacy/Input/Input.internal.story.tsx
index 4d389079c38..a9975be2e6f 100644
--- a/packages/grafana-ui/src/components/Forms/Legacy/Input/Input.internal.story.tsx
+++ b/packages/grafana-ui/src/components/Forms/Legacy/Input/Input.internal.story.tsx
@@ -1,6 +1,6 @@
import { Meta, StoryFn } from '@storybook/react';
import { zip, fromPairs } from 'lodash';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { EventsWithValidation } from '../../../../utils';
diff --git a/packages/grafana-ui/src/components/Forms/Legacy/Input/Input.test.tsx b/packages/grafana-ui/src/components/Forms/Legacy/Input/Input.test.tsx
index acf7cd850a5..dbd4ca81323 100644
--- a/packages/grafana-ui/src/components/Forms/Legacy/Input/Input.test.tsx
+++ b/packages/grafana-ui/src/components/Forms/Legacy/Input/Input.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { ValidationEvents } from '../../../../types';
import { EventsWithValidation } from '../../../../utils';
diff --git a/packages/grafana-ui/src/components/Forms/Legacy/Input/Input.tsx b/packages/grafana-ui/src/components/Forms/Legacy/Input/Input.tsx
index 4561ae71c84..40090eee8a5 100644
--- a/packages/grafana-ui/src/components/Forms/Legacy/Input/Input.tsx
+++ b/packages/grafana-ui/src/components/Forms/Legacy/Input/Input.tsx
@@ -1,5 +1,6 @@
import classNames from 'classnames';
-import React, { PureComponent, ChangeEvent } from 'react';
+import { PureComponent, ChangeEvent } from 'react';
+import * as React from 'react';
import { ValidationEvents, ValidationRule } from '../../../../types';
import { validate, EventsWithValidation, hasValidationEvent } from '../../../../utils';
diff --git a/packages/grafana-ui/src/components/Forms/Legacy/Select/IndicatorsContainer.tsx b/packages/grafana-ui/src/components/Forms/Legacy/Select/IndicatorsContainer.tsx
index 0ec07bebd8d..3297dab37dc 100644
--- a/packages/grafana-ui/src/components/Forms/Legacy/Select/IndicatorsContainer.tsx
+++ b/packages/grafana-ui/src/components/Forms/Legacy/Select/IndicatorsContainer.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { components, IndicatorsContainerProps } from 'react-select';
import { Icon } from '../../../Icon/Icon';
diff --git a/packages/grafana-ui/src/components/Forms/Legacy/Select/NoOptionsMessage.tsx b/packages/grafana-ui/src/components/Forms/Legacy/Select/NoOptionsMessage.tsx
index 88693083998..4b50a802abb 100644
--- a/packages/grafana-ui/src/components/Forms/Legacy/Select/NoOptionsMessage.tsx
+++ b/packages/grafana-ui/src/components/Forms/Legacy/Select/NoOptionsMessage.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { components, NoticeProps, GroupBase } from 'react-select';
import { SelectableValue } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Forms/Legacy/Select/Select.internal.story.tsx b/packages/grafana-ui/src/components/Forms/Legacy/Select/Select.internal.story.tsx
index 96cd2f7f275..5e156ab8f9c 100644
--- a/packages/grafana-ui/src/components/Forms/Legacy/Select/Select.internal.story.tsx
+++ b/packages/grafana-ui/src/components/Forms/Legacy/Select/Select.internal.story.tsx
@@ -1,7 +1,7 @@
import { action } from '@storybook/addon-actions';
import { useArgs } from '@storybook/preview-api';
import { Meta, StoryFn } from '@storybook/react';
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { SelectableValue } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Forms/Legacy/Select/Select.tsx b/packages/grafana-ui/src/components/Forms/Legacy/Select/Select.tsx
index 19fe15a32d3..f449c7cee47 100644
--- a/packages/grafana-ui/src/components/Forms/Legacy/Select/Select.tsx
+++ b/packages/grafana-ui/src/components/Forms/Legacy/Select/Select.tsx
@@ -1,6 +1,7 @@
// Libraries
import classNames from 'classnames';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
+import * as React from 'react';
import { default as ReactSelect, components, MenuListProps } from 'react-select';
import { default as ReactAsyncSelect } from 'react-select/async';
import Creatable from 'react-select/creatable';
diff --git a/packages/grafana-ui/src/components/Forms/Legacy/Select/SelectOption.test.tsx b/packages/grafana-ui/src/components/Forms/Legacy/Select/SelectOption.test.tsx
index 1d3078e0a78..d0a2ffafa24 100644
--- a/packages/grafana-ui/src/components/Forms/Legacy/Select/SelectOption.test.tsx
+++ b/packages/grafana-ui/src/components/Forms/Legacy/Select/SelectOption.test.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { OptionProps } from 'react-select';
import renderer from 'react-test-renderer';
diff --git a/packages/grafana-ui/src/components/Forms/Legacy/Select/SelectOption.tsx b/packages/grafana-ui/src/components/Forms/Legacy/Select/SelectOption.tsx
index c618e71605e..164df8d7dd6 100644
--- a/packages/grafana-ui/src/components/Forms/Legacy/Select/SelectOption.tsx
+++ b/packages/grafana-ui/src/components/Forms/Legacy/Select/SelectOption.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { components, OptionProps } from 'react-select';
import { Icon } from '../../../Icon/Icon';
diff --git a/packages/grafana-ui/src/components/Forms/Legacy/Select/SelectOptionGroup.tsx b/packages/grafana-ui/src/components/Forms/Legacy/Select/SelectOptionGroup.tsx
index 1948a4d486b..ad478885975 100644
--- a/packages/grafana-ui/src/components/Forms/Legacy/Select/SelectOptionGroup.tsx
+++ b/packages/grafana-ui/src/components/Forms/Legacy/Select/SelectOptionGroup.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { GroupProps } from 'react-select';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Forms/Legacy/Switch/Switch.internal.story.tsx b/packages/grafana-ui/src/components/Forms/Legacy/Switch/Switch.internal.story.tsx
index b95dcbe1f6d..a5578b4116a 100644
--- a/packages/grafana-ui/src/components/Forms/Legacy/Switch/Switch.internal.story.tsx
+++ b/packages/grafana-ui/src/components/Forms/Legacy/Switch/Switch.internal.story.tsx
@@ -1,5 +1,5 @@
import { Meta, StoryFn } from '@storybook/react';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { Switch } from './Switch';
diff --git a/packages/grafana-ui/src/components/Forms/Legacy/Switch/Switch.tsx b/packages/grafana-ui/src/components/Forms/Legacy/Switch/Switch.tsx
index c3476f1a560..dc9532511a0 100644
--- a/packages/grafana-ui/src/components/Forms/Legacy/Switch/Switch.tsx
+++ b/packages/grafana-ui/src/components/Forms/Legacy/Switch/Switch.tsx
@@ -1,7 +1,8 @@
import { css, cx } from '@emotion/css';
import { Placement } from '@popperjs/core';
import { uniqueId } from 'lodash';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Forms/Legend.story.tsx b/packages/grafana-ui/src/components/Forms/Legend.story.tsx
index fbbebf27f6d..ec0b38c1968 100644
--- a/packages/grafana-ui/src/components/Forms/Legend.story.tsx
+++ b/packages/grafana-ui/src/components/Forms/Legend.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { Legend } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/Forms/Legend.tsx b/packages/grafana-ui/src/components/Forms/Legend.tsx
index 019e7a9a768..fd799dcda94 100644
--- a/packages/grafana-ui/src/components/Forms/Legend.tsx
+++ b/packages/grafana-ui/src/components/Forms/Legend.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { ReactNode } from 'react';
+import { ReactNode } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Forms/RadioButtonGroup/RadioButton.tsx b/packages/grafana-ui/src/components/Forms/RadioButtonGroup/RadioButton.tsx
index b3318923934..898247dff7d 100644
--- a/packages/grafana-ui/src/components/Forms/RadioButtonGroup/RadioButton.tsx
+++ b/packages/grafana-ui/src/components/Forms/RadioButtonGroup/RadioButton.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { StringSelector, selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-ui/src/components/Forms/RadioButtonGroup/RadioButtonGroup.story.tsx b/packages/grafana-ui/src/components/Forms/RadioButtonGroup/RadioButtonGroup.story.tsx
index ed40caa0b01..f75f45c3c0b 100644
--- a/packages/grafana-ui/src/components/Forms/RadioButtonGroup/RadioButtonGroup.story.tsx
+++ b/packages/grafana-ui/src/components/Forms/RadioButtonGroup/RadioButtonGroup.story.tsx
@@ -1,5 +1,5 @@
import { Meta, StoryFn } from '@storybook/react';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { RadioButtonGroup } from './RadioButtonGroup';
import mdx from './RadioButtonGroup.mdx';
diff --git a/packages/grafana-ui/src/components/Forms/RadioButtonGroup/RadioButtonGroup.tsx b/packages/grafana-ui/src/components/Forms/RadioButtonGroup/RadioButtonGroup.tsx
index 1ac45002e6a..1fc51fb350c 100644
--- a/packages/grafana-ui/src/components/Forms/RadioButtonGroup/RadioButtonGroup.tsx
+++ b/packages/grafana-ui/src/components/Forms/RadioButtonGroup/RadioButtonGroup.tsx
@@ -1,6 +1,6 @@
import { css, cx } from '@emotion/css';
import { uniqueId } from 'lodash';
-import React, { useCallback, useEffect, useRef } from 'react';
+import { useCallback, useEffect, useRef } from 'react';
import { GrafanaTheme2, SelectableValue, toIconName } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Forms/RadioButtonList/RadioButtonDot.tsx b/packages/grafana-ui/src/components/Forms/RadioButtonList/RadioButtonDot.tsx
index 148e14e3ec7..6567ae9b3ad 100644
--- a/packages/grafana-ui/src/components/Forms/RadioButtonList/RadioButtonDot.tsx
+++ b/packages/grafana-ui/src/components/Forms/RadioButtonList/RadioButtonDot.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Forms/RadioButtonList/RadioButtonList.story.tsx b/packages/grafana-ui/src/components/Forms/RadioButtonList/RadioButtonList.story.tsx
index c87712434df..6f0fbd383f9 100644
--- a/packages/grafana-ui/src/components/Forms/RadioButtonList/RadioButtonList.story.tsx
+++ b/packages/grafana-ui/src/components/Forms/RadioButtonList/RadioButtonList.story.tsx
@@ -1,5 +1,6 @@
import { Meta, StoryFn } from '@storybook/react';
-import React, { useState } from 'react';
+import { useState } from 'react';
+import * as React from 'react';
import { SelectableValue } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Forms/RadioButtonList/RadioButtonList.tsx b/packages/grafana-ui/src/components/Forms/RadioButtonList/RadioButtonList.tsx
index a0c0d32bf41..011749924e5 100644
--- a/packages/grafana-ui/src/components/Forms/RadioButtonList/RadioButtonList.tsx
+++ b/packages/grafana-ui/src/components/Forms/RadioButtonList/RadioButtonList.tsx
@@ -1,6 +1,5 @@
import { css, cx } from '@emotion/css';
import { uniqueId } from 'lodash';
-import React from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Gauge/Gauge.test.tsx b/packages/grafana-ui/src/components/Gauge/Gauge.test.tsx
index 87c56b4ef45..5c0c80cceec 100644
--- a/packages/grafana-ui/src/components/Gauge/Gauge.test.tsx
+++ b/packages/grafana-ui/src/components/Gauge/Gauge.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { ThresholdsMode, FieldConfig, FieldColorModeId, createTheme } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Gauge/Gauge.tsx b/packages/grafana-ui/src/components/Gauge/Gauge.tsx
index c1fc9d8a3bf..cecd0351f5e 100644
--- a/packages/grafana-ui/src/components/Gauge/Gauge.tsx
+++ b/packages/grafana-ui/src/components/Gauge/Gauge.tsx
@@ -1,5 +1,6 @@
import $ from 'jquery';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
+import * as React from 'react';
import {
DisplayValue,
diff --git a/packages/grafana-ui/src/components/Icon/Icon.story.tsx b/packages/grafana-ui/src/components/Icon/Icon.story.tsx
index 67647a2336f..2fed58dc304 100644
--- a/packages/grafana-ui/src/components/Icon/Icon.story.tsx
+++ b/packages/grafana-ui/src/components/Icon/Icon.story.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { Meta } from '@storybook/react';
-import React, { ChangeEvent, useState } from 'react';
+import { ChangeEvent, useState } from 'react';
import { toIconName, IconName } from '@grafana/data';
import { Input, Field, Icon } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/Icon/Icon.tsx b/packages/grafana-ui/src/components/Icon/Icon.tsx
index d4ade1c4796..d760c3a3185 100644
--- a/packages/grafana-ui/src/components/Icon/Icon.tsx
+++ b/packages/grafana-ui/src/components/Icon/Icon.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import SVG from 'react-inlinesvg';
import { GrafanaTheme2, isIconName } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/IconButton/IconButton.story.tsx b/packages/grafana-ui/src/components/IconButton/IconButton.story.tsx
index cfa0867297a..95a50b0e8ec 100644
--- a/packages/grafana-ui/src/components/IconButton/IconButton.story.tsx
+++ b/packages/grafana-ui/src/components/IconButton/IconButton.story.tsx
@@ -1,6 +1,5 @@
import { css } from '@emotion/css';
import { StoryFn, Meta } from '@storybook/react';
-import React from 'react';
import { useTheme2 } from '../../themes';
import { IconSize, IconName } from '../../types';
diff --git a/packages/grafana-ui/src/components/IconButton/IconButton.tsx b/packages/grafana-ui/src/components/IconButton/IconButton.tsx
index a81f5ac9f11..8a694fa39ce 100644
--- a/packages/grafana-ui/src/components/IconButton/IconButton.tsx
+++ b/packages/grafana-ui/src/components/IconButton/IconButton.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2, colorManipulator, deprecationWarning } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/InfoBox/FeatureInfoBox.tsx b/packages/grafana-ui/src/components/InfoBox/FeatureInfoBox.tsx
index 54394183151..c466528c97d 100644
--- a/packages/grafana-ui/src/components/InfoBox/FeatureInfoBox.tsx
+++ b/packages/grafana-ui/src/components/InfoBox/FeatureInfoBox.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import { memo, forwardRef } from 'react';
import { FeatureState, GrafanaTheme2 } from '@grafana/data';
@@ -14,8 +14,8 @@ export interface FeatureInfoBoxProps extends Omit
(({ title, featureState, ...otherProps }, ref) => {
+export const FeatureInfoBox = memo(
+ forwardRef(({ title, featureState, ...otherProps }, ref) => {
const styles = useStyles2(getFeatureInfoBoxStyles);
const titleEl = featureState ? (
diff --git a/packages/grafana-ui/src/components/InfoBox/InfoBox.story.tsx b/packages/grafana-ui/src/components/InfoBox/InfoBox.story.tsx
index 2f767731676..c60d501cf0d 100644
--- a/packages/grafana-ui/src/components/InfoBox/InfoBox.story.tsx
+++ b/packages/grafana-ui/src/components/InfoBox/InfoBox.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { FeatureState } from '@grafana/data';
import { InfoBox, FeatureInfoBox, VerticalGroup } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/InfoBox/InfoBox.tsx b/packages/grafana-ui/src/components/InfoBox/InfoBox.tsx
index 3ce7197a9c9..8aff84620cf 100644
--- a/packages/grafana-ui/src/components/InfoBox/InfoBox.tsx
+++ b/packages/grafana-ui/src/components/InfoBox/InfoBox.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/InfoTooltip/InfoTooltip.internal.story.tsx b/packages/grafana-ui/src/components/InfoTooltip/InfoTooltip.internal.story.tsx
index 6d7219f6c3e..1ddd48f6cf4 100644
--- a/packages/grafana-ui/src/components/InfoTooltip/InfoTooltip.internal.story.tsx
+++ b/packages/grafana-ui/src/components/InfoTooltip/InfoTooltip.internal.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { InfoTooltip } from './InfoTooltip';
diff --git a/packages/grafana-ui/src/components/InfoTooltip/InfoTooltip.tsx b/packages/grafana-ui/src/components/InfoTooltip/InfoTooltip.tsx
index 8eaaf3fa68f..83f411fedf8 100644
--- a/packages/grafana-ui/src/components/InfoTooltip/InfoTooltip.tsx
+++ b/packages/grafana-ui/src/components/InfoTooltip/InfoTooltip.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { IconButton } from '../IconButton/IconButton';
import { TooltipProps, PopoverContent } from '../Tooltip';
diff --git a/packages/grafana-ui/src/components/InlineToast/InlineToast.internal.story.tsx b/packages/grafana-ui/src/components/InlineToast/InlineToast.internal.story.tsx
index d7443c3e744..7a34a3ec30f 100644
--- a/packages/grafana-ui/src/components/InlineToast/InlineToast.internal.story.tsx
+++ b/packages/grafana-ui/src/components/InlineToast/InlineToast.internal.story.tsx
@@ -1,5 +1,5 @@
import { Meta, StoryFn } from '@storybook/react';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { ClipboardButton } from '../ClipboardButton/ClipboardButton';
import { Input } from '../Input/Input';
diff --git a/packages/grafana-ui/src/components/InlineToast/InlineToast.tsx b/packages/grafana-ui/src/components/InlineToast/InlineToast.tsx
index 7efde97f352..37edf67dea5 100644
--- a/packages/grafana-ui/src/components/InlineToast/InlineToast.tsx
+++ b/packages/grafana-ui/src/components/InlineToast/InlineToast.tsx
@@ -1,6 +1,7 @@
import { css, cx } from '@emotion/css';
import { autoUpdate, flip, offset, shift, Side, useFloating, useTransitionStyles } from '@floating-ui/react';
-import React, { useLayoutEffect } from 'react';
+import { useLayoutEffect } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Input/AutoSizeInput.story.tsx b/packages/grafana-ui/src/components/Input/AutoSizeInput.story.tsx
index c25970b1e95..f33faef0941 100644
--- a/packages/grafana-ui/src/components/Input/AutoSizeInput.story.tsx
+++ b/packages/grafana-ui/src/components/Input/AutoSizeInput.story.tsx
@@ -1,5 +1,4 @@
import { StoryFn, Meta } from '@storybook/react';
-import React from 'react';
import { Button, AutoSizeInput } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/Input/AutoSizeInput.test.tsx b/packages/grafana-ui/src/components/Input/AutoSizeInput.test.tsx
index cea1de3eabb..64c34f1ba17 100644
--- a/packages/grafana-ui/src/components/Input/AutoSizeInput.test.tsx
+++ b/packages/grafana-ui/src/components/Input/AutoSizeInput.test.tsx
@@ -1,5 +1,4 @@
import { screen, render, fireEvent, waitFor } from '@testing-library/react';
-import React from 'react';
import { measureText } from '../../utils/measureText';
diff --git a/packages/grafana-ui/src/components/Input/AutoSizeInput.tsx b/packages/grafana-ui/src/components/Input/AutoSizeInput.tsx
index 3575f10b485..c4fec7c6172 100644
--- a/packages/grafana-ui/src/components/Input/AutoSizeInput.tsx
+++ b/packages/grafana-ui/src/components/Input/AutoSizeInput.tsx
@@ -1,4 +1,5 @@
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
+import * as React from 'react';
import { measureText } from '../../utils/measureText';
diff --git a/packages/grafana-ui/src/components/Input/Input.story.tsx b/packages/grafana-ui/src/components/Input/Input.story.tsx
index 6d1c3ccc418..165709fd51e 100644
--- a/packages/grafana-ui/src/components/Input/Input.story.tsx
+++ b/packages/grafana-ui/src/components/Input/Input.story.tsx
@@ -1,5 +1,5 @@
import { StoryFn, Meta } from '@storybook/react';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { KeyValue } from '@grafana/data';
import { Field, Button, Input } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/Input/Input.tsx b/packages/grafana-ui/src/components/Input/Input.tsx
index 8f451f2c73b..8bd92e180d8 100644
--- a/packages/grafana-ui/src/components/Input/Input.tsx
+++ b/packages/grafana-ui/src/components/Input/Input.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { HTMLProps, ReactNode } from 'react';
+import { forwardRef, HTMLProps, ReactNode } from 'react';
import useMeasure from 'react-use/lib/useMeasure';
import { GrafanaTheme2 } from '@grafana/data';
@@ -31,7 +31,7 @@ interface StyleDeps {
width?: number;
}
-export const Input = React.forwardRef((props, ref) => {
+export const Input = forwardRef((props, ref) => {
const { className, addonAfter, addonBefore, prefix, suffix, invalid, loading, width = 0, ...restProps } = props;
/**
* Prefix & suffix are positioned absolutely within inputWrapper. We use client rects below to apply correct padding to the input
diff --git a/packages/grafana-ui/src/components/Input/storyUtils.tsx b/packages/grafana-ui/src/components/Input/storyUtils.tsx
index 2ca010b73bc..beae0700baf 100644
--- a/packages/grafana-ui/src/components/Input/storyUtils.tsx
+++ b/packages/grafana-ui/src/components/Input/storyUtils.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { toIconName } from '@grafana/data';
import { Icon } from '../Icon/Icon';
diff --git a/packages/grafana-ui/src/components/InteractiveTable/Expander/index.tsx b/packages/grafana-ui/src/components/InteractiveTable/Expander/index.tsx
index 9a57e38fc50..e40d34d4ae8 100644
--- a/packages/grafana-ui/src/components/InteractiveTable/Expander/index.tsx
+++ b/packages/grafana-ui/src/components/InteractiveTable/Expander/index.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { CellProps, HeaderProps } from 'react-table';
import { IconButton } from '../../IconButton/IconButton';
diff --git a/packages/grafana-ui/src/components/InteractiveTable/InteractiveTable.story.tsx b/packages/grafana-ui/src/components/InteractiveTable/InteractiveTable.story.tsx
index c4deeb1ed4a..feae88ce3f4 100644
--- a/packages/grafana-ui/src/components/InteractiveTable/InteractiveTable.story.tsx
+++ b/packages/grafana-ui/src/components/InteractiveTable/InteractiveTable.story.tsx
@@ -1,5 +1,5 @@
import { Meta, StoryFn, StoryObj } from '@storybook/react';
-import React, { useCallback, useMemo, useState } from 'react';
+import { useCallback, useMemo, useState } from 'react';
import { InteractiveTable, CellProps, LinkButton } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/InteractiveTable/InteractiveTable.test.tsx b/packages/grafana-ui/src/components/InteractiveTable/InteractiveTable.test.tsx
index ec6c704f832..6526c22a0cd 100644
--- a/packages/grafana-ui/src/components/InteractiveTable/InteractiveTable.test.tsx
+++ b/packages/grafana-ui/src/components/InteractiveTable/InteractiveTable.test.tsx
@@ -1,6 +1,6 @@
import { getByRole, render, screen, cleanup } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
+import * as React from 'react';
import { InteractiveTable } from './InteractiveTable';
import { Column } from './types';
diff --git a/packages/grafana-ui/src/components/InteractiveTable/InteractiveTable.tsx b/packages/grafana-ui/src/components/InteractiveTable/InteractiveTable.tsx
index e750b29bb1c..0ad083f5452 100644
--- a/packages/grafana-ui/src/components/InteractiveTable/InteractiveTable.tsx
+++ b/packages/grafana-ui/src/components/InteractiveTable/InteractiveTable.tsx
@@ -1,6 +1,6 @@
import { css, cx } from '@emotion/css';
import { uniqueId } from 'lodash';
-import React, { Fragment, ReactNode, useCallback, useEffect, useMemo } from 'react';
+import { Fragment, ReactNode, useCallback, useEffect, useMemo } from 'react';
import {
HeaderGroup,
PluginHook,
diff --git a/packages/grafana-ui/src/components/JSONFormatter/JSONFormatter.tsx b/packages/grafana-ui/src/components/JSONFormatter/JSONFormatter.tsx
index 5a0bb78c353..089fd514418 100644
--- a/packages/grafana-ui/src/components/JSONFormatter/JSONFormatter.tsx
+++ b/packages/grafana-ui/src/components/JSONFormatter/JSONFormatter.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent, createRef } from 'react';
+import { PureComponent, createRef } from 'react';
import { JsonExplorer, JsonExplorerConfig } from './json_explorer/json_explorer'; // We have made some monkey-patching of json-formatter-js so we can't switch right now
diff --git a/packages/grafana-ui/src/components/Layout/Box/Box.story.tsx b/packages/grafana-ui/src/components/Layout/Box/Box.story.tsx
index b564a3d2476..01e2c175fc3 100644
--- a/packages/grafana-ui/src/components/Layout/Box/Box.story.tsx
+++ b/packages/grafana-ui/src/components/Layout/Box/Box.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { SpacingTokenControl } from '../../../utils/storybook/themeStorybookControls';
import { Text } from '../../Text/Text';
diff --git a/packages/grafana-ui/src/components/Layout/Box/Box.tsx b/packages/grafana-ui/src/components/Layout/Box/Box.tsx
index 85354bca07a..e8a8a6a0264 100644
--- a/packages/grafana-ui/src/components/Layout/Box/Box.tsx
+++ b/packages/grafana-ui/src/components/Layout/Box/Box.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { ElementType, forwardRef, PropsWithChildren } from 'react';
+import { ElementType, forwardRef, PropsWithChildren } from 'react';
+import * as React from 'react';
import { GrafanaTheme2, ThemeSpacingTokens, ThemeShape, ThemeShadows } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Layout/Grid/Grid.story.tsx b/packages/grafana-ui/src/components/Layout/Grid/Grid.story.tsx
index d4dadc083ad..5eb6d6aae2b 100644
--- a/packages/grafana-ui/src/components/Layout/Grid/Grid.story.tsx
+++ b/packages/grafana-ui/src/components/Layout/Grid/Grid.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { useTheme2 } from '../../../themes';
diff --git a/packages/grafana-ui/src/components/Layout/Grid/Grid.tsx b/packages/grafana-ui/src/components/Layout/Grid/Grid.tsx
index 4225bb6074b..b85fdcafa4e 100644
--- a/packages/grafana-ui/src/components/Layout/Grid/Grid.tsx
+++ b/packages/grafana-ui/src/components/Layout/Grid/Grid.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { forwardRef, HTMLAttributes } from 'react';
+import { forwardRef, HTMLAttributes } from 'react';
+import * as React from 'react';
import { GrafanaTheme2, ThemeSpacingTokens } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Layout/Layout.story.tsx b/packages/grafana-ui/src/components/Layout/Layout.story.tsx
index e3d27197648..ab890009c80 100644
--- a/packages/grafana-ui/src/components/Layout/Layout.story.tsx
+++ b/packages/grafana-ui/src/components/Layout/Layout.story.tsx
@@ -1,5 +1,4 @@
import { StoryFn, Meta } from '@storybook/react';
-import React from 'react';
import { Button, VerticalGroup, HorizontalGroup } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/Layout/Layout.tsx b/packages/grafana-ui/src/components/Layout/Layout.tsx
index 7fcd44af454..06b0b3faf06 100644
--- a/packages/grafana-ui/src/components/Layout/Layout.tsx
+++ b/packages/grafana-ui/src/components/Layout/Layout.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { HTMLProps } from 'react';
+import { HTMLProps } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Layout/Space.story.tsx b/packages/grafana-ui/src/components/Layout/Space.story.tsx
index fd6ca746db7..4b8ae94f908 100644
--- a/packages/grafana-ui/src/components/Layout/Space.story.tsx
+++ b/packages/grafana-ui/src/components/Layout/Space.story.tsx
@@ -1,5 +1,4 @@
import { StoryFn, Meta } from '@storybook/react';
-import React from 'react';
import { SpacingTokenControl } from '../../utils/storybook/themeStorybookControls';
diff --git a/packages/grafana-ui/src/components/Layout/Space.tsx b/packages/grafana-ui/src/components/Layout/Space.tsx
index 6e3c53ed2ee..2df48501ea4 100644
--- a/packages/grafana-ui/src/components/Layout/Space.tsx
+++ b/packages/grafana-ui/src/components/Layout/Space.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { ThemeSpacingTokens } from '@grafana/data';
import { Box } from './Box/Box';
diff --git a/packages/grafana-ui/src/components/Layout/Stack/Stack.story.tsx b/packages/grafana-ui/src/components/Layout/Stack/Stack.story.tsx
index 259c67e9132..aace7d3f546 100644
--- a/packages/grafana-ui/src/components/Layout/Stack/Stack.story.tsx
+++ b/packages/grafana-ui/src/components/Layout/Stack/Stack.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { ThemeSpacingTokens } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Layout/Stack/Stack.tsx b/packages/grafana-ui/src/components/Layout/Stack/Stack.tsx
index 3fb75ec9fcc..1f3279ae9c1 100644
--- a/packages/grafana-ui/src/components/Layout/Stack/Stack.tsx
+++ b/packages/grafana-ui/src/components/Layout/Stack/Stack.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2, ThemeSpacingTokens } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Link/Link.tsx b/packages/grafana-ui/src/components/Link/Link.tsx
index c9040f5231a..390a681265c 100644
--- a/packages/grafana-ui/src/components/Link/Link.tsx
+++ b/packages/grafana-ui/src/components/Link/Link.tsx
@@ -1,4 +1,4 @@
-import React, { AnchorHTMLAttributes, forwardRef } from 'react';
+import { AnchorHTMLAttributes, forwardRef } from 'react';
import { Link as RouterLink } from 'react-router-dom';
import { locationUtil, textUtil } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Link/TextLink.story.tsx b/packages/grafana-ui/src/components/Link/TextLink.story.tsx
index 65a0238f21e..2126daf6d50 100644
--- a/packages/grafana-ui/src/components/Link/TextLink.story.tsx
+++ b/packages/grafana-ui/src/components/Link/TextLink.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { StoryExample } from '../../utils/storybook/StoryExample';
import { Stack } from '../Layout/Stack/Stack';
diff --git a/packages/grafana-ui/src/components/Link/TextLink.test.tsx b/packages/grafana-ui/src/components/Link/TextLink.test.tsx
index 442bbcf1025..f1cb7d77468 100644
--- a/packages/grafana-ui/src/components/Link/TextLink.test.tsx
+++ b/packages/grafana-ui/src/components/Link/TextLink.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import { GrafanaConfig, locationUtil } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Link/TextLink.tsx b/packages/grafana-ui/src/components/Link/TextLink.tsx
index 2d5a253bee8..4a57b04ff6c 100644
--- a/packages/grafana-ui/src/components/Link/TextLink.tsx
+++ b/packages/grafana-ui/src/components/Link/TextLink.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { AnchorHTMLAttributes, forwardRef } from 'react';
+import { AnchorHTMLAttributes, forwardRef } from 'react';
import { GrafanaTheme2, locationUtil, textUtil, ThemeTypographyVariantTypes } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/List/AbstractList.test.tsx b/packages/grafana-ui/src/components/List/AbstractList.test.tsx
index 614887012e8..d1c0e01c8eb 100644
--- a/packages/grafana-ui/src/components/List/AbstractList.test.tsx
+++ b/packages/grafana-ui/src/components/List/AbstractList.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { AbstractList } from './AbstractList';
diff --git a/packages/grafana-ui/src/components/List/AbstractList.tsx b/packages/grafana-ui/src/components/List/AbstractList.tsx
index 7fe7d358164..2ed732e8106 100644
--- a/packages/grafana-ui/src/components/List/AbstractList.tsx
+++ b/packages/grafana-ui/src/components/List/AbstractList.tsx
@@ -1,5 +1,5 @@
import { cx, css } from '@emotion/css';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { stylesFactory } from '../../themes';
diff --git a/packages/grafana-ui/src/components/List/InlineList.tsx b/packages/grafana-ui/src/components/List/InlineList.tsx
index bcf34178155..454a897db47 100644
--- a/packages/grafana-ui/src/components/List/InlineList.tsx
+++ b/packages/grafana-ui/src/components/List/InlineList.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { ListProps, AbstractList } from './AbstractList';
diff --git a/packages/grafana-ui/src/components/List/List.internal.story.tsx b/packages/grafana-ui/src/components/List/List.internal.story.tsx
index 9d7e7dedc57..b7b36a13735 100644
--- a/packages/grafana-ui/src/components/List/List.internal.story.tsx
+++ b/packages/grafana-ui/src/components/List/List.internal.story.tsx
@@ -1,6 +1,5 @@
import { css, cx } from '@emotion/css';
import { StoryFn, Meta } from '@storybook/react';
-import React from 'react';
import tinycolor from 'tinycolor2';
import { InlineList } from './InlineList';
diff --git a/packages/grafana-ui/src/components/List/List.tsx b/packages/grafana-ui/src/components/List/List.tsx
index 243cab5ba15..b257dfb4459 100644
--- a/packages/grafana-ui/src/components/List/List.tsx
+++ b/packages/grafana-ui/src/components/List/List.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { ListProps, AbstractList } from './AbstractList';
diff --git a/packages/grafana-ui/src/components/LoadingBar/LoadingBar.story.tsx b/packages/grafana-ui/src/components/LoadingBar/LoadingBar.story.tsx
index 56a850d709e..e71ebc6659e 100644
--- a/packages/grafana-ui/src/components/LoadingBar/LoadingBar.story.tsx
+++ b/packages/grafana-ui/src/components/LoadingBar/LoadingBar.story.tsx
@@ -1,6 +1,5 @@
import { css } from '@emotion/css';
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { LoadingBar, LoadingBarProps, useStyles2 } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/LoadingBar/LoadingBar.tsx b/packages/grafana-ui/src/components/LoadingBar/LoadingBar.tsx
index 29091d7bb36..a6e558422eb 100644
--- a/packages/grafana-ui/src/components/LoadingBar/LoadingBar.tsx
+++ b/packages/grafana-ui/src/components/LoadingBar/LoadingBar.tsx
@@ -1,5 +1,5 @@
import { css, keyframes } from '@emotion/css';
-import React, { CSSProperties } from 'react';
+import { CSSProperties } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/LoadingPlaceholder/LoadingPlaceholder.story.tsx b/packages/grafana-ui/src/components/LoadingPlaceholder/LoadingPlaceholder.story.tsx
index 61126ffa12d..fa91db5d128 100644
--- a/packages/grafana-ui/src/components/LoadingPlaceholder/LoadingPlaceholder.story.tsx
+++ b/packages/grafana-ui/src/components/LoadingPlaceholder/LoadingPlaceholder.story.tsx
@@ -1,5 +1,4 @@
import { StoryFn, Meta } from '@storybook/react';
-import React from 'react';
import { LoadingPlaceholder, LoadingPlaceholderProps } from './LoadingPlaceholder';
import mdx from './LoadingPlaceholder.mdx';
diff --git a/packages/grafana-ui/src/components/LoadingPlaceholder/LoadingPlaceholder.tsx b/packages/grafana-ui/src/components/LoadingPlaceholder/LoadingPlaceholder.tsx
index 018d965602f..695b43ab0cf 100644
--- a/packages/grafana-ui/src/components/LoadingPlaceholder/LoadingPlaceholder.tsx
+++ b/packages/grafana-ui/src/components/LoadingPlaceholder/LoadingPlaceholder.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { HTMLAttributes } from 'react';
+import { HTMLAttributes } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/MatchersUI/FieldNameByRegexMatcherEditor.tsx b/packages/grafana-ui/src/components/MatchersUI/FieldNameByRegexMatcherEditor.tsx
index 5a99d3bd304..ec78e37d8a8 100644
--- a/packages/grafana-ui/src/components/MatchersUI/FieldNameByRegexMatcherEditor.tsx
+++ b/packages/grafana-ui/src/components/MatchersUI/FieldNameByRegexMatcherEditor.tsx
@@ -1,4 +1,5 @@
-import React, { memo, useCallback } from 'react';
+import { memo, useCallback } from 'react';
+import * as React from 'react';
import { FieldMatcherID, fieldMatchers } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/MatchersUI/FieldNameMatcherEditor.tsx b/packages/grafana-ui/src/components/MatchersUI/FieldNameMatcherEditor.tsx
index 91b346df459..109b2eb5392 100644
--- a/packages/grafana-ui/src/components/MatchersUI/FieldNameMatcherEditor.tsx
+++ b/packages/grafana-ui/src/components/MatchersUI/FieldNameMatcherEditor.tsx
@@ -1,4 +1,4 @@
-import React, { memo, useCallback } from 'react';
+import { memo, useCallback } from 'react';
import { FieldMatcherID, fieldMatchers, SelectableValue } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/MatchersUI/FieldNamePicker.tsx b/packages/grafana-ui/src/components/MatchersUI/FieldNamePicker.tsx
index 0db0740945b..2dda1448627 100644
--- a/packages/grafana-ui/src/components/MatchersUI/FieldNamePicker.tsx
+++ b/packages/grafana-ui/src/components/MatchersUI/FieldNamePicker.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { FieldNamePickerConfigSettings, SelectableValue, StandardEditorProps } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/MatchersUI/FieldNamesMatcherEditor.tsx b/packages/grafana-ui/src/components/MatchersUI/FieldNamesMatcherEditor.tsx
index 8d6d6633962..fff601dd946 100644
--- a/packages/grafana-ui/src/components/MatchersUI/FieldNamesMatcherEditor.tsx
+++ b/packages/grafana-ui/src/components/MatchersUI/FieldNamesMatcherEditor.tsx
@@ -1,4 +1,4 @@
-import React, { memo, useCallback } from 'react';
+import { memo, useCallback } from 'react';
import { FieldMatcherID, fieldMatchers, SelectableValue, ByNamesMatcherOptions } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/MatchersUI/FieldTypeMatcherEditor.tsx b/packages/grafana-ui/src/components/MatchersUI/FieldTypeMatcherEditor.tsx
index c196290adef..a1fc6ac7171 100644
--- a/packages/grafana-ui/src/components/MatchersUI/FieldTypeMatcherEditor.tsx
+++ b/packages/grafana-ui/src/components/MatchersUI/FieldTypeMatcherEditor.tsx
@@ -1,4 +1,4 @@
-import React, { memo, useMemo, useCallback } from 'react';
+import { memo, useMemo, useCallback } from 'react';
import { FieldMatcherID, fieldMatchers, SelectableValue, FieldType, DataFrame } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/MatchersUI/FieldValueMatcher.tsx b/packages/grafana-ui/src/components/MatchersUI/FieldValueMatcher.tsx
index 5ea9de41b7d..a2a97b3ef8e 100644
--- a/packages/grafana-ui/src/components/MatchersUI/FieldValueMatcher.tsx
+++ b/packages/grafana-ui/src/components/MatchersUI/FieldValueMatcher.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useMemo, useCallback } from 'react';
+import { useMemo, useCallback } from 'react';
+import * as React from 'react';
import {
FieldMatcherID,
diff --git a/packages/grafana-ui/src/components/MatchersUI/FieldsByFrameRefIdMatcher.test.tsx b/packages/grafana-ui/src/components/MatchersUI/FieldsByFrameRefIdMatcher.test.tsx
index a7038ee2bc6..0ff7c4e1d7a 100644
--- a/packages/grafana-ui/src/components/MatchersUI/FieldsByFrameRefIdMatcher.test.tsx
+++ b/packages/grafana-ui/src/components/MatchersUI/FieldsByFrameRefIdMatcher.test.tsx
@@ -1,5 +1,4 @@
import { fireEvent, render, screen } from '@testing-library/react';
-import React from 'react';
import { toDataFrame, FieldType } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-ui/src/components/MatchersUI/FieldsByFrameRefIdMatcher.tsx b/packages/grafana-ui/src/components/MatchersUI/FieldsByFrameRefIdMatcher.tsx
index 05cf8d84bbd..ef8f2835151 100644
--- a/packages/grafana-ui/src/components/MatchersUI/FieldsByFrameRefIdMatcher.tsx
+++ b/packages/grafana-ui/src/components/MatchersUI/FieldsByFrameRefIdMatcher.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo, useState, useCallback } from 'react';
+import { useMemo, useState, useCallback } from 'react';
import { DataFrame, getFrameDisplayName, FieldMatcherID, fieldMatchers, SelectableValue } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/MatchersUI/types.ts b/packages/grafana-ui/src/components/MatchersUI/types.ts
index 868adc8a527..b1674e55bdc 100644
--- a/packages/grafana-ui/src/components/MatchersUI/types.ts
+++ b/packages/grafana-ui/src/components/MatchersUI/types.ts
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { DataFrame, RegistryItem, FieldMatcherInfo } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Menu/Menu.story.tsx b/packages/grafana-ui/src/components/Menu/Menu.story.tsx
index edae46c59ad..bc0b311f6fd 100644
--- a/packages/grafana-ui/src/components/Menu/Menu.story.tsx
+++ b/packages/grafana-ui/src/components/Menu/Menu.story.tsx
@@ -1,5 +1,4 @@
import { Meta } from '@storybook/react';
-import React from 'react';
import { GraphContextMenuHeader } from '..';
import { StoryExample } from '../../utils/storybook/StoryExample';
diff --git a/packages/grafana-ui/src/components/Menu/Menu.test.tsx b/packages/grafana-ui/src/components/Menu/Menu.test.tsx
index 0df2af1c7ad..e1122c1f8a8 100644
--- a/packages/grafana-ui/src/components/Menu/Menu.test.tsx
+++ b/packages/grafana-ui/src/components/Menu/Menu.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-ui/src/components/Menu/Menu.tsx b/packages/grafana-ui/src/components/Menu/Menu.tsx
index 9dc03f1ee55..c3b905e5117 100644
--- a/packages/grafana-ui/src/components/Menu/Menu.tsx
+++ b/packages/grafana-ui/src/components/Menu/Menu.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { useImperativeHandle, useRef } from 'react';
+import { useImperativeHandle, useRef } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Menu/MenuDivider.tsx b/packages/grafana-ui/src/components/Menu/MenuDivider.tsx
index cf818fcad36..64e2e832eaf 100644
--- a/packages/grafana-ui/src/components/Menu/MenuDivider.tsx
+++ b/packages/grafana-ui/src/components/Menu/MenuDivider.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Menu/MenuGroup.tsx b/packages/grafana-ui/src/components/Menu/MenuGroup.tsx
index 4241dd2e608..8f508a6732e 100644
--- a/packages/grafana-ui/src/components/Menu/MenuGroup.tsx
+++ b/packages/grafana-ui/src/components/Menu/MenuGroup.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { uniqueId } from 'lodash';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Menu/MenuItem.test.tsx b/packages/grafana-ui/src/components/Menu/MenuItem.test.tsx
index c15876d206c..1011634810e 100644
--- a/packages/grafana-ui/src/components/Menu/MenuItem.test.tsx
+++ b/packages/grafana-ui/src/components/Menu/MenuItem.test.tsx
@@ -1,5 +1,4 @@
import { fireEvent, render, screen } from '@testing-library/react';
-import React from 'react';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-ui/src/components/Menu/MenuItem.tsx b/packages/grafana-ui/src/components/Menu/MenuItem.tsx
index 49d4b41d145..11048b850c8 100644
--- a/packages/grafana-ui/src/components/Menu/MenuItem.tsx
+++ b/packages/grafana-ui/src/components/Menu/MenuItem.tsx
@@ -1,13 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, {
- ReactElement,
- useCallback,
- useState,
- useRef,
- useImperativeHandle,
- CSSProperties,
- AriaRole,
-} from 'react';
+import { ReactElement, useCallback, useState, useRef, useImperativeHandle, CSSProperties, AriaRole } from 'react';
+import * as React from 'react';
import { GrafanaTheme2, LinkTarget } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Menu/SubMenu.test.tsx b/packages/grafana-ui/src/components/Menu/SubMenu.test.tsx
index b86d43e5e34..d93a49e04cc 100644
--- a/packages/grafana-ui/src/components/Menu/SubMenu.test.tsx
+++ b/packages/grafana-ui/src/components/Menu/SubMenu.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-ui/src/components/Menu/SubMenu.tsx b/packages/grafana-ui/src/components/Menu/SubMenu.tsx
index 50b49828874..696a71c9a75 100644
--- a/packages/grafana-ui/src/components/Menu/SubMenu.tsx
+++ b/packages/grafana-ui/src/components/Menu/SubMenu.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { CSSProperties, ReactElement, useEffect, useRef, useState } from 'react';
+import { memo, CSSProperties, ReactElement, useEffect, useRef, useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
@@ -24,7 +24,7 @@ export interface SubMenuProps {
}
/** @internal */
-export const SubMenu = React.memo(({ items, isOpen, close, customStyle }: SubMenuProps) => {
+export const SubMenu = memo(({ items, isOpen, close, customStyle }: SubMenuProps) => {
const styles = useStyles2(getStyles);
const localRef = useRef(null);
const [handleKeys] = useMenuFocus({
diff --git a/packages/grafana-ui/src/components/Menu/hooks.test.tsx b/packages/grafana-ui/src/components/Menu/hooks.test.tsx
index 4ca9e69045c..9ad532b14ca 100644
--- a/packages/grafana-ui/src/components/Menu/hooks.test.tsx
+++ b/packages/grafana-ui/src/components/Menu/hooks.test.tsx
@@ -1,5 +1,5 @@
import { act, fireEvent, render, renderHook, screen } from '@testing-library/react';
-import React, { createRef, KeyboardEvent, RefObject } from 'react';
+import { createRef, KeyboardEvent, RefObject } from 'react';
import { useMenuFocus } from './hooks';
diff --git a/packages/grafana-ui/src/components/Modal/Modal.story.tsx b/packages/grafana-ui/src/components/Modal/Modal.story.tsx
index e3f719faf42..d46fc8bb981 100644
--- a/packages/grafana-ui/src/components/Modal/Modal.story.tsx
+++ b/packages/grafana-ui/src/components/Modal/Modal.story.tsx
@@ -1,7 +1,7 @@
import { css, cx } from '@emotion/css';
import { StoryFn, Meta } from '@storybook/react';
import { oneLineTrim } from 'common-tags';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { Button, Modal, ModalTabsHeader, TabContent } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/Modal/Modal.test.tsx b/packages/grafana-ui/src/components/Modal/Modal.test.tsx
index 7f4a79d8480..8d5294412f8 100644
--- a/packages/grafana-ui/src/components/Modal/Modal.test.tsx
+++ b/packages/grafana-ui/src/components/Modal/Modal.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { Modal } from './Modal';
diff --git a/packages/grafana-ui/src/components/Modal/Modal.tsx b/packages/grafana-ui/src/components/Modal/Modal.tsx
index 9cedc4b298a..db59a62f013 100644
--- a/packages/grafana-ui/src/components/Modal/Modal.tsx
+++ b/packages/grafana-ui/src/components/Modal/Modal.tsx
@@ -2,7 +2,8 @@ import { cx } from '@emotion/css';
import { useDialog } from '@react-aria/dialog';
import { FocusScope } from '@react-aria/focus';
import { OverlayContainer, useOverlay } from '@react-aria/overlays';
-import React, { PropsWithChildren, useRef } from 'react';
+import { PropsWithChildren, useRef } from 'react';
+import * as React from 'react';
import { useStyles2 } from '../../themes';
import { IconName } from '../../types';
diff --git a/packages/grafana-ui/src/components/Modal/ModalHeader.tsx b/packages/grafana-ui/src/components/Modal/ModalHeader.tsx
index 5967dd1541e..c580df54acb 100644
--- a/packages/grafana-ui/src/components/Modal/ModalHeader.tsx
+++ b/packages/grafana-ui/src/components/Modal/ModalHeader.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { useStyles2 } from '../../themes';
import { IconName } from '../../types';
diff --git a/packages/grafana-ui/src/components/Modal/ModalTabContent.tsx b/packages/grafana-ui/src/components/Modal/ModalTabContent.tsx
index 2919b8d381b..1efe5b489e4 100644
--- a/packages/grafana-ui/src/components/Modal/ModalTabContent.tsx
+++ b/packages/grafana-ui/src/components/Modal/ModalTabContent.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { IconName } from '../../types';
diff --git a/packages/grafana-ui/src/components/Modal/ModalTabsHeader.tsx b/packages/grafana-ui/src/components/Modal/ModalTabsHeader.tsx
index 51c5d6c4cbf..ab1785d1d0a 100644
--- a/packages/grafana-ui/src/components/Modal/ModalTabsHeader.tsx
+++ b/packages/grafana-ui/src/components/Modal/ModalTabsHeader.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { NavModelItem } from '@grafana/data';
import { IconName } from '../../types';
diff --git a/packages/grafana-ui/src/components/Modal/ModalsContext.tsx b/packages/grafana-ui/src/components/Modal/ModalsContext.tsx
index aa69fc4ed52..4a540716fee 100644
--- a/packages/grafana-ui/src/components/Modal/ModalsContext.tsx
+++ b/packages/grafana-ui/src/components/Modal/ModalsContext.tsx
@@ -1,4 +1,5 @@
-import React, { Component } from 'react';
+import { Component } from 'react';
+import * as React from 'react';
export interface ModalsContextState {
component: React.ComponentType | null;
diff --git a/packages/grafana-ui/src/components/Monaco/CodeEditor.internal.story.tsx b/packages/grafana-ui/src/components/Monaco/CodeEditor.internal.story.tsx
index f1ae3fce9e7..39a713cf26a 100644
--- a/packages/grafana-ui/src/components/Monaco/CodeEditor.internal.story.tsx
+++ b/packages/grafana-ui/src/components/Monaco/CodeEditor.internal.story.tsx
@@ -1,6 +1,5 @@
import { action } from '@storybook/addon-actions';
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { CodeEditor } from './CodeEditor';
import mdx from './CodeEditor.mdx';
diff --git a/packages/grafana-ui/src/components/Monaco/CodeEditor.tsx b/packages/grafana-ui/src/components/Monaco/CodeEditor.tsx
index 7ab4854ec2c..ae959975bbb 100644
--- a/packages/grafana-ui/src/components/Monaco/CodeEditor.tsx
+++ b/packages/grafana-ui/src/components/Monaco/CodeEditor.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import type * as monacoType from 'monaco-editor/esm/vs/editor/editor.api';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { GrafanaTheme2, monacoLanguageRegistry } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-ui/src/components/Monaco/ReactMonacoEditor.tsx b/packages/grafana-ui/src/components/Monaco/ReactMonacoEditor.tsx
index 0f0ab1b3ee3..b447fabf164 100644
--- a/packages/grafana-ui/src/components/Monaco/ReactMonacoEditor.tsx
+++ b/packages/grafana-ui/src/components/Monaco/ReactMonacoEditor.tsx
@@ -1,6 +1,6 @@
import Editor, { loader as monacoEditorLoader, Monaco } from '@monaco-editor/react';
import * as monaco from 'monaco-editor';
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { useTheme2 } from '../../themes';
diff --git a/packages/grafana-ui/src/components/Monaco/ReactMonacoEditorLazy.tsx b/packages/grafana-ui/src/components/Monaco/ReactMonacoEditorLazy.tsx
index eecfc033198..4946ead2ba5 100644
--- a/packages/grafana-ui/src/components/Monaco/ReactMonacoEditorLazy.tsx
+++ b/packages/grafana-ui/src/components/Monaco/ReactMonacoEditorLazy.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-ui/src/components/PageLayout/PageToolbar.story.tsx b/packages/grafana-ui/src/components/PageLayout/PageToolbar.story.tsx
index 6e9638efdf5..2890cd763f3 100644
--- a/packages/grafana-ui/src/components/PageLayout/PageToolbar.story.tsx
+++ b/packages/grafana-ui/src/components/PageLayout/PageToolbar.story.tsx
@@ -1,6 +1,5 @@
import { action } from '@storybook/addon-actions';
import { Meta } from '@storybook/react';
-import React from 'react';
import { ToolbarButton, Stack } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/PageLayout/PageToolbar.test.tsx b/packages/grafana-ui/src/components/PageLayout/PageToolbar.test.tsx
index bfba98620ea..e74bb4a4776 100644
--- a/packages/grafana-ui/src/components/PageLayout/PageToolbar.test.tsx
+++ b/packages/grafana-ui/src/components/PageLayout/PageToolbar.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { PageToolbar } from '..';
diff --git a/packages/grafana-ui/src/components/PageLayout/PageToolbar.tsx b/packages/grafana-ui/src/components/PageLayout/PageToolbar.tsx
index 3d9e7605750..b76f75f5063 100644
--- a/packages/grafana-ui/src/components/PageLayout/PageToolbar.tsx
+++ b/packages/grafana-ui/src/components/PageLayout/PageToolbar.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { ReactNode } from 'react';
+import { memo, Children, ReactNode } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
@@ -34,7 +34,7 @@ export interface Props {
}
/** @alpha */
-export const PageToolbar = React.memo(
+export const PageToolbar = memo(
({
title,
section,
@@ -146,7 +146,7 @@ export const PageToolbar = React.memo(
- {React.Children.toArray(children).filter(Boolean)}
+ {Children.toArray(children).filter(Boolean)}
);
diff --git a/packages/grafana-ui/src/components/Pagination/Pagination.story.tsx b/packages/grafana-ui/src/components/Pagination/Pagination.story.tsx
index 4164c069807..f3f1aca724a 100644
--- a/packages/grafana-ui/src/components/Pagination/Pagination.story.tsx
+++ b/packages/grafana-ui/src/components/Pagination/Pagination.story.tsx
@@ -1,5 +1,5 @@
import { Meta, StoryFn } from '@storybook/react';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { Pagination } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/Pagination/Pagination.test.tsx b/packages/grafana-ui/src/components/Pagination/Pagination.test.tsx
index 68a85e6746c..2e9fe1a44e5 100644
--- a/packages/grafana-ui/src/components/Pagination/Pagination.test.tsx
+++ b/packages/grafana-ui/src/components/Pagination/Pagination.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { Pagination } from './Pagination';
diff --git a/packages/grafana-ui/src/components/Pagination/Pagination.tsx b/packages/grafana-ui/src/components/Pagination/Pagination.tsx
index bdfa1ec7cf8..5917185f2bb 100644
--- a/packages/grafana-ui/src/components/Pagination/Pagination.tsx
+++ b/packages/grafana-ui/src/components/Pagination/Pagination.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { useStyles2 } from '../../themes';
import { Button, ButtonVariant } from '../Button';
diff --git a/packages/grafana-ui/src/components/PanelChrome/HoverWidget.tsx b/packages/grafana-ui/src/components/PanelChrome/HoverWidget.tsx
index b0fda6d1013..fa767de0d53 100644
--- a/packages/grafana-ui/src/components/PanelChrome/HoverWidget.tsx
+++ b/packages/grafana-ui/src/components/PanelChrome/HoverWidget.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { ReactElement, useCallback, useRef } from 'react';
+import { ReactElement, useCallback, useRef } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors as e2eSelectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-ui/src/components/PanelChrome/LoadingIndicator.tsx b/packages/grafana-ui/src/components/PanelChrome/LoadingIndicator.tsx
index 27db3b16f79..dc1357c521d 100644
--- a/packages/grafana-ui/src/components/PanelChrome/LoadingIndicator.tsx
+++ b/packages/grafana-ui/src/components/PanelChrome/LoadingIndicator.tsx
@@ -1,5 +1,4 @@
import { css, cx, keyframes } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-ui/src/components/PanelChrome/PanelChrome.story.tsx b/packages/grafana-ui/src/components/PanelChrome/PanelChrome.story.tsx
index 9367b187d16..584bc082c4b 100644
--- a/packages/grafana-ui/src/components/PanelChrome/PanelChrome.story.tsx
+++ b/packages/grafana-ui/src/components/PanelChrome/PanelChrome.story.tsx
@@ -1,7 +1,7 @@
import { action } from '@storybook/addon-actions';
import { Meta, StoryFn } from '@storybook/react';
import { merge } from 'lodash';
-import React, { CSSProperties, useState, ReactNode } from 'react';
+import { CSSProperties, useState, ReactNode } from 'react';
import { useInterval, useToggle } from 'react-use';
import { LoadingState } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/PanelChrome/PanelChrome.test.tsx b/packages/grafana-ui/src/components/PanelChrome/PanelChrome.test.tsx
index a048c384a25..d9acab30c2d 100644
--- a/packages/grafana-ui/src/components/PanelChrome/PanelChrome.test.tsx
+++ b/packages/grafana-ui/src/components/PanelChrome/PanelChrome.test.tsx
@@ -1,5 +1,4 @@
import { screen, render, fireEvent } from '@testing-library/react';
-import React from 'react';
import { useToggle } from 'react-use';
import { LoadingState } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/PanelChrome/PanelChrome.tsx b/packages/grafana-ui/src/components/PanelChrome/PanelChrome.tsx
index e6f36c80491..4928c84fd3f 100644
--- a/packages/grafana-ui/src/components/PanelChrome/PanelChrome.tsx
+++ b/packages/grafana-ui/src/components/PanelChrome/PanelChrome.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { CSSProperties, ReactElement, ReactNode, useId } from 'react';
+import { CSSProperties, ReactElement, ReactNode, useId } from 'react';
+import * as React from 'react';
import { useMeasure, useToggle } from 'react-use';
import { GrafanaTheme2, LoadingState } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/PanelChrome/PanelContext.ts b/packages/grafana-ui/src/components/PanelChrome/PanelContext.ts
index 17dd87270a2..b05e3e9d211 100644
--- a/packages/grafana-ui/src/components/PanelChrome/PanelContext.ts
+++ b/packages/grafana-ui/src/components/PanelChrome/PanelContext.ts
@@ -1,4 +1,4 @@
-import React from 'react';
+import { createContext, useContext } from 'react';
import {
EventBusSrv,
@@ -99,7 +99,7 @@ export interface PanelContext {
dataLinkPostProcessor?: DataLinkPostProcessor;
}
-export const PanelContextRoot = React.createContext
({
+export const PanelContextRoot = createContext({
eventsScope: 'global',
eventBus: new EventBusSrv(),
});
@@ -112,4 +112,4 @@ export const PanelContextProvider = PanelContextRoot.Provider;
/**
* @alpha
*/
-export const usePanelContext = () => React.useContext(PanelContextRoot);
+export const usePanelContext = () => useContext(PanelContextRoot);
diff --git a/packages/grafana-ui/src/components/PanelChrome/PanelDescription.tsx b/packages/grafana-ui/src/components/PanelChrome/PanelDescription.tsx
index 0f7909cada4..b9e74f5c39d 100644
--- a/packages/grafana-ui/src/components/PanelChrome/PanelDescription.tsx
+++ b/packages/grafana-ui/src/components/PanelChrome/PanelDescription.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/PanelChrome/PanelMenu.tsx b/packages/grafana-ui/src/components/PanelChrome/PanelMenu.tsx
index 595bda416e0..d11fd2d4243 100644
--- a/packages/grafana-ui/src/components/PanelChrome/PanelMenu.tsx
+++ b/packages/grafana-ui/src/components/PanelChrome/PanelMenu.tsx
@@ -1,5 +1,5 @@
import { cx } from '@emotion/css';
-import React, { ReactElement, useCallback } from 'react';
+import { ReactElement, useCallback } from 'react';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-ui/src/components/PanelChrome/PanelStatus.tsx b/packages/grafana-ui/src/components/PanelChrome/PanelStatus.tsx
index 9b92be7a9b3..9667163d12a 100644
--- a/packages/grafana-ui/src/components/PanelChrome/PanelStatus.tsx
+++ b/packages/grafana-ui/src/components/PanelChrome/PanelStatus.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-ui/src/components/PanelChrome/TitleItem.tsx b/packages/grafana-ui/src/components/PanelChrome/TitleItem.tsx
index b3a87fb4919..a4922f2331b 100644
--- a/packages/grafana-ui/src/components/PanelChrome/TitleItem.tsx
+++ b/packages/grafana-ui/src/components/PanelChrome/TitleItem.tsx
@@ -1,5 +1,6 @@
import { cx, css } from '@emotion/css';
-import React, { forwardRef } from 'react';
+import { forwardRef } from 'react';
+import * as React from 'react';
import { GrafanaTheme2, LinkModel, LinkTarget } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/PanelChrome/index.ts b/packages/grafana-ui/src/components/PanelChrome/index.ts
index 92cdb6bd5a7..73a11ed6ac7 100644
--- a/packages/grafana-ui/src/components/PanelChrome/index.ts
+++ b/packages/grafana-ui/src/components/PanelChrome/index.ts
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { LoadingIndicator } from './LoadingIndicator';
import { PanelChrome as PanelChromeComponent, PanelChromeProps } from './PanelChrome';
diff --git a/packages/grafana-ui/src/components/PanelContainer/PanelContainer.story.tsx b/packages/grafana-ui/src/components/PanelContainer/PanelContainer.story.tsx
index ed26a020a71..cafb8150597 100644
--- a/packages/grafana-ui/src/components/PanelContainer/PanelContainer.story.tsx
+++ b/packages/grafana-ui/src/components/PanelContainer/PanelContainer.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { PanelContainer } from './PanelContainer';
import mdx from './PanelContainer.mdx';
diff --git a/packages/grafana-ui/src/components/PanelContainer/PanelContainer.tsx b/packages/grafana-ui/src/components/PanelContainer/PanelContainer.tsx
index fc7b8b5ff8c..e84e295f654 100644
--- a/packages/grafana-ui/src/components/PanelContainer/PanelContainer.tsx
+++ b/packages/grafana-ui/src/components/PanelContainer/PanelContainer.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { DetailedHTMLProps, HTMLAttributes } from 'react';
+import { DetailedHTMLProps, HTMLAttributes } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/PluginSignatureBadge/PluginSignatureBadge.story.tsx b/packages/grafana-ui/src/components/PluginSignatureBadge/PluginSignatureBadge.story.tsx
index 075c5b1ff86..ed7925c8ee6 100644
--- a/packages/grafana-ui/src/components/PluginSignatureBadge/PluginSignatureBadge.story.tsx
+++ b/packages/grafana-ui/src/components/PluginSignatureBadge/PluginSignatureBadge.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { PluginSignatureStatus } from '@grafana/data';
import { PluginSignatureBadge } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/PluginSignatureBadge/PluginSignatureBadge.tsx b/packages/grafana-ui/src/components/PluginSignatureBadge/PluginSignatureBadge.tsx
index 7cb452c3340..af8720cca61 100644
--- a/packages/grafana-ui/src/components/PluginSignatureBadge/PluginSignatureBadge.tsx
+++ b/packages/grafana-ui/src/components/PluginSignatureBadge/PluginSignatureBadge.tsx
@@ -1,4 +1,4 @@
-import React, { HTMLAttributes } from 'react';
+import { HTMLAttributes } from 'react';
import { PluginSignatureStatus } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Portal/Portal.tsx b/packages/grafana-ui/src/components/Portal/Portal.tsx
index 0e00c7b2025..867ee890821 100644
--- a/packages/grafana-ui/src/components/Portal/Portal.tsx
+++ b/packages/grafana-ui/src/components/Portal/Portal.tsx
@@ -1,4 +1,5 @@
-import React, { PropsWithChildren, useLayoutEffect, useRef } from 'react';
+import { PropsWithChildren, useLayoutEffect, useRef } from 'react';
+import * as React from 'react';
import ReactDOM from 'react-dom';
import { useTheme2 } from '../../themes';
diff --git a/packages/grafana-ui/src/components/QueryField/QueryField.story.tsx b/packages/grafana-ui/src/components/QueryField/QueryField.story.tsx
index 79923177a2a..bd9d92659e8 100644
--- a/packages/grafana-ui/src/components/QueryField/QueryField.story.tsx
+++ b/packages/grafana-ui/src/components/QueryField/QueryField.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { TypeaheadInput } from '../../types';
diff --git a/packages/grafana-ui/src/components/QueryField/QueryField.test.tsx b/packages/grafana-ui/src/components/QueryField/QueryField.test.tsx
index bf11342d2ff..391d257b137 100644
--- a/packages/grafana-ui/src/components/QueryField/QueryField.test.tsx
+++ b/packages/grafana-ui/src/components/QueryField/QueryField.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { createTheme } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/QueryField/QueryField.tsx b/packages/grafana-ui/src/components/QueryField/QueryField.tsx
index d42fa8ab3b8..1c79e62239e 100644
--- a/packages/grafana-ui/src/components/QueryField/QueryField.tsx
+++ b/packages/grafana-ui/src/components/QueryField/QueryField.tsx
@@ -1,7 +1,8 @@
import { css, cx } from '@emotion/css';
import classnames from 'classnames';
import { debounce } from 'lodash';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
+import * as React from 'react';
import { Value } from 'slate';
import Plain from 'slate-plain-serializer';
import { Editor, EventHook, Plugin } from 'slate-react';
diff --git a/packages/grafana-ui/src/components/RefreshPicker/RefreshPicker.story.tsx b/packages/grafana-ui/src/components/RefreshPicker/RefreshPicker.story.tsx
index 6dae97df6c8..bdd3926d041 100644
--- a/packages/grafana-ui/src/components/RefreshPicker/RefreshPicker.story.tsx
+++ b/packages/grafana-ui/src/components/RefreshPicker/RefreshPicker.story.tsx
@@ -1,7 +1,6 @@
import { action } from '@storybook/addon-actions';
import { useArgs } from '@storybook/preview-api';
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { RefreshPicker } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/RefreshPicker/RefreshPicker.tsx b/packages/grafana-ui/src/components/RefreshPicker/RefreshPicker.tsx
index de754714c6e..d207288ba89 100644
--- a/packages/grafana-ui/src/components/RefreshPicker/RefreshPicker.tsx
+++ b/packages/grafana-ui/src/components/RefreshPicker/RefreshPicker.tsx
@@ -1,5 +1,5 @@
import { formatDuration } from 'date-fns';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { SelectableValue, parseDuration } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-ui/src/components/RenderUserContentAsHTML/RenderUserContentAsHTML.story.tsx b/packages/grafana-ui/src/components/RenderUserContentAsHTML/RenderUserContentAsHTML.story.tsx
index 2c5ad838dbc..3cc29fa45e6 100644
--- a/packages/grafana-ui/src/components/RenderUserContentAsHTML/RenderUserContentAsHTML.story.tsx
+++ b/packages/grafana-ui/src/components/RenderUserContentAsHTML/RenderUserContentAsHTML.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { RenderUserContentAsHTML } from './RenderUserContentAsHTML';
import mdx from './RenderUserContentAsHTML.mdx';
diff --git a/packages/grafana-ui/src/components/RenderUserContentAsHTML/RenderUserContentAsHTML.test.tsx b/packages/grafana-ui/src/components/RenderUserContentAsHTML/RenderUserContentAsHTML.test.tsx
index 7962ed9fd8c..3f4712e95ff 100644
--- a/packages/grafana-ui/src/components/RenderUserContentAsHTML/RenderUserContentAsHTML.test.tsx
+++ b/packages/grafana-ui/src/components/RenderUserContentAsHTML/RenderUserContentAsHTML.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { RenderUserContentAsHTML } from './RenderUserContentAsHTML';
diff --git a/packages/grafana-ui/src/components/RenderUserContentAsHTML/RenderUserContentAsHTML.tsx b/packages/grafana-ui/src/components/RenderUserContentAsHTML/RenderUserContentAsHTML.tsx
index 2d4e3e87b99..d5ec22c2440 100644
--- a/packages/grafana-ui/src/components/RenderUserContentAsHTML/RenderUserContentAsHTML.tsx
+++ b/packages/grafana-ui/src/components/RenderUserContentAsHTML/RenderUserContentAsHTML.tsx
@@ -1,4 +1,5 @@
-import React, { HTMLAttributes, PropsWithChildren } from 'react';
+import { HTMLAttributes, PropsWithChildren } from 'react';
+import * as React from 'react';
import { textUtil } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/SecretFormField/SecretFormField.internal.story.tsx b/packages/grafana-ui/src/components/SecretFormField/SecretFormField.internal.story.tsx
index faad4feb28a..8c5b7943625 100644
--- a/packages/grafana-ui/src/components/SecretFormField/SecretFormField.internal.story.tsx
+++ b/packages/grafana-ui/src/components/SecretFormField/SecretFormField.internal.story.tsx
@@ -1,7 +1,6 @@
import { action } from '@storybook/addon-actions';
import { useArgs } from '@storybook/preview-api';
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { SecretFormField } from './SecretFormField';
diff --git a/packages/grafana-ui/src/components/SecretFormField/SecretFormField.tsx b/packages/grafana-ui/src/components/SecretFormField/SecretFormField.tsx
index 94e4ee9808f..297df8b49f3 100644
--- a/packages/grafana-ui/src/components/SecretFormField/SecretFormField.tsx
+++ b/packages/grafana-ui/src/components/SecretFormField/SecretFormField.tsx
@@ -1,6 +1,7 @@
import { css, cx } from '@emotion/css';
import { omit } from 'lodash';
-import React, { InputHTMLAttributes } from 'react';
+import { InputHTMLAttributes } from 'react';
+import * as React from 'react';
import { Button } from '../Button/Button';
import { FormField } from '../FormField/FormField';
diff --git a/packages/grafana-ui/src/components/SecretInput/SecretInput.story.tsx b/packages/grafana-ui/src/components/SecretInput/SecretInput.story.tsx
index d83b007a1f8..bc02d0f7204 100644
--- a/packages/grafana-ui/src/components/SecretInput/SecretInput.story.tsx
+++ b/packages/grafana-ui/src/components/SecretInput/SecretInput.story.tsx
@@ -1,5 +1,5 @@
import { StoryFn, Meta } from '@storybook/react';
-import React, { useState, ChangeEvent } from 'react';
+import { useState, ChangeEvent } from 'react';
import { SecretInput } from './SecretInput';
import mdx from './SecretInput.mdx';
diff --git a/packages/grafana-ui/src/components/SecretInput/SecretInput.test.tsx b/packages/grafana-ui/src/components/SecretInput/SecretInput.test.tsx
index 284b30fbf35..aeb9adf4cef 100644
--- a/packages/grafana-ui/src/components/SecretInput/SecretInput.test.tsx
+++ b/packages/grafana-ui/src/components/SecretInput/SecretInput.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { SecretInput, RESET_BUTTON_TEXT, CONFIGURED_TEXT } from './SecretInput';
diff --git a/packages/grafana-ui/src/components/SecretTextArea/SecretTextArea.story.tsx b/packages/grafana-ui/src/components/SecretTextArea/SecretTextArea.story.tsx
index f48f09c3f2f..4e71c1fd66a 100644
--- a/packages/grafana-ui/src/components/SecretTextArea/SecretTextArea.story.tsx
+++ b/packages/grafana-ui/src/components/SecretTextArea/SecretTextArea.story.tsx
@@ -1,5 +1,5 @@
import { StoryFn, Meta } from '@storybook/react';
-import React, { useState, ChangeEvent } from 'react';
+import { useState, ChangeEvent } from 'react';
import { SecretTextArea } from './SecretTextArea';
diff --git a/packages/grafana-ui/src/components/SecretTextArea/SecretTextArea.test.tsx b/packages/grafana-ui/src/components/SecretTextArea/SecretTextArea.test.tsx
index 7290dcf6454..f2543a5002c 100644
--- a/packages/grafana-ui/src/components/SecretTextArea/SecretTextArea.test.tsx
+++ b/packages/grafana-ui/src/components/SecretTextArea/SecretTextArea.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { SecretTextArea, RESET_BUTTON_TEXT, CONFIGURED_TEXT } from './SecretTextArea';
diff --git a/packages/grafana-ui/src/components/Segment/Segment.story.tsx b/packages/grafana-ui/src/components/Segment/Segment.story.tsx
index 771fc011ba7..fbe8a4eb3a0 100644
--- a/packages/grafana-ui/src/components/Segment/Segment.story.tsx
+++ b/packages/grafana-ui/src/components/Segment/Segment.story.tsx
@@ -1,6 +1,7 @@
import { action } from '@storybook/addon-actions';
import { Meta, StoryFn } from '@storybook/react';
-import React, { useState } from 'react';
+import { useState } from 'react';
+import * as React from 'react';
import { SelectableValue } from '@grafana/data';
import { Segment, Icon, SegmentSection } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/Segment/Segment.tsx b/packages/grafana-ui/src/components/Segment/Segment.tsx
index cb74127cdca..36ae2552a8d 100644
--- a/packages/grafana-ui/src/components/Segment/Segment.tsx
+++ b/packages/grafana-ui/src/components/Segment/Segment.tsx
@@ -1,6 +1,7 @@
import { cx } from '@emotion/css';
import { isObject } from 'lodash';
-import React, { HTMLProps } from 'react';
+import { HTMLProps } from 'react';
+import * as React from 'react';
import { SelectableValue } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Segment/SegmentAsync.story.tsx b/packages/grafana-ui/src/components/Segment/SegmentAsync.story.tsx
index edf49d25647..9aaaf008867 100644
--- a/packages/grafana-ui/src/components/Segment/SegmentAsync.story.tsx
+++ b/packages/grafana-ui/src/components/Segment/SegmentAsync.story.tsx
@@ -1,6 +1,7 @@
import { action } from '@storybook/addon-actions';
import { Meta, StoryFn } from '@storybook/react';
-import React, { useState } from 'react';
+import { useState } from 'react';
+import * as React from 'react';
import { AsyncState } from 'react-use/lib/useAsync';
import { SelectableValue } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Segment/SegmentAsync.tsx b/packages/grafana-ui/src/components/Segment/SegmentAsync.tsx
index 29408d1b319..b0f9907554b 100644
--- a/packages/grafana-ui/src/components/Segment/SegmentAsync.tsx
+++ b/packages/grafana-ui/src/components/Segment/SegmentAsync.tsx
@@ -1,6 +1,7 @@
import { cx } from '@emotion/css';
import { isObject } from 'lodash';
-import React, { HTMLProps } from 'react';
+import { HTMLProps } from 'react';
+import * as React from 'react';
import { useAsyncFn } from 'react-use';
import { AsyncState } from 'react-use/lib/useAsync';
diff --git a/packages/grafana-ui/src/components/Segment/SegmentInput.story.tsx b/packages/grafana-ui/src/components/Segment/SegmentInput.story.tsx
index 85e9122ef4f..64a3a9c8fee 100644
--- a/packages/grafana-ui/src/components/Segment/SegmentInput.story.tsx
+++ b/packages/grafana-ui/src/components/Segment/SegmentInput.story.tsx
@@ -1,6 +1,7 @@
import { action } from '@storybook/addon-actions';
import { Meta, StoryFn } from '@storybook/react';
-import React, { useState } from 'react';
+import { useState } from 'react';
+import * as React from 'react';
import { SegmentInput, Icon, SegmentSection } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/Segment/SegmentInput.tsx b/packages/grafana-ui/src/components/Segment/SegmentInput.tsx
index 49bfe8454e4..24ab7e8af1e 100644
--- a/packages/grafana-ui/src/components/Segment/SegmentInput.tsx
+++ b/packages/grafana-ui/src/components/Segment/SegmentInput.tsx
@@ -1,5 +1,6 @@
import { cx, css } from '@emotion/css';
-import React, { HTMLProps, useRef, useState } from 'react';
+import { HTMLProps, useRef, useState } from 'react';
+import * as React from 'react';
import useClickAway from 'react-use/lib/useClickAway';
import { useStyles2 } from '../../themes';
diff --git a/packages/grafana-ui/src/components/Segment/SegmentSection.tsx b/packages/grafana-ui/src/components/Segment/SegmentSection.tsx
index e2e2353182f..bdd03681d73 100644
--- a/packages/grafana-ui/src/components/Segment/SegmentSection.tsx
+++ b/packages/grafana-ui/src/components/Segment/SegmentSection.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Segment/SegmentSelect.tsx b/packages/grafana-ui/src/components/Segment/SegmentSelect.tsx
index e3755c4435a..42efd93063d 100644
--- a/packages/grafana-ui/src/components/Segment/SegmentSelect.tsx
+++ b/packages/grafana-ui/src/components/Segment/SegmentSelect.tsx
@@ -1,4 +1,5 @@
-import React, { HTMLProps, useRef } from 'react';
+import { HTMLProps, useRef } from 'react';
+import * as React from 'react';
import { SelectableValue } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Segment/useExpandableLabel.tsx b/packages/grafana-ui/src/components/Segment/useExpandableLabel.tsx
index 5e1d8bf215e..bc80d49f457 100644
--- a/packages/grafana-ui/src/components/Segment/useExpandableLabel.tsx
+++ b/packages/grafana-ui/src/components/Segment/useExpandableLabel.tsx
@@ -1,4 +1,5 @@
-import React, { useState, useRef, ReactElement } from 'react';
+import { useState, useRef, ReactElement } from 'react';
+import * as React from 'react';
import { useStyles2 } from '../../themes';
import { clearButtonStyles } from '../Button';
diff --git a/packages/grafana-ui/src/components/Select/CustomInput.tsx b/packages/grafana-ui/src/components/Select/CustomInput.tsx
index 5531b314ec2..d87cb5372df 100644
--- a/packages/grafana-ui/src/components/Select/CustomInput.tsx
+++ b/packages/grafana-ui/src/components/Select/CustomInput.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { components, InputProps } from 'react-select';
/**
diff --git a/packages/grafana-ui/src/components/Select/DropdownIndicator.tsx b/packages/grafana-ui/src/components/Select/DropdownIndicator.tsx
index 5e56ce531d6..ed0f4213544 100644
--- a/packages/grafana-ui/src/components/Select/DropdownIndicator.tsx
+++ b/packages/grafana-ui/src/components/Select/DropdownIndicator.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { DropdownIndicatorProps } from 'react-select';
import { Icon } from '../Icon/Icon';
diff --git a/packages/grafana-ui/src/components/Select/IndicatorsContainer.tsx b/packages/grafana-ui/src/components/Select/IndicatorsContainer.tsx
index 9ed79985614..36891e7678b 100644
--- a/packages/grafana-ui/src/components/Select/IndicatorsContainer.tsx
+++ b/packages/grafana-ui/src/components/Select/IndicatorsContainer.tsx
@@ -1,10 +1,10 @@
import { cx, css } from '@emotion/css';
-import React from 'react';
+import { forwardRef } from 'react';
import { useTheme2 } from '../../themes/ThemeContext';
import { getInputStyles } from '../Input/Input';
-export const IndicatorsContainer = React.forwardRef((props, ref) => {
+export const IndicatorsContainer = forwardRef((props, ref) => {
const { children } = props;
const theme = useTheme2();
const styles = getInputStyles({ theme, invalid: false });
diff --git a/packages/grafana-ui/src/components/Select/InputControl.tsx b/packages/grafana-ui/src/components/Select/InputControl.tsx
index c4a3e4b90f2..4635b6a27dc 100644
--- a/packages/grafana-ui/src/components/Select/InputControl.tsx
+++ b/packages/grafana-ui/src/components/Select/InputControl.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
+import { forwardRef } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
@@ -16,7 +16,7 @@ interface InputControlProps {
innerProps: JSX.IntrinsicElements['div'];
}
-export const InputControl = React.forwardRef>(
+export const InputControl = forwardRef>(
function InputControl({ focused, invalid, disabled, children, innerProps, prefix, ...otherProps }, ref) {
const styles = useStyles2(getInputControlStyles, invalid, !!prefix);
diff --git a/packages/grafana-ui/src/components/Select/MultiValue.tsx b/packages/grafana-ui/src/components/Select/MultiValue.tsx
index cc05170f756..c92a788ba5d 100644
--- a/packages/grafana-ui/src/components/Select/MultiValue.tsx
+++ b/packages/grafana-ui/src/components/Select/MultiValue.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { useTheme2 } from '../../themes';
import { IconButton, Props as IconButtonProps } from '../IconButton/IconButton';
diff --git a/packages/grafana-ui/src/components/Select/Select.mdx b/packages/grafana-ui/src/components/Select/Select.mdx
index 5af27ea2344..29d4c320a99 100644
--- a/packages/grafana-ui/src/components/Select/Select.mdx
+++ b/packages/grafana-ui/src/components/Select/Select.mdx
@@ -65,7 +65,7 @@ const SelectComponent = () => {
If you want to reset the selected value from outside the component, e.g. if there are two Select components that should be in sync, you can set the dependent Select value to `null` in the `onChange` handler of the first Select component.
```tsx
-import React, { useState } from 'react';
+import { useState } from 'react';
import { Select } from '@grafana/ui';
const SelectComponent = () => {
diff --git a/packages/grafana-ui/src/components/Select/Select.story.tsx b/packages/grafana-ui/src/components/Select/Select.story.tsx
index 20d3d29e416..c56102ca64e 100644
--- a/packages/grafana-ui/src/components/Select/Select.story.tsx
+++ b/packages/grafana-ui/src/components/Select/Select.story.tsx
@@ -2,7 +2,7 @@ import { auto } from '@popperjs/core';
import { action } from '@storybook/addon-actions';
import { Meta, StoryFn } from '@storybook/react';
import Chance from 'chance';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { SelectableValue, toIconName } from '@grafana/data';
import { Icon, Select, AsyncSelect, MultiSelect, AsyncMultiSelect } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/Select/Select.tsx b/packages/grafana-ui/src/components/Select/Select.tsx
index d118d9ada33..5a24d2d97c0 100644
--- a/packages/grafana-ui/src/components/Select/Select.tsx
+++ b/packages/grafana-ui/src/components/Select/Select.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SelectableValue } from '@grafana/data';
import { SelectBase } from './SelectBase';
diff --git a/packages/grafana-ui/src/components/Select/SelectBase.test.tsx b/packages/grafana-ui/src/components/Select/SelectBase.test.tsx
index d36fc8de979..895e0d055b1 100644
--- a/packages/grafana-ui/src/components/Select/SelectBase.test.tsx
+++ b/packages/grafana-ui/src/components/Select/SelectBase.test.tsx
@@ -1,6 +1,6 @@
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { select } from 'react-select-event';
import { SelectableValue } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Select/SelectBase.tsx b/packages/grafana-ui/src/components/Select/SelectBase.tsx
index 34eccfc4aa5..a37634653d6 100644
--- a/packages/grafana-ui/src/components/Select/SelectBase.tsx
+++ b/packages/grafana-ui/src/components/Select/SelectBase.tsx
@@ -1,5 +1,6 @@
import { t } from 'i18next';
-import React, { ComponentProps, useCallback, useEffect, useRef, useState } from 'react';
+import { ComponentProps, useCallback, useEffect, useRef, useState } from 'react';
+import * as React from 'react';
import {
default as ReactSelect,
IndicatorsContainerProps,
diff --git a/packages/grafana-ui/src/components/Select/SelectContainer.tsx b/packages/grafana-ui/src/components/Select/SelectContainer.tsx
index 8e6f4ff895d..cdac2582193 100644
--- a/packages/grafana-ui/src/components/Select/SelectContainer.tsx
+++ b/packages/grafana-ui/src/components/Select/SelectContainer.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { components, ContainerProps as BaseContainerProps, GroupBase } from 'react-select';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Select/SelectMenu.tsx b/packages/grafana-ui/src/components/Select/SelectMenu.tsx
index a0dc9336d09..c8a6aff1712 100644
--- a/packages/grafana-ui/src/components/Select/SelectMenu.tsx
+++ b/packages/grafana-ui/src/components/Select/SelectMenu.tsx
@@ -1,6 +1,7 @@
import { cx } from '@emotion/css';
import { max } from 'lodash';
-import React, { RefCallback, useEffect, useMemo, useRef } from 'react';
+import { RefCallback, useEffect, useMemo, useRef } from 'react';
+import * as React from 'react';
import { MenuListProps } from 'react-select';
import { FixedSizeList as List } from 'react-window';
diff --git a/packages/grafana-ui/src/components/Select/SelectOptionGroup.tsx b/packages/grafana-ui/src/components/Select/SelectOptionGroup.tsx
index 940d0088fb8..def8c1cd414 100644
--- a/packages/grafana-ui/src/components/Select/SelectOptionGroup.tsx
+++ b/packages/grafana-ui/src/components/Select/SelectOptionGroup.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { GroupProps } from 'react-select';
import { useStyles2 } from '../../themes/ThemeContext';
diff --git a/packages/grafana-ui/src/components/Select/SelectOptionGroupHeader.tsx b/packages/grafana-ui/src/components/Select/SelectOptionGroupHeader.tsx
index bdcc4ec0139..c88ee5b7eb1 100644
--- a/packages/grafana-ui/src/components/Select/SelectOptionGroupHeader.tsx
+++ b/packages/grafana-ui/src/components/Select/SelectOptionGroupHeader.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { GroupHeadingProps } from 'react-select';
import { useStyles2 } from '../../themes/ThemeContext';
diff --git a/packages/grafana-ui/src/components/Select/SelectPerf.internal.story.tsx b/packages/grafana-ui/src/components/Select/SelectPerf.internal.story.tsx
index 93f20cdfe1c..d147b90a2b5 100644
--- a/packages/grafana-ui/src/components/Select/SelectPerf.internal.story.tsx
+++ b/packages/grafana-ui/src/components/Select/SelectPerf.internal.story.tsx
@@ -1,5 +1,5 @@
import { Meta } from '@storybook/react';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import ReactSelect, { createFilter } from 'react-select';
import { SelectableValue } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Select/SingleValue.tsx b/packages/grafana-ui/src/components/Select/SingleValue.tsx
index 849c232e1e9..98e5dde07d6 100644
--- a/packages/grafana-ui/src/components/Select/SingleValue.tsx
+++ b/packages/grafana-ui/src/components/Select/SingleValue.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { components, GroupBase, SingleValueProps } from 'react-select';
import { GrafanaTheme2, SelectableValue, toIconName } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Select/ValueContainer.tsx b/packages/grafana-ui/src/components/Select/ValueContainer.tsx
index 5ad36ce8f92..303217009ec 100644
--- a/packages/grafana-ui/src/components/Select/ValueContainer.tsx
+++ b/packages/grafana-ui/src/components/Select/ValueContainer.tsx
@@ -1,5 +1,5 @@
import { cx } from '@emotion/css';
-import React, { Component, ReactNode } from 'react';
+import { Component, ReactNode } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Select/types.ts b/packages/grafana-ui/src/components/Select/types.ts
index 9ab7b930664..ae97e63adfd 100644
--- a/packages/grafana-ui/src/components/Select/types.ts
+++ b/packages/grafana-ui/src/components/Select/types.ts
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import {
ActionMeta as SelectActionMeta,
CommonProps as ReactSelectCommonProps,
diff --git a/packages/grafana-ui/src/components/Slider/HandleTooltip.tsx b/packages/grafana-ui/src/components/Slider/HandleTooltip.tsx
index 50845a0608d..9bdcc4d6952 100644
--- a/packages/grafana-ui/src/components/Slider/HandleTooltip.tsx
+++ b/packages/grafana-ui/src/components/Slider/HandleTooltip.tsx
@@ -1,6 +1,7 @@
import { css } from '@emotion/css';
import Tooltip, { TooltipRef } from 'rc-tooltip';
-import React, { useEffect, useRef } from 'react';
+import { useEffect, useRef } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Slider/RangeSlider.story.tsx b/packages/grafana-ui/src/components/Slider/RangeSlider.story.tsx
index f72558db309..0dc85ec4d05 100644
--- a/packages/grafana-ui/src/components/Slider/RangeSlider.story.tsx
+++ b/packages/grafana-ui/src/components/Slider/RangeSlider.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { RangeSlider } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/Slider/RangeSlider.test.tsx b/packages/grafana-ui/src/components/Slider/RangeSlider.test.tsx
index 081921efa8e..25c89e2dd4c 100644
--- a/packages/grafana-ui/src/components/Slider/RangeSlider.test.tsx
+++ b/packages/grafana-ui/src/components/Slider/RangeSlider.test.tsx
@@ -1,5 +1,4 @@
import { render } from '@testing-library/react';
-import React from 'react';
import { RangeSlider } from './RangeSlider';
import { RangeSliderProps } from './types';
diff --git a/packages/grafana-ui/src/components/Slider/RangeSlider.tsx b/packages/grafana-ui/src/components/Slider/RangeSlider.tsx
index a95ca126ffb..34b9d403085 100644
--- a/packages/grafana-ui/src/components/Slider/RangeSlider.tsx
+++ b/packages/grafana-ui/src/components/Slider/RangeSlider.tsx
@@ -1,7 +1,7 @@
import { cx } from '@emotion/css';
import { Global } from '@emotion/react';
import Slider, { SliderProps } from 'rc-slider';
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { useStyles2 } from '../../themes/ThemeContext';
diff --git a/packages/grafana-ui/src/components/Slider/Slider.story.tsx b/packages/grafana-ui/src/components/Slider/Slider.story.tsx
index 3c6910e546b..7e87faf6212 100644
--- a/packages/grafana-ui/src/components/Slider/Slider.story.tsx
+++ b/packages/grafana-ui/src/components/Slider/Slider.story.tsx
@@ -1,5 +1,4 @@
import { StoryFn, Meta } from '@storybook/react';
-import React from 'react';
import { Slider } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/Slider/Slider.test.tsx b/packages/grafana-ui/src/components/Slider/Slider.test.tsx
index 97e0ed4fe2c..2723a180b3c 100644
--- a/packages/grafana-ui/src/components/Slider/Slider.test.tsx
+++ b/packages/grafana-ui/src/components/Slider/Slider.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { Slider } from './Slider';
import { SliderProps } from './types';
diff --git a/packages/grafana-ui/src/components/Slider/Slider.tsx b/packages/grafana-ui/src/components/Slider/Slider.tsx
index 4a52fb1ca33..5da049a3d0c 100644
--- a/packages/grafana-ui/src/components/Slider/Slider.tsx
+++ b/packages/grafana-ui/src/components/Slider/Slider.tsx
@@ -1,7 +1,7 @@
import { cx } from '@emotion/css';
import { Global } from '@emotion/react';
import SliderComponent from 'rc-slider';
-import React, { useState, useCallback, ChangeEvent, FocusEvent } from 'react';
+import { useState, useCallback, ChangeEvent, FocusEvent } from 'react';
import { useStyles2 } from '../../themes/ThemeContext';
import { Input } from '../Input/Input';
diff --git a/packages/grafana-ui/src/components/Sparkline/Sparkline.tsx b/packages/grafana-ui/src/components/Sparkline/Sparkline.tsx
index 245baabee7c..1ecba02b578 100644
--- a/packages/grafana-ui/src/components/Sparkline/Sparkline.tsx
+++ b/packages/grafana-ui/src/components/Sparkline/Sparkline.tsx
@@ -1,5 +1,5 @@
import { isEqual } from 'lodash';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { AlignedData, Range } from 'uplot';
import {
diff --git a/packages/grafana-ui/src/components/Spinner/Spinner.story.tsx b/packages/grafana-ui/src/components/Spinner/Spinner.story.tsx
index a2f0e76b988..f9531f3e48b 100644
--- a/packages/grafana-ui/src/components/Spinner/Spinner.story.tsx
+++ b/packages/grafana-ui/src/components/Spinner/Spinner.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { Spinner } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/Spinner/Spinner.tsx b/packages/grafana-ui/src/components/Spinner/Spinner.tsx
index 013f7332a2a..079aa3997d5 100644
--- a/packages/grafana-ui/src/components/Spinner/Spinner.tsx
+++ b/packages/grafana-ui/src/components/Spinner/Spinner.tsx
@@ -1,5 +1,5 @@
import { cx, css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import SVG from 'react-inlinesvg';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Splitter/useSplitter.story.tsx b/packages/grafana-ui/src/components/Splitter/useSplitter.story.tsx
index ca929b79efc..9445b5ed53e 100644
--- a/packages/grafana-ui/src/components/Splitter/useSplitter.story.tsx
+++ b/packages/grafana-ui/src/components/Splitter/useSplitter.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { Box } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/Splitter/useSplitter.ts b/packages/grafana-ui/src/components/Splitter/useSplitter.ts
index 5f3b0b8e4a8..0ba04256876 100644
--- a/packages/grafana-ui/src/components/Splitter/useSplitter.ts
+++ b/packages/grafana-ui/src/components/Splitter/useSplitter.ts
@@ -1,6 +1,7 @@
import { css } from '@emotion/css';
import { clamp, throttle } from 'lodash';
-import React, { useCallback, useId, useLayoutEffect, useRef } from 'react';
+import { useCallback, useId, useLayoutEffect, useRef } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/StatsPicker/StatsPicker.story.tsx b/packages/grafana-ui/src/components/StatsPicker/StatsPicker.story.tsx
index 149afab4640..48317679183 100644
--- a/packages/grafana-ui/src/components/StatsPicker/StatsPicker.story.tsx
+++ b/packages/grafana-ui/src/components/StatsPicker/StatsPicker.story.tsx
@@ -1,6 +1,6 @@
import { action } from '@storybook/addon-actions';
import { Meta, StoryFn } from '@storybook/react';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { StatsPicker } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/StatsPicker/StatsPicker.tsx b/packages/grafana-ui/src/components/StatsPicker/StatsPicker.tsx
index 895f849104f..009ae565dfe 100644
--- a/packages/grafana-ui/src/components/StatsPicker/StatsPicker.tsx
+++ b/packages/grafana-ui/src/components/StatsPicker/StatsPicker.tsx
@@ -1,5 +1,5 @@
import { difference } from 'lodash';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { fieldReducers, SelectableValue, FieldReducerInfo } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Switch/Switch.story.tsx b/packages/grafana-ui/src/components/Switch/Switch.story.tsx
index 12bbef7d675..3243e072f76 100644
--- a/packages/grafana-ui/src/components/Switch/Switch.story.tsx
+++ b/packages/grafana-ui/src/components/Switch/Switch.story.tsx
@@ -1,5 +1,6 @@
import { Meta, StoryFn } from '@storybook/react';
-import React, { useState, useCallback } from 'react';
+import { useState, useCallback } from 'react';
+import * as React from 'react';
import { InlineField, Switch, InlineSwitch } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/Switch/Switch.tsx b/packages/grafana-ui/src/components/Switch/Switch.tsx
index bee3ea4949f..53414c56aa6 100644
--- a/packages/grafana-ui/src/components/Switch/Switch.tsx
+++ b/packages/grafana-ui/src/components/Switch/Switch.tsx
@@ -1,6 +1,6 @@
import { css, cx } from '@emotion/css';
import { uniqueId } from 'lodash';
-import React, { HTMLProps, useRef } from 'react';
+import { forwardRef, HTMLProps, useRef } from 'react';
import { GrafanaTheme2, deprecationWarning } from '@grafana/data';
@@ -14,7 +14,7 @@ export interface Props extends Omit, 'value'> {
invalid?: boolean;
}
-export const Switch = React.forwardRef(
+export const Switch = forwardRef(
({ value, checked, onChange, id, label, disabled, invalid = false, ...inputProps }, ref) => {
if (checked) {
deprecationWarning('Switch', 'checked prop', 'value');
@@ -53,7 +53,7 @@ export interface InlineSwitchProps extends Props {
transparent?: boolean;
}
-export const InlineSwitch = React.forwardRef(
+export const InlineSwitch = forwardRef(
({ transparent, className, showLabel, label, value, id, invalid, ...props }, ref) => {
const styles = useStyles2(getSwitchStyles, transparent);
diff --git a/packages/grafana-ui/src/components/TabbedContainer/TabbedContainer.tsx b/packages/grafana-ui/src/components/TabbedContainer/TabbedContainer.tsx
index 59e635a3c28..3feff5be763 100644
--- a/packages/grafana-ui/src/components/TabbedContainer/TabbedContainer.tsx
+++ b/packages/grafana-ui/src/components/TabbedContainer/TabbedContainer.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
+import * as React from 'react';
import { SelectableValue, GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Table/BarGaugeCell.tsx b/packages/grafana-ui/src/components/Table/BarGaugeCell.tsx
index 4580c37ae6b..9bc9e199afb 100644
--- a/packages/grafana-ui/src/components/Table/BarGaugeCell.tsx
+++ b/packages/grafana-ui/src/components/Table/BarGaugeCell.tsx
@@ -1,5 +1,4 @@
import { isFunction } from 'lodash';
-import React from 'react';
import { ThresholdsConfig, ThresholdsMode, VizOrientation, getFieldConfigWithMinMax } from '@grafana/data';
import { BarGaugeDisplayMode, BarGaugeValueMode, TableCellDisplayMode } from '@grafana/schema';
diff --git a/packages/grafana-ui/src/components/Table/CellActions.tsx b/packages/grafana-ui/src/components/Table/CellActions.tsx
index c7455711747..e5908664428 100644
--- a/packages/grafana-ui/src/components/Table/CellActions.tsx
+++ b/packages/grafana-ui/src/components/Table/CellActions.tsx
@@ -1,4 +1,5 @@
-import React, { useCallback, useState } from 'react';
+import { useCallback, useState } from 'react';
+import * as React from 'react';
import { IconSize } from '../../types/icon';
import { IconButton } from '../IconButton/IconButton';
diff --git a/packages/grafana-ui/src/components/Table/DataLinksCell.tsx b/packages/grafana-ui/src/components/Table/DataLinksCell.tsx
index 45d8d3eb093..9a6383039e1 100644
--- a/packages/grafana-ui/src/components/Table/DataLinksCell.tsx
+++ b/packages/grafana-ui/src/components/Table/DataLinksCell.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { getCellLinks } from '../../utils';
import { TableCellProps } from './types';
diff --git a/packages/grafana-ui/src/components/Table/DefaultCell.tsx b/packages/grafana-ui/src/components/Table/DefaultCell.tsx
index 0a910f07eda..37e115e2259 100644
--- a/packages/grafana-ui/src/components/Table/DefaultCell.tsx
+++ b/packages/grafana-ui/src/components/Table/DefaultCell.tsx
@@ -1,5 +1,6 @@
import { cx } from '@emotion/css';
-import React, { ReactElement, useState } from 'react';
+import { ReactElement, useState } from 'react';
+import * as React from 'react';
import { DisplayValue, formattedValueToString } from '@grafana/data';
import { TableCellDisplayMode } from '@grafana/schema';
diff --git a/packages/grafana-ui/src/components/Table/ExpandedRow.tsx b/packages/grafana-ui/src/components/Table/ExpandedRow.tsx
index 113c31aaa40..a7e8f56f767 100644
--- a/packages/grafana-ui/src/components/Table/ExpandedRow.tsx
+++ b/packages/grafana-ui/src/components/Table/ExpandedRow.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { CSSProperties } from 'react';
+import { CSSProperties } from 'react';
+import * as React from 'react';
import { DataFrame, Field, GrafanaTheme2 } from '@grafana/data';
import { TableCellHeight } from '@grafana/schema';
diff --git a/packages/grafana-ui/src/components/Table/Filter.tsx b/packages/grafana-ui/src/components/Table/Filter.tsx
index dd5b4ca8ba6..572fa6f5347 100644
--- a/packages/grafana-ui/src/components/Table/Filter.tsx
+++ b/packages/grafana-ui/src/components/Table/Filter.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { useCallback, useMemo, useRef, useState } from 'react';
+import { useCallback, useMemo, useRef, useState } from 'react';
import { Field, GrafanaTheme2, SelectableValue } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Table/FilterList.tsx b/packages/grafana-ui/src/components/Table/FilterList.tsx
index 1ea721809d5..e4ca6d19df8 100644
--- a/packages/grafana-ui/src/components/Table/FilterList.tsx
+++ b/packages/grafana-ui/src/components/Table/FilterList.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { useCallback, useMemo } from 'react';
+import { useCallback, useMemo } from 'react';
+import * as React from 'react';
import { FixedSizeList as List } from 'react-window';
import { GrafanaTheme2, formattedValueToString, getValueFormat, SelectableValue } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Table/FilterPopup.tsx b/packages/grafana-ui/src/components/Table/FilterPopup.tsx
index a8f6b675a35..9b3071d549a 100644
--- a/packages/grafana-ui/src/components/Table/FilterPopup.tsx
+++ b/packages/grafana-ui/src/components/Table/FilterPopup.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { useCallback, useMemo, useState } from 'react';
+import { useCallback, useMemo, useState } from 'react';
+import * as React from 'react';
import { Field, GrafanaTheme2, SelectableValue } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Table/FooterCell.tsx b/packages/grafana-ui/src/components/Table/FooterCell.tsx
index 992ecae9b5a..72393d91140 100644
--- a/packages/grafana-ui/src/components/Table/FooterCell.tsx
+++ b/packages/grafana-ui/src/components/Table/FooterCell.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { KeyValue } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Table/FooterRow.tsx b/packages/grafana-ui/src/components/Table/FooterRow.tsx
index 83c8c0e6cd5..10321992b45 100644
--- a/packages/grafana-ui/src/components/Table/FooterRow.tsx
+++ b/packages/grafana-ui/src/components/Table/FooterRow.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { ColumnInstance, HeaderGroup } from 'react-table';
import { fieldReducers, ReducerID } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Table/GeoCell.tsx b/packages/grafana-ui/src/components/Table/GeoCell.tsx
index 1ac13627427..d5e156f8b70 100644
--- a/packages/grafana-ui/src/components/Table/GeoCell.tsx
+++ b/packages/grafana-ui/src/components/Table/GeoCell.tsx
@@ -1,6 +1,5 @@
import WKT from 'ol/format/WKT';
import { Geometry } from 'ol/geom';
-import React from 'react';
import { TableCellProps } from './types';
diff --git a/packages/grafana-ui/src/components/Table/HeaderRow.tsx b/packages/grafana-ui/src/components/Table/HeaderRow.tsx
index 2bd1ef04801..6f3fc92fcaa 100644
--- a/packages/grafana-ui/src/components/Table/HeaderRow.tsx
+++ b/packages/grafana-ui/src/components/Table/HeaderRow.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { HeaderGroup, Column } from 'react-table';
import { Field } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Table/ImageCell.tsx b/packages/grafana-ui/src/components/Table/ImageCell.tsx
index 6732bb6c54f..3f507aff232 100644
--- a/packages/grafana-ui/src/components/Table/ImageCell.tsx
+++ b/packages/grafana-ui/src/components/Table/ImageCell.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { getCellLinks } from '../../utils';
import { DataLinksContextMenu } from '../DataLinks/DataLinksContextMenu';
diff --git a/packages/grafana-ui/src/components/Table/JSONViewCell.tsx b/packages/grafana-ui/src/components/Table/JSONViewCell.tsx
index d7840fb339d..ba5691b2c7e 100644
--- a/packages/grafana-ui/src/components/Table/JSONViewCell.tsx
+++ b/packages/grafana-ui/src/components/Table/JSONViewCell.tsx
@@ -1,6 +1,5 @@
import { css, cx } from '@emotion/css';
import { isString } from 'lodash';
-import React from 'react';
import { useStyles2 } from '../../themes';
import { getCellLinks } from '../../utils';
diff --git a/packages/grafana-ui/src/components/Table/RowExpander.tsx b/packages/grafana-ui/src/components/Table/RowExpander.tsx
index 17366aed255..ca678472cab 100644
--- a/packages/grafana-ui/src/components/Table/RowExpander.tsx
+++ b/packages/grafana-ui/src/components/Table/RowExpander.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Icon } from '../Icon/Icon';
import { TableStyles } from './styles';
diff --git a/packages/grafana-ui/src/components/Table/RowsList.tsx b/packages/grafana-ui/src/components/Table/RowsList.tsx
index aa061dd1bc1..29ee0701a7a 100644
--- a/packages/grafana-ui/src/components/Table/RowsList.tsx
+++ b/packages/grafana-ui/src/components/Table/RowsList.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { CSSProperties, UIEventHandler, useCallback, useEffect, useMemo, useState } from 'react';
+import { CSSProperties, UIEventHandler, useCallback, useEffect, useMemo, useState } from 'react';
+import * as React from 'react';
import { Cell, Row, TableState, HeaderGroup } from 'react-table';
import { VariableSizeList } from 'react-window';
import { Subscription, debounceTime } from 'rxjs';
diff --git a/packages/grafana-ui/src/components/Table/SparklineCell.tsx b/packages/grafana-ui/src/components/Table/SparklineCell.tsx
index bfb1b8e5eb0..3c047c0fdf0 100644
--- a/packages/grafana-ui/src/components/Table/SparklineCell.tsx
+++ b/packages/grafana-ui/src/components/Table/SparklineCell.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import {
FieldType,
diff --git a/packages/grafana-ui/src/components/Table/Table.story.tsx b/packages/grafana-ui/src/components/Table/Table.story.tsx
index 596e5baa134..4fa86ae69a4 100644
--- a/packages/grafana-ui/src/components/Table/Table.story.tsx
+++ b/packages/grafana-ui/src/components/Table/Table.story.tsx
@@ -1,6 +1,5 @@
import { Meta, StoryFn } from '@storybook/react';
import { merge } from 'lodash';
-import React from 'react';
import {
DataFrame,
diff --git a/packages/grafana-ui/src/components/Table/Table.test.tsx b/packages/grafana-ui/src/components/Table/Table.test.tsx
index 0910e889cca..c59b8dbb798 100644
--- a/packages/grafana-ui/src/components/Table/Table.test.tsx
+++ b/packages/grafana-ui/src/components/Table/Table.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { applyFieldOverrides, createTheme, DataFrame, FieldType, toDataFrame } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Table/Table.tsx b/packages/grafana-ui/src/components/Table/Table.tsx
index 43acfb25fdb..3beb04bda7c 100644
--- a/packages/grafana-ui/src/components/Table/Table.tsx
+++ b/packages/grafana-ui/src/components/Table/Table.tsx
@@ -1,4 +1,4 @@
-import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
+import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import {
useAbsoluteLayout,
useExpanded,
diff --git a/packages/grafana-ui/src/components/Table/TableCell.tsx b/packages/grafana-ui/src/components/Table/TableCell.tsx
index 4c4b4a0e501..56649902761 100644
--- a/packages/grafana-ui/src/components/Table/TableCell.tsx
+++ b/packages/grafana-ui/src/components/Table/TableCell.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { Cell } from 'react-table';
import { TimeRange, DataFrame } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Table/TableCellInspector.tsx b/packages/grafana-ui/src/components/Table/TableCellInspector.tsx
index cca2b8a7385..7cc49f706b6 100644
--- a/packages/grafana-ui/src/components/Table/TableCellInspector.tsx
+++ b/packages/grafana-ui/src/components/Table/TableCellInspector.tsx
@@ -1,5 +1,4 @@
import { isString } from 'lodash';
-import React from 'react';
import { ClipboardButton } from '../ClipboardButton/ClipboardButton';
import { Drawer } from '../Drawer/Drawer';
diff --git a/packages/grafana-ui/src/components/Table/hooks.ts b/packages/grafana-ui/src/components/Table/hooks.ts
index f6060fd15c5..bb9b6b13d0c 100644
--- a/packages/grafana-ui/src/components/Table/hooks.ts
+++ b/packages/grafana-ui/src/components/Table/hooks.ts
@@ -1,4 +1,5 @@
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
+import * as React from 'react';
import { VariableSizeList } from 'react-window';
import { DataFrame } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/TableInputCSV/TableInputCSV.internal.story.tsx b/packages/grafana-ui/src/components/TableInputCSV/TableInputCSV.internal.story.tsx
index f2fe55ed5d6..ccac99b8644 100644
--- a/packages/grafana-ui/src/components/TableInputCSV/TableInputCSV.internal.story.tsx
+++ b/packages/grafana-ui/src/components/TableInputCSV/TableInputCSV.internal.story.tsx
@@ -1,6 +1,5 @@
import { action } from '@storybook/addon-actions';
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { DataFrame } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/TableInputCSV/TableInputCSV.test.tsx b/packages/grafana-ui/src/components/TableInputCSV/TableInputCSV.test.tsx
index 246352eff1b..4bbc69352c3 100644
--- a/packages/grafana-ui/src/components/TableInputCSV/TableInputCSV.test.tsx
+++ b/packages/grafana-ui/src/components/TableInputCSV/TableInputCSV.test.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import renderer from 'react-test-renderer';
import { DataFrame } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/TableInputCSV/TableInputCSV.tsx b/packages/grafana-ui/src/components/TableInputCSV/TableInputCSV.tsx
index 2486ff9cc71..8070fd613b4 100644
--- a/packages/grafana-ui/src/components/TableInputCSV/TableInputCSV.tsx
+++ b/packages/grafana-ui/src/components/TableInputCSV/TableInputCSV.tsx
@@ -1,6 +1,7 @@
import { css } from '@emotion/css';
import { debounce } from 'lodash';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
+import * as React from 'react';
import { DataFrame, CSVConfig, readCSV, GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Tabs/Counter.tsx b/packages/grafana-ui/src/components/Tabs/Counter.tsx
index 8a8c507bff2..c224e3d129d 100644
--- a/packages/grafana-ui/src/components/Tabs/Counter.tsx
+++ b/packages/grafana-ui/src/components/Tabs/Counter.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2, locale } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Tabs/Tab.tsx b/packages/grafana-ui/src/components/Tabs/Tab.tsx
index 109637fedcd..02980a66860 100644
--- a/packages/grafana-ui/src/components/Tabs/Tab.tsx
+++ b/packages/grafana-ui/src/components/Tabs/Tab.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { HTMLProps } from 'react';
+import { HTMLProps } from 'react';
+import * as React from 'react';
import { GrafanaTheme2, NavModelItem } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-ui/src/components/Tabs/TabContent.tsx b/packages/grafana-ui/src/components/Tabs/TabContent.tsx
index 76c7b88f182..e7259f7e823 100644
--- a/packages/grafana-ui/src/components/Tabs/TabContent.tsx
+++ b/packages/grafana-ui/src/components/Tabs/TabContent.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { HTMLAttributes, ReactNode } from 'react';
+import { HTMLAttributes, ReactNode } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Tabs/Tabs.story.tsx b/packages/grafana-ui/src/components/Tabs/Tabs.story.tsx
index b3c51675d0b..e78bff5ae9c 100644
--- a/packages/grafana-ui/src/components/Tabs/Tabs.story.tsx
+++ b/packages/grafana-ui/src/components/Tabs/Tabs.story.tsx
@@ -1,5 +1,5 @@
import { Meta, StoryFn } from '@storybook/react';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { TabsBar, Tab, TabContent, Counter as TabCounter } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/Tabs/TabsBar.tsx b/packages/grafana-ui/src/components/Tabs/TabsBar.tsx
index d886e924647..99d2e8c3b18 100644
--- a/packages/grafana-ui/src/components/Tabs/TabsBar.tsx
+++ b/packages/grafana-ui/src/components/Tabs/TabsBar.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { ReactNode } from 'react';
+import { forwardRef, ReactNode } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
@@ -13,7 +13,7 @@ export interface Props {
hideBorder?: boolean;
}
-export const TabsBar = React.forwardRef(({ children, className, hideBorder = false }, ref) => {
+export const TabsBar = forwardRef(({ children, className, hideBorder = false }, ref) => {
const styles = useStyles2(getStyles);
return (
diff --git a/packages/grafana-ui/src/components/Tabs/VerticalTab.tsx b/packages/grafana-ui/src/components/Tabs/VerticalTab.tsx
index 06e00a1042e..eb235089dfa 100644
--- a/packages/grafana-ui/src/components/Tabs/VerticalTab.tsx
+++ b/packages/grafana-ui/src/components/Tabs/VerticalTab.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
+import { forwardRef } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
@@ -10,7 +10,7 @@ import { Icon } from '../Icon/Icon';
import { Counter } from './Counter';
import { TabProps } from './Tab';
-export const VerticalTab = React.forwardRef(
+export const VerticalTab = forwardRef(
({ label, active, icon, counter, className, suffix: Suffix, onChangeTab, href, ...otherProps }, ref) => {
const tabsStyles = useStyles2(getTabStyles);
const content = () => (
diff --git a/packages/grafana-ui/src/components/Tags/Tag.story.tsx b/packages/grafana-ui/src/components/Tags/Tag.story.tsx
index 47d74a6b831..3610fa381fe 100644
--- a/packages/grafana-ui/src/components/Tags/Tag.story.tsx
+++ b/packages/grafana-ui/src/components/Tags/Tag.story.tsx
@@ -1,6 +1,5 @@
import { action } from '@storybook/addon-actions';
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { Tag } from './Tag';
import mdx from './Tag.mdx';
diff --git a/packages/grafana-ui/src/components/Tags/Tag.tsx b/packages/grafana-ui/src/components/Tags/Tag.tsx
index 81a857ee4ff..a5e9c4912e3 100644
--- a/packages/grafana-ui/src/components/Tags/Tag.tsx
+++ b/packages/grafana-ui/src/components/Tags/Tag.tsx
@@ -1,5 +1,6 @@
import { cx, css } from '@emotion/css';
-import React, { forwardRef, HTMLAttributes } from 'react';
+import { forwardRef, HTMLAttributes } from 'react';
+import * as React from 'react';
import Skeleton from 'react-loading-skeleton';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Tags/TagList.story.tsx b/packages/grafana-ui/src/components/Tags/TagList.story.tsx
index 6178d8a6bbd..56acb2e3f39 100644
--- a/packages/grafana-ui/src/components/Tags/TagList.story.tsx
+++ b/packages/grafana-ui/src/components/Tags/TagList.story.tsx
@@ -1,6 +1,5 @@
import { action } from '@storybook/addon-actions';
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { TagList } from './TagList';
import mdx from './TagList.mdx';
diff --git a/packages/grafana-ui/src/components/Tags/TagList.tsx b/packages/grafana-ui/src/components/Tags/TagList.tsx
index fefd90c4b4c..df317ca12f3 100644
--- a/packages/grafana-ui/src/components/Tags/TagList.tsx
+++ b/packages/grafana-ui/src/components/Tags/TagList.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { forwardRef, memo } from 'react';
+import { forwardRef, memo } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/TagsInput/TagItem.tsx b/packages/grafana-ui/src/components/TagsInput/TagItem.tsx
index c74f573ded1..1e7019c456f 100644
--- a/packages/grafana-ui/src/components/TagsInput/TagItem.tsx
+++ b/packages/grafana-ui/src/components/TagsInput/TagItem.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/TagsInput/TagsInput.story.tsx b/packages/grafana-ui/src/components/TagsInput/TagsInput.story.tsx
index b0d830469bd..295357be5e3 100644
--- a/packages/grafana-ui/src/components/TagsInput/TagsInput.story.tsx
+++ b/packages/grafana-ui/src/components/TagsInput/TagsInput.story.tsx
@@ -1,5 +1,5 @@
import { Meta, StoryFn } from '@storybook/react';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { StoryExample } from '../../utils/storybook/StoryExample';
diff --git a/packages/grafana-ui/src/components/TagsInput/TagsInput.test.tsx b/packages/grafana-ui/src/components/TagsInput/TagsInput.test.tsx
index 950f111a24f..5ea09e6f8da 100644
--- a/packages/grafana-ui/src/components/TagsInput/TagsInput.test.tsx
+++ b/packages/grafana-ui/src/components/TagsInput/TagsInput.test.tsx
@@ -1,5 +1,4 @@
import { render, fireEvent, screen } from '@testing-library/react';
-import React from 'react';
import { TagsInput } from './TagsInput';
diff --git a/packages/grafana-ui/src/components/TagsInput/TagsInput.tsx b/packages/grafana-ui/src/components/TagsInput/TagsInput.tsx
index be1c1b0e2ad..38bec70cf1c 100644
--- a/packages/grafana-ui/src/components/TagsInput/TagsInput.tsx
+++ b/packages/grafana-ui/src/components/TagsInput/TagsInput.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { useCallback, useState } from 'react';
+import { useCallback, useState } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Text/Text.story.tsx b/packages/grafana-ui/src/components/Text/Text.story.tsx
index 1d14299d916..07071f64b02 100644
--- a/packages/grafana-ui/src/components/Text/Text.story.tsx
+++ b/packages/grafana-ui/src/components/Text/Text.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { StoryExample } from '../../utils/storybook/StoryExample';
import { Stack } from '../Layout/Stack/Stack';
diff --git a/packages/grafana-ui/src/components/Text/Text.test.tsx b/packages/grafana-ui/src/components/Text/Text.test.tsx
index f05d37d06a6..bd0965c27cb 100644
--- a/packages/grafana-ui/src/components/Text/Text.test.tsx
+++ b/packages/grafana-ui/src/components/Text/Text.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { createTheme, ThemeTypographyVariantTypes } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Text/Text.tsx b/packages/grafana-ui/src/components/Text/Text.tsx
index 0ffa52e7e88..2978f6448da 100644
--- a/packages/grafana-ui/src/components/Text/Text.tsx
+++ b/packages/grafana-ui/src/components/Text/Text.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { createElement, CSSProperties } from 'react';
+import { createElement, CSSProperties } from 'react';
+import * as React from 'react';
import { GrafanaTheme2, ThemeTypographyVariantTypes } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Text/TruncatedText.tsx b/packages/grafana-ui/src/components/Text/TruncatedText.tsx
index e74cbd36bb7..349c111eb0c 100644
--- a/packages/grafana-ui/src/components/Text/TruncatedText.tsx
+++ b/packages/grafana-ui/src/components/Text/TruncatedText.tsx
@@ -1,4 +1,5 @@
-import React, { useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
+import { useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
+import * as React from 'react';
import ReactDOMServer from 'react-dom/server';
import { Tooltip } from '../Tooltip/Tooltip';
diff --git a/packages/grafana-ui/src/components/Text/Typography.internal.story.tsx b/packages/grafana-ui/src/components/Text/Typography.internal.story.tsx
index d7014936a02..d9c347a4bf7 100644
--- a/packages/grafana-ui/src/components/Text/Typography.internal.story.tsx
+++ b/packages/grafana-ui/src/components/Text/Typography.internal.story.tsx
@@ -1,5 +1,6 @@
import { Meta, StoryFn } from '@storybook/react';
-import React, { useState } from 'react';
+import { useState } from 'react';
+import * as React from 'react';
import { Divider } from '../Divider/Divider';
import { Field } from '../Forms/Field';
diff --git a/packages/grafana-ui/src/components/TextArea/TextArea.story.tsx b/packages/grafana-ui/src/components/TextArea/TextArea.story.tsx
index 9cf01ad61b2..cec604d0cf2 100644
--- a/packages/grafana-ui/src/components/TextArea/TextArea.story.tsx
+++ b/packages/grafana-ui/src/components/TextArea/TextArea.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { TextArea } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/TextArea/TextArea.tsx b/packages/grafana-ui/src/components/TextArea/TextArea.tsx
index 5f438b9982c..b7002bc5742 100644
--- a/packages/grafana-ui/src/components/TextArea/TextArea.tsx
+++ b/packages/grafana-ui/src/components/TextArea/TextArea.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { HTMLProps } from 'react';
+import { forwardRef, HTMLProps } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
@@ -11,7 +11,7 @@ export interface Props extends Omit, 'size'> {
invalid?: boolean;
}
-export const TextArea = React.forwardRef(({ invalid, className, ...props }, ref) => {
+export const TextArea = forwardRef(({ invalid, className, ...props }, ref) => {
const styles = useStyles2(getTextAreaStyle, invalid);
return ;
diff --git a/packages/grafana-ui/src/components/ThemeDemos/EmotionPerfTest.tsx b/packages/grafana-ui/src/components/ThemeDemos/EmotionPerfTest.tsx
index df6a5b01ad9..1f0b6cfad48 100644
--- a/packages/grafana-ui/src/components/ThemeDemos/EmotionPerfTest.tsx
+++ b/packages/grafana-ui/src/components/ThemeDemos/EmotionPerfTest.tsx
@@ -1,7 +1,6 @@
+/** @jsxImportSource @emotion/react */
/** @jsxRuntime classic */
-/** @jsx jsx */
import { css, cx } from '@emotion/css';
-import { jsx } from '@emotion/react';
import classnames from 'classnames';
import { Profiler, ProfilerOnRenderCallback, useState, FC } from 'react';
diff --git a/packages/grafana-ui/src/components/ThemeDemos/ThemeDemo.story.tsx b/packages/grafana-ui/src/components/ThemeDemos/ThemeDemo.story.tsx
index a821379992f..edb28e35fcf 100644
--- a/packages/grafana-ui/src/components/ThemeDemos/ThemeDemo.story.tsx
+++ b/packages/grafana-ui/src/components/ThemeDemos/ThemeDemo.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { EmotionPerfTest } from './EmotionPerfTest';
import { ThemeDemo as NewThemeDemoComponent } from './ThemeDemo';
diff --git a/packages/grafana-ui/src/components/ThemeDemos/ThemeDemo.tsx b/packages/grafana-ui/src/components/ThemeDemos/ThemeDemo.tsx
index 7ef26ad74ef..a37cba070d9 100644
--- a/packages/grafana-ui/src/components/ThemeDemos/ThemeDemo.tsx
+++ b/packages/grafana-ui/src/components/ThemeDemos/ThemeDemo.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
+import * as React from 'react';
import { GrafanaTheme2, ThemeRichColor } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Toggletip/Toggletip.story.tsx b/packages/grafana-ui/src/components/Toggletip/Toggletip.story.tsx
index 1a4ebea1fec..5e600869666 100644
--- a/packages/grafana-ui/src/components/Toggletip/Toggletip.story.tsx
+++ b/packages/grafana-ui/src/components/Toggletip/Toggletip.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { Button } from '../Button';
import { CustomScrollbar } from '../CustomScrollbar/CustomScrollbar';
diff --git a/packages/grafana-ui/src/components/Toggletip/Toggletip.test.tsx b/packages/grafana-ui/src/components/Toggletip/Toggletip.test.tsx
index ddc49db1c41..347f2273624 100644
--- a/packages/grafana-ui/src/components/Toggletip/Toggletip.test.tsx
+++ b/packages/grafana-ui/src/components/Toggletip/Toggletip.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { Button, LinkButton } from '../Button';
diff --git a/packages/grafana-ui/src/components/Toggletip/Toggletip.tsx b/packages/grafana-ui/src/components/Toggletip/Toggletip.tsx
index f45fee44831..5e6bc85f869 100644
--- a/packages/grafana-ui/src/components/Toggletip/Toggletip.tsx
+++ b/packages/grafana-ui/src/components/Toggletip/Toggletip.tsx
@@ -13,7 +13,7 @@ import {
useInteractions,
} from '@floating-ui/react';
import { Placement } from '@popperjs/core';
-import React, { useRef, useState } from 'react';
+import { memo, cloneElement, isValidElement, useRef, useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
@@ -48,7 +48,7 @@ export interface ToggletipProps {
onOpen?: () => void;
}
-export const Toggletip = React.memo(
+export const Toggletip = memo(
({
children,
theme = 'info',
@@ -111,7 +111,7 @@ export const Toggletip = React.memo(
return (
<>
- {React.cloneElement(children, {
+ {cloneElement(children, {
ref: refs.setReference,
tabIndex: 0,
'aria-expanded': isOpen,
@@ -150,7 +150,7 @@ export const Toggletip = React.memo(
)}
- {(typeof content === 'string' || React.isValidElement(content)) && content}
+ {(typeof content === 'string' || isValidElement(content)) && content}
{typeof content === 'function' && content({})}
{Boolean(footer) &&
{footer}
}
diff --git a/packages/grafana-ui/src/components/ToolbarButton/ToolbarButton.story.tsx b/packages/grafana-ui/src/components/ToolbarButton/ToolbarButton.story.tsx
index 4f278b96c22..8cea57b401c 100644
--- a/packages/grafana-ui/src/components/ToolbarButton/ToolbarButton.story.tsx
+++ b/packages/grafana-ui/src/components/ToolbarButton/ToolbarButton.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { DashboardStoryCanvas } from '../../utils/storybook/DashboardStoryCanvas';
import { ButtonGroup } from '../Button';
diff --git a/packages/grafana-ui/src/components/ToolbarButton/ToolbarButton.tsx b/packages/grafana-ui/src/components/ToolbarButton/ToolbarButton.tsx
index 767ecd7d81b..b99e176a142 100644
--- a/packages/grafana-ui/src/components/ToolbarButton/ToolbarButton.tsx
+++ b/packages/grafana-ui/src/components/ToolbarButton/ToolbarButton.tsx
@@ -1,5 +1,6 @@
import { cx, css } from '@emotion/css';
-import React, { forwardRef, ButtonHTMLAttributes } from 'react';
+import { forwardRef, ButtonHTMLAttributes } from 'react';
+import * as React from 'react';
import { GrafanaTheme2, IconName, isIconName } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-ui/src/components/ToolbarButton/ToolbarButtonRow.story.tsx b/packages/grafana-ui/src/components/ToolbarButton/ToolbarButtonRow.story.tsx
index df044b01c14..45bd93b0d60 100644
--- a/packages/grafana-ui/src/components/ToolbarButton/ToolbarButtonRow.story.tsx
+++ b/packages/grafana-ui/src/components/ToolbarButton/ToolbarButtonRow.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { DashboardStoryCanvas } from '../../utils/storybook/DashboardStoryCanvas';
diff --git a/packages/grafana-ui/src/components/ToolbarButton/ToolbarButtonRow.tsx b/packages/grafana-ui/src/components/ToolbarButton/ToolbarButtonRow.tsx
index c3f59a9d9f9..497f320299e 100644
--- a/packages/grafana-ui/src/components/ToolbarButton/ToolbarButtonRow.tsx
+++ b/packages/grafana-ui/src/components/ToolbarButton/ToolbarButtonRow.tsx
@@ -2,7 +2,7 @@ import { css, cx } from '@emotion/css';
import { useDialog } from '@react-aria/dialog';
import { FocusScope } from '@react-aria/focus';
import { useOverlay } from '@react-aria/overlays';
-import React, { forwardRef, HTMLAttributes, useState, useRef, useLayoutEffect, createRef } from 'react';
+import { Children, forwardRef, HTMLAttributes, useState, useRef, useLayoutEffect, createRef } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
@@ -19,7 +19,7 @@ export interface Props extends HTMLAttributes
{
export const ToolbarButtonRow = forwardRef(
({ alignment = 'left', className, children, ...rest }, ref) => {
// null/undefined are valid react children so we need to filter them out to prevent unnecessary padding
- const childrenWithoutNull = React.Children.toArray(children).filter((child) => child != null);
+ const childrenWithoutNull = Children.toArray(children).filter((child) => child != null);
const [childVisibility, setChildVisibility] = useState(Array(childrenWithoutNull.length).fill(false));
const containerRef = useRef(null);
const [showOverflowItems, setShowOverflowItems] = useState(false);
diff --git a/packages/grafana-ui/src/components/Tooltip/Popover.tsx b/packages/grafana-ui/src/components/Tooltip/Popover.tsx
index 81527f3cde6..729e4dfce3d 100644
--- a/packages/grafana-ui/src/components/Tooltip/Popover.tsx
+++ b/packages/grafana-ui/src/components/Tooltip/Popover.tsx
@@ -8,7 +8,8 @@
useFloating,
useTransitionStyles,
} from '@floating-ui/react';
-import React, { useLayoutEffect, useRef } from 'react';
+import { useLayoutEffect, useRef } from 'react';
+import * as React from 'react';
import { useTheme2 } from '../../themes';
import { getPlacement } from '../../utils/tooltipUtils';
diff --git a/packages/grafana-ui/src/components/Tooltip/Tooltip.story.tsx b/packages/grafana-ui/src/components/Tooltip/Tooltip.story.tsx
index 23f66282e90..a768069770d 100644
--- a/packages/grafana-ui/src/components/Tooltip/Tooltip.story.tsx
+++ b/packages/grafana-ui/src/components/Tooltip/Tooltip.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { Button } from '../Button';
import { Stack } from '../Layout/Stack/Stack';
diff --git a/packages/grafana-ui/src/components/Tooltip/Tooltip.test.tsx b/packages/grafana-ui/src/components/Tooltip/Tooltip.test.tsx
index 009b7e749f3..2c92413df8b 100644
--- a/packages/grafana-ui/src/components/Tooltip/Tooltip.test.tsx
+++ b/packages/grafana-ui/src/components/Tooltip/Tooltip.test.tsx
@@ -1,6 +1,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { MutableRefObject } from 'react';
+import { MutableRefObject } from 'react';
import { Tooltip } from './Tooltip';
diff --git a/packages/grafana-ui/src/components/Tooltip/Tooltip.tsx b/packages/grafana-ui/src/components/Tooltip/Tooltip.tsx
index dcc37ac9f32..bd2d02fc348 100644
--- a/packages/grafana-ui/src/components/Tooltip/Tooltip.tsx
+++ b/packages/grafana-ui/src/components/Tooltip/Tooltip.tsx
@@ -11,7 +11,7 @@ import {
useHover,
useInteractions,
} from '@floating-ui/react';
-import React, { useCallback, useId, useRef, useState } from 'react';
+import { forwardRef, cloneElement, isValidElement, useCallback, useId, useRef, useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
@@ -34,7 +34,7 @@ export interface TooltipProps {
interactive?: boolean;
}
-export const Tooltip = React.forwardRef(
+export const Tooltip = forwardRef(
({ children, theme, interactive, show, placement, content }, forwardedRef) => {
const arrowRef = useRef(null);
const [controlledVisible, setControlledVisible] = useState(show);
@@ -101,7 +101,7 @@ export const Tooltip = React.forwardRef(
return (
<>
- {React.cloneElement(children, {
+ {cloneElement(children, {
ref: handleRef,
tabIndex: 0, // tooltip trigger should be keyboard focusable
'aria-describedby': !childHasMatchingAriaLabel && isOpen ? tooltipId : undefined,
@@ -118,7 +118,7 @@ export const Tooltip = React.forwardRef(
className={style.container}
>
{typeof content === 'string' && content}
- {React.isValidElement(content) && React.cloneElement(content)}
+ {isValidElement(content) && cloneElement(content)}
{contentIsFunction && content({})}
diff --git a/packages/grafana-ui/src/components/Typeahead/PartialHighlighter.test.tsx b/packages/grafana-ui/src/components/Typeahead/PartialHighlighter.test.tsx
index 13a8c7a118e..164f0a86232 100644
--- a/packages/grafana-ui/src/components/Typeahead/PartialHighlighter.test.tsx
+++ b/packages/grafana-ui/src/components/Typeahead/PartialHighlighter.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { PartialHighlighter } from './PartialHighlighter';
diff --git a/packages/grafana-ui/src/components/Typeahead/PartialHighlighter.tsx b/packages/grafana-ui/src/components/Typeahead/PartialHighlighter.tsx
index b35967c8235..a1c5603a4e5 100644
--- a/packages/grafana-ui/src/components/Typeahead/PartialHighlighter.tsx
+++ b/packages/grafana-ui/src/components/Typeahead/PartialHighlighter.tsx
@@ -1,4 +1,4 @@
-import React, { createElement } from 'react';
+import { createElement } from 'react';
import { HighlightPart } from '../../types';
diff --git a/packages/grafana-ui/src/components/Typeahead/Typeahead.test.tsx b/packages/grafana-ui/src/components/Typeahead/Typeahead.test.tsx
index 2d8dd1174ae..c26a0df1e13 100644
--- a/packages/grafana-ui/src/components/Typeahead/Typeahead.test.tsx
+++ b/packages/grafana-ui/src/components/Typeahead/Typeahead.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { CompletionItemGroup } from '../../types';
diff --git a/packages/grafana-ui/src/components/Typeahead/Typeahead.tsx b/packages/grafana-ui/src/components/Typeahead/Typeahead.tsx
index c1365403da6..9f1a7dc44bf 100644
--- a/packages/grafana-ui/src/components/Typeahead/Typeahead.tsx
+++ b/packages/grafana-ui/src/components/Typeahead/Typeahead.tsx
@@ -1,6 +1,7 @@
import { css } from '@emotion/css';
import { isEqual } from 'lodash';
-import React, { createRef, PureComponent } from 'react';
+import { createRef, PureComponent } from 'react';
+import * as React from 'react';
import ReactDOM from 'react-dom';
import { FixedSizeList } from 'react-window';
diff --git a/packages/grafana-ui/src/components/Typeahead/TypeaheadInfo.test.tsx b/packages/grafana-ui/src/components/Typeahead/TypeaheadInfo.test.tsx
index 214be3e5e7e..65bdfbd0009 100644
--- a/packages/grafana-ui/src/components/Typeahead/TypeaheadInfo.test.tsx
+++ b/packages/grafana-ui/src/components/Typeahead/TypeaheadInfo.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { CompletionItem } from '../../types';
diff --git a/packages/grafana-ui/src/components/Typeahead/TypeaheadInfo.tsx b/packages/grafana-ui/src/components/Typeahead/TypeaheadInfo.tsx
index 7ab042ec528..0938eb0f25a 100644
--- a/packages/grafana-ui/src/components/Typeahead/TypeaheadInfo.tsx
+++ b/packages/grafana-ui/src/components/Typeahead/TypeaheadInfo.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2, renderMarkdown } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/Typeahead/TypeaheadItem.tsx b/packages/grafana-ui/src/components/Typeahead/TypeaheadItem.tsx
index de90392647b..e8467a0e79c 100644
--- a/packages/grafana-ui/src/components/Typeahead/TypeaheadItem.tsx
+++ b/packages/grafana-ui/src/components/Typeahead/TypeaheadItem.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import Highlighter from 'react-highlight-words';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/UnitPicker/UnitPicker.story.tsx b/packages/grafana-ui/src/components/UnitPicker/UnitPicker.story.tsx
index fdc6f406970..440aa4c7e03 100644
--- a/packages/grafana-ui/src/components/UnitPicker/UnitPicker.story.tsx
+++ b/packages/grafana-ui/src/components/UnitPicker/UnitPicker.story.tsx
@@ -1,6 +1,5 @@
import { action } from '@storybook/addon-actions';
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { UnitPicker, UnitPickerProps } from './UnitPicker';
import mdx from './UnitPicker.mdx';
diff --git a/packages/grafana-ui/src/components/UnitPicker/UnitPicker.tsx b/packages/grafana-ui/src/components/UnitPicker/UnitPicker.tsx
index b9142f46b0d..6d35750995f 100644
--- a/packages/grafana-ui/src/components/UnitPicker/UnitPicker.tsx
+++ b/packages/grafana-ui/src/components/UnitPicker/UnitPicker.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { getValueFormats, SelectableValue } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/UsersIndicator/Avatar.story.tsx b/packages/grafana-ui/src/components/UsersIndicator/Avatar.story.tsx
index 23aec35c409..86a90a2496e 100644
--- a/packages/grafana-ui/src/components/UsersIndicator/Avatar.story.tsx
+++ b/packages/grafana-ui/src/components/UsersIndicator/Avatar.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { Avatar } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/UsersIndicator/Avatar.tsx b/packages/grafana-ui/src/components/UsersIndicator/Avatar.tsx
index c5485058094..473787febd3 100644
--- a/packages/grafana-ui/src/components/UsersIndicator/Avatar.tsx
+++ b/packages/grafana-ui/src/components/UsersIndicator/Avatar.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2, ThemeSpacingTokens } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/UsersIndicator/UserIcon.story.tsx b/packages/grafana-ui/src/components/UsersIndicator/UserIcon.story.tsx
index 19c85f9738f..c8e2ebd55f5 100644
--- a/packages/grafana-ui/src/components/UsersIndicator/UserIcon.story.tsx
+++ b/packages/grafana-ui/src/components/UsersIndicator/UserIcon.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { UserIcon } from './UserIcon';
import mdx from './UserIcon.mdx';
diff --git a/packages/grafana-ui/src/components/UsersIndicator/UserIcon.test.tsx b/packages/grafana-ui/src/components/UsersIndicator/UserIcon.test.tsx
index 436925ee16a..215a765e520 100644
--- a/packages/grafana-ui/src/components/UsersIndicator/UserIcon.test.tsx
+++ b/packages/grafana-ui/src/components/UsersIndicator/UserIcon.test.tsx
@@ -1,6 +1,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
+import * as React from 'react';
import { UserIcon } from './UserIcon';
diff --git a/packages/grafana-ui/src/components/UsersIndicator/UserIcon.tsx b/packages/grafana-ui/src/components/UsersIndicator/UserIcon.tsx
index 23a639ad457..9776a0e2ab8 100644
--- a/packages/grafana-ui/src/components/UsersIndicator/UserIcon.tsx
+++ b/packages/grafana-ui/src/components/UsersIndicator/UserIcon.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { useMemo, PropsWithChildren } from 'react';
+import { useMemo, PropsWithChildren } from 'react';
import { dateTime, DateTimeInput, GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/UsersIndicator/UsersIndicator.story.tsx b/packages/grafana-ui/src/components/UsersIndicator/UsersIndicator.story.tsx
index eaccb0114da..00a16d4c304 100644
--- a/packages/grafana-ui/src/components/UsersIndicator/UsersIndicator.story.tsx
+++ b/packages/grafana-ui/src/components/UsersIndicator/UsersIndicator.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { UsersIndicator } from './UsersIndicator';
import mdx from './UsersIndicator.mdx';
diff --git a/packages/grafana-ui/src/components/UsersIndicator/UsersIndicator.test.tsx b/packages/grafana-ui/src/components/UsersIndicator/UsersIndicator.test.tsx
index 5b7112a3232..ca0c50ac7da 100644
--- a/packages/grafana-ui/src/components/UsersIndicator/UsersIndicator.test.tsx
+++ b/packages/grafana-ui/src/components/UsersIndicator/UsersIndicator.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { UsersIndicator } from './UsersIndicator';
diff --git a/packages/grafana-ui/src/components/UsersIndicator/UsersIndicator.tsx b/packages/grafana-ui/src/components/UsersIndicator/UsersIndicator.tsx
index d6e3c1fb9dc..5326be62fc8 100644
--- a/packages/grafana-ui/src/components/UsersIndicator/UsersIndicator.tsx
+++ b/packages/grafana-ui/src/components/UsersIndicator/UsersIndicator.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/ValuePicker/ValuePicker.story.tsx b/packages/grafana-ui/src/components/ValuePicker/ValuePicker.story.tsx
index 06f0ac554bf..b6e8bd3dd76 100644
--- a/packages/grafana-ui/src/components/ValuePicker/ValuePicker.story.tsx
+++ b/packages/grafana-ui/src/components/ValuePicker/ValuePicker.story.tsx
@@ -1,5 +1,4 @@
import { Meta, StoryFn } from '@storybook/react';
-import React from 'react';
import { ValuePicker } from '@grafana/ui';
diff --git a/packages/grafana-ui/src/components/ValuePicker/ValuePicker.tsx b/packages/grafana-ui/src/components/ValuePicker/ValuePicker.tsx
index 092d09a1931..382d3fc2b2e 100644
--- a/packages/grafana-ui/src/components/ValuePicker/ValuePicker.tsx
+++ b/packages/grafana-ui/src/components/ValuePicker/ValuePicker.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { SelectableValue } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-ui/src/components/VizLayout/VizLayout.story.tsx b/packages/grafana-ui/src/components/VizLayout/VizLayout.story.tsx
index 6893ef49f8a..7e8e93a5a9c 100644
--- a/packages/grafana-ui/src/components/VizLayout/VizLayout.story.tsx
+++ b/packages/grafana-ui/src/components/VizLayout/VizLayout.story.tsx
@@ -1,5 +1,5 @@
import { Meta, StoryFn } from '@storybook/react';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { VizLayout } from './VizLayout';
diff --git a/packages/grafana-ui/src/components/VizLayout/VizLayout.tsx b/packages/grafana-ui/src/components/VizLayout/VizLayout.tsx
index d41ca7fd46c..29fa9ddc0b7 100644
--- a/packages/grafana-ui/src/components/VizLayout/VizLayout.tsx
+++ b/packages/grafana-ui/src/components/VizLayout/VizLayout.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { FC, CSSProperties, ComponentType } from 'react';
+import { FC, CSSProperties, ComponentType } from 'react';
+import * as React from 'react';
import { useMeasure } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/VizLegend/SeriesIcon.test.tsx b/packages/grafana-ui/src/components/VizLegend/SeriesIcon.test.tsx
index 79672cd68ee..312f964182d 100644
--- a/packages/grafana-ui/src/components/VizLegend/SeriesIcon.test.tsx
+++ b/packages/grafana-ui/src/components/VizLegend/SeriesIcon.test.tsx
@@ -1,5 +1,4 @@
import { render } from '@testing-library/react';
-import React from 'react';
import { SeriesIcon } from './SeriesIcon';
diff --git a/packages/grafana-ui/src/components/VizLegend/SeriesIcon.tsx b/packages/grafana-ui/src/components/VizLegend/SeriesIcon.tsx
index 981bad51eb6..12f64d89520 100644
--- a/packages/grafana-ui/src/components/VizLegend/SeriesIcon.tsx
+++ b/packages/grafana-ui/src/components/VizLegend/SeriesIcon.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { CSSProperties } from 'react';
+import { CSSProperties } from 'react';
+import * as React from 'react';
import { GrafanaTheme2, fieldColorModeRegistry } from '@grafana/data';
import { LineStyle } from '@grafana/schema';
diff --git a/packages/grafana-ui/src/components/VizLegend/VizLegend.story.tsx b/packages/grafana-ui/src/components/VizLegend/VizLegend.story.tsx
index b581fc6e6af..3b346056719 100644
--- a/packages/grafana-ui/src/components/VizLegend/VizLegend.story.tsx
+++ b/packages/grafana-ui/src/components/VizLegend/VizLegend.story.tsx
@@ -1,5 +1,5 @@
import { StoryFn, Meta } from '@storybook/react';
-import React, { FC, useEffect, useState } from 'react';
+import { FC, useEffect, useState } from 'react';
import { DisplayValue, GrafanaTheme2 } from '@grafana/data';
import { LegendDisplayMode, LegendPlacement } from '@grafana/schema';
diff --git a/packages/grafana-ui/src/components/VizLegend/VizLegend.tsx b/packages/grafana-ui/src/components/VizLegend/VizLegend.tsx
index 8aad8d1decc..789a90a1087 100644
--- a/packages/grafana-ui/src/components/VizLegend/VizLegend.tsx
+++ b/packages/grafana-ui/src/components/VizLegend/VizLegend.tsx
@@ -1,4 +1,5 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
+import * as React from 'react';
import { DataHoverClearEvent, DataHoverEvent } from '@grafana/data';
import { LegendDisplayMode } from '@grafana/schema';
diff --git a/packages/grafana-ui/src/components/VizLegend/VizLegendList.tsx b/packages/grafana-ui/src/components/VizLegend/VizLegendList.tsx
index 8a30511c012..2de3007a5da 100644
--- a/packages/grafana-ui/src/components/VizLegend/VizLegendList.tsx
+++ b/packages/grafana-ui/src/components/VizLegend/VizLegendList.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/VizLegend/VizLegendListItem.tsx b/packages/grafana-ui/src/components/VizLegend/VizLegendListItem.tsx
index f19b2d61d8f..4b6280a0f86 100644
--- a/packages/grafana-ui/src/components/VizLegend/VizLegendListItem.tsx
+++ b/packages/grafana-ui/src/components/VizLegend/VizLegendListItem.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/packages/grafana-ui/src/components/VizLegend/VizLegendSeriesIcon.tsx b/packages/grafana-ui/src/components/VizLegend/VizLegendSeriesIcon.tsx
index e7e16c48f64..aa565e4ee64 100644
--- a/packages/grafana-ui/src/components/VizLegend/VizLegendSeriesIcon.tsx
+++ b/packages/grafana-ui/src/components/VizLegend/VizLegendSeriesIcon.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { memo, useCallback } from 'react';
import { LineStyle } from '@grafana/schema';
@@ -18,7 +18,7 @@ interface Props {
/**
* @internal
*/
-export const VizLegendSeriesIcon = React.memo(({ seriesName, color, gradient, readonly, lineStyle }: Props) => {
+export const VizLegendSeriesIcon = memo(({ seriesName, color, gradient, readonly, lineStyle }: Props) => {
const { onSeriesColorChange } = usePanelContext();
const onChange = useCallback(
(color: string) => {
diff --git a/packages/grafana-ui/src/components/VizLegend/VizLegendStatsList.tsx b/packages/grafana-ui/src/components/VizLegend/VizLegendStatsList.tsx
index 4c41e4b3905..84de78ed3a9 100644
--- a/packages/grafana-ui/src/components/VizLegend/VizLegendStatsList.tsx
+++ b/packages/grafana-ui/src/components/VizLegend/VizLegendStatsList.tsx
@@ -1,6 +1,5 @@
import { css } from '@emotion/css';
import { capitalize } from 'lodash';
-import React from 'react';
import { DisplayValue, formattedValueToString } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/VizLegend/VizLegendTable.tsx b/packages/grafana-ui/src/components/VizLegend/VizLegendTable.tsx
index 6d289dd1cc7..0383aa1eab1 100644
--- a/packages/grafana-ui/src/components/VizLegend/VizLegendTable.tsx
+++ b/packages/grafana-ui/src/components/VizLegend/VizLegendTable.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/VizLegend/VizLegendTableItem.tsx b/packages/grafana-ui/src/components/VizLegend/VizLegendTableItem.tsx
index bf66a48e8dd..3784bbabd5f 100644
--- a/packages/grafana-ui/src/components/VizLegend/VizLegendTableItem.tsx
+++ b/packages/grafana-ui/src/components/VizLegend/VizLegendTableItem.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
+import * as React from 'react';
import { formattedValueToString, GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/VizLegend/types.ts b/packages/grafana-ui/src/components/VizLegend/types.ts
index ed1fd196c61..cf718a64756 100644
--- a/packages/grafana-ui/src/components/VizLegend/types.ts
+++ b/packages/grafana-ui/src/components/VizLegend/types.ts
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { DataFrameFieldIndex, DisplayValue } from '@grafana/data';
import { LegendDisplayMode, LegendPlacement, LineStyle } from '@grafana/schema';
diff --git a/packages/grafana-ui/src/components/VizRepeater/VizRepeater.tsx b/packages/grafana-ui/src/components/VizRepeater/VizRepeater.tsx
index 44e4b0569fd..ee2f0585aad 100644
--- a/packages/grafana-ui/src/components/VizRepeater/VizRepeater.tsx
+++ b/packages/grafana-ui/src/components/VizRepeater/VizRepeater.tsx
@@ -1,5 +1,6 @@
import { clamp } from 'lodash';
-import React, { PureComponent, CSSProperties } from 'react';
+import { PureComponent, CSSProperties } from 'react';
+import * as React from 'react';
import { VizOrientation } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/VizTooltip/SeriesTable.story.tsx b/packages/grafana-ui/src/components/VizTooltip/SeriesTable.story.tsx
index 83328dcdb1e..9b5b1d30699 100644
--- a/packages/grafana-ui/src/components/VizTooltip/SeriesTable.story.tsx
+++ b/packages/grafana-ui/src/components/VizTooltip/SeriesTable.story.tsx
@@ -1,5 +1,4 @@
import { StoryFn, Meta } from '@storybook/react';
-import React from 'react';
import { SeriesTable } from './SeriesTable';
diff --git a/packages/grafana-ui/src/components/VizTooltip/SeriesTable.tsx b/packages/grafana-ui/src/components/VizTooltip/SeriesTable.tsx
index 6d683fd5147..f563e14784b 100644
--- a/packages/grafana-ui/src/components/VizTooltip/SeriesTable.tsx
+++ b/packages/grafana-ui/src/components/VizTooltip/SeriesTable.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2, GraphSeriesValue } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/VizTooltip/VizTooltip.tsx b/packages/grafana-ui/src/components/VizTooltip/VizTooltip.tsx
index 5f7c4cf551e..23b39b18356 100644
--- a/packages/grafana-ui/src/components/VizTooltip/VizTooltip.tsx
+++ b/packages/grafana-ui/src/components/VizTooltip/VizTooltip.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { Dimensions, TimeZone } from '@grafana/data';
import { TooltipDisplayMode } from '@grafana/schema';
diff --git a/packages/grafana-ui/src/components/VizTooltip/VizTooltipColorIndicator.tsx b/packages/grafana-ui/src/components/VizTooltip/VizTooltipColorIndicator.tsx
index 5118ef2020b..b61905c7d4f 100644
--- a/packages/grafana-ui/src/components/VizTooltip/VizTooltipColorIndicator.tsx
+++ b/packages/grafana-ui/src/components/VizTooltip/VizTooltipColorIndicator.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { FALLBACK_COLOR, GrafanaTheme2 } from '@grafana/data';
import { LineStyle } from '@grafana/schema';
diff --git a/packages/grafana-ui/src/components/VizTooltip/VizTooltipContainer.tsx b/packages/grafana-ui/src/components/VizTooltip/VizTooltipContainer.tsx
index 055023aa0d1..b30b4e5ff81 100644
--- a/packages/grafana-ui/src/components/VizTooltip/VizTooltipContainer.tsx
+++ b/packages/grafana-ui/src/components/VizTooltip/VizTooltipContainer.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { useState, HTMLAttributes, useMemo, useRef, useLayoutEffect } from 'react';
+import { useState, HTMLAttributes, useMemo, useRef, useLayoutEffect } from 'react';
+import * as React from 'react';
import { useWindowSize } from 'react-use';
import { Dimensions2D, GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/VizTooltip/VizTooltipContent.tsx b/packages/grafana-ui/src/components/VizTooltip/VizTooltipContent.tsx
index a6e3fcf1e5e..66fa1d71b44 100644
--- a/packages/grafana-ui/src/components/VizTooltip/VizTooltipContent.tsx
+++ b/packages/grafana-ui/src/components/VizTooltip/VizTooltipContent.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { CSSProperties, ReactNode } from 'react';
+import { CSSProperties, ReactNode } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/VizTooltip/VizTooltipFooter.tsx b/packages/grafana-ui/src/components/VizTooltip/VizTooltipFooter.tsx
index 834c3b1f54d..e455f8591aa 100644
--- a/packages/grafana-ui/src/components/VizTooltip/VizTooltipFooter.tsx
+++ b/packages/grafana-ui/src/components/VizTooltip/VizTooltipFooter.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { Field, GrafanaTheme2, LinkModel } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/VizTooltip/VizTooltipHeader.tsx b/packages/grafana-ui/src/components/VizTooltip/VizTooltipHeader.tsx
index 360145db48f..d10180ac823 100644
--- a/packages/grafana-ui/src/components/VizTooltip/VizTooltipHeader.tsx
+++ b/packages/grafana-ui/src/components/VizTooltip/VizTooltipHeader.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/VizTooltip/VizTooltipRow.tsx b/packages/grafana-ui/src/components/VizTooltip/VizTooltipRow.tsx
index 956b634cd57..2fbb00c0fe2 100644
--- a/packages/grafana-ui/src/components/VizTooltip/VizTooltipRow.tsx
+++ b/packages/grafana-ui/src/components/VizTooltip/VizTooltipRow.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { CSSProperties, ReactNode, useEffect, useRef, useState } from 'react';
+import { CSSProperties, ReactNode, useEffect, useRef, useState } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/transitions/FadeTransition.tsx b/packages/grafana-ui/src/components/transitions/FadeTransition.tsx
index 4127dcbd60c..72f1424fa38 100644
--- a/packages/grafana-ui/src/components/transitions/FadeTransition.tsx
+++ b/packages/grafana-ui/src/components/transitions/FadeTransition.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useRef } from 'react';
+import { useRef } from 'react';
+import * as React from 'react';
import { CSSTransition } from 'react-transition-group';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/transitions/SlideOutTransition.tsx b/packages/grafana-ui/src/components/transitions/SlideOutTransition.tsx
index d6241042143..e2d12a350ee 100644
--- a/packages/grafana-ui/src/components/transitions/SlideOutTransition.tsx
+++ b/packages/grafana-ui/src/components/transitions/SlideOutTransition.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useRef } from 'react';
+import { useRef } from 'react';
+import * as React from 'react';
import { CSSTransition } from 'react-transition-group';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/uPlot/Plot.test.tsx b/packages/grafana-ui/src/components/uPlot/Plot.test.tsx
index 5dd3ae544f7..045b27a576d 100644
--- a/packages/grafana-ui/src/components/uPlot/Plot.test.tsx
+++ b/packages/grafana-ui/src/components/uPlot/Plot.test.tsx
@@ -1,6 +1,5 @@
import { render } from '@testing-library/react';
import createMockRaf from 'mock-raf';
-import React from 'react';
import uPlot from 'uplot';
import { FieldConfig, FieldType, MutableDataFrame } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/uPlot/Plot.tsx b/packages/grafana-ui/src/components/uPlot/Plot.tsx
index a6690e77c5e..0eca0ba3b15 100644
--- a/packages/grafana-ui/src/components/uPlot/Plot.tsx
+++ b/packages/grafana-ui/src/components/uPlot/Plot.tsx
@@ -1,4 +1,4 @@
-import React, { Component, createRef } from 'react';
+import { Component, createRef } from 'react';
import uPlot, { AlignedData, Options } from 'uplot';
import { PlotProps } from './types';
diff --git a/packages/grafana-ui/src/components/uPlot/PlotLegend.tsx b/packages/grafana-ui/src/components/uPlot/PlotLegend.tsx
index 50325873e06..0163d9483c5 100644
--- a/packages/grafana-ui/src/components/uPlot/PlotLegend.tsx
+++ b/packages/grafana-ui/src/components/uPlot/PlotLegend.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import { memo } from 'react';
import { DataFrame, getFieldDisplayName, getFieldSeriesColor } from '@grafana/data';
import { VizLegendOptions, AxisPlacement } from '@grafana/schema';
@@ -39,7 +39,7 @@ export function hasVisibleLegendSeries(config: UPlotConfigBuilder, data: DataFra
});
}
-export const PlotLegend = React.memo(
+export const PlotLegend = memo(
({ data, config, placement, calcs, displayMode, ...vizLayoutLegendProps }: PlotLegendProps) => {
const theme = useTheme2();
const legendItems = config
diff --git a/packages/grafana-ui/src/components/uPlot/geometries/EventsCanvas.tsx b/packages/grafana-ui/src/components/uPlot/geometries/EventsCanvas.tsx
index 60223af3884..a246bfd59f8 100644
--- a/packages/grafana-ui/src/components/uPlot/geometries/EventsCanvas.tsx
+++ b/packages/grafana-ui/src/components/uPlot/geometries/EventsCanvas.tsx
@@ -1,4 +1,5 @@
-import React, { useLayoutEffect, useMemo, useRef, useState } from 'react';
+import { useLayoutEffect, useMemo, useRef, useState } from 'react';
+import * as React from 'react';
import { useMountedState } from 'react-use';
import uPlot from 'uplot';
diff --git a/packages/grafana-ui/src/components/uPlot/geometries/Marker.tsx b/packages/grafana-ui/src/components/uPlot/geometries/Marker.tsx
index 7cad3518f9c..e6940c324a9 100644
--- a/packages/grafana-ui/src/components/uPlot/geometries/Marker.tsx
+++ b/packages/grafana-ui/src/components/uPlot/geometries/Marker.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
interface MarkerProps {
/** x position relative to plotting area bounding box*/
diff --git a/packages/grafana-ui/src/components/uPlot/geometries/XYCanvas.tsx b/packages/grafana-ui/src/components/uPlot/geometries/XYCanvas.tsx
index a2d0a0413ff..1acb778b299 100644
--- a/packages/grafana-ui/src/components/uPlot/geometries/XYCanvas.tsx
+++ b/packages/grafana-ui/src/components/uPlot/geometries/XYCanvas.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
+import * as React from 'react';
interface XYCanvasProps {
top: number; // css pxls
diff --git a/packages/grafana-ui/src/components/uPlot/plugins/CloseButton.tsx b/packages/grafana-ui/src/components/uPlot/plugins/CloseButton.tsx
index 6fab4b71c21..30212dcedc3 100644
--- a/packages/grafana-ui/src/components/uPlot/plugins/CloseButton.tsx
+++ b/packages/grafana-ui/src/components/uPlot/plugins/CloseButton.tsx
@@ -1,6 +1,6 @@
// mostly copy/pasted from: public/app/core/components/CloseButton/CloseButton.tsx
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/components/uPlot/plugins/TooltipPlugin2.tsx b/packages/grafana-ui/src/components/uPlot/plugins/TooltipPlugin2.tsx
index bc40f0506ba..0c3678d8394 100644
--- a/packages/grafana-ui/src/components/uPlot/plugins/TooltipPlugin2.tsx
+++ b/packages/grafana-ui/src/components/uPlot/plugins/TooltipPlugin2.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { useLayoutEffect, useRef, useReducer, CSSProperties } from 'react';
+import { useLayoutEffect, useRef, useReducer, CSSProperties } from 'react';
+import * as React from 'react';
import { createPortal } from 'react-dom';
import uPlot from 'uplot';
diff --git a/packages/grafana-ui/src/components/uPlot/types.ts b/packages/grafana-ui/src/components/uPlot/types.ts
index 864e5ec274a..a22875d15d4 100644
--- a/packages/grafana-ui/src/components/uPlot/types.ts
+++ b/packages/grafana-ui/src/components/uPlot/types.ts
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import uPlot, { Options, AlignedData } from 'uplot';
import { UPlotConfigBuilder } from './config/UPlotConfigBuilder';
diff --git a/packages/grafana-ui/src/graveyard/Graph/Graph.test.tsx b/packages/grafana-ui/src/graveyard/Graph/Graph.test.tsx
index 847d6e883c0..748c126a431 100644
--- a/packages/grafana-ui/src/graveyard/Graph/Graph.test.tsx
+++ b/packages/grafana-ui/src/graveyard/Graph/Graph.test.tsx
@@ -1,6 +1,5 @@
import { act, render, screen } from '@testing-library/react';
import $ from 'jquery';
-import React from 'react';
import { GraphSeriesXY, FieldType, dateTime, FieldColorModeId, DisplayProcessor } from '@grafana/data';
import { TooltipDisplayMode } from '@grafana/schema';
diff --git a/packages/grafana-ui/src/graveyard/Graph/Graph.tsx b/packages/grafana-ui/src/graveyard/Graph/Graph.tsx
index 624d19e29c6..759e041decd 100644
--- a/packages/grafana-ui/src/graveyard/Graph/Graph.tsx
+++ b/packages/grafana-ui/src/graveyard/Graph/Graph.tsx
@@ -1,7 +1,8 @@
// Libraries
import $ from 'jquery';
import { uniqBy } from 'lodash';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
+import * as React from 'react';
// Types
import { TimeRange, GraphSeriesXY, TimeZone, createDimension } from '@grafana/data';
diff --git a/packages/grafana-ui/src/graveyard/Graph/GraphContextMenu.tsx b/packages/grafana-ui/src/graveyard/Graph/GraphContextMenu.tsx
index 5b3da31708a..2d8775d9a44 100644
--- a/packages/grafana-ui/src/graveyard/Graph/GraphContextMenu.tsx
+++ b/packages/grafana-ui/src/graveyard/Graph/GraphContextMenu.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import {
FlotDataPoint,
diff --git a/packages/grafana-ui/src/graveyard/Graph/GraphSeriesToggler.tsx b/packages/grafana-ui/src/graveyard/Graph/GraphSeriesToggler.tsx
index fc960695a68..3361b077b03 100644
--- a/packages/grafana-ui/src/graveyard/Graph/GraphSeriesToggler.tsx
+++ b/packages/grafana-ui/src/graveyard/Graph/GraphSeriesToggler.tsx
@@ -1,5 +1,6 @@
import { difference, isEqual } from 'lodash';
-import React, { Component } from 'react';
+import { Component } from 'react';
+import * as React from 'react';
import { GraphSeriesXY } from '@grafana/data';
diff --git a/packages/grafana-ui/src/graveyard/Graph/GraphTooltip/GraphTooltip.tsx b/packages/grafana-ui/src/graveyard/Graph/GraphTooltip/GraphTooltip.tsx
index d58c0816dfe..dc85f6ba423 100644
--- a/packages/grafana-ui/src/graveyard/Graph/GraphTooltip/GraphTooltip.tsx
+++ b/packages/grafana-ui/src/graveyard/Graph/GraphTooltip/GraphTooltip.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { TooltipDisplayMode } from '@grafana/schema';
import { VizTooltipContentProps } from '../../../components/VizTooltip';
diff --git a/packages/grafana-ui/src/graveyard/Graph/GraphTooltip/MultiModeGraphTooltip.test.tsx b/packages/grafana-ui/src/graveyard/Graph/GraphTooltip/MultiModeGraphTooltip.test.tsx
index 1af501183a6..f105e1b311b 100644
--- a/packages/grafana-ui/src/graveyard/Graph/GraphTooltip/MultiModeGraphTooltip.test.tsx
+++ b/packages/grafana-ui/src/graveyard/Graph/GraphTooltip/MultiModeGraphTooltip.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { createDimension, createTheme, FieldType, DisplayProcessor } from '@grafana/data';
diff --git a/packages/grafana-ui/src/graveyard/Graph/GraphTooltip/MultiModeGraphTooltip.tsx b/packages/grafana-ui/src/graveyard/Graph/GraphTooltip/MultiModeGraphTooltip.tsx
index bfe2856c700..642fa3c4846 100644
--- a/packages/grafana-ui/src/graveyard/Graph/GraphTooltip/MultiModeGraphTooltip.tsx
+++ b/packages/grafana-ui/src/graveyard/Graph/GraphTooltip/MultiModeGraphTooltip.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { getValueFromDimension } from '@grafana/data';
import { SeriesTable } from '../../../components/VizTooltip';
diff --git a/packages/grafana-ui/src/graveyard/Graph/GraphTooltip/SingleModeGraphTooltip.tsx b/packages/grafana-ui/src/graveyard/Graph/GraphTooltip/SingleModeGraphTooltip.tsx
index 7eb4d61872c..f6b98499d20 100644
--- a/packages/grafana-ui/src/graveyard/Graph/GraphTooltip/SingleModeGraphTooltip.tsx
+++ b/packages/grafana-ui/src/graveyard/Graph/GraphTooltip/SingleModeGraphTooltip.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import {
getValueFromDimension,
getColumnFromDimension,
diff --git a/packages/grafana-ui/src/graveyard/Graph/GraphWithLegend.internal.story.tsx b/packages/grafana-ui/src/graveyard/Graph/GraphWithLegend.internal.story.tsx
index cec30da88a0..cb613aa228f 100644
--- a/packages/grafana-ui/src/graveyard/Graph/GraphWithLegend.internal.story.tsx
+++ b/packages/grafana-ui/src/graveyard/Graph/GraphWithLegend.internal.story.tsx
@@ -1,5 +1,4 @@
import { StoryFn } from '@storybook/react';
-import React from 'react';
import { GraphSeriesXY, FieldType, dateTime, FieldColorModeId } from '@grafana/data';
import { LegendDisplayMode } from '@grafana/schema';
diff --git a/packages/grafana-ui/src/graveyard/Graph/GraphWithLegend.tsx b/packages/grafana-ui/src/graveyard/Graph/GraphWithLegend.tsx
index a590d5d1ed1..4fcda58d8ea 100644
--- a/packages/grafana-ui/src/graveyard/Graph/GraphWithLegend.tsx
+++ b/packages/grafana-ui/src/graveyard/Graph/GraphWithLegend.tsx
@@ -1,7 +1,7 @@
// Libraries
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2, GraphSeriesValue } from '@grafana/data';
import { LegendDisplayMode, LegendPlacement } from '@grafana/schema';
diff --git a/packages/grafana-ui/src/graveyard/GraphNG/GraphNG.tsx b/packages/grafana-ui/src/graveyard/GraphNG/GraphNG.tsx
index 52dfadb27a6..61acbfe2dee 100644
--- a/packages/grafana-ui/src/graveyard/GraphNG/GraphNG.tsx
+++ b/packages/grafana-ui/src/graveyard/GraphNG/GraphNG.tsx
@@ -1,4 +1,5 @@
-import React, { Component } from 'react';
+import { Component } from 'react';
+import * as React from 'react';
import { Subscription } from 'rxjs';
import { throttleTime } from 'rxjs/operators';
import uPlot, { AlignedData } from 'uplot';
diff --git a/packages/grafana-ui/src/graveyard/GraphNG/hooks.ts b/packages/grafana-ui/src/graveyard/GraphNG/hooks.ts
index e4f1d46550a..7a92874e6f3 100644
--- a/packages/grafana-ui/src/graveyard/GraphNG/hooks.ts
+++ b/packages/grafana-ui/src/graveyard/GraphNG/hooks.ts
@@ -1,4 +1,4 @@
-import React, { useCallback, useContext } from 'react';
+import { createContext, useCallback, useContext } from 'react';
import { DataFrame, DataFrameFieldIndex, Field } from '@grafana/data';
@@ -12,7 +12,7 @@ interface GraphNGContextType {
}
/** @deprecated */
-export const GraphNGContext = React.createContext({} as GraphNGContextType);
+export const GraphNGContext = createContext({} as GraphNGContextType);
/** @deprecated */
export const useGraphNGContext = () => {
diff --git a/packages/grafana-ui/src/graveyard/TimeSeries/TimeSeries.tsx b/packages/grafana-ui/src/graveyard/TimeSeries/TimeSeries.tsx
index 19f6706a300..223409a2da6 100644
--- a/packages/grafana-ui/src/graveyard/TimeSeries/TimeSeries.tsx
+++ b/packages/grafana-ui/src/graveyard/TimeSeries/TimeSeries.tsx
@@ -1,4 +1,5 @@
-import React, { Component } from 'react';
+import { Component } from 'react';
+import * as React from 'react';
import { DataFrame, TimeRange } from '@grafana/data';
diff --git a/packages/grafana-ui/src/graveyard/uPlot/plugins/TooltipPlugin.tsx b/packages/grafana-ui/src/graveyard/uPlot/plugins/TooltipPlugin.tsx
index 74d0bc4941c..a6328d27aff 100644
--- a/packages/grafana-ui/src/graveyard/uPlot/plugins/TooltipPlugin.tsx
+++ b/packages/grafana-ui/src/graveyard/uPlot/plugins/TooltipPlugin.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useLayoutEffect, useRef, useState } from 'react';
+import { useLayoutEffect, useRef, useState } from 'react';
+import * as React from 'react';
import { useMountedState } from 'react-use';
import uPlot from 'uplot';
diff --git a/packages/grafana-ui/src/options/builder/axis.tsx b/packages/grafana-ui/src/options/builder/axis.tsx
index 6bbb5c32ccf..7e7730bfcb3 100644
--- a/packages/grafana-ui/src/options/builder/axis.tsx
+++ b/packages/grafana-ui/src/options/builder/axis.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import {
FieldConfigEditorBuilder,
FieldType,
diff --git a/packages/grafana-ui/src/options/builder/hideSeries.tsx b/packages/grafana-ui/src/options/builder/hideSeries.tsx
index 6acb16ad363..ecc17a09154 100644
--- a/packages/grafana-ui/src/options/builder/hideSeries.tsx
+++ b/packages/grafana-ui/src/options/builder/hideSeries.tsx
@@ -1,5 +1,5 @@
import { startCase } from 'lodash';
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { FieldConfigEditorBuilder, StandardEditorProps } from '@grafana/data';
import { HideableFieldConfig, HideSeriesConfig } from '@grafana/schema';
diff --git a/packages/grafana-ui/src/options/builder/stacking.tsx b/packages/grafana-ui/src/options/builder/stacking.tsx
index b099157cbff..c51a83d1059 100644
--- a/packages/grafana-ui/src/options/builder/stacking.tsx
+++ b/packages/grafana-ui/src/options/builder/stacking.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import {
FieldConfigEditorBuilder,
StandardEditorProps,
diff --git a/packages/grafana-ui/src/slate-plugins/indentation.ts b/packages/grafana-ui/src/slate-plugins/indentation.ts
index d4e78355cd9..4d926b50226 100644
--- a/packages/grafana-ui/src/slate-plugins/indentation.ts
+++ b/packages/grafana-ui/src/slate-plugins/indentation.ts
@@ -1,5 +1,5 @@
import { isKeyHotkey } from 'is-hotkey';
-import React from 'react';
+import * as React from 'react';
import { RangeJSON, Range as SlateRange } from 'slate';
import Plain from 'slate-plain-serializer';
import { Editor, Plugin } from 'slate-react';
diff --git a/packages/grafana-ui/src/slate-plugins/runner.ts b/packages/grafana-ui/src/slate-plugins/runner.ts
index 1b1c93d3403..63e38456071 100644
--- a/packages/grafana-ui/src/slate-plugins/runner.ts
+++ b/packages/grafana-ui/src/slate-plugins/runner.ts
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { Plugin } from 'slate-react';
export function RunnerPlugin({ handler }: { handler?: (e: React.KeyboardEvent) => void }): Plugin {
diff --git a/packages/grafana-ui/src/slate-plugins/slate-prism/options.tsx b/packages/grafana-ui/src/slate-plugins/slate-prism/options.tsx
index 4964fe5b62d..5798ec71cb1 100644
--- a/packages/grafana-ui/src/slate-plugins/slate-prism/options.tsx
+++ b/packages/grafana-ui/src/slate-plugins/slate-prism/options.tsx
@@ -1,5 +1,5 @@
import { Record } from 'immutable';
-import React from 'react';
+import * as React from 'react';
import { Mark, Node, Decoration } from 'slate';
import { Editor } from 'slate-react';
diff --git a/packages/grafana-ui/src/slate-plugins/suggestions.tsx b/packages/grafana-ui/src/slate-plugins/suggestions.tsx
index 917895c437f..7e27a5adfe6 100644
--- a/packages/grafana-ui/src/slate-plugins/suggestions.tsx
+++ b/packages/grafana-ui/src/slate-plugins/suggestions.tsx
@@ -1,5 +1,4 @@
import { debounce, sortBy } from 'lodash';
-import React from 'react';
import { Editor, Plugin as SlatePlugin } from 'slate-react';
import { BootData } from '@grafana/data';
diff --git a/packages/grafana-ui/src/themes/GlobalStyles/GlobalStyles.tsx b/packages/grafana-ui/src/themes/GlobalStyles/GlobalStyles.tsx
index 5e8742109d8..f5504a82bad 100644
--- a/packages/grafana-ui/src/themes/GlobalStyles/GlobalStyles.tsx
+++ b/packages/grafana-ui/src/themes/GlobalStyles/GlobalStyles.tsx
@@ -1,5 +1,4 @@
import { Global } from '@emotion/react';
-import React from 'react';
import { useTheme2 } from '../ThemeContext';
diff --git a/packages/grafana-ui/src/themes/ThemeContext.test.tsx b/packages/grafana-ui/src/themes/ThemeContext.test.tsx
index 825fcc9fa3c..4c1b6a363a5 100644
--- a/packages/grafana-ui/src/themes/ThemeContext.test.tsx
+++ b/packages/grafana-ui/src/themes/ThemeContext.test.tsx
@@ -1,6 +1,5 @@
import { css } from '@emotion/css';
import { render, renderHook } from '@testing-library/react';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/packages/grafana-ui/src/themes/ThemeContext.tsx b/packages/grafana-ui/src/themes/ThemeContext.tsx
index 5a953458698..e83401a04de 100644
--- a/packages/grafana-ui/src/themes/ThemeContext.tsx
+++ b/packages/grafana-ui/src/themes/ThemeContext.tsx
@@ -1,6 +1,7 @@
import hoistNonReactStatics from 'hoist-non-react-statics';
import memoize from 'micro-memoize';
-import React, { useContext } from 'react';
+import { useContext } from 'react';
+import * as React from 'react';
import { GrafanaTheme, GrafanaTheme2, ThemeContext } from '@grafana/data';
diff --git a/packages/grafana-ui/src/utils/DelayRender.tsx b/packages/grafana-ui/src/utils/DelayRender.tsx
index 9439c208922..f845ebe041b 100644
--- a/packages/grafana-ui/src/utils/DelayRender.tsx
+++ b/packages/grafana-ui/src/utils/DelayRender.tsx
@@ -1,4 +1,5 @@
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
+import * as React from 'react';
interface Props {
children: React.ReactNode;
diff --git a/packages/grafana-ui/src/utils/i18n.tsx b/packages/grafana-ui/src/utils/i18n.tsx
index 06cd0731653..06b32503000 100644
--- a/packages/grafana-ui/src/utils/i18n.tsx
+++ b/packages/grafana-ui/src/utils/i18n.tsx
@@ -1,5 +1,4 @@
import i18next from 'i18next';
-import React from 'react';
import { Trans as I18NextTrans, initReactI18next } from 'react-i18next'; // eslint-disable-line no-restricted-imports
// We want to translate grafana-ui without introducing any breaking changes for consumers
diff --git a/packages/grafana-ui/src/utils/reactUtils.ts b/packages/grafana-ui/src/utils/reactUtils.ts
index 9ed5b9428a2..3a4b1ede950 100644
--- a/packages/grafana-ui/src/utils/reactUtils.ts
+++ b/packages/grafana-ui/src/utils/reactUtils.ts
@@ -1,4 +1,5 @@
-import React, { ReactElement } from 'react';
+import { ReactElement } from 'react';
+import * as React from 'react';
/** Returns the ID value of the first, and only, child element */
export function getChildId(children: ReactElement): string | undefined {
diff --git a/packages/grafana-ui/src/utils/skeleton.tsx b/packages/grafana-ui/src/utils/skeleton.tsx
index 042e14e3ea4..2efa4cb7890 100644
--- a/packages/grafana-ui/src/utils/skeleton.tsx
+++ b/packages/grafana-ui/src/utils/skeleton.tsx
@@ -1,5 +1,5 @@
import { keyframes } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
const fadeIn = keyframes({
'0%': {
diff --git a/packages/grafana-ui/src/utils/storybook/DashboardStoryCanvas.tsx b/packages/grafana-ui/src/utils/storybook/DashboardStoryCanvas.tsx
index 43cdc88cbba..4537c9ab13a 100644
--- a/packages/grafana-ui/src/utils/storybook/DashboardStoryCanvas.tsx
+++ b/packages/grafana-ui/src/utils/storybook/DashboardStoryCanvas.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { useTheme2 } from '../../themes';
diff --git a/packages/grafana-ui/src/utils/storybook/StoryExample.tsx b/packages/grafana-ui/src/utils/storybook/StoryExample.tsx
index 8d2584308d0..29b47f9c227 100644
--- a/packages/grafana-ui/src/utils/storybook/StoryExample.tsx
+++ b/packages/grafana-ui/src/utils/storybook/StoryExample.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { useTheme2 } from '../../themes/ThemeContext';
diff --git a/packages/grafana-ui/src/utils/storybook/ThemedDocsContainer.tsx b/packages/grafana-ui/src/utils/storybook/ThemedDocsContainer.tsx
index 1d70cc86598..962c3fd353f 100644
--- a/packages/grafana-ui/src/utils/storybook/ThemedDocsContainer.tsx
+++ b/packages/grafana-ui/src/utils/storybook/ThemedDocsContainer.tsx
@@ -1,6 +1,6 @@
// Wrap the DocsContainer for storybook-dark-mode theme switching support.
import { DocsContainer, DocsContextProps } from '@storybook/addon-docs';
-import React from 'react';
+import * as React from 'react';
import { useDarkMode } from 'storybook-dark-mode';
import { GrafanaLight, GrafanaDark } from '../../../.storybook/storybookTheme';
diff --git a/packages/grafana-ui/src/utils/storybook/withStoryContainer.tsx b/packages/grafana-ui/src/utils/storybook/withStoryContainer.tsx
index f276970fd37..a23bd7685c2 100644
--- a/packages/grafana-ui/src/utils/storybook/withStoryContainer.tsx
+++ b/packages/grafana-ui/src/utils/storybook/withStoryContainer.tsx
@@ -1,6 +1,6 @@
import { css, cx } from '@emotion/css';
import { Args, Decorator } from '@storybook/react';
-import React from 'react';
+import * as React from 'react';
interface Props {
width?: number;
diff --git a/packages/grafana-ui/src/utils/storybook/withTheme.tsx b/packages/grafana-ui/src/utils/storybook/withTheme.tsx
index 654473dff5d..d4abd8965b5 100644
--- a/packages/grafana-ui/src/utils/storybook/withTheme.tsx
+++ b/packages/grafana-ui/src/utils/storybook/withTheme.tsx
@@ -1,5 +1,5 @@
import { Decorator } from '@storybook/react';
-import React from 'react';
+import * as React from 'react';
import { useDarkMode } from 'storybook-dark-mode';
import { createTheme, GrafanaTheme2, ThemeContext } from '@grafana/data';
diff --git a/packages/grafana-ui/src/utils/useCombinedRefs.ts b/packages/grafana-ui/src/utils/useCombinedRefs.ts
index 4070edb3fc0..226580c401e 100644
--- a/packages/grafana-ui/src/utils/useCombinedRefs.ts
+++ b/packages/grafana-ui/src/utils/useCombinedRefs.ts
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
export function useCombinedRefs(
...refs: Array | React.ForwardedRef | ((instance: T | null) => void)>
diff --git a/packages/grafana-ui/src/utils/useDelayedSwitch.internal.story.tsx b/packages/grafana-ui/src/utils/useDelayedSwitch.internal.story.tsx
index 50dd06af75d..c00cdc86e11 100644
--- a/packages/grafana-ui/src/utils/useDelayedSwitch.internal.story.tsx
+++ b/packages/grafana-ui/src/utils/useDelayedSwitch.internal.story.tsx
@@ -1,5 +1,4 @@
import { StoryFn } from '@storybook/react';
-import React from 'react';
import { useDelayedSwitch } from './useDelayedSwitch';
diff --git a/packages/grafana-ui/tsconfig.json b/packages/grafana-ui/tsconfig.json
index 1a531bc1db6..7601a6e1e18 100644
--- a/packages/grafana-ui/tsconfig.json
+++ b/packages/grafana-ui/tsconfig.json
@@ -1,5 +1,6 @@
{
"compilerOptions": {
+ "jsx": "react-jsx",
"baseUrl": "./",
"declarationDir": "./compiled",
"emitDeclarationOnly": true,
diff --git a/pkg/services/annotations/annotationsimpl/loki/historian_store.go b/pkg/services/annotations/annotationsimpl/loki/historian_store.go
index b4e411b4a54..3fd0d7ca907 100644
--- a/pkg/services/annotations/annotationsimpl/loki/historian_store.go
+++ b/pkg/services/annotations/annotationsimpl/loki/historian_store.go
@@ -45,6 +45,7 @@ var (
type lokiQueryClient interface {
RangeQuery(ctx context.Context, query string, start, end, limit int64) (historian.QueryRes, error)
+ MaxQuerySize() int
}
// LokiHistorianStore is a read store that queries Loki for alert state history.
@@ -98,8 +99,12 @@ func (r *LokiHistorianStore) Get(ctx context.Context, query *annotations.ItemQue
}
}
- logQL, err := historian.BuildLogQuery(buildHistoryQuery(query, accessResources.Dashboards, rule.UID))
+ logQL, err := historian.BuildLogQuery(buildHistoryQuery(query, accessResources.Dashboards, rule.UID), r.client.MaxQuerySize())
if err != nil {
+ grafanaErr := errutil.Error{}
+ if errors.As(err, &grafanaErr) {
+ return make([]*annotations.ItemDTO, 0), err
+ }
return make([]*annotations.ItemDTO, 0), ErrLokiStoreInternal.Errorf("failed to build loki query: %w", err)
}
diff --git a/pkg/services/annotations/annotationsimpl/loki/historian_store_test.go b/pkg/services/annotations/annotationsimpl/loki/historian_store_test.go
index 5202952cda9..ff08aaee047 100644
--- a/pkg/services/annotations/annotationsimpl/loki/historian_store_test.go
+++ b/pkg/services/annotations/annotationsimpl/loki/historian_store_test.go
@@ -778,6 +778,7 @@ func NewFakeLokiClient() *FakeLokiClient {
ReadPathURL: url,
Encoder: historian.JsonEncoder{},
MaxQueryLength: 721 * time.Hour,
+ MaxQuerySize: 65536,
},
metrics: metrics,
log: log.New("ngalert.state.historian", "backend", "loki"),
@@ -812,6 +813,10 @@ func (c *FakeLokiClient) RangeQuery(ctx context.Context, query string, from, to,
return res, nil
}
+func (c *FakeLokiClient) MaxQuerySize() int {
+ return c.cfg.MaxQuerySize
+}
+
func TestUseStore(t *testing.T) {
t.Run("false if state history disabled", func(t *testing.T) {
cfg := setting.UnifiedAlertingStateHistorySettings{
diff --git a/pkg/services/authz/zanzana/client.go b/pkg/services/authz/zanzana/client.go
index e7a093fd426..b61cd4b46fd 100644
--- a/pkg/services/authz/zanzana/client.go
+++ b/pkg/services/authz/zanzana/client.go
@@ -3,9 +3,10 @@ package zanzana
import (
"context"
- openfgav1 "github.com/openfga/api/proto/openfga/v1"
"google.golang.org/grpc"
+ openfgav1 "github.com/openfga/api/proto/openfga/v1"
+
"github.com/grafana/grafana/pkg/infra/log"
)
diff --git a/pkg/services/authz/zanzana/server.go b/pkg/services/authz/zanzana/server.go
index 3d4ddc50b6a..1b9d1c119c6 100644
--- a/pkg/services/authz/zanzana/server.go
+++ b/pkg/services/authz/zanzana/server.go
@@ -8,7 +8,7 @@ import (
)
func NewServer(store storage.OpenFGADatastore, logger log.Logger) (*server.Server, error) {
- // FIXME(kalleep): add support for more options, configure logging, tracing etc
+ // FIXME(kalleep): add support for more options, tracing etc
opts := []server.OpenFGAServiceV1Option{
server.WithDatastore(store),
server.WithLogger(newZanzanaLogger(logger)),
diff --git a/pkg/services/authz/zanzana/store.go b/pkg/services/authz/zanzana/store.go
index 66da617d522..1166aafeeed 100644
--- a/pkg/services/authz/zanzana/store.go
+++ b/pkg/services/authz/zanzana/store.go
@@ -1,21 +1,22 @@
package zanzana
import (
- "errors"
"fmt"
- "strings"
"time"
+ "xorm.io/xorm"
+
"github.com/openfga/openfga/assets"
"github.com/openfga/openfga/pkg/storage"
- "github.com/openfga/openfga/pkg/storage/memory"
"github.com/openfga/openfga/pkg/storage/mysql"
"github.com/openfga/openfga/pkg/storage/postgres"
"github.com/openfga/openfga/pkg/storage/sqlcommon"
- "xorm.io/xorm"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/log"
+ zstore "github.com/grafana/grafana/pkg/services/authz/zanzana/store"
+ "github.com/grafana/grafana/pkg/services/authz/zanzana/store/migration"
+ "github.com/grafana/grafana/pkg/services/authz/zanzana/store/sqlite"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
"github.com/grafana/grafana/pkg/setting"
@@ -31,19 +32,37 @@ func NewStore(cfg *setting.Cfg, logger log.Logger) (storage.OpenFGADatastore, er
switch grafanaDBCfg.Type {
case migrator.SQLite:
- return memory.New(), nil
+ connStr := grafanaDBCfg.ConnectionString
+ // Initilize connection using xorm engine so we can reuse it for both migrations and data store
+ engine, err := xorm.NewEngine(grafanaDBCfg.Type, connStr)
+ if err != nil {
+ return nil, fmt.Errorf("failed to connect to database: %w", err)
+ }
+
+ m := migrator.NewMigrator(engine, cfg)
+ if err := migration.RunWithMigrator(m, cfg, zstore.EmbedMigrations, zstore.SQLiteMigrationDir); err != nil {
+ return nil, fmt.Errorf("failed to run migrations: %w", err)
+ }
+
+ return sqlite.NewWithDB(engine.DB().DB, &sqlite.Config{
+ Config: zanzanaDBCfg,
+ QueryRetries: grafanaDBCfg.QueryRetries,
+ })
case migrator.MySQL:
// For mysql we need to pass parseTime parameter in connection string
connStr := grafanaDBCfg.ConnectionString + "&parseTime=true"
- if err := runMigrations(cfg, migrator.MySQL, connStr, assets.MySQLMigrationDir); err != nil {
+ if err := migration.Run(cfg, migrator.MySQL, connStr, assets.EmbedMigrations, assets.MySQLMigrationDir); err != nil {
return nil, fmt.Errorf("failed to run migrations: %w", err)
}
+
return mysql.New(connStr, zanzanaDBCfg)
case migrator.Postgres:
- if err := runMigrations(cfg, migrator.Postgres, grafanaDBCfg.ConnectionString, assets.PostgresMigrationDir); err != nil {
+ connStr := grafanaDBCfg.ConnectionString
+ if err := migration.Run(cfg, migrator.Postgres, connStr, assets.EmbedMigrations, assets.PostgresMigrationDir); err != nil {
return nil, fmt.Errorf("failed to run migrations: %w", err)
}
- return postgres.New(grafanaDBCfg.ConnectionString, zanzanaDBCfg)
+
+ return postgres.New(connStr, zanzanaDBCfg)
}
// Should never happen
@@ -60,18 +79,24 @@ func NewEmbeddedStore(cfg *setting.Cfg, db db.DB, logger log.Logger) (storage.Op
switch grafanaDBCfg.Type {
case migrator.SQLite:
- // FIXME(kalleep): At the moment sqlite is not a supported data store.
- // So we just return in memory store for now.
- return memory.New(), nil
+ if err := migration.RunWithMigrator(m, cfg, zstore.EmbedMigrations, zstore.SQLiteMigrationDir); err != nil {
+ return nil, fmt.Errorf("failed to run migrations: %w", err)
+ }
+
+ // FIXME(kalleep): We should work on getting sqlite implemtation merged upstream and replace this one
+ return sqlite.NewWithDB(db.GetEngine().DB().DB, &sqlite.Config{
+ Config: zanzanaDBCfg,
+ QueryRetries: grafanaDBCfg.QueryRetries,
+ })
case migrator.MySQL:
- if err := runMigrationsWithMigrator(m, cfg, assets.MySQLMigrationDir); err != nil {
+ if err := migration.RunWithMigrator(m, cfg, assets.EmbedMigrations, assets.MySQLMigrationDir); err != nil {
return nil, fmt.Errorf("failed to run migrations: %w", err)
}
// For mysql we need to pass parseTime parameter in connection string
return mysql.New(grafanaDBCfg.ConnectionString+"&parseTime=true", zanzanaDBCfg)
case migrator.Postgres:
- if err := runMigrationsWithMigrator(m, cfg, assets.PostgresMigrationDir); err != nil {
+ if err := migration.RunWithMigrator(m, cfg, assets.EmbedMigrations, assets.PostgresMigrationDir); err != nil {
return nil, fmt.Errorf("failed to run migrations: %w", err)
}
@@ -101,114 +126,3 @@ func parseConfig(cfg *setting.Cfg, logger log.Logger) (*sqlstore.DatabaseConfig,
return grafanaDBCfg, zanzanaDBCfg, nil
}
-
-func runMigrations(cfg *setting.Cfg, typ, connStr, path string) error {
- engine, err := xorm.NewEngine(typ, connStr)
- if err != nil {
- return fmt.Errorf("failed to parse database config: %w", err)
- }
-
- m := migrator.NewMigrator(engine, cfg)
- m.AddCreateMigration()
-
- return runMigrationsWithMigrator(m, cfg, path)
-}
-
-func runMigrationsWithMigrator(m *migrator.Migrator, cfg *setting.Cfg, path string) error {
- migrations, err := getMigrations(path)
- if err != nil {
- return err
- }
-
- for _, mig := range migrations {
- m.AddMigration(mig.name, mig.migration)
- }
-
- sec := cfg.Raw.Section("database")
- return m.Start(
- sec.Key("migration_locking").MustBool(true),
- sec.Key("locking_attempt_timeout_sec").MustInt(),
- )
-}
-
-type migration struct {
- name string
- migration migrator.Migration
-}
-
-func getMigrations(path string) ([]migration, error) {
- entries, err := assets.EmbedMigrations.ReadDir(path)
- if err != nil {
- return nil, fmt.Errorf("failed to read migration dir: %w", err)
- }
-
- // parseStatements extracts statements from a sql file so we can execute
- // them as separate migrations. OpenFGA uses Goose as their migration egine
- // and Goose uses a single sql file for both up and down migrations.
- // Grafana only supports up migration so we strip out the down migration
- // and parse each individual statement
- parseStatements := func(data []byte) ([]string, error) {
- scripts := strings.Split(strings.TrimPrefix(string(data), "-- +goose Up"), "-- +goose Down")
- if len(scripts) != 2 {
- return nil, errors.New("malformed migration file")
- }
-
- // We assume that up migrations are always before down migrations
- parts := strings.SplitAfter(scripts[0], ";")
- stmts := make([]string, 0, len(parts))
- for _, p := range parts {
- p = strings.TrimSpace(p)
- if p != "" {
- stmts = append(stmts, p)
- }
- }
-
- return stmts, nil
- }
-
- formatName := func(name string) string {
- // Each migration file start with XXX where X is a number.
- // We remove that part and prefix each migration with "zanzana".
- return strings.TrimSuffix("zanzana"+name[3:], ".sql")
- }
-
- migrations := make([]migration, 0, len(entries))
- for _, e := range entries {
- data, err := assets.EmbedMigrations.ReadFile(path + "/" + e.Name())
- if err != nil {
- return nil, fmt.Errorf("failed to read migration file: %w", err)
- }
-
- stmts, err := parseStatements(data)
- if err != nil {
- return nil, fmt.Errorf("failed to parse migration: %w", err)
- }
-
- migrations = append(migrations, migration{
- name: formatName(e.Name()),
- migration: &rawMigration{stmts: stmts},
- })
- }
-
- return migrations, nil
-}
-
-var _ migrator.CodeMigration = (*rawMigration)(nil)
-
-type rawMigration struct {
- stmts []string
- migrator.MigrationBase
-}
-
-func (m *rawMigration) Exec(sess *xorm.Session, migrator *migrator.Migrator) error {
- for _, stmt := range m.stmts {
- if _, err := sess.Exec(stmt); err != nil {
- return fmt.Errorf("failed to run migration: %w", err)
- }
- }
- return nil
-}
-
-func (m *rawMigration) SQL(dialect migrator.Dialect) string {
- return strings.Join(m.stmts, "\n")
-}
diff --git a/pkg/services/authz/zanzana/store/assets.go b/pkg/services/authz/zanzana/store/assets.go
new file mode 100644
index 00000000000..e61b32e5b93
--- /dev/null
+++ b/pkg/services/authz/zanzana/store/assets.go
@@ -0,0 +1,10 @@
+package store
+
+import "embed"
+
+// EmbedMigrations within the grafana binary.
+//
+//go:embed migrations/*
+var EmbedMigrations embed.FS
+
+const SQLiteMigrationDir = "migrations/sqlite"
diff --git a/pkg/services/authz/zanzana/store/migration/migrator.go b/pkg/services/authz/zanzana/store/migration/migrator.go
new file mode 100644
index 00000000000..3f0d13f7343
--- /dev/null
+++ b/pkg/services/authz/zanzana/store/migration/migrator.go
@@ -0,0 +1,124 @@
+package migration
+
+import (
+ "embed"
+ "errors"
+ "fmt"
+ "strings"
+
+ "xorm.io/xorm"
+
+ "github.com/grafana/grafana/pkg/services/sqlstore/migrator"
+ "github.com/grafana/grafana/pkg/setting"
+)
+
+func Run(cfg *setting.Cfg, typ, connStr string, fs embed.FS, path string) error {
+ engine, err := xorm.NewEngine(typ, connStr)
+ if err != nil {
+ return fmt.Errorf("failed to parse database config: %w", err)
+ }
+
+ m := migrator.NewMigrator(engine, cfg)
+ m.AddCreateMigration()
+
+ return RunWithMigrator(m, cfg, fs, path)
+}
+
+func RunWithMigrator(m *migrator.Migrator, cfg *setting.Cfg, fs embed.FS, path string) error {
+ migrations, err := getMigrations(fs, path)
+ if err != nil {
+ return err
+ }
+
+ for _, mig := range migrations {
+ m.AddMigration(mig.name, mig.migration)
+ }
+
+ sec := cfg.Raw.Section("database")
+ return m.Start(
+ sec.Key("migration_locking").MustBool(true),
+ sec.Key("locking_attempt_timeout_sec").MustInt(),
+ )
+}
+
+type migration struct {
+ name string
+ migration migrator.Migration
+}
+
+func getMigrations(fs embed.FS, path string) ([]migration, error) {
+ entries, err := fs.ReadDir(path)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read migration dir: %w", err)
+ }
+
+ // parseStatements extracts statements from a sql file so we can execute
+ // them as separate migrations. OpenFGA uses Goose as their migration egine
+ // and Goose uses a single sql file for both up and down migrations.
+ // Grafana only supports up migration so we strip out the down migration
+ // and parse each individual statement
+ parseStatements := func(data []byte) ([]string, error) {
+ scripts := strings.Split(strings.TrimPrefix(string(data), "-- +goose Up"), "-- +goose Down")
+ if len(scripts) != 2 {
+ return nil, errors.New("malformed migration file")
+ }
+
+ // We assume that up migrations are always before down migrations
+ parts := strings.SplitAfter(scripts[0], ";")
+ stmts := make([]string, 0, len(parts))
+ for _, p := range parts {
+ p = strings.TrimSpace(p)
+ if p != "" {
+ stmts = append(stmts, p)
+ }
+ }
+
+ return stmts, nil
+ }
+
+ formatName := func(name string) string {
+ // Each migration file start with XXX where X is a number.
+ // We remove that part and prefix each migration with "zanzana".
+ return strings.TrimSuffix("zanzana"+name[3:], ".sql")
+ }
+
+ migrations := make([]migration, 0, len(entries))
+ for _, e := range entries {
+ data, err := fs.ReadFile(path + "/" + e.Name())
+ if err != nil {
+ return nil, fmt.Errorf("failed to read migration file: %w", err)
+ }
+
+ stmts, err := parseStatements(data)
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse migration: %w", err)
+ }
+
+ migrations = append(migrations, migration{
+ name: formatName(e.Name()),
+ migration: &rawMigration{stmts: stmts},
+ })
+ }
+
+ return migrations, nil
+}
+
+var _ migrator.CodeMigration = (*rawMigration)(nil)
+
+type rawMigration struct {
+ stmts []string
+ migrator.MigrationBase
+}
+
+func (m *rawMigration) Exec(sess *xorm.Session, migrator *migrator.Migrator) error {
+ for _, stmt := range m.stmts {
+ if _, err := sess.Exec(stmt); err != nil {
+ return fmt.Errorf("failed to run migration: %w", err)
+ }
+ }
+ return nil
+}
+
+func (m *rawMigration) SQL(dialect migrator.Dialect) string {
+ return strings.Join(m.stmts, "\n")
+}
diff --git a/pkg/services/authz/zanzana/store/migrations/sqlite/001_initialize_schema.sql b/pkg/services/authz/zanzana/store/migrations/sqlite/001_initialize_schema.sql
new file mode 100644
index 00000000000..ecceebfb58b
--- /dev/null
+++ b/pkg/services/authz/zanzana/store/migrations/sqlite/001_initialize_schema.sql
@@ -0,0 +1,56 @@
+-- +goose Up
+CREATE TABLE tuple (
+ store CHAR(26) NOT NULL,
+ object_type VARCHAR(128) NOT NULL,
+ object_id VARCHAR(128) NOT NULL,
+ relation VARCHAR(50) NOT NULL,
+ _user VARCHAR(256) NOT NULL,
+ user_type VARCHAR(7) NOT NULL,
+ ulid CHAR(26) NOT NULL,
+ inserted_at TIMESTAMP NOT NULL,
+ PRIMARY KEY (store, object_type, object_id, relation, _user)
+);
+
+CREATE UNIQUE INDEX idx_tuple_ulid ON tuple (ulid);
+
+CREATE TABLE authorization_model (
+ store CHAR(26) NOT NULL,
+ authorization_model_id CHAR(26) NOT NULL,
+ type VARCHAR(256) NOT NULL,
+ type_definition BLOB,
+ PRIMARY KEY (store, authorization_model_id, type)
+);
+
+CREATE TABLE store (
+ id CHAR(26) PRIMARY KEY,
+ name VARCHAR(64) NOT NULL,
+ created_at TIMESTAMP NOT NULL,
+ updated_at TIMESTAMP,
+ deleted_at TIMESTAMP
+);
+
+CREATE TABLE assertion (
+ store CHAR(26) NOT NULL,
+ authorization_model_id CHAR(26) NOT NULL,
+ assertions BLOB,
+ PRIMARY KEY (store, authorization_model_id)
+);
+
+CREATE TABLE changelog (
+ store CHAR(26) NOT NULL,
+ object_type VARCHAR(256) NOT NULL,
+ object_id VARCHAR(256) NOT NULL,
+ relation VARCHAR(50) NOT NULL,
+ _user VARCHAR(512) NOT NULL,
+ operation INTEGER NOT NULL,
+ ulid CHAR(26) NOT NULL,
+ inserted_at TIMESTAMP NOT NULL,
+ PRIMARY KEY (store, ulid, object_type)
+);
+
+-- +goose Down
+DROP TABLE tuple;
+DROP TABLE authorization_model;
+DROP TABLE store;
+DROP TABLE assertion;
+DROP TABLE changelog;
diff --git a/pkg/services/authz/zanzana/store/migrations/sqlite/002_add_authorization_model_version.sql b/pkg/services/authz/zanzana/store/migrations/sqlite/002_add_authorization_model_version.sql
new file mode 100644
index 00000000000..26ce15ac18b
--- /dev/null
+++ b/pkg/services/authz/zanzana/store/migrations/sqlite/002_add_authorization_model_version.sql
@@ -0,0 +1,5 @@
+-- +goose Up
+ALTER TABLE authorization_model ADD COLUMN schema_version VARCHAR(5) NOT NULL DEFAULT '1.0';
+
+-- +goose Down
+ALTER TABLE authorization_model DROP COLUMN schema_version;
diff --git a/pkg/services/authz/zanzana/store/migrations/sqlite/003_add_reverse_lookup_index.sql b/pkg/services/authz/zanzana/store/migrations/sqlite/003_add_reverse_lookup_index.sql
new file mode 100644
index 00000000000..9a3ee2a82bc
--- /dev/null
+++ b/pkg/services/authz/zanzana/store/migrations/sqlite/003_add_reverse_lookup_index.sql
@@ -0,0 +1,5 @@
+-- +goose Up
+CREATE INDEX idx_reverse_lookup_user on tuple (store, object_type, relation, _user);
+
+-- +goose Down
+DROP INDEX idx_reverse_lookup_user on tuple;
diff --git a/pkg/services/authz/zanzana/store/migrations/sqlite/004_add_authorization_model_serialized_protobuf.sql b/pkg/services/authz/zanzana/store/migrations/sqlite/004_add_authorization_model_serialized_protobuf.sql
new file mode 100644
index 00000000000..1e47f290e51
--- /dev/null
+++ b/pkg/services/authz/zanzana/store/migrations/sqlite/004_add_authorization_model_serialized_protobuf.sql
@@ -0,0 +1,5 @@
+-- +goose Up
+ALTER TABLE authorization_model ADD COLUMN serialized_protobuf LONGBLOB;
+
+-- +goose Down
+ALTER TABLE authorization_model DROP COLUMN serialized_protobuf;
diff --git a/pkg/services/authz/zanzana/store/migrations/sqlite/005_add_conditions_to_tuples.sql b/pkg/services/authz/zanzana/store/migrations/sqlite/005_add_conditions_to_tuples.sql
new file mode 100644
index 00000000000..37d039ca799
--- /dev/null
+++ b/pkg/services/authz/zanzana/store/migrations/sqlite/005_add_conditions_to_tuples.sql
@@ -0,0 +1,11 @@
+-- +goose Up
+ALTER TABLE tuple ADD COLUMN condition_name VARCHAR(256);
+ALTER TABLE tuple ADD COLUMN condition_context LONGBLOB;
+ALTER TABLE changelog ADD COLUMN condition_name VARCHAR(256);
+ALTER TABLE changelog ADD COLUMN condition_context LONGBLOB;
+
+-- +goose Down
+ALTER TABLE tuple DROP COLUMN condition_name;
+ALTER TABLE tuple DROP COLUMN condition_context;
+ALTER TABLE changelog DROP COLUMN condition_name;
+ALTER TABLE changelog DROP COLUMN condition_context;
diff --git a/pkg/services/authz/zanzana/store/sqlite/config.go b/pkg/services/authz/zanzana/store/sqlite/config.go
new file mode 100644
index 00000000000..b47404d6028
--- /dev/null
+++ b/pkg/services/authz/zanzana/store/sqlite/config.go
@@ -0,0 +1,15 @@
+package sqlite
+
+import "github.com/openfga/openfga/pkg/storage/sqlcommon"
+
+type Config struct {
+ *sqlcommon.Config
+ QueryRetries int
+}
+
+func NewConfig() *Config {
+ return &Config{
+ Config: sqlcommon.NewConfig(),
+ QueryRetries: 0,
+ }
+}
diff --git a/pkg/services/authz/zanzana/store/sqlite/store.go b/pkg/services/authz/zanzana/store/sqlite/store.go
new file mode 100644
index 00000000000..0860eb3b968
--- /dev/null
+++ b/pkg/services/authz/zanzana/store/sqlite/store.go
@@ -0,0 +1,821 @@
+package sqlite
+
+import (
+ "context"
+ "database/sql"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "net/url"
+ "strings"
+ "time"
+
+ sq "github.com/Masterminds/squirrel"
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/collectors"
+ "go.opentelemetry.io/otel"
+ "google.golang.org/protobuf/proto"
+ "google.golang.org/protobuf/types/known/structpb"
+ "google.golang.org/protobuf/types/known/timestamppb"
+
+ // Pull in sqlite driver.
+ "github.com/mattn/go-sqlite3"
+
+ openfgav1 "github.com/openfga/api/proto/openfga/v1"
+ "github.com/openfga/openfga/pkg/logger"
+ "github.com/openfga/openfga/pkg/storage"
+ "github.com/openfga/openfga/pkg/storage/sqlcommon"
+ tupleUtils "github.com/openfga/openfga/pkg/tuple"
+)
+
+var tracer = otel.Tracer("openfga/pkg/storage/sqlite")
+
+// SQLite provides a SQLite based implementation of [storage.OpenFGADatastore].
+type SQLite struct {
+ stbl sq.StatementBuilderType
+ cfg *Config
+ db *sql.DB
+ dbInfo *sqlcommon.DBInfo
+ sqlTime sq.Sqlizer
+ logger logger.Logger
+ dbStatsCollector prometheus.Collector
+}
+
+// Ensures that SQLite implements the OpenFGADatastore interface.
+var _ storage.OpenFGADatastore = (*SQLite)(nil)
+
+// New creates a new [SQLite] storage.
+func New(uri string, cfg *Config) (*SQLite, error) {
+ // Set journal mode and busy timeout pragmas if not specified.
+ query := url.Values{}
+ var err error
+
+ if i := strings.Index(uri, "?"); i != -1 {
+ query, err = url.ParseQuery(uri[i+1:])
+ if err != nil {
+ return nil, fmt.Errorf("error parsing dsn: %w", err)
+ }
+
+ uri = uri[:i]
+ }
+
+ foundJournalMode := false
+ foundBusyTimeout := false
+ for _, val := range query["_pragma"] {
+ if strings.HasPrefix(val, "journal_mode") {
+ foundJournalMode = true
+ } else if strings.HasPrefix(val, "busy_timeout") {
+ foundBusyTimeout = true
+ }
+ }
+
+ if !foundJournalMode {
+ query.Add("_pragma", "journal_mode(WAL)")
+ }
+ if !foundBusyTimeout {
+ query.Add("_pragma", "busy_timeout(500)")
+ }
+
+ uri += "?" + query.Encode()
+
+ db, err := sql.Open("sqlite", uri)
+ if err != nil {
+ return nil, fmt.Errorf("initialize sqlite connection: %w", err)
+ }
+
+ return NewWithDB(db, cfg)
+}
+
+// NewWithDB creates a new [SQLite] storage using provided [*sql.DB]
+func NewWithDB(db *sql.DB, cfg *Config) (*SQLite, error) {
+ var collector prometheus.Collector
+ if cfg.ExportMetrics {
+ collector = collectors.NewDBStatsCollector(db, "openfga")
+ if err := prometheus.Register(collector); err != nil {
+ return nil, fmt.Errorf("initialize metrics: %w", err)
+ }
+ }
+
+ sqlTime := sq.Expr("datetime('subsec')")
+ stbl := sq.StatementBuilder.RunWith(db)
+ dbInfo := sqlcommon.NewDBInfo(db, stbl, sqlTime)
+
+ return &SQLite{
+ cfg: cfg,
+ stbl: stbl,
+ db: db,
+ sqlTime: sqlTime,
+ dbInfo: dbInfo,
+ logger: cfg.Logger,
+ dbStatsCollector: collector,
+ }, nil
+}
+
+// Close see [storage.OpenFGADatastore].Close.
+func (m *SQLite) Close() {
+ if m.dbStatsCollector != nil {
+ prometheus.Unregister(m.dbStatsCollector)
+ }
+ _ = m.db.Close()
+}
+
+// Read see [storage.RelationshipTupleReader].Read.
+func (m *SQLite) Read(ctx context.Context, store string, tupleKey *openfgav1.TupleKey) (storage.TupleIterator, error) {
+ ctx, span := tracer.Start(ctx, "sqlite.Read")
+ defer span.End()
+
+ return m.read(ctx, store, tupleKey, nil)
+}
+
+// ReadPage see [storage.RelationshipTupleReader].ReadPage.
+func (m *SQLite) ReadPage(
+ ctx context.Context,
+ store string,
+ tupleKey *openfgav1.TupleKey,
+ opts storage.PaginationOptions,
+) ([]*openfgav1.Tuple, []byte, error) {
+ ctx, span := tracer.Start(ctx, "sqlite.ReadPage")
+ defer span.End()
+
+ iter, err := m.read(ctx, store, tupleKey, &opts)
+ if err != nil {
+ return nil, nil, err
+ }
+ defer iter.Stop()
+
+ return iter.ToArray(opts)
+}
+
+func (m *SQLite) read(ctx context.Context, store string, tupleKey *openfgav1.TupleKey, opts *storage.PaginationOptions) (*sqlcommon.SQLTupleIterator, error) {
+ ctx, span := tracer.Start(ctx, "sqlite.read")
+ defer span.End()
+
+ sb := m.stbl.
+ Select(
+ "store", "object_type", "object_id", "relation", "_user",
+ "condition_name", "condition_context", "ulid", "inserted_at",
+ ).
+ From("tuple").
+ Where(sq.Eq{"store": store})
+ if opts != nil {
+ sb = sb.OrderBy("ulid")
+ }
+ objectType, objectID := tupleUtils.SplitObject(tupleKey.GetObject())
+ if objectType != "" {
+ sb = sb.Where(sq.Eq{"object_type": objectType})
+ }
+ if objectID != "" {
+ sb = sb.Where(sq.Eq{"object_id": objectID})
+ }
+ if tupleKey.GetRelation() != "" {
+ sb = sb.Where(sq.Eq{"relation": tupleKey.GetRelation()})
+ }
+ if tupleKey.GetUser() != "" {
+ sb = sb.Where(sq.Eq{"_user": tupleKey.GetUser()})
+ }
+ if opts != nil && opts.From != "" {
+ token, err := sqlcommon.UnmarshallContToken(opts.From)
+ if err != nil {
+ return nil, err
+ }
+ sb = sb.Where(sq.GtOrEq{"ulid": token.Ulid})
+ }
+ if opts != nil && opts.PageSize != 0 {
+ sb = sb.Limit(uint64(opts.PageSize + 1)) // + 1 is used to determine whether to return a continuation token.
+ }
+
+ rows, err := sb.QueryContext(ctx)
+ if err != nil {
+ return nil, handleSQLError(err)
+ }
+
+ return sqlcommon.NewSQLTupleIterator(rows), nil
+}
+
+// Write see [storage.RelationshipTupleWriter].Write.
+func (m *SQLite) Write(ctx context.Context, store string, deletes storage.Deletes, writes storage.Writes) error {
+ ctx, span := tracer.Start(ctx, "sqlite.Write")
+ defer span.End()
+
+ if len(deletes)+len(writes) > m.MaxTuplesPerWrite() {
+ return storage.ErrExceededWriteBatchLimit
+ }
+
+ return m.busyRetry(func() error {
+ now := time.Now().UTC()
+ return write(ctx, m.db, m.stbl, m.sqlTime, store, deletes, writes, now)
+ })
+}
+
+// ReadUserTuple see [storage.RelationshipTupleReader].ReadUserTuple.
+func (m *SQLite) ReadUserTuple(ctx context.Context, store string, tupleKey *openfgav1.TupleKey) (*openfgav1.Tuple, error) {
+ ctx, span := tracer.Start(ctx, "sqlite.ReadUserTuple")
+ defer span.End()
+
+ objectType, objectID := tupleUtils.SplitObject(tupleKey.GetObject())
+ userType := tupleUtils.GetUserTypeFromUser(tupleKey.GetUser())
+
+ var conditionName sql.NullString
+ var conditionContext []byte
+ var record storage.TupleRecord
+ err := m.stbl.
+ Select(
+ "object_type", "object_id", "relation", "_user",
+ "condition_name", "condition_context",
+ ).
+ From("tuple").
+ Where(sq.Eq{
+ "store": store,
+ "object_type": objectType,
+ "object_id": objectID,
+ "relation": tupleKey.GetRelation(),
+ "_user": tupleKey.GetUser(),
+ "user_type": userType,
+ }).
+ QueryRowContext(ctx).
+ Scan(
+ &record.ObjectType,
+ &record.ObjectID,
+ &record.Relation,
+ &record.User,
+ &conditionName,
+ &conditionContext,
+ )
+ if err != nil {
+ return nil, handleSQLError(err)
+ }
+
+ if conditionName.String != "" {
+ record.ConditionName = conditionName.String
+
+ if conditionContext != nil {
+ var conditionContextStruct structpb.Struct
+ if err := proto.Unmarshal(conditionContext, &conditionContextStruct); err != nil {
+ return nil, err
+ }
+ record.ConditionContext = &conditionContextStruct
+ }
+ }
+
+ return record.AsTuple(), nil
+}
+
+// ReadUsersetTuples see [storage.RelationshipTupleReader].ReadUsersetTuples.
+func (m *SQLite) ReadUsersetTuples(
+ ctx context.Context,
+ store string,
+ filter storage.ReadUsersetTuplesFilter,
+) (storage.TupleIterator, error) {
+ ctx, span := tracer.Start(ctx, "sqlite.ReadUsersetTuples")
+ defer span.End()
+
+ sb := m.stbl.
+ Select(
+ "store", "object_type", "object_id", "relation", "_user",
+ "condition_name", "condition_context", "ulid", "inserted_at",
+ ).
+ From("tuple").
+ Where(sq.Eq{"store": store}).
+ Where(sq.Eq{"user_type": tupleUtils.UserSet})
+
+ objectType, objectID := tupleUtils.SplitObject(filter.Object)
+ if objectType != "" {
+ sb = sb.Where(sq.Eq{"object_type": objectType})
+ }
+ if objectID != "" {
+ sb = sb.Where(sq.Eq{"object_id": objectID})
+ }
+ if filter.Relation != "" {
+ sb = sb.Where(sq.Eq{"relation": filter.Relation})
+ }
+ if len(filter.AllowedUserTypeRestrictions) > 0 {
+ orConditions := sq.Or{}
+ for _, userset := range filter.AllowedUserTypeRestrictions {
+ if _, ok := userset.GetRelationOrWildcard().(*openfgav1.RelationReference_Relation); ok {
+ orConditions = append(orConditions, sq.Like{"_user": userset.GetType() + ":%#" + userset.GetRelation()})
+ }
+ if _, ok := userset.GetRelationOrWildcard().(*openfgav1.RelationReference_Wildcard); ok {
+ orConditions = append(orConditions, sq.Eq{"_user": userset.GetType() + ":*"})
+ }
+ }
+ sb = sb.Where(orConditions)
+ }
+ rows, err := sb.QueryContext(ctx)
+ if err != nil {
+ return nil, handleSQLError(err)
+ }
+
+ return sqlcommon.NewSQLTupleIterator(rows), nil
+}
+
+// ReadStartingWithUser see [storage.RelationshipTupleReader].ReadStartingWithUser.
+func (m *SQLite) ReadStartingWithUser(
+ ctx context.Context,
+ store string,
+ opts storage.ReadStartingWithUserFilter,
+) (storage.TupleIterator, error) {
+ ctx, span := tracer.Start(ctx, "sqlite.ReadStartingWithUser")
+ defer span.End()
+
+ targetUsersArg := make([]string, 0, len(opts.UserFilter))
+ for _, u := range opts.UserFilter {
+ targetUser := u.GetObject()
+ if u.GetRelation() != "" {
+ targetUser = strings.Join([]string{u.GetObject(), u.GetRelation()}, "#")
+ }
+ targetUsersArg = append(targetUsersArg, targetUser)
+ }
+
+ rows, err := m.stbl.
+ Select(
+ "store", "object_type", "object_id", "relation", "_user",
+ "condition_name", "condition_context", "ulid", "inserted_at",
+ ).
+ From("tuple").
+ Where(sq.Eq{
+ "store": store,
+ "object_type": opts.ObjectType,
+ "relation": opts.Relation,
+ "_user": targetUsersArg,
+ }).QueryContext(ctx)
+ if err != nil {
+ return nil, handleSQLError(err)
+ }
+
+ return sqlcommon.NewSQLTupleIterator(rows), nil
+}
+
+// MaxTuplesPerWrite see [storage.RelationshipTupleWriter].MaxTuplesPerWrite.
+func (m *SQLite) MaxTuplesPerWrite() int {
+ return m.cfg.MaxTuplesPerWriteField
+}
+
+// ReadAuthorizationModel see [storage.AuthorizationModelReadBackend].ReadAuthorizationModel.
+func (m *SQLite) ReadAuthorizationModel(ctx context.Context, store string, modelID string) (*openfgav1.AuthorizationModel, error) {
+ ctx, span := tracer.Start(ctx, "sqlite.ReadAuthorizationModel")
+ defer span.End()
+
+ return sqlcommon.ReadAuthorizationModel(ctx, m.dbInfo, store, modelID)
+}
+
+// ReadAuthorizationModels see [storage.AuthorizationModelReadBackend].ReadAuthorizationModels.
+func (m *SQLite) ReadAuthorizationModels(
+ ctx context.Context,
+ store string,
+ opts storage.PaginationOptions,
+) ([]*openfgav1.AuthorizationModel, []byte, error) {
+ ctx, span := tracer.Start(ctx, "sqlite.ReadAuthorizationModels")
+ defer span.End()
+
+ sb := m.stbl.Select("authorization_model_id").
+ Distinct().
+ From("authorization_model").
+ Where(sq.Eq{"store": store}).
+ OrderBy("authorization_model_id desc")
+
+ if opts.From != "" {
+ token, err := sqlcommon.UnmarshallContToken(opts.From)
+ if err != nil {
+ return nil, nil, err
+ }
+ sb = sb.Where(sq.LtOrEq{"authorization_model_id": token.Ulid})
+ }
+ if opts.PageSize > 0 {
+ sb = sb.Limit(uint64(opts.PageSize + 1)) // + 1 is used to determine whether to return a continuation token.
+ }
+
+ rows, err := sb.QueryContext(ctx)
+ if err != nil {
+ return nil, nil, handleSQLError(err)
+ }
+ defer func() { _ = rows.Close() }()
+
+ var modelIDs []string
+ var modelID string
+
+ for rows.Next() {
+ err = rows.Scan(&modelID)
+ if err != nil {
+ return nil, nil, handleSQLError(err)
+ }
+
+ modelIDs = append(modelIDs, modelID)
+ }
+
+ if err := rows.Err(); err != nil {
+ return nil, nil, handleSQLError(err)
+ }
+
+ var token []byte
+ numModelIDs := len(modelIDs)
+ if len(modelIDs) > opts.PageSize {
+ numModelIDs = opts.PageSize
+ token, err = json.Marshal(sqlcommon.NewContToken(modelID, ""))
+ if err != nil {
+ return nil, nil, err
+ }
+ }
+
+ // TODO: make this concurrent with a maximum of 5 goroutines. This may be helpful:
+ // https://stackoverflow.com/questions/25306073/always-have-x-number-of-goroutines-running-at-any-time
+ models := make([]*openfgav1.AuthorizationModel, 0, numModelIDs)
+ // We use numModelIDs here to avoid retrieving possibly one extra model.
+ for i := 0; i < numModelIDs; i++ {
+ model, err := m.ReadAuthorizationModel(ctx, store, modelIDs[i])
+ if err != nil {
+ return nil, nil, err
+ }
+ models = append(models, model)
+ }
+
+ return models, token, nil
+}
+
+// FindLatestAuthorizationModel see [storage.AuthorizationModelReadBackend].FindLatestAuthorizationModel.
+func (m *SQLite) FindLatestAuthorizationModel(ctx context.Context, store string) (*openfgav1.AuthorizationModel, error) {
+ ctx, span := tracer.Start(ctx, "sqlite.FindLatestAuthorizationModel")
+ defer span.End()
+
+ return sqlcommon.FindLatestAuthorizationModel(ctx, m.dbInfo, store)
+}
+
+// MaxTypesPerAuthorizationModel see [storage.TypeDefinitionWriteBackend].MaxTypesPerAuthorizationModel.
+func (m *SQLite) MaxTypesPerAuthorizationModel() int {
+ return m.cfg.MaxTypesPerModelField
+}
+
+// WriteAuthorizationModel see [storage.TypeDefinitionWriteBackend].WriteAuthorizationModel.
+func (m *SQLite) WriteAuthorizationModel(ctx context.Context, store string, model *openfgav1.AuthorizationModel) error {
+ ctx, span := tracer.Start(ctx, "sqlite.WriteAuthorizationModel")
+ defer span.End()
+
+ typeDefinitions := model.GetTypeDefinitions()
+
+ if len(typeDefinitions) > m.MaxTypesPerAuthorizationModel() {
+ return storage.ExceededMaxTypeDefinitionsLimitError(m.MaxTypesPerAuthorizationModel())
+ }
+
+ return m.busyRetry(func() error {
+ return sqlcommon.WriteAuthorizationModel(ctx, m.dbInfo, store, model)
+ })
+}
+
+// CreateStore adds a new store to the SQLite storage.
+func (m *SQLite) CreateStore(ctx context.Context, store *openfgav1.Store) (*openfgav1.Store, error) {
+ ctx, span := tracer.Start(ctx, "sqlite.CreateStore")
+ defer span.End()
+
+ txn, err := m.db.BeginTx(ctx, &sql.TxOptions{})
+ if err != nil {
+ return nil, handleSQLError(err)
+ }
+ defer func() {
+ _ = txn.Rollback()
+ }()
+
+ _, err = m.stbl.
+ Insert("store").
+ Columns("id", "name", "created_at", "updated_at").
+ Values(store.GetId(), store.GetName(), sq.Expr("datetime('subsec')"), sq.Expr("datetime('subsec')")).
+ RunWith(txn).
+ ExecContext(ctx)
+ if err != nil {
+ return nil, handleSQLError(err)
+ }
+
+ var createdAt time.Time
+ var id, name string
+ err = m.stbl.
+ Select("id", "name", "created_at").
+ From("store").
+ Where(sq.Eq{"id": store.GetId()}).
+ RunWith(txn).
+ QueryRowContext(ctx).
+ Scan(&id, &name, &createdAt)
+ if err != nil {
+ return nil, handleSQLError(err)
+ }
+
+ err = txn.Commit()
+ if err != nil {
+ return nil, handleSQLError(err)
+ }
+
+ return &openfgav1.Store{
+ Id: id,
+ Name: name,
+ CreatedAt: timestamppb.New(createdAt),
+ UpdatedAt: timestamppb.New(createdAt),
+ }, nil
+}
+
+// GetStore retrieves the details of a specific store from the SQLite using its storeID.
+func (m *SQLite) GetStore(ctx context.Context, id string) (*openfgav1.Store, error) {
+ ctx, span := tracer.Start(ctx, "sqlite.GetStore")
+ defer span.End()
+
+ row := m.stbl.
+ Select("id", "name", "created_at", "updated_at").
+ From("store").
+ Where(sq.Eq{
+ "id": id,
+ "deleted_at": nil,
+ }).
+ QueryRowContext(ctx)
+
+ var storeID, name string
+ var createdAt, updatedAt time.Time
+ err := row.Scan(&storeID, &name, &createdAt, &updatedAt)
+ if err != nil {
+ if errors.Is(err, sql.ErrNoRows) {
+ return nil, storage.ErrNotFound
+ }
+ return nil, handleSQLError(err)
+ }
+
+ return &openfgav1.Store{
+ Id: storeID,
+ Name: name,
+ CreatedAt: timestamppb.New(createdAt),
+ UpdatedAt: timestamppb.New(updatedAt),
+ }, nil
+}
+
+// ListStores provides a paginated list of all stores present in the SQLite storage.
+func (m *SQLite) ListStores(ctx context.Context, opts storage.PaginationOptions) ([]*openfgav1.Store, []byte, error) {
+ ctx, span := tracer.Start(ctx, "sqlite.ListStores")
+ defer span.End()
+
+ sb := m.stbl.
+ Select("id", "name", "created_at", "updated_at").
+ From("store").
+ Where(sq.Eq{"deleted_at": nil}).
+ OrderBy("id")
+
+ if opts.From != "" {
+ token, err := sqlcommon.UnmarshallContToken(opts.From)
+ if err != nil {
+ return nil, nil, err
+ }
+ sb = sb.Where(sq.GtOrEq{"id": token.Ulid})
+ }
+ if opts.PageSize > 0 {
+ sb = sb.Limit(uint64(opts.PageSize + 1)) // + 1 is used to determine whether to return a continuation token.
+ }
+
+ rows, err := sb.QueryContext(ctx)
+ if err != nil {
+ return nil, nil, handleSQLError(err)
+ }
+ defer func() { _ = rows.Close() }()
+
+ var stores []*openfgav1.Store
+ var id string
+ for rows.Next() {
+ var name string
+ var createdAt, updatedAt time.Time
+ err := rows.Scan(&id, &name, &createdAt, &updatedAt)
+ if err != nil {
+ return nil, nil, handleSQLError(err)
+ }
+
+ stores = append(stores, &openfgav1.Store{
+ Id: id,
+ Name: name,
+ CreatedAt: timestamppb.New(createdAt),
+ UpdatedAt: timestamppb.New(updatedAt),
+ })
+ }
+
+ if err := rows.Err(); err != nil {
+ return nil, nil, handleSQLError(err)
+ }
+
+ if len(stores) > opts.PageSize {
+ contToken, err := json.Marshal(sqlcommon.NewContToken(id, ""))
+ if err != nil {
+ return nil, nil, err
+ }
+ return stores[:opts.PageSize], contToken, nil
+ }
+
+ return stores, nil, nil
+}
+
+// DeleteStore removes a store from the SQLite storage.
+func (m *SQLite) DeleteStore(ctx context.Context, id string) error {
+ ctx, span := tracer.Start(ctx, "sqlite.DeleteStore")
+ defer span.End()
+
+ _, err := m.stbl.
+ Update("store").
+ Set("deleted_at", sq.Expr("datetime('subsec')")).
+ Where(sq.Eq{"id": id}).
+ ExecContext(ctx)
+ if err != nil {
+ return handleSQLError(err)
+ }
+
+ return nil
+}
+
+// WriteAssertions see [storage.AssertionsBackend].WriteAssertions.
+func (m *SQLite) WriteAssertions(ctx context.Context, store, modelID string, assertions []*openfgav1.Assertion) error {
+ ctx, span := tracer.Start(ctx, "sqlite.WriteAssertions")
+ defer span.End()
+
+ marshalledAssertions, err := proto.Marshal(&openfgav1.Assertions{Assertions: assertions})
+ if err != nil {
+ return err
+ }
+
+ return m.busyRetry(func() error {
+ _, err = m.stbl.
+ Insert("assertion").
+ Columns("store", "authorization_model_id", "assertions").
+ Values(store, modelID, marshalledAssertions).
+ Suffix("ON CONFLICT(store,authorization_model_id) DO UPDATE SET assertions = ?", marshalledAssertions).
+ ExecContext(ctx)
+ if err != nil {
+ return handleSQLError(err)
+ }
+
+ return nil
+ })
+}
+
+// ReadAssertions see [storage.AssertionsBackend].ReadAssertions.
+func (m *SQLite) ReadAssertions(ctx context.Context, store, modelID string) ([]*openfgav1.Assertion, error) {
+ ctx, span := tracer.Start(ctx, "sqlite.ReadAssertions")
+ defer span.End()
+
+ var marshalledAssertions []byte
+ err := m.stbl.
+ Select("assertions").
+ From("assertion").
+ Where(sq.Eq{
+ "store": store,
+ "authorization_model_id": modelID,
+ }).
+ QueryRowContext(ctx).
+ Scan(&marshalledAssertions)
+ if err != nil {
+ if errors.Is(err, sql.ErrNoRows) {
+ return []*openfgav1.Assertion{}, nil
+ }
+ return nil, handleSQLError(err)
+ }
+
+ var assertions openfgav1.Assertions
+ err = proto.Unmarshal(marshalledAssertions, &assertions)
+ if err != nil {
+ return nil, err
+ }
+
+ return assertions.GetAssertions(), nil
+}
+
+// ReadChanges see [storage.ChangelogBackend].ReadChanges.
+func (m *SQLite) ReadChanges(
+ ctx context.Context,
+ store, objectTypeFilter string,
+ opts storage.PaginationOptions,
+ horizonOffset time.Duration,
+) ([]*openfgav1.TupleChange, []byte, error) {
+ ctx, span := tracer.Start(ctx, "sqlite.ReadChanges")
+ defer span.End()
+
+ sb := m.stbl.
+ Select(
+ "ulid", "object_type", "object_id", "relation", "_user", "operation",
+ "condition_name", "condition_context", "inserted_at",
+ ).
+ From("changelog").
+ Where(sq.Eq{"store": store}).
+ Where(fmt.Sprintf("inserted_at <= datetime('subsec','-%f seconds')", horizonOffset.Seconds())).
+ OrderBy("ulid asc")
+
+ if objectTypeFilter != "" {
+ sb = sb.Where(sq.Eq{"object_type": objectTypeFilter})
+ }
+ if opts.From != "" {
+ token, err := sqlcommon.UnmarshallContToken(opts.From)
+ if err != nil {
+ return nil, nil, err
+ }
+ if token.ObjectType != objectTypeFilter {
+ return nil, nil, storage.ErrMismatchObjectType
+ }
+
+ sb = sb.Where(sq.Gt{"ulid": token.Ulid}) // > as we always return a continuation token.
+ }
+ if opts.PageSize > 0 {
+ sb = sb.Limit(uint64(opts.PageSize)) // + 1 is NOT used here as we always return a continuation token.
+ }
+
+ rows, err := sb.QueryContext(ctx)
+ if err != nil {
+ return nil, nil, handleSQLError(err)
+ }
+ defer func() { _ = rows.Close() }()
+
+ var changes []*openfgav1.TupleChange
+ var ulid string
+ for rows.Next() {
+ var objectType, objectID, relation, user string
+ var operation int
+ var insertedAt time.Time
+ var conditionName sql.NullString
+ var conditionContext []byte
+
+ err = rows.Scan(
+ &ulid,
+ &objectType,
+ &objectID,
+ &relation,
+ &user,
+ &operation,
+ &conditionName,
+ &conditionContext,
+ &insertedAt,
+ )
+ if err != nil {
+ return nil, nil, handleSQLError(err)
+ }
+
+ var conditionContextStruct structpb.Struct
+ if conditionName.String != "" {
+ if conditionContext != nil {
+ if err := proto.Unmarshal(conditionContext, &conditionContextStruct); err != nil {
+ return nil, nil, err
+ }
+ }
+ }
+
+ tk := tupleUtils.NewTupleKeyWithCondition(
+ tupleUtils.BuildObject(objectType, objectID),
+ relation,
+ user,
+ conditionName.String,
+ &conditionContextStruct,
+ )
+
+ changes = append(changes, &openfgav1.TupleChange{
+ TupleKey: tk,
+ Operation: openfgav1.TupleOperation(operation),
+ Timestamp: timestamppb.New(insertedAt.UTC()),
+ })
+ }
+
+ if len(changes) == 0 {
+ return nil, nil, storage.ErrNotFound
+ }
+
+ contToken, err := json.Marshal(sqlcommon.NewContToken(ulid, objectTypeFilter))
+ if err != nil {
+ return nil, nil, err
+ }
+
+ return changes, contToken, nil
+}
+
+func (m *SQLite) IsReady(ctx context.Context) (storage.ReadinessStatus, error) {
+ if err := m.db.PingContext(ctx); err != nil {
+ return storage.ReadinessStatus{}, err
+ }
+ return storage.ReadinessStatus{
+ IsReady: true,
+ }, nil
+}
+
+// SQLite will return an SQLITE_BUSY error when the database is locked rather than waiting for the lock.
+// This function retries the operation up to 5 times before returning the error.
+func (m *SQLite) busyRetry(fn func() error) error {
+ for retries := 0; ; retries++ {
+ err := fn()
+ if err == nil || retries == m.cfg.QueryRetries {
+ return err
+ }
+
+ var sqliteErr *sqlite3.Error
+ if errors.As(err, &sqliteErr) && (sqliteErr.Code == sqlite3.ErrLocked || sqliteErr.Code == sqlite3.ErrBusy) {
+ time.Sleep(10 * time.Millisecond)
+ continue
+ }
+
+ return err
+ }
+}
+
+func handleSQLError(err error, args ...any) error {
+ if strings.Contains(err.Error(), "UNIQUE constraint failed:") {
+ if len(args) > 0 {
+ if tk, ok := args[0].(*openfgav1.TupleKey); ok {
+ return storage.InvalidWriteInputError(tk, openfgav1.TupleOperation_TUPLE_OPERATION_WRITE)
+ }
+ }
+ return storage.ErrCollision
+ }
+
+ return sqlcommon.HandleSQLError(err, args...)
+}
diff --git a/pkg/services/authz/zanzana/store/sqlite/store_test.go b/pkg/services/authz/zanzana/store/sqlite/store_test.go
new file mode 100644
index 00000000000..2274fec3822
--- /dev/null
+++ b/pkg/services/authz/zanzana/store/sqlite/store_test.go
@@ -0,0 +1,294 @@
+package sqlite
+
+import (
+ "context"
+ "database/sql"
+ "testing"
+ "time"
+
+ sq "github.com/Masterminds/squirrel"
+ "github.com/oklog/ulid/v2"
+ openfgav1 "github.com/openfga/api/proto/openfga/v1"
+ "github.com/stretchr/testify/require"
+ "google.golang.org/protobuf/proto"
+
+ "github.com/openfga/openfga/pkg/storage"
+ "github.com/openfga/openfga/pkg/storage/sqlcommon"
+ "github.com/openfga/openfga/pkg/storage/test"
+ "github.com/openfga/openfga/pkg/tuple"
+ "github.com/openfga/openfga/pkg/typesystem"
+
+ "github.com/grafana/grafana/pkg/infra/db"
+ "github.com/grafana/grafana/pkg/services/authz/zanzana/store"
+ "github.com/grafana/grafana/pkg/services/authz/zanzana/store/migration"
+ "github.com/grafana/grafana/pkg/services/sqlstore/migrator"
+ "github.com/grafana/grafana/pkg/tests/testsuite"
+)
+
+func TestMain(m *testing.M) {
+ testsuite.Run(m)
+}
+
+// TestIntegrationDatastore runs open fga default datastore test suite
+func TestIntegrationDatastore(t *testing.T) {
+ db := sqliteIntegrationTest(t)
+ ds, err := NewWithDB(db, NewConfig())
+ require.NoError(t, err)
+ test.RunAllTests(t, ds)
+}
+
+// TestIntegrationReadEnsureNoOrder asserts that the read response is not ordered by ulid.
+func TestIntegrationReadEnsureNoOrder(t *testing.T) {
+ db := sqliteIntegrationTest(t)
+
+ ds, err := NewWithDB(db, NewConfig())
+ require.NoError(t, err)
+
+ ctx := context.Background()
+ store := "store"
+ firstTuple := tuple.NewTupleKey("doc:object_id_1", "relation", "user:user_1")
+ secondTuple := tuple.NewTupleKey("doc:object_id_2", "relation", "user:user_2")
+
+ err = sqlcommon.Write(ctx,
+ sqlcommon.NewDBInfo(ds.db, ds.stbl, sq.Expr("datetime('subsec')")),
+ store,
+ []*openfgav1.TupleKeyWithoutCondition{},
+ []*openfgav1.TupleKey{firstTuple},
+ time.Now())
+ require.NoError(t, err)
+
+ // Tweak time so that ULID is smaller.
+ err = sqlcommon.Write(ctx,
+ sqlcommon.NewDBInfo(ds.db, ds.stbl, sq.Expr("datetime('subsec')")),
+ store,
+ []*openfgav1.TupleKeyWithoutCondition{},
+ []*openfgav1.TupleKey{secondTuple},
+ time.Now().Add(time.Minute*-1))
+ require.NoError(t, err)
+
+ iter, err := ds.Read(ctx,
+ store,
+ tuple.NewTupleKey("doc:", "relation", ""))
+ defer iter.Stop()
+
+ require.NoError(t, err)
+
+ // We expect that objectID1 will return first because it is inserted first.
+ curTuple, err := iter.Next(ctx)
+ require.NoError(t, err)
+ require.Equal(t, firstTuple, curTuple.GetKey())
+
+ curTuple, err = iter.Next(ctx)
+ require.NoError(t, err)
+ require.Equal(t, secondTuple, curTuple.GetKey())
+}
+
+// TestIntegrationReadPageEnsureNoOrder asserts that the read page is ordered by ulid.
+func TestIntegrationReadPageEnsureOrder(t *testing.T) {
+ db := sqliteIntegrationTest(t)
+
+ ds, err := NewWithDB(db, NewConfig())
+ require.NoError(t, err)
+
+ ctx := context.Background()
+
+ store := "store"
+ firstTuple := tuple.NewTupleKey("doc:object_id_1", "relation", "user:user_1")
+ secondTuple := tuple.NewTupleKey("doc:object_id_2", "relation", "user:user_2")
+
+ err = sqlcommon.Write(ctx,
+ sqlcommon.NewDBInfo(ds.db, ds.stbl, sq.Expr("datetime('subsec')")),
+ store,
+ []*openfgav1.TupleKeyWithoutCondition{},
+ []*openfgav1.TupleKey{firstTuple},
+ time.Now())
+ require.NoError(t, err)
+
+ // Tweak time so that ULID is smaller.
+ err = sqlcommon.Write(ctx,
+ sqlcommon.NewDBInfo(ds.db, ds.stbl, sq.Expr("datetime('subsec')")),
+ store,
+ []*openfgav1.TupleKeyWithoutCondition{},
+ []*openfgav1.TupleKey{secondTuple},
+ time.Now().Add(time.Minute*-1))
+ require.NoError(t, err)
+
+ tuples, _, err := ds.ReadPage(ctx,
+ store,
+ tuple.NewTupleKey("doc:", "relation", ""),
+ storage.NewPaginationOptions(0, ""))
+ require.NoError(t, err)
+
+ require.Len(t, tuples, 2)
+ // We expect that objectID2 will return first because it has a smaller ulid.
+ require.Equal(t, secondTuple, tuples[0].GetKey())
+ require.Equal(t, firstTuple, tuples[1].GetKey())
+}
+
+func TestIntegrationReadAuthorizationModelUnmarshallError(t *testing.T) {
+ db := sqliteIntegrationTest(t)
+
+ ds, err := NewWithDB(db, NewConfig())
+ require.NoError(t, err)
+
+ ctx := context.Background()
+ store := "store"
+ modelID := "foo"
+ schemaVersion := typesystem.SchemaVersion1_0
+
+ bytes, err := proto.Marshal(&openfgav1.TypeDefinition{Type: "document"})
+ require.NoError(t, err)
+ pbdata := []byte{0x01, 0x02, 0x03}
+
+ _, err = ds.db.ExecContext(ctx, "INSERT INTO authorization_model (store, authorization_model_id, schema_version, type, type_definition, serialized_protobuf) VALUES (?, ?, ?, ?, ?, ?)", store, modelID, schemaVersion, "document", bytes, pbdata)
+ require.NoError(t, err)
+
+ _, err = ds.ReadAuthorizationModel(ctx, store, modelID)
+ require.Error(t, err)
+ require.Contains(t, err.Error(), "cannot parse invalid wire-format data")
+}
+
+// TestIntegrationAllowNullCondition tests that tuple and changelog rows existing before
+// migration 005_add_conditions_to_tuples can be successfully read.
+func TestIntegrationAllowNullCondition(t *testing.T) {
+ db := sqliteIntegrationTest(t)
+
+ ds, err := NewWithDB(db, NewConfig())
+ require.NoError(t, err)
+
+ ctx := context.Background()
+
+ stmt := `
+ INSERT INTO tuple (
+ store, object_type, object_id, relation, _user, user_type, ulid,
+ condition_name, condition_context, inserted_at
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('subsec'));
+ `
+ _, err = ds.db.ExecContext(
+ ctx, stmt, "store", "folder", "2021-budget", "owner", "user:anne", "user",
+ ulid.Make().String(), nil, nil,
+ )
+ require.NoError(t, err)
+
+ tk := tuple.NewTupleKey("folder:2021-budget", "owner", "user:anne")
+ iter, err := ds.Read(ctx, "store", tk)
+ require.NoError(t, err)
+ defer iter.Stop()
+
+ curTuple, err := iter.Next(ctx)
+ require.NoError(t, err)
+ require.Equal(t, tk, curTuple.GetKey())
+
+ tuples, _, err := ds.ReadPage(ctx, "store", &openfgav1.TupleKey{}, storage.PaginationOptions{
+ PageSize: 2,
+ })
+ require.NoError(t, err)
+ require.Len(t, tuples, 1)
+ require.Equal(t, tk, tuples[0].GetKey())
+
+ userTuple, err := ds.ReadUserTuple(ctx, "store", tk)
+ require.NoError(t, err)
+ require.Equal(t, tk, userTuple.GetKey())
+
+ tk2 := tuple.NewTupleKey("folder:2022-budget", "viewer", "user:anne")
+ _, err = ds.db.ExecContext(
+ ctx, stmt, "store", "folder", "2022-budget", "viewer", "user:anne", "userset",
+ ulid.Make().String(), nil, nil,
+ )
+
+ require.NoError(t, err)
+ iter, err = ds.ReadUsersetTuples(ctx, "store", storage.ReadUsersetTuplesFilter{Object: "folder:2022-budget"})
+ require.NoError(t, err)
+ defer iter.Stop()
+
+ curTuple, err = iter.Next(ctx)
+ require.NoError(t, err)
+ require.Equal(t, tk2, curTuple.GetKey())
+
+ iter, err = ds.ReadStartingWithUser(ctx, "store", storage.ReadStartingWithUserFilter{
+ ObjectType: "folder",
+ Relation: "owner",
+ UserFilter: []*openfgav1.ObjectRelation{
+ {Object: "user:anne"},
+ },
+ })
+ require.NoError(t, err)
+ defer iter.Stop()
+
+ curTuple, err = iter.Next(ctx)
+ require.NoError(t, err)
+ require.Equal(t, tk, curTuple.GetKey())
+
+ stmt = `
+ INSERT INTO changelog (
+ store, object_type, object_id, relation, _user, ulid,
+ condition_name, condition_context, inserted_at, operation
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, datetime('subsec'), ?);
+`
+ _, err = ds.db.ExecContext(
+ ctx, stmt, "store", "folder", "2021-budget", "owner", "user:anne",
+ ulid.Make().String(), nil, nil, openfgav1.TupleOperation_TUPLE_OPERATION_WRITE,
+ )
+ require.NoError(t, err)
+
+ _, err = ds.db.ExecContext(
+ ctx, stmt, "store", "folder", "2021-budget", "owner", "user:anne",
+ ulid.Make().String(), nil, nil, openfgav1.TupleOperation_TUPLE_OPERATION_DELETE,
+ )
+ require.NoError(t, err)
+
+ changes, _, err := ds.ReadChanges(ctx, "store", "folder", storage.PaginationOptions{}, 0)
+ require.NoError(t, err)
+ require.Len(t, changes, 2)
+ require.Equal(t, tk, changes[0].GetTupleKey())
+ require.Equal(t, tk, changes[1].GetTupleKey())
+}
+
+// TestIntegrationMarshalledAssertions tests that previously persisted marshalled
+// assertions can be read back. In any case where the Assertions proto model
+// needs to change, we'll likely need to introduce a series of data migrations.
+func TestIntegrationMarshalledAssertions(t *testing.T) {
+ db := sqliteIntegrationTest(t)
+
+ ds, err := NewWithDB(db, NewConfig())
+ require.NoError(t, err)
+
+ ctx := context.Background()
+ // Note: this represents an assertion written on v1.3.7.
+ stmt := `
+ INSERT INTO assertion (
+ store, authorization_model_id, assertions
+ ) VALUES (?, ?, UNHEX('0A2B0A270A12666F6C6465723A323032312D62756467657412056F776E65721A0A757365723A616E6E657A1001'));
+ `
+ _, err = ds.db.ExecContext(ctx, stmt, "store", "model")
+ require.NoError(t, err)
+
+ assertions, err := ds.ReadAssertions(ctx, "store", "model")
+ require.NoError(t, err)
+
+ expectedAssertions := []*openfgav1.Assertion{
+ {
+ TupleKey: &openfgav1.AssertionTupleKey{
+ Object: "folder:2021-budget",
+ Relation: "owner",
+ User: "user:annez",
+ },
+ Expectation: true,
+ },
+ }
+ require.Equal(t, expectedAssertions, assertions)
+}
+
+func sqliteIntegrationTest(tb testing.TB) *sql.DB {
+ if testing.Short() || !db.IsTestDbSQLite() {
+ tb.Skip("skipping integration test")
+ }
+
+ db, cfg := db.InitTestDBWithCfg(tb)
+
+ m := migrator.NewMigrator(db.GetEngine(), cfg)
+ err := migration.RunWithMigrator(m, cfg, store.EmbedMigrations, store.SQLiteMigrationDir)
+ require.NoError(tb, err)
+
+ return db.GetEngine().DB().DB
+}
diff --git a/pkg/services/authz/zanzana/store/sqlite/write.go b/pkg/services/authz/zanzana/store/sqlite/write.go
new file mode 100644
index 00000000000..4e5dd79610b
--- /dev/null
+++ b/pkg/services/authz/zanzana/store/sqlite/write.go
@@ -0,0 +1,165 @@
+package sqlite
+
+import (
+ "context"
+ "database/sql"
+ "time"
+
+ sq "github.com/Masterminds/squirrel"
+ "github.com/oklog/ulid/v2"
+ "google.golang.org/protobuf/proto"
+
+ openfgav1 "github.com/openfga/api/proto/openfga/v1"
+ "github.com/openfga/openfga/pkg/storage"
+ tupleUtils "github.com/openfga/openfga/pkg/tuple"
+)
+
+// write is copied from https://github.com/openfga/openfga/blob/main/pkg/storage/sqlcommon/sqlcommon.go#L330-L456
+// but uses custom handleSQLError.
+func write(
+ ctx context.Context,
+ db *sql.DB,
+ stbl sq.StatementBuilderType,
+ sqlTime any,
+ store string,
+ deletes storage.Deletes,
+ writes storage.Writes,
+ now time.Time,
+) error {
+ txn, err := db.BeginTx(ctx, nil)
+ if err != nil {
+ return handleSQLError(err)
+ }
+ defer func() {
+ _ = txn.Rollback()
+ }()
+
+ changelogBuilder := stbl.
+ Insert("changelog").
+ Columns(
+ "store", "object_type", "object_id", "relation", "_user",
+ "condition_name", "condition_context", "operation", "ulid", "inserted_at",
+ )
+
+ deleteBuilder := stbl.Delete("tuple")
+
+ for _, tk := range deletes {
+ id := ulid.MustNew(ulid.Timestamp(now), ulid.DefaultEntropy()).String()
+ objectType, objectID := tupleUtils.SplitObject(tk.GetObject())
+
+ res, err := deleteBuilder.
+ Where(sq.Eq{
+ "store": store,
+ "object_type": objectType,
+ "object_id": objectID,
+ "relation": tk.GetRelation(),
+ "_user": tk.GetUser(),
+ "user_type": tupleUtils.GetUserTypeFromUser(tk.GetUser()),
+ }).
+ RunWith(txn). // Part of a txn.
+ ExecContext(ctx)
+ if err != nil {
+ return handleSQLError(err, tk)
+ }
+
+ rowsAffected, err := res.RowsAffected()
+ if err != nil {
+ return handleSQLError(err)
+ }
+
+ if rowsAffected != 1 {
+ return storage.InvalidWriteInputError(
+ tk,
+ openfgav1.TupleOperation_TUPLE_OPERATION_DELETE,
+ )
+ }
+
+ changelogBuilder = changelogBuilder.Values(
+ store, objectType, objectID,
+ tk.GetRelation(), tk.GetUser(),
+ "", nil, // Redact condition info for deletes since we only need the base triplet (object, relation, user).
+ openfgav1.TupleOperation_TUPLE_OPERATION_DELETE,
+ id, sqlTime,
+ )
+ }
+
+ insertBuilder := stbl.
+ Insert("tuple").
+ Columns(
+ "store", "object_type", "object_id", "relation", "_user", "user_type",
+ "condition_name", "condition_context", "ulid", "inserted_at",
+ )
+
+ for _, tk := range writes {
+ id := ulid.MustNew(ulid.Timestamp(now), ulid.DefaultEntropy()).String()
+ objectType, objectID := tupleUtils.SplitObject(tk.GetObject())
+
+ conditionName, conditionContext, err := marshalRelationshipCondition(tk.GetCondition())
+ if err != nil {
+ return err
+ }
+
+ _, err = insertBuilder.
+ Values(
+ store,
+ objectType,
+ objectID,
+ tk.GetRelation(),
+ tk.GetUser(),
+ tupleUtils.GetUserTypeFromUser(tk.GetUser()),
+ conditionName,
+ conditionContext,
+ id,
+ sqlTime,
+ ).
+ RunWith(txn). // Part of a txn.
+ ExecContext(ctx)
+ if err != nil {
+ return handleSQLError(err, tk)
+ }
+
+ changelogBuilder = changelogBuilder.Values(
+ store,
+ objectType,
+ objectID,
+ tk.GetRelation(),
+ tk.GetUser(),
+ conditionName,
+ conditionContext,
+ openfgav1.TupleOperation_TUPLE_OPERATION_WRITE,
+ id,
+ sqlTime,
+ )
+ }
+
+ if len(writes) > 0 || len(deletes) > 0 {
+ _, err := changelogBuilder.RunWith(txn).ExecContext(ctx) // Part of a txn.
+ if err != nil {
+ return handleSQLError(err)
+ }
+ }
+
+ if err := txn.Commit(); err != nil {
+ return handleSQLError(err)
+ }
+
+ return nil
+}
+
+// copied from https://github.com/openfga/openfga/blob/main/pkg/storage/sqlcommon/encoding.go#L8-L24
+func marshalRelationshipCondition(
+ rel *openfgav1.RelationshipCondition,
+) (name string, context []byte, err error) {
+ if rel != nil {
+ if rel.GetContext() != nil && len(rel.GetContext().GetFields()) > 0 {
+ context, err = proto.Marshal(rel.GetContext())
+ if err != nil {
+ return name, context, err
+ }
+ }
+
+ return rel.GetName(), context, err
+ }
+
+ return name, context, err
+}
diff --git a/pkg/services/cloudmigration/api/api.go b/pkg/services/cloudmigration/api/api.go
index 96d1679ade6..cc221f66b98 100644
--- a/pkg/services/cloudmigration/api/api.go
+++ b/pkg/services/cloudmigration/api/api.go
@@ -412,23 +412,32 @@ func (cma *CloudMigrationAPI) GetSnapshot(c *contextmodel.ReqContext) response.R
return response.ErrOrFallback(http.StatusBadRequest, "invalid snapshot uid", err)
}
- snapshot, err := cma.cloudMigrationService.GetSnapshot(ctx, sessUid, snapshotUid)
+ q := cloudmigration.GetSnapshotsQuery{
+ SnapshotUID: snapshotUid,
+ SessionUID: sessUid,
+ ResultPage: c.QueryInt("resultPage"),
+ ResultLimit: c.QueryInt("resultLimit"),
+ }
+ if q.ResultLimit == 0 {
+ q.ResultLimit = 100
+ }
+ if q.ResultPage < 1 {
+ q.ResultPage = 1
+ }
+ snapshot, err := cma.cloudMigrationService.GetSnapshot(ctx, q)
if err != nil {
return response.ErrOrFallback(http.StatusInternalServerError, "error retrieving snapshot", err)
}
- result, err := snapshot.GetSnapshotResult()
- if err != nil {
- return response.ErrOrFallback(http.StatusInternalServerError, "error snapshot reading snapshot results", err)
- }
+ results := snapshot.Resources
- dtoResults := make([]MigrateDataResponseItemDTO, len(result))
- for i := 0; i < len(result); i++ {
+ dtoResults := make([]MigrateDataResponseItemDTO, len(results))
+ for i := 0; i < len(results); i++ {
dtoResults[i] = MigrateDataResponseItemDTO{
- Type: MigrateDataType(result[i].Type),
- RefID: result[i].RefID,
- Status: ItemStatus(result[i].Status),
- Error: result[i].Error,
+ Type: MigrateDataType(results[i].Type),
+ RefID: results[i].RefID,
+ Status: ItemStatus(results[i].Status),
+ Error: results[i].Error,
}
}
@@ -467,11 +476,14 @@ func (cma *CloudMigrationAPI) GetSnapshotList(c *contextmodel.ReqContext) respon
q := cloudmigration.ListSnapshotsQuery{
SessionUID: uid,
Limit: c.QueryInt("limit"),
- Offset: c.QueryInt("offset"),
+ Page: c.QueryInt("page"),
}
if q.Limit == 0 {
q.Limit = 100
}
+ if q.Page < 1 {
+ q.Page = 1
+ }
snapshotList, err := cma.cloudMigrationService.GetSnapshotList(ctx, q)
if err != nil {
diff --git a/pkg/services/cloudmigration/api/curl_commands.txt b/pkg/services/cloudmigration/api/curl_commands.txt
index 7013234aaa3..f4556aae0e1 100644
--- a/pkg/services/cloudmigration/api/curl_commands.txt
+++ b/pkg/services/cloudmigration/api/curl_commands.txt
@@ -11,10 +11,10 @@ curl -X POST -H "Content-Type: application/json" \
http://admin:admin@localhost:3000/api/cloudmigration/migration/{sessionUid}/snapshot
[get snapshot list]
-curl -X GET http://admin:admin@localhost:3000/api/cloudmigration/migration/{sessionUid}/snapshots?limit=100&offset=0
+curl -X GET http://admin:admin@localhost:3000/api/cloudmigration/migration/{sessionUid}/snapshots?limit=100&page=1
[get snapshot]
-curl -X GET http://admin:admin@localhost:3000/api/cloudmigration/migration/{sessionUid}/snapshot/{snapshotUid}
+curl -X GET http://admin:admin@localhost:3000/api/cloudmigration/migration/{sessionUid}/snapshot/{snapshotUid}?resultLimit=100&resultPage=1
[upload snapshot]
curl -X POST -H "Content-Type: application/json" \
diff --git a/pkg/services/cloudmigration/api/dtos.go b/pkg/services/cloudmigration/api/dtos.go
index e410ea5efea..b5707895807 100644
--- a/pkg/services/cloudmigration/api/dtos.go
+++ b/pkg/services/cloudmigration/api/dtos.go
@@ -128,8 +128,10 @@ const (
type ItemStatus string
const (
- ItemStatusOK ItemStatus = "OK"
- ItemStatusError ItemStatus = "ERROR"
+ ItemStatusOK ItemStatus = "OK"
+ ItemStatusError ItemStatus = "ERROR"
+ ItemStatusPending ItemStatus = "PENDING"
+ ItemStatusUnknown ItemStatus = "UNKNOWN"
)
// swagger:parameters getCloudMigrationRun
@@ -268,6 +270,18 @@ type CreateSnapshotResponseDTO struct {
// swagger:parameters getSnapshot
type GetSnapshotParams struct {
+ // ResultPage is used for pagination with ResultLimit
+ // in:query
+ // required:false
+ // default: 1
+ ResultPage int `json:"resultPage"`
+
+ // Max limit for snapshot results returned.
+ // in:query
+ // required:false
+ // default: 100
+ ResultLimit int `json:"resultLimit"`
+
// Session UID of a session
// in: path
UID string `json:"uid"`
@@ -290,16 +304,18 @@ type GetSnapshotResponseDTO struct {
// swagger:parameters getShapshotList
type GetSnapshotListParams struct {
- // Offset is used for pagination with limit
+ // Page is used for pagination with limit
// in:query
// required:false
- // default: 0
- Offset int `json:"offset"`
+ // default: 1
+ Page int `json:"page"`
+
// Max limit for results returned.
// in:query
// required:false
// default: 100
Limit int `json:"limit"`
+
// Session UID of a session
// in: path
UID string `json:"uid"`
diff --git a/pkg/services/cloudmigration/cloudmigration.go b/pkg/services/cloudmigration/cloudmigration.go
index a49e35ea947..a431ba10f67 100644
--- a/pkg/services/cloudmigration/cloudmigration.go
+++ b/pkg/services/cloudmigration/cloudmigration.go
@@ -25,7 +25,7 @@ type Service interface {
GetMigrationRunList(ctx context.Context, migUID string) (*CloudMigrationRunList, error)
CreateSnapshot(ctx context.Context, sessionUid string) (*CloudMigrationSnapshot, error)
- GetSnapshot(ctx context.Context, sessionUid string, snapshotUid string) (*CloudMigrationSnapshot, error)
+ GetSnapshot(ctx context.Context, query GetSnapshotsQuery) (*CloudMigrationSnapshot, error)
GetSnapshotList(ctx context.Context, query ListSnapshotsQuery) ([]CloudMigrationSnapshot, error)
UploadSnapshot(ctx context.Context, sessionUid string, snapshotUid string) error
CancelSnapshot(ctx context.Context, sessionUid string, snapshotUid string) error
diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration.go b/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration.go
index e349b15c91c..3b631d84bd9 100644
--- a/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration.go
+++ b/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration.go
@@ -404,16 +404,10 @@ func (s *Service) RunMigration(ctx context.Context, uid string) (*cloudmigration
return nil, fmt.Errorf("migrate data error: %w", err)
}
- respData, err := json.Marshal(resp)
- if err != nil {
- s.log.Error("error marshalling migration response data: %w", err)
- return nil, fmt.Errorf("marshalling migration response data: %w", err)
- }
-
// save the result of the migration
runUID, err := s.createMigrationRun(ctx, cloudmigration.CloudMigrationSnapshot{
SessionUID: migration.UID,
- Result: respData,
+ Resources: resp.Items,
})
if err != nil {
response.Error(http.StatusInternalServerError, "migration run save error", err)
@@ -513,11 +507,12 @@ func (s *Service) CreateSnapshot(ctx context.Context, sessionUid string) (*cloud
}
// GetSnapshot returns the on-prem version of a snapshot, supplemented with processing status from GMS
-func (s *Service) GetSnapshot(ctx context.Context, sessionUid string, snapshotUid string) (*cloudmigration.CloudMigrationSnapshot, error) {
+func (s *Service) GetSnapshot(ctx context.Context, query cloudmigration.GetSnapshotsQuery) (*cloudmigration.CloudMigrationSnapshot, error) {
ctx, span := s.tracer.Start(ctx, "CloudMigrationService.GetSnapshot")
defer span.End()
- snapshot, err := s.store.GetSnapshotByUID(ctx, snapshotUid)
+ sessionUid, snapshotUid := query.SessionUID, query.SnapshotUID
+ snapshot, err := s.store.GetSnapshotByUID(ctx, snapshotUid, query.ResultPage, query.ResultLimit)
if err != nil {
return nil, fmt.Errorf("fetching snapshot for uid %s: %w", snapshotUid, err)
}
@@ -534,16 +529,12 @@ func (s *Service) GetSnapshot(ctx context.Context, sessionUid string, snapshotUi
return nil, fmt.Errorf("error fetching snapshot status from GMS: sessionUid: %s, snapshotUid: %s", sessionUid, snapshotUid)
}
- // grab any result available
- // TODO: figure out a more intelligent way to do this, will depend on GMS apis
- snapshot.Result = snapshotMeta.Result
-
if snapshotMeta.Status == cloudmigration.SnapshotStatusFinished {
// we need to update the snapshot in our db before reporting anything finished to the client
if err := s.store.UpdateSnapshot(ctx, cloudmigration.UpdateSnapshotCmd{
- UID: snapshot.UID,
- Status: cloudmigration.SnapshotStatusFinished,
- Result: snapshot.Result,
+ UID: snapshot.UID,
+ Status: cloudmigration.SnapshotStatusFinished,
+ Resources: snapshotMeta.Resources,
}); err != nil {
return nil, fmt.Errorf("error updating snapshot status: %w", err)
}
@@ -568,7 +559,10 @@ func (s *Service) UploadSnapshot(ctx context.Context, sessionUid string, snapsho
ctx, span := s.tracer.Start(ctx, "CloudMigrationService.UploadSnapshot")
defer span.End()
- snapshot, err := s.GetSnapshot(ctx, sessionUid, snapshotUid)
+ snapshot, err := s.GetSnapshot(ctx, cloudmigration.GetSnapshotsQuery{
+ SnapshotUID: snapshotUid,
+ SessionUID: sessionUid,
+ })
if err != nil {
return fmt.Errorf("fetching snapshot with uid %s: %w", snapshotUid, err)
}
diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_noop.go b/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_noop.go
index 3365f16c77b..d435b9f1ba8 100644
--- a/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_noop.go
+++ b/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_noop.go
@@ -64,7 +64,7 @@ func (s *NoopServiceImpl) CreateSnapshot(ctx context.Context, sessionUid string)
return nil, cloudmigration.ErrFeatureDisabledError
}
-func (s *NoopServiceImpl) GetSnapshot(ctx context.Context, sessionUid string, snapshotUid string) (*cloudmigration.CloudMigrationSnapshot, error) {
+func (s *NoopServiceImpl) GetSnapshot(ctx context.Context, query cloudmigration.GetSnapshotsQuery) (*cloudmigration.CloudMigrationSnapshot, error) {
return nil, cloudmigration.ErrFeatureDisabledError
}
diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_test.go b/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_test.go
index 83ecb800381..04ac1ff3217 100644
--- a/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_test.go
+++ b/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_test.go
@@ -145,18 +145,28 @@ func Test_ExecuteAsyncWorkflow(t *testing.T) {
require.Equal(t, sessionUid, snapshotResp.SessionUID)
snapshotUid := snapshotResp.UID
- snapshot, err := s.GetSnapshot(ctxWithSignedInUser(), sessionUid, snapshotUid)
+ // Service doesn't currently expose updating a snapshot externally, so we will just manually add a resource
+ err = (s.(*Service)).store.CreateUpdateSnapshotResources(context.Background(), snapshotUid, []cloudmigration.CloudMigrationResource{{Type: cloudmigration.DashboardDataType, RefID: "qwerty", Status: cloudmigration.ItemStatusOK}})
+ assert.NoError(t, err)
+
+ snapshot, err := s.GetSnapshot(ctxWithSignedInUser(), cloudmigration.GetSnapshotsQuery{
+ SnapshotUID: snapshotUid,
+ SessionUID: sessionUid,
+ ResultPage: 1,
+ ResultLimit: 100,
+ })
require.NoError(t, err)
assert.Equal(t, snapshotResp.UID, snapshot.UID)
assert.Equal(t, snapshotResp.EncryptionKey, snapshot.EncryptionKey)
- assert.Empty(t, snapshot.Result) // will change once we create a new table for migration items
+ assert.Len(t, snapshot.Resources, 1)
+ assert.Equal(t, "qwerty", snapshot.Resources[0].RefID)
- snapshots, err := s.GetSnapshotList(ctxWithSignedInUser(), cloudmigration.ListSnapshotsQuery{SessionUID: sessionUid, Limit: 100})
+ snapshots, err := s.GetSnapshotList(ctxWithSignedInUser(), cloudmigration.ListSnapshotsQuery{SessionUID: sessionUid, Page: 1, Limit: 100})
require.NoError(t, err)
assert.Len(t, snapshots, 1)
assert.Equal(t, snapshotResp.UID, snapshots[0].UID)
assert.Equal(t, snapshotResp.EncryptionKey, snapshots[0].EncryptionKey)
- assert.Empty(t, snapshots[0].Result) // should remain this way even after we create a new table
+ assert.Empty(t, snapshots[0].Resources)
err = s.UploadSnapshot(ctxWithSignedInUser(), sessionUid, snapshotUid)
require.NoError(t, err)
diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/fake/cloudmigration_fake.go b/pkg/services/cloudmigration/cloudmigrationimpl/fake/cloudmigration_fake.go
index 4b636ecd874..2de9080c4f0 100644
--- a/pkg/services/cloudmigration/cloudmigrationimpl/fake/cloudmigration_fake.go
+++ b/pkg/services/cloudmigration/cloudmigrationimpl/fake/cloudmigration_fake.go
@@ -2,7 +2,6 @@ package fake
import (
"context"
- "encoding/json"
"fmt"
"time"
@@ -93,7 +92,7 @@ func (m FakeServiceImpl) RunMigration(_ context.Context, _ string) (*cloudmigrat
func fakeMigrateDataResponseDTO() cloudmigration.MigrateDataResponse {
return cloudmigration.MigrateDataResponse{
RunUID: "fake_uid",
- Items: []cloudmigration.MigrateDataResponseItem{
+ Items: []cloudmigration.CloudMigrationResource{
{Type: "type", RefID: "make_refid", Status: "ok", Error: "none"},
},
}
@@ -107,15 +106,11 @@ func (m FakeServiceImpl) GetMigrationStatus(_ context.Context, _ string) (*cloud
if m.ReturnError {
return nil, fmt.Errorf("mock error")
}
- result, err := json.Marshal(fakeMigrateDataResponseDTO())
- if err != nil {
- return nil, err
- }
return &cloudmigration.CloudMigrationSnapshot{
ID: 0,
UID: "fake_uid",
SessionUID: "fake_mig_uid",
- Result: result,
+ Resources: fakeMigrateDataResponseDTO().Items,
Created: fixedDate,
Updated: fixedDate,
Finished: fixedDate,
@@ -145,7 +140,7 @@ func (m FakeServiceImpl) CreateSnapshot(ctx context.Context, sessionUid string)
}, nil
}
-func (m FakeServiceImpl) GetSnapshot(ctx context.Context, sessionUid string, snapshotUid string) (*cloudmigration.CloudMigrationSnapshot, error) {
+func (m FakeServiceImpl) GetSnapshot(ctx context.Context, query cloudmigration.GetSnapshotsQuery) (*cloudmigration.CloudMigrationSnapshot, error) {
if m.ReturnError {
return nil, fmt.Errorf("mock error")
}
diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/store.go b/pkg/services/cloudmigration/cloudmigrationimpl/store.go
index e499dcf5c23..fa855290505 100644
--- a/pkg/services/cloudmigration/cloudmigrationimpl/store.go
+++ b/pkg/services/cloudmigration/cloudmigrationimpl/store.go
@@ -18,6 +18,10 @@ type store interface {
CreateSnapshot(ctx context.Context, snapshot cloudmigration.CloudMigrationSnapshot) (string, error)
UpdateSnapshot(ctx context.Context, snapshot cloudmigration.UpdateSnapshotCmd) error
- GetSnapshotByUID(ctx context.Context, uid string) (*cloudmigration.CloudMigrationSnapshot, error)
+ GetSnapshotByUID(ctx context.Context, uid string, resultPage int, resultLimit int) (*cloudmigration.CloudMigrationSnapshot, error)
GetSnapshotList(ctx context.Context, query cloudmigration.ListSnapshotsQuery) ([]cloudmigration.CloudMigrationSnapshot, error)
+
+ CreateUpdateSnapshotResources(ctx context.Context, snapshotUid string, resources []cloudmigration.CloudMigrationResource) error
+ GetSnapshotResources(ctx context.Context, snapshotUid string, page int, limit int) ([]cloudmigration.CloudMigrationResource, error)
+ DeleteSnapshotResources(ctx context.Context, snapshotUid string) error
}
diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store.go b/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store.go
index 22d9e809070..8c0fcf684b8 100644
--- a/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store.go
+++ b/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store.go
@@ -150,9 +150,7 @@ func (ss *sqlStore) CreateSnapshot(ctx context.Context, snapshot cloudmigration.
if err := ss.encryptKey(ctx, &snapshot); err != nil {
return "", err
}
- if snapshot.Result == nil {
- snapshot.Result = make([]byte, 0)
- }
+
if snapshot.UID == "" {
snapshot.UID = util.GenerateShortUID()
}
@@ -181,38 +179,31 @@ func (ss *sqlStore) UpdateSnapshot(ctx context.Context, update cloudmigration.Up
}
err := ss.db.InTransaction(ctx, func(ctx context.Context) error {
// Update status if set
- if err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
- if update.Status != "" {
+ if update.Status != "" {
+ if err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
rawSQL := "UPDATE cloud_migration_snapshot SET status=? WHERE uid=?"
if _, err := sess.Exec(rawSQL, update.Status, update.UID); err != nil {
return fmt.Errorf("updating snapshot status for uid %s: %w", update.UID, err)
}
+ return nil
+ }); err != nil {
+ return err
}
- return nil
- }); err != nil {
- return err
}
- // Update result if set
- if err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
- if len(update.Result) > 0 {
- rawSQL := "UPDATE cloud_migration_snapshot SET result=? WHERE uid=?"
- if _, err := sess.Exec(rawSQL, update.Result, update.UID); err != nil {
- return fmt.Errorf("updating snapshot result for uid %s: %w", update.UID, err)
- }
+ // Update resources if set
+ if len(update.Resources) > 0 {
+ if err := ss.CreateUpdateSnapshotResources(ctx, update.UID, update.Resources); err != nil {
+ return err
}
- return nil
- }); err != nil {
- return err
}
-
return nil
})
return err
}
-func (ss *sqlStore) GetSnapshotByUID(ctx context.Context, uid string) (*cloudmigration.CloudMigrationSnapshot, error) {
+func (ss *sqlStore) GetSnapshotByUID(ctx context.Context, uid string, resultPage int, resultLimit int) (*cloudmigration.CloudMigrationSnapshot, error) {
var snapshot cloudmigration.CloudMigrationSnapshot
err := ss.db.WithDbSession(ctx, func(sess *db.Session) error {
exist, err := sess.Where("uid=?", uid).Get(&snapshot)
@@ -224,18 +215,28 @@ func (ss *sqlStore) GetSnapshotByUID(ctx context.Context, uid string) (*cloudmig
}
return nil
})
+ if err != nil {
+ return nil, err
+ }
if err := ss.decryptKey(ctx, &snapshot); err != nil {
return &snapshot, err
}
+ resources, err := ss.GetSnapshotResources(ctx, uid, resultPage, resultLimit)
+ if err == nil {
+ snapshot.Resources = resources
+ }
+
return &snapshot, err
}
+// GetSnapshotList returns snapshots without resources included. Use GetSnapshotByUID to get individual snapshot results.
func (ss *sqlStore) GetSnapshotList(ctx context.Context, query cloudmigration.ListSnapshotsQuery) ([]cloudmigration.CloudMigrationSnapshot, error) {
var snapshots = make([]cloudmigration.CloudMigrationSnapshot, 0)
err := ss.db.WithDbSession(ctx, func(sess *db.Session) error {
- sess.Limit(query.Limit, query.Offset)
+ offset := (query.Page - 1) * query.Limit
+ sess.Limit(query.Limit, offset)
return sess.Find(&snapshots, &cloudmigration.CloudMigrationSnapshot{
SessionUID: query.SessionUID,
})
@@ -252,6 +253,70 @@ func (ss *sqlStore) GetSnapshotList(ctx context.Context, query cloudmigration.Li
return snapshots, nil
}
+func (ss *sqlStore) CreateUpdateSnapshotResources(ctx context.Context, snapshotUid string, resources []cloudmigration.CloudMigrationResource) error {
+ // ensure snapshot_uids are consistent so that we can use them to query when uid isn't known
+ for i := 0; i < len(resources); i++ {
+ resources[i].SnapshotUID = snapshotUid
+ }
+
+ return ss.db.InTransaction(ctx, func(ctx context.Context) error {
+ sql := "UPDATE cloud_migration_resource SET status=?, error_string=? WHERE uid=? OR (snapshot_uid=? AND resource_uid=?)"
+ err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
+ for _, r := range resources {
+ // try an update first
+ result, err := sess.Exec(sql, r.Status, r.Error, r.UID, snapshotUid, r.RefID)
+ if err != nil {
+ return err
+ }
+ // if this had no effect, assign a uid and insert instead
+ n, err := result.RowsAffected()
+ if err != nil {
+ return err
+ } else if n == 0 {
+ r.UID = util.GenerateShortUID()
+ _, err := sess.Insert(r)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+ })
+ if err != nil {
+ return fmt.Errorf("updating resources: %w", err)
+ }
+
+ return nil
+ })
+}
+
+func (ss *sqlStore) GetSnapshotResources(ctx context.Context, snapshotUid string, page int, limit int) ([]cloudmigration.CloudMigrationResource, error) {
+ var resources []cloudmigration.CloudMigrationResource
+ if limit == 0 {
+ return resources, nil
+ }
+ err := ss.db.WithDbSession(ctx, func(sess *db.Session) error {
+ offset := (page - 1) * limit
+ sess.Limit(limit, offset)
+ return sess.Find(&resources, &cloudmigration.CloudMigrationResource{
+ SnapshotUID: snapshotUid,
+ })
+ })
+ if err != nil {
+ return nil, err
+ }
+ return resources, nil
+}
+
+func (ss *sqlStore) DeleteSnapshotResources(ctx context.Context, snapshotUid string) error {
+ return ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
+ _, err := sess.Delete(cloudmigration.CloudMigrationResource{
+ SnapshotUID: snapshotUid,
+ })
+ return err
+ })
+}
+
func (ss *sqlStore) encryptToken(ctx context.Context, cm *cloudmigration.CloudMigrationSession) error {
s, err := ss.secretsService.Encrypt(ctx, []byte(cm.AuthToken), secrets.WithoutScope())
if err != nil {
diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store_test.go b/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store_test.go
index 186033cc2c2..83b94ba9ecf 100644
--- a/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store_test.go
+++ b/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store_test.go
@@ -12,6 +12,7 @@ import (
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/tests/testsuite"
"github.com/grafana/grafana/pkg/util"
+ "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -111,10 +112,9 @@ func Test_CreateMigrationRun(t *testing.T) {
ctx := context.Background()
t.Run("creates a session run and retrieves it from db", func(t *testing.T) {
- result := []byte("OK")
cmr := cloudmigration.CloudMigrationSnapshot{
SessionUID: "asdfg",
- Result: result,
+ Status: cloudmigration.SnapshotStatusFinished,
}
createResp, err := s.CreateMigrationRun(ctx, cmr)
@@ -123,7 +123,7 @@ func Test_CreateMigrationRun(t *testing.T) {
getMRResp, err := s.GetMigrationStatus(ctx, createResp)
require.NoError(t, err)
- require.Equal(t, result, getMRResp.Result)
+ require.Equal(t, cmr.Status, getMRResp.Status)
})
}
@@ -181,7 +181,7 @@ func Test_SnapshotManagement(t *testing.T) {
require.NotEmpty(t, snapshotUid)
//retrieve it from the db
- snapshot, err := s.GetSnapshotByUID(ctx, snapshotUid)
+ snapshot, err := s.GetSnapshotByUID(ctx, snapshotUid, 0, 0)
require.NoError(t, err)
require.Equal(t, cloudmigration.SnapshotStatusInitializing, string(snapshot.Status))
@@ -190,18 +190,71 @@ func Test_SnapshotManagement(t *testing.T) {
require.NoError(t, err)
//retrieve it again
- snapshot, err = s.GetSnapshotByUID(ctx, snapshotUid)
+ snapshot, err = s.GetSnapshotByUID(ctx, snapshotUid, 0, 0)
require.NoError(t, err)
require.Equal(t, cloudmigration.SnapshotStatusCreating, string(snapshot.Status))
// lists snapshots and ensures it's in there
- snapshots, err := s.GetSnapshotList(ctx, cloudmigration.ListSnapshotsQuery{SessionUID: sessionUid, Offset: 0, Limit: 100})
+ snapshots, err := s.GetSnapshotList(ctx, cloudmigration.ListSnapshotsQuery{SessionUID: sessionUid, Page: 1, Limit: 100})
require.NoError(t, err)
require.Len(t, snapshots, 1)
require.Equal(t, *snapshot, snapshots[0])
})
}
+func Test_SnapshotResources(t *testing.T) {
+ _, s := setUpTest(t)
+ ctx := context.Background()
+
+ t.Run("tests CRUD of snapshot resources", func(t *testing.T) {
+ // Get the default rows from the test
+ resources, err := s.GetSnapshotResources(ctx, "poiuy", 0, 100)
+ assert.NoError(t, err)
+ assert.Len(t, resources, 3)
+
+ // create a new resource and update an existing resource
+ err = s.CreateUpdateSnapshotResources(ctx, "poiuy", []cloudmigration.CloudMigrationResource{
+ {
+ Type: cloudmigration.DatasourceDataType,
+ RefID: "mi39fj",
+ Status: cloudmigration.ItemStatusOK,
+ },
+ {
+ UID: "qwerty",
+ Status: cloudmigration.ItemStatusOK,
+ },
+ })
+ assert.NoError(t, err)
+
+ // Get resources again
+ resources, err = s.GetSnapshotResources(ctx, "poiuy", 0, 100)
+ assert.NoError(t, err)
+ assert.Len(t, resources, 4)
+ // ensure existing resource was updated
+ for _, r := range resources {
+ if r.UID == "querty" {
+ assert.Equal(t, cloudmigration.ItemStatusOK, r.Status)
+ break
+ }
+ }
+ // ensure a new one was made
+ for _, r := range resources {
+ if r.UID == "mi39fj" {
+ assert.Equal(t, cloudmigration.ItemStatusOK, r.Status)
+ break
+ }
+ }
+
+ // delete snapshot resources
+ err = s.DeleteSnapshotResources(ctx, "poiuy")
+ assert.NoError(t, err)
+ // make sure they're gone
+ resources, err = s.GetSnapshotResources(ctx, "poiuy", 0, 100)
+ assert.NoError(t, err)
+ assert.Len(t, resources, 0)
+ })
+}
+
func setUpTest(t *testing.T) (*sqlstore.SQLStore, *sqlStore) {
testDB := db.InitTestDB(t)
s := &sqlStore{
@@ -212,12 +265,12 @@ func setUpTest(t *testing.T) (*sqlstore.SQLStore, *sqlStore) {
// insert cloud migration test data
_, err := testDB.GetSqlxSession().Exec(ctx, `
- INSERT INTO
- cloud_migration_session (id, uid, auth_token, slug, stack_id, region_slug, cluster_slug, created, updated)
- VALUES
- (1,'qwerty', ?, '11111', 11111, 'test', 'test', '2024-03-25 15:30:36.000', '2024-03-27 15:30:43.000'),
- (2,'asdfgh', ?, '22222', 22222, 'test', 'test', '2024-03-25 15:30:36.000', '2024-03-27 15:30:43.000'),
- (3,'zxcvbn', ?, '33333', 33333, 'test', 'test', '2024-03-25 15:30:36.000', '2024-03-27 15:30:43.000');
+ INSERT INTO
+ cloud_migration_session (id, uid, auth_token, slug, stack_id, region_slug, cluster_slug, created, updated)
+ VALUES
+ (1,'qwerty', ?, '11111', 11111, 'test', 'test', '2024-03-25 15:30:36.000', '2024-03-27 15:30:43.000'),
+ (2,'asdfgh', ?, '22222', 22222, 'test', 'test', '2024-03-25 15:30:36.000', '2024-03-27 15:30:43.000'),
+ (3,'zxcvbn', ?, '33333', 33333, 'test', 'test', '2024-03-25 15:30:36.000', '2024-03-27 15:30:43.000');
`,
encodeToken("12345"),
encodeToken("6789"),
@@ -227,16 +280,25 @@ func setUpTest(t *testing.T) (*sqlstore.SQLStore, *sqlStore) {
// insert cloud migration run test data
_, err = testDB.GetSqlxSession().Exec(ctx, `
- INSERT INTO
- cloud_migration_snapshot (session_uid, uid, result, created, updated, finished, status)
- VALUES
- ('qwerty', 'poiuy', ?, '2024-03-25 15:30:36.000', '2024-03-27 15:30:43.000', '2024-03-27 15:30:43.000', "finished"),
- ('qwerty', 'lkjhg', ?, '2024-03-25 15:30:36.000', '2024-03-27 15:30:43.000', '2024-03-27 15:30:43.000', "finished"),
- ('zxcvbn', 'mnbvvc', ?, '2024-03-25 15:30:36.000', '2024-03-27 15:30:43.000', '2024-03-27 15:30:43.000', "finished");
- `,
- []byte("ERROR"),
- []byte("OK"),
- []byte("OK"),
+ INSERT INTO
+ cloud_migration_snapshot (session_uid, uid, created, updated, finished, status)
+ VALUES
+ ('qwerty', 'poiuy', '2024-03-25 15:30:36.000', '2024-03-27 15:30:43.000', '2024-03-27 15:30:43.000', "finished"),
+ ('qwerty', 'lkjhg', '2024-03-25 15:30:36.000', '2024-03-27 15:30:43.000', '2024-03-27 15:30:43.000', "finished"),
+ ('zxcvbn', 'mnbvvc', '2024-03-25 15:30:36.000', '2024-03-27 15:30:43.000', '2024-03-27 15:30:43.000', "finished");
+ `,
+ )
+ require.NoError(t, err)
+
+ _, err = testDB.GetSqlxSession().Exec(ctx, `
+ INSERT INTO
+ cloud_migration_resource (uid, snapshot_uid, resource_type, resource_uid, status, error_string)
+ VALUES
+ ('mnbvde', 'poiuy', 'DATASOURCE', 'jf38gh', 'OK', ''),
+ ('qwerty', 'poiuy', 'DASHBOARD', 'ejcx4d', 'ERROR', 'fake error'),
+ ('zxcvbn', 'poiuy', 'FOLDER', 'fi39fj', 'PENDING', ''),
+ ('4fi9sd', '39fi39', 'FOLDER', 'fi39fj', 'OK', '');
+ `,
)
require.NoError(t, err)
diff --git a/pkg/services/cloudmigration/gmsclient/gms_client.go b/pkg/services/cloudmigration/gmsclient/gms_client.go
index 428b39d4294..383fcabb8e2 100644
--- a/pkg/services/cloudmigration/gmsclient/gms_client.go
+++ b/pkg/services/cloudmigration/gmsclient/gms_client.go
@@ -137,10 +137,10 @@ func convertRequestToDTO(request cloudmigration.MigrateDataRequest) MigrateDataR
}
func convertResponseFromDTO(result MigrateDataResponseDTO) cloudmigration.MigrateDataResponse {
- items := make([]cloudmigration.MigrateDataResponseItem, len(result.Items))
+ items := make([]cloudmigration.CloudMigrationResource, len(result.Items))
for i := 0; i < len(result.Items); i++ {
item := result.Items[i]
- items[i] = cloudmigration.MigrateDataResponseItem{
+ items[i] = cloudmigration.CloudMigrationResource{
Type: cloudmigration.MigrateDataType(item.Type),
RefID: item.RefID,
Status: cloudmigration.ItemStatus(item.Status),
diff --git a/pkg/services/cloudmigration/gmsclient/inmemory_client.go b/pkg/services/cloudmigration/gmsclient/inmemory_client.go
index d2baa595f6f..3148fb109f1 100644
--- a/pkg/services/cloudmigration/gmsclient/inmemory_client.go
+++ b/pkg/services/cloudmigration/gmsclient/inmemory_client.go
@@ -2,7 +2,6 @@ package gmsclient
import (
"context"
- "encoding/json"
"math/rand"
"time"
@@ -29,11 +28,11 @@ func (c *memoryClientImpl) MigrateData(
request cloudmigration.MigrateDataRequest,
) (*cloudmigration.MigrateDataResponse, error) {
result := cloudmigration.MigrateDataResponse{
- Items: make([]cloudmigration.MigrateDataResponseItem, len(request.Items)),
+ Items: make([]cloudmigration.CloudMigrationResource, len(request.Items)),
}
for i, v := range request.Items {
- result.Items[i] = cloudmigration.MigrateDataResponseItem{
+ result.Items[i] = cloudmigration.CloudMigrationResource{
Type: v.Type,
RefID: v.RefID,
Status: cloudmigration.ItemStatusOK,
@@ -60,38 +59,32 @@ func (c *memoryClientImpl) InitializeSnapshot(context.Context, cloudmigration.Cl
}
func (c *memoryClientImpl) GetSnapshotStatus(ctx context.Context, session cloudmigration.CloudMigrationSession, snapshot cloudmigration.CloudMigrationSnapshot) (*cloudmigration.CloudMigrationSnapshot, error) {
- // just fake an entire response
- gmsSnapshot := cloudmigration.CloudMigrationSnapshot{
- Status: cloudmigration.SnapshotStatusFinished,
- GMSSnapshotUID: util.GenerateShortUID(),
- Result: []byte{},
- Finished: time.Now(),
- }
-
- result := []cloudmigration.MigrateDataResponseItem{
+ results := []cloudmigration.CloudMigrationResource{
{
Type: cloudmigration.DashboardDataType,
- RefID: util.GenerateShortUID(),
+ RefID: "dash1",
Status: cloudmigration.ItemStatusOK,
},
{
Type: cloudmigration.DatasourceDataType,
- RefID: util.GenerateShortUID(),
+ RefID: "ds1",
Status: cloudmigration.ItemStatusError,
Error: "fake error",
},
{
Type: cloudmigration.FolderDataType,
- RefID: util.GenerateShortUID(),
+ RefID: "folder1",
Status: cloudmigration.ItemStatusOK,
},
}
- b, err := json.Marshal(result)
- if err != nil {
- return nil, err
+ // just fake an entire response
+ gmsSnapshot := cloudmigration.CloudMigrationSnapshot{
+ Status: cloudmigration.SnapshotStatusFinished,
+ GMSSnapshotUID: "gmssnapshotuid",
+ Resources: results,
+ Finished: time.Now(),
}
- gmsSnapshot.Result = b
return &gmsSnapshot, nil
}
diff --git a/pkg/services/cloudmigration/model.go b/pkg/services/cloudmigration/model.go
index 3974af3a046..40904dd4d93 100644
--- a/pkg/services/cloudmigration/model.go
+++ b/pkg/services/cloudmigration/model.go
@@ -1,8 +1,6 @@
package cloudmigration
import (
- "encoding/json"
- "errors"
"time"
"github.com/grafana/grafana/pkg/apimachinery/errutil"
@@ -45,8 +43,8 @@ type CloudMigrationSnapshot struct {
Updated time.Time
Finished time.Time
- // []MigrateDataResponseItem
- Result []byte `xorm:"result"` //store raw gms response body
+ // Stored in the cloud_migration_resource table
+ Resources []CloudMigrationResource `xorm:"-"`
}
type SnapshotStatus string
@@ -63,14 +61,24 @@ const (
SnapshotStatusUnknown = "unknown"
)
+type CloudMigrationResource struct {
+ ID int64 `xorm:"pk autoincr 'id'"`
+ UID string `xorm:"uid"`
+
+ Type MigrateDataType `xorm:"resource_type"`
+ RefID string `xorm:"resource_uid"`
+ Status ItemStatus `xorm:"status"`
+ Error string `xorm:"error_string"`
+
+ SnapshotUID string `xorm:"snapshot_uid"`
+}
+
// Deprecated, use GetSnapshotResult for the async workflow
func (s CloudMigrationSnapshot) GetResult() (*MigrateDataResponse, error) {
- var result MigrateDataResponse
- err := json.Unmarshal(s.Result, &result)
- if err != nil {
- return nil, errors.New("could not parse result of run")
+ result := MigrateDataResponse{
+ RunUID: s.UID,
+ Items: s.Resources,
}
- result.RunUID = s.UID
return &result, nil
}
@@ -78,17 +86,6 @@ func (s CloudMigrationSnapshot) ShouldQueryGMS() bool {
return s.Status == SnapshotStatusPendingProcessing || s.Status == SnapshotStatusProcessing
}
-func (s CloudMigrationSnapshot) GetSnapshotResult() ([]MigrateDataResponseItem, error) {
- var result []MigrateDataResponseItem
- if len(s.Result) > 0 {
- err := json.Unmarshal(s.Result, &result)
- if err != nil {
- return nil, errors.New("could not parse result of run")
- }
- }
- return result, nil
-}
-
type CloudMigrationRunList struct {
Runs []MigrateDataResponseList
}
@@ -108,16 +105,23 @@ type CloudMigrationSessionListResponse struct {
Sessions []CloudMigrationSessionResponse
}
+type GetSnapshotsQuery struct {
+ SnapshotUID string
+ SessionUID string
+ ResultPage int
+ ResultLimit int
+}
+
type ListSnapshotsQuery struct {
SessionUID string
- Offset int
+ Page int
Limit int
}
type UpdateSnapshotCmd struct {
- UID string
- Status SnapshotStatus
- Result []byte //store raw gms response body
+ UID string
+ Status SnapshotStatus
+ Resources []CloudMigrationResource
}
// access token
@@ -172,26 +176,21 @@ type MigrateDataRequestItem struct {
type ItemStatus string
const (
- ItemStatusOK ItemStatus = "OK"
- ItemStatusError ItemStatus = "ERROR"
+ ItemStatusOK ItemStatus = "OK"
+ ItemStatusError ItemStatus = "ERROR"
+ ItemStatusPending ItemStatus = "PENDING"
+ ItemStatusUnknown ItemStatus = "UNKNOWN"
)
type MigrateDataResponse struct {
RunUID string
- Items []MigrateDataResponseItem
+ Items []CloudMigrationResource
}
type MigrateDataResponseList struct {
RunUID string
}
-type MigrateDataResponseItem struct {
- Type MigrateDataType
- RefID string
- Status ItemStatus
- Error string
-}
-
type CreateSessionResponse struct {
SnapshotUid string
}
diff --git a/pkg/services/dashboardsnapshots/database/database.go b/pkg/services/dashboardsnapshots/database/database.go
index 94a38fb9444..dcd71ccb55a 100644
--- a/pkg/services/dashboardsnapshots/database/database.go
+++ b/pkg/services/dashboardsnapshots/database/database.go
@@ -45,7 +45,7 @@ func (d *DashboardSnapshotStore) DeleteExpiredSnapshots(ctx context.Context, cmd
d.log.Warn("[Deprecated] The snapshot_remove_expired setting is outdated. Please remove from your config.")
return nil
}
- return d.store.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
+ return d.store.WithDbSession(ctx, func(sess *db.Session) error {
deleteExpiredSQL := "DELETE FROM dashboard_snapshot WHERE expires < ?"
expiredResponse, err := sess.Exec(deleteExpiredSQL, time.Now())
if err != nil {
@@ -59,7 +59,7 @@ func (d *DashboardSnapshotStore) DeleteExpiredSnapshots(ctx context.Context, cmd
func (d *DashboardSnapshotStore) CreateDashboardSnapshot(ctx context.Context, cmd *dashboardsnapshots.CreateDashboardSnapshotCommand) (*dashboardsnapshots.DashboardSnapshot, error) {
var result *dashboardsnapshots.DashboardSnapshot
- err := d.store.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
+ err := d.store.WithDbSession(ctx, func(sess *db.Session) error {
var expires = time.Now().Add(time.Hour * 24 * 365 * 50)
if cmd.Expires > 0 {
expires = time.Now().Add(time.Second * time.Duration(cmd.Expires))
@@ -92,7 +92,7 @@ func (d *DashboardSnapshotStore) CreateDashboardSnapshot(ctx context.Context, cm
}
func (d *DashboardSnapshotStore) DeleteDashboardSnapshot(ctx context.Context, cmd *dashboardsnapshots.DeleteDashboardSnapshotCommand) error {
- return d.store.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
+ return d.store.WithDbSession(ctx, func(sess *db.Session) error {
var rawSQL = "DELETE FROM dashboard_snapshot WHERE delete_key=?"
_, err := sess.Exec(rawSQL, cmd.DeleteKey)
return err
diff --git a/pkg/services/dashboardversion/dashverimpl/xorm_store.go b/pkg/services/dashboardversion/dashverimpl/xorm_store.go
index 63b9753850b..08b7d045b85 100644
--- a/pkg/services/dashboardversion/dashverimpl/xorm_store.go
+++ b/pkg/services/dashboardversion/dashverimpl/xorm_store.go
@@ -38,7 +38,7 @@ func (ss *sqlStore) Get(ctx context.Context, query *dashver.GetDashboardVersionQ
func (ss *sqlStore) GetBatch(ctx context.Context, cmd *dashver.DeleteExpiredVersionsCommand, perBatch int, versionsToKeep int) ([]any, error) {
var versionIds []any
- err := ss.db.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
+ err := ss.db.WithDbSession(ctx, func(sess *db.Session) error {
versionIdsToDeleteQuery := `SELECT id
FROM dashboard_version, (
SELECT dashboard_id, count(version) as count, min(version) as min
@@ -57,7 +57,7 @@ func (ss *sqlStore) GetBatch(ctx context.Context, cmd *dashver.DeleteExpiredVers
func (ss *sqlStore) DeleteBatch(ctx context.Context, cmd *dashver.DeleteExpiredVersionsCommand, versionIdsToDelete []any) (int64, error) {
var deleted int64
- err := ss.db.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
+ err := ss.db.WithDbSession(ctx, func(sess *db.Session) error {
deleteExpiredSQL := `DELETE FROM dashboard_version WHERE id IN (?` + strings.Repeat(",?", len(versionIdsToDelete)-1) + `)`
sqlOrArgs := append([]any{deleteExpiredSQL}, versionIdsToDelete...)
expiredResponse, err := sess.Exec(sqlOrArgs...)
diff --git a/pkg/services/folder/folderimpl/dashboard_folder_store.go b/pkg/services/folder/folderimpl/dashboard_folder_store.go
index f829d571adc..a7e5dbf2bb9 100644
--- a/pkg/services/folder/folderimpl/dashboard_folder_store.go
+++ b/pkg/services/folder/folderimpl/dashboard_folder_store.go
@@ -30,7 +30,7 @@ func (d *DashboardFolderStoreImpl) GetFolderByTitle(ctx context.Context, orgID i
metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Folder).Inc()
// nolint:staticcheck
dashboard := dashboards.Dashboard{OrgID: orgID, FolderID: 0, Title: title}
- err := d.store.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
+ err := d.store.WithDbSession(ctx, func(sess *db.Session) error {
s := sess.Table(&dashboards.Dashboard{}).Where("is_folder = " + d.store.GetDialect().BooleanStr(true))
if folderUID != nil {
s = s.Where("folder_uid = ?", *folderUID)
@@ -55,7 +55,7 @@ func (d *DashboardFolderStoreImpl) GetFolderByID(ctx context.Context, orgID int6
metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Folder).Inc()
// nolint:staticcheck
dashboard := dashboards.Dashboard{OrgID: orgID, FolderID: 0, ID: id}
- err := d.store.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
+ err := d.store.WithDbSession(ctx, func(sess *db.Session) error {
has, err := sess.Table(&dashboards.Dashboard{}).Where("is_folder = " + d.store.GetDialect().BooleanStr(true)).Get(&dashboard)
if err != nil {
return err
@@ -80,7 +80,7 @@ func (d *DashboardFolderStoreImpl) GetFolderByUID(ctx context.Context, orgID int
metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Folder).Inc()
// nolint:staticcheck
dashboard := dashboards.Dashboard{OrgID: orgID, FolderID: 0, UID: uid}
- err := d.store.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
+ err := d.store.WithDbSession(ctx, func(sess *db.Session) error {
has, err := sess.Table(&dashboards.Dashboard{}).Where("is_folder = " + d.store.GetDialect().BooleanStr(true)).Get(&dashboard)
if err != nil {
return err
diff --git a/pkg/services/ngalert/state/historian/loki.go b/pkg/services/ngalert/state/historian/loki.go
index fd163a3a806..fefbe48e462 100644
--- a/pkg/services/ngalert/state/historian/loki.go
+++ b/pkg/services/ngalert/state/historian/loki.go
@@ -12,6 +12,7 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/data"
"go.opentelemetry.io/otel/trace"
+ "github.com/grafana/grafana/pkg/apimachinery/errutil"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/tracing"
@@ -41,10 +42,30 @@ const (
const defaultQueryRange = 6 * time.Hour
+var (
+ ErrLokiQueryTooLong = errutil.BadRequest("loki.requestTooLong").MustTemplate(
+ "Request to Loki exceeded ({{.Public.QuerySize}} bytes) configured maximum size of {{.Public.MaxLimit}} bytes",
+ errutil.WithPublic("Query for Loki exceeded the configured limit of {{.Public.MaxLimit}} bytes. Remove some filters and try again."),
+ )
+)
+
+func NewErrLokiQueryTooLong(query string, maxLimit int) error {
+ return ErrLokiQueryTooLong.Build(errutil.TemplateData{
+ Private: map[string]any{
+ "query": query,
+ },
+ Public: map[string]any{
+ "MaxLimit": maxLimit,
+ "QuerySize": len(query),
+ },
+ })
+}
+
type remoteLokiClient interface {
Ping(context.Context) error
Push(context.Context, []Stream) error
RangeQuery(ctx context.Context, logQL string, start, end, limit int64) (QueryRes, error)
+ MaxQuerySize() int
}
// RemoteLokibackend is a state.Historian that records state history to an external Loki instance.
@@ -112,7 +133,7 @@ func (h *RemoteLokiBackend) Record(ctx context.Context, rule history_model.RuleM
// Query retrieves state history entries from an external Loki instance and formats the results into a dataframe.
func (h *RemoteLokiBackend) Query(ctx context.Context, query models.HistoryQuery) (*data.Frame, error) {
- logQL, err := BuildLogQuery(query)
+ logQL, err := BuildLogQuery(query, h.client.MaxQuerySize())
if err != nil {
return nil, err
}
@@ -366,7 +387,9 @@ func isValidOperator(op string) bool {
return false
}
-func BuildLogQuery(query models.HistoryQuery) (string, error) {
+// BuildLogQuery converts models.HistoryQuery and a list of folder UIDs to a Loki query.
+// Returns a Loki query or error if log query cannot be constructed. If user-defined query exceeds maximum allowed size returns ErrLokiQueryTooLong
+func BuildLogQuery(query models.HistoryQuery, maxQuerySize int) (string, error) {
selectors, err := buildSelectors(query)
if err != nil {
return "", fmt.Errorf("failed to build the provided selectors: %w", err)
@@ -400,6 +423,10 @@ func BuildLogQuery(query models.HistoryQuery) (string, error) {
}
logQL += labelFilters
+ if len(logQL) > maxQuerySize {
+ // if the query is too long even without filter by folders, then fail
+ return "", NewErrLokiQueryTooLong(logQL, maxQuerySize)
+ }
return logQL, nil
}
diff --git a/pkg/services/ngalert/state/historian/loki_http.go b/pkg/services/ngalert/state/historian/loki_http.go
index 2d9ca11ba13..3e8b94a1585 100644
--- a/pkg/services/ngalert/state/historian/loki_http.go
+++ b/pkg/services/ngalert/state/historian/loki_http.go
@@ -42,6 +42,7 @@ type LokiConfig struct {
ExternalLabels map[string]string
Encoder encoder
MaxQueryLength time.Duration
+ MaxQuerySize int
}
func NewLokiConfig(cfg setting.UnifiedAlertingStateHistorySettings) (LokiConfig, error) {
@@ -77,6 +78,7 @@ func NewLokiConfig(cfg setting.UnifiedAlertingStateHistorySettings) (LokiConfig,
TenantID: cfg.LokiTenantID,
ExternalLabels: cfg.ExternalLabels,
MaxQueryLength: cfg.LokiMaxQueryLength,
+ MaxQuerySize: cfg.LokiMaxQuerySize,
// Snappy-compressed protobuf is the default, same goes for Promtail.
Encoder: SnappyProtoEncoder{},
}, nil
@@ -281,6 +283,10 @@ func (c *HttpLokiClient) RangeQuery(ctx context.Context, logQL string, start, en
return result, nil
}
+func (c *HttpLokiClient) MaxQuerySize() int {
+ return c.cfg.MaxQuerySize
+}
+
type QueryRes struct {
Data QueryData `json:"data"`
}
diff --git a/pkg/services/ngalert/state/historian/loki_test.go b/pkg/services/ngalert/state/historian/loki_test.go
index dad1e0503a0..ac92673f06a 100644
--- a/pkg/services/ngalert/state/historian/loki_test.go
+++ b/pkg/services/ngalert/state/historian/loki_test.go
@@ -8,10 +8,15 @@ import (
"io"
"net/http"
"net/url"
+ "strings"
"testing"
"time"
"github.com/grafana/grafana-plugin-sdk-go/data"
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/testutil"
+ "github.com/stretchr/testify/require"
+
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/services/ngalert/client"
@@ -20,9 +25,6 @@ import (
"github.com/grafana/grafana/pkg/services/ngalert/models"
"github.com/grafana/grafana/pkg/services/ngalert/state"
history_model "github.com/grafana/grafana/pkg/services/ngalert/state/historian/model"
- "github.com/prometheus/client_golang/prometheus"
- "github.com/prometheus/client_golang/prometheus/testutil"
- "github.com/stretchr/testify/require"
)
func TestRemoteLokiBackend(t *testing.T) {
@@ -214,81 +216,110 @@ func TestRemoteLokiBackend(t *testing.T) {
selector, err = NewSelector("label", "invalid", "value")
require.Error(t, err)
})
+}
- t.Run("buildLogQuery", func(t *testing.T) {
- cases := []struct {
- name string
- query models.HistoryQuery
- exp string
- }{
- {
- name: "default includes state history label and orgID label",
- query: models.HistoryQuery{},
- exp: `{orgID="0",from="state-history"}`,
+func TestBuildLogQuery(t *testing.T) {
+ maxQuerySize := 110
+ cases := []struct {
+ name string
+ query models.HistoryQuery
+ exp string
+ expErr error
+ }{
+ {
+ name: "default includes state history label and orgID label",
+ query: models.HistoryQuery{},
+ exp: `{orgID="0",from="state-history"}`,
+ },
+ {
+ name: "adds stream label filter for orgID",
+ query: models.HistoryQuery{
+ OrgID: 123,
},
- {
- name: "adds stream label filter for orgID",
- query: models.HistoryQuery{
- OrgID: 123,
+ exp: `{orgID="123",from="state-history"}`,
+ },
+ {
+ name: "filters ruleUID in log line",
+ query: models.HistoryQuery{
+ OrgID: 123,
+ RuleUID: "rule-uid",
+ },
+ exp: `{orgID="123",from="state-history"} | json | ruleUID="rule-uid"`,
+ },
+ {
+ name: "filters dashboardUID in log line",
+ query: models.HistoryQuery{
+ OrgID: 123,
+ DashboardUID: "dash-uid",
+ },
+ exp: `{orgID="123",from="state-history"} | json | dashboardUID="dash-uid"`,
+ },
+ {
+ name: "filters panelID in log line",
+ query: models.HistoryQuery{
+ OrgID: 123,
+ PanelID: 456,
+ },
+ exp: `{orgID="123",from="state-history"} | json | panelID=456`,
+ },
+ {
+ name: "filters instance labels in log line",
+ query: models.HistoryQuery{
+ OrgID: 123,
+ Labels: map[string]string{
+ "customlabel": "customvalue",
+ "labeltwo": "labelvaluetwo",
},
- exp: `{orgID="123",from="state-history"}`,
},
- {
- name: "filters ruleUID in log line",
- query: models.HistoryQuery{
- OrgID: 123,
- RuleUID: "rule-uid",
+ exp: `{orgID="123",from="state-history"} | json | labels_customlabel="customvalue" | labels_labeltwo="labelvaluetwo"`,
+ },
+ {
+ name: "filters both instance labels + ruleUID",
+ query: models.HistoryQuery{
+ OrgID: 123,
+ RuleUID: "rule-uid",
+ Labels: map[string]string{
+ "customlabel": "customvalue",
},
- exp: `{orgID="123",from="state-history"} | json | ruleUID="rule-uid"`,
},
- {
- name: "filters dashboardUID in log line",
- query: models.HistoryQuery{
- OrgID: 123,
- DashboardUID: "dash-uid",
+ exp: `{orgID="123",from="state-history"} | json | ruleUID="rule-uid" | labels_customlabel="customvalue"`,
+ },
+ {
+ name: "should return if query does not exceed max limit",
+ query: models.HistoryQuery{
+ OrgID: 123,
+ RuleUID: "rule-uid",
+ Labels: map[string]string{
+ "customlabel": strings.Repeat("!", 24),
},
- exp: `{orgID="123",from="state-history"} | json | dashboardUID="dash-uid"`,
},
- {
- name: "filters panelID in log line",
- query: models.HistoryQuery{
- OrgID: 123,
- PanelID: 456,
+ exp: `{orgID="123",from="state-history"} | json | ruleUID="rule-uid" | labels_customlabel="!!!!!!!!!!!!!!!!!!!!!!!!"`,
+ },
+ {
+ name: "should return error if query is too long",
+ query: models.HistoryQuery{
+ OrgID: 123,
+ RuleUID: "rule-uid",
+ Labels: map[string]string{
+ "customlabel": strings.Repeat("!", 25),
},
- exp: `{orgID="123",from="state-history"} | json | panelID=456`,
},
- {
- name: "filters instance labels in log line",
- query: models.HistoryQuery{
- OrgID: 123,
- Labels: map[string]string{
- "customlabel": "customvalue",
- "labeltwo": "labelvaluetwo",
- },
- },
- exp: `{orgID="123",from="state-history"} | json | labels_customlabel="customvalue" | labels_labeltwo="labelvaluetwo"`,
- },
- {
- name: "filters both instance labels + ruleUID",
- query: models.HistoryQuery{
- OrgID: 123,
- RuleUID: "rule-uid",
- Labels: map[string]string{
- "customlabel": "customvalue",
- },
- },
- exp: `{orgID="123",from="state-history"} | json | ruleUID="rule-uid" | labels_customlabel="customvalue"`,
- },
- }
+ expErr: ErrLokiQueryTooLong,
+ },
+ }
- for _, tc := range cases {
- t.Run(tc.name, func(t *testing.T) {
- res, err := BuildLogQuery(tc.query)
- require.NoError(t, err)
- require.Equal(t, tc.exp, res)
- })
- }
- })
+ for _, tc := range cases {
+ t.Run(tc.name, func(t *testing.T) {
+ res, err := BuildLogQuery(tc.query, maxQuerySize)
+ if tc.expErr != nil {
+ require.ErrorIs(t, err, tc.expErr)
+ return
+ }
+ require.LessOrEqual(t, len(res), maxQuerySize)
+ require.NoError(t, err)
+ require.Equal(t, tc.exp, res)
+ })
+ }
}
func TestMerge(t *testing.T) {
diff --git a/pkg/services/ngalert/state/manager_private_test.go b/pkg/services/ngalert/state/manager_private_test.go
index 6f2993d6d88..322f649bdda 100644
--- a/pkg/services/ngalert/state/manager_private_test.go
+++ b/pkg/services/ngalert/state/manager_private_test.go
@@ -3521,6 +3521,123 @@ func TestProcessEvalResults_StateTransitions(t *testing.T) {
},
},
},
+ {
+ desc: "t1[QueryError] t2[GenericError] at t1, t2",
+
+ results: map[time.Time]eval.Results{
+ t1: {
+ newResult(eval.WithError(datasourceError)),
+ },
+ t2: {
+ newResult(eval.WithError(genericError)),
+ },
+ },
+ expectedTransitions: map[ngmodels.ExecutionErrorState]map[time.Time][]StateTransition{
+ ngmodels.ErrorErrState: {
+ t1: {
+ {
+ PreviousState: eval.Normal,
+ State: &State{
+ CacheID: labels["system + rule"].Fingerprint(),
+ Labels: labels["system + rule + datasource-error"],
+ State: eval.Error,
+ Error: datasourceError,
+ LatestResult: newEvaluation(t1, eval.Error),
+ StartsAt: t1,
+ EndsAt: t1.Add(ResendDelay * 4),
+ LastEvaluationTime: t1,
+ Annotations: mergeLabels(baseRule.Annotations, data.Labels{
+ "Error": datasourceError.Error(),
+ }),
+ },
+ },
+ },
+ t2: {
+ {
+ PreviousState: eval.Error,
+ State: &State{
+ CacheID: labels["system + rule"].Fingerprint(),
+ Labels: labels["system + rule + datasource-error"],
+ State: eval.Error,
+ Error: genericError,
+ LatestResult: newEvaluation(t2, eval.Error),
+ StartsAt: t1,
+ EndsAt: t2.Add(ResendDelay * 4),
+ LastEvaluationTime: t2,
+ Annotations: mergeLabels(baseRule.Annotations, data.Labels{
+ "Error": genericError.Error(),
+ }),
+ },
+ },
+ },
+ },
+ ngmodels.AlertingErrState: {
+ t1: {
+ {
+ PreviousState: eval.Normal,
+ State: &State{
+ Labels: labels["system + rule"],
+ State: eval.Alerting,
+ StateReason: eval.Error.String(),
+ Error: datasourceError,
+ LatestResult: newEvaluation(t1, eval.Error),
+ StartsAt: t1,
+ EndsAt: t1.Add(ResendDelay * 4),
+ LastEvaluationTime: t1,
+ },
+ },
+ },
+ t2: {
+ {
+ PreviousState: eval.Alerting,
+ PreviousStateReason: eval.Error.String(),
+ State: &State{
+ Labels: labels["system + rule"],
+ State: eval.Alerting,
+ StateReason: eval.Error.String(),
+ Error: genericError,
+ LatestResult: newEvaluation(t2, eval.Error),
+ StartsAt: t1,
+ EndsAt: t2.Add(ResendDelay * 4),
+ LastEvaluationTime: t2,
+ },
+ },
+ },
+ },
+ ngmodels.OkErrState: {
+ t1: {
+ {
+ PreviousState: eval.Normal,
+ State: &State{
+ Labels: labels["system + rule"],
+ State: eval.Normal,
+ StateReason: eval.Error.String(),
+ LatestResult: newEvaluation(t1, eval.Error),
+ StartsAt: t1,
+ EndsAt: t1,
+ LastEvaluationTime: t1,
+ },
+ },
+ },
+ },
+ ngmodels.KeepLastErrState: {
+ t1: {
+ {
+ PreviousState: eval.Normal,
+ State: &State{
+ Labels: labels["system + rule"],
+ State: eval.Normal,
+ StateReason: ngmodels.ConcatReasons(eval.Error.String(), ngmodels.StateReasonKeepLast),
+ LatestResult: newEvaluation(t1, eval.Error),
+ StartsAt: t1,
+ EndsAt: t1,
+ LastEvaluationTime: t1,
+ },
+ },
+ },
+ },
+ },
+ },
}
for _, tc := range testCases {
diff --git a/pkg/services/ngalert/state/manager_test.go b/pkg/services/ngalert/state/manager_test.go
index b31eab7402d..50954c2dd92 100644
--- a/pkg/services/ngalert/state/manager_test.go
+++ b/pkg/services/ngalert/state/manager_test.go
@@ -1244,6 +1244,7 @@ func TestProcessEvalResults(t *testing.T) {
EndsAt: tn(6).Add(state.ResendDelay * 4),
LastEvaluationTime: tn(6),
LastSentAt: util.Pointer(tn(6)), // After 30s resend delay, last sent at is t6.
+ Annotations: map[string]string{"annotation": "test", "Error": "with_state_error"},
},
},
},
diff --git a/pkg/services/ngalert/state/state.go b/pkg/services/ngalert/state/state.go
index 260dd92aeef..ea48dd2f616 100644
--- a/pkg/services/ngalert/state/state.go
+++ b/pkg/services/ngalert/state/state.go
@@ -141,6 +141,28 @@ func (a *State) Maintain(interval int64, evaluatedAt time.Time) {
a.EndsAt = nextEndsTime(interval, evaluatedAt)
}
+// AddErrorAnnotations adds annotations to the state to indicate that an error occurred.
+func (a *State) AddErrorAnnotations(err error, rule *models.AlertRule) {
+ if err == nil {
+ return
+ }
+
+ a.Annotations["Error"] = err.Error()
+ // If the evaluation failed because a query returned an error then add the Ref ID and
+ // Datasource UID as labels
+ var utilError errutil.Error
+ if errors.As(a.Error, &utilError) &&
+ (errors.Is(a.Error, expr.QueryError) || errors.Is(a.Error, expr.ConversionError)) {
+ for _, next := range rule.Data {
+ if next.RefID == utilError.PublicPayload["refId"].(string) {
+ a.Labels["ref_id"] = next.RefID
+ a.Labels["datasource_uid"] = next.DatasourceUID
+ break
+ }
+ }
+ }
+}
+
// IsNormalStateWithNoReason returns true if the state is Normal and reason is empty
func IsNormalStateWithNoReason(s *State) bool {
return s.State == eval.Normal && s.StateReason == ""
@@ -272,6 +294,8 @@ func resultError(state *State, rule *models.AlertRule, result eval.Result, logge
case models.ErrorErrState:
if state.State == eval.Error {
prevEndsAt := state.EndsAt
+ state.Error = result.Error
+ state.AddErrorAnnotations(result.Error, rule)
state.Maintain(rule.IntervalSeconds, result.EvaluatedAt)
logger.Debug("Keeping state",
"state",
@@ -293,23 +317,7 @@ func resultError(state *State, rule *models.AlertRule, result eval.Result, logge
"next_ends_at",
nextEndsAt)
state.SetError(result.Error, result.EvaluatedAt, nextEndsAt)
-
- if result.Error != nil {
- state.Annotations["Error"] = result.Error.Error()
- // If the evaluation failed because a query returned an error then add the Ref ID and
- // Datasource UID as labels
- var utilError errutil.Error
- if errors.As(state.Error, &utilError) &&
- (errors.Is(state.Error, expr.QueryError) || errors.Is(state.Error, expr.ConversionError)) {
- for _, next := range rule.Data {
- if next.RefID == utilError.PublicPayload["refId"].(string) {
- state.Labels["ref_id"] = next.RefID
- state.Labels["datasource_uid"] = next.DatasourceUID
- break
- }
- }
- }
- }
+ state.AddErrorAnnotations(result.Error, rule)
}
case models.OkErrState:
logger.Debug("Execution error state is Normal", "handler", "resultNormal", "previous_handler", handlerStr)
diff --git a/pkg/services/preference/prefimpl/xorm_store.go b/pkg/services/preference/prefimpl/xorm_store.go
index eadcb81a749..286abd57885 100644
--- a/pkg/services/preference/prefimpl/xorm_store.go
+++ b/pkg/services/preference/prefimpl/xorm_store.go
@@ -63,7 +63,7 @@ func (s *sqlStore) List(ctx context.Context, query *pref.Preference) ([]*pref.Pr
}
func (s *sqlStore) Update(ctx context.Context, cmd *pref.Preference) error {
- return s.db.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
+ return s.db.WithDbSession(ctx, func(sess *db.Session) error {
_, err := sess.ID(cmd.ID).AllCols().Update(cmd)
return err
})
@@ -72,7 +72,7 @@ func (s *sqlStore) Update(ctx context.Context, cmd *pref.Preference) error {
func (s *sqlStore) Insert(ctx context.Context, cmd *pref.Preference) (int64, error) {
var ID int64
var err error
- err = s.db.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
+ err = s.db.WithDbSession(ctx, func(sess *db.Session) error {
_, err = sess.Insert(cmd)
ID = cmd.ID
return err
diff --git a/pkg/services/queryhistory/database.go b/pkg/services/queryhistory/database.go
index a6357d48014..536ab9aa95a 100644
--- a/pkg/services/queryhistory/database.go
+++ b/pkg/services/queryhistory/database.go
@@ -137,7 +137,7 @@ func (s QueryHistoryService) patchQueryComment(ctx context.Context, user *user.S
var queryHistory QueryHistory
var isStarred bool
- err := s.store.WithTransactionalDbSession(ctx, func(session *db.Session) error {
+ err := s.store.WithDbSession(ctx, func(session *db.Session) error {
exists, err := session.Where("org_id = ? AND created_by = ? AND uid = ?", user.OrgID, user.UserID, UID).Get(&queryHistory)
if err != nil {
return err
@@ -182,7 +182,7 @@ func (s QueryHistoryService) starQuery(ctx context.Context, user *user.SignedInU
var queryHistory QueryHistory
var isStarred bool
- err := s.store.WithTransactionalDbSession(ctx, func(session *db.Session) error {
+ err := s.store.WithDbSession(ctx, func(session *db.Session) error {
// Check if query exists as we want to star only existing queries
exists, err := session.Table("query_history").Where("org_id = ? AND created_by = ? AND uid = ?", user.OrgID, user.UserID, UID).Get(&queryHistory)
if err != nil {
@@ -232,7 +232,7 @@ func (s QueryHistoryService) unstarQuery(ctx context.Context, user *user.SignedI
var queryHistory QueryHistory
var isStarred bool
- err := s.store.WithTransactionalDbSession(ctx, func(session *db.Session) error {
+ err := s.store.WithDbSession(ctx, func(session *db.Session) error {
exists, err := session.Table("query_history").Where("org_id = ? AND created_by = ? AND uid = ?", user.OrgID, user.UserID, UID).Get(&queryHistory)
if err != nil {
return err
@@ -312,7 +312,7 @@ func (s QueryHistoryService) deleteStaleQueries(ctx context.Context, olderThan i
func (s QueryHistoryService) enforceQueryHistoryRowLimit(ctx context.Context, limit int, starredQueries bool) (int, error) {
var deletedRowsCount int64
- err := s.store.WithTransactionalDbSession(ctx, func(session *db.Session) error {
+ err := s.store.WithDbSession(ctx, func(session *db.Session) error {
var rowsCount int64
var err error
if starredQueries {
diff --git a/pkg/services/serviceaccounts/database/store.go b/pkg/services/serviceaccounts/database/store.go
index b99925c9978..381470048e5 100644
--- a/pkg/services/serviceaccounts/database/store.go
+++ b/pkg/services/serviceaccounts/database/store.go
@@ -185,7 +185,7 @@ func (s *ServiceAccountsStoreImpl) deleteServiceAccount(sess *db.Session, orgId,
// EnableServiceAccount enable/disable service account
func (s *ServiceAccountsStoreImpl) EnableServiceAccount(ctx context.Context, orgID, serviceAccountID int64, enable bool) error {
- return s.sqlStore.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
+ return s.sqlStore.WithDbSession(ctx, func(sess *db.Session) error {
query := "UPDATE " + s.sqlStore.GetDialect().Quote("user") + " SET is_disabled = ? WHERE id = ? AND is_service_account = ?"
_, err := sess.Exec(query, !enable, serviceAccountID, true)
return err
diff --git a/pkg/services/sqlstore/migrations/cloud_migrations.go b/pkg/services/sqlstore/migrations/cloud_migrations.go
index db134e268cc..b64eb59d69e 100644
--- a/pkg/services/sqlstore/migrations/cloud_migrations.go
+++ b/pkg/services/sqlstore/migrations/cloud_migrations.go
@@ -139,4 +139,23 @@ func addCloudMigrationsMigrations(mg *Migrator) {
errorStringColumn := Column{Name: "error_string", Type: DB_Text, Nullable: true}
mg.AddMigration("add snapshot error_string column", NewAddColumnMigration(migrationSnapshotTable, &errorStringColumn))
+
+ // --- create table for tracking resource migrations
+ migrationResourceTable := Table{
+ Name: "cloud_migration_resource",
+ Columns: []*Column{
+ {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
+ {Name: "uid", Type: DB_NVarchar, Length: 40, Nullable: false},
+ {Name: "resource_type", Type: DB_NVarchar, Length: 40, Nullable: false},
+ {Name: "resource_uid", Type: DB_NVarchar, Length: 40, Nullable: false},
+ {Name: "status", Type: DB_NVarchar, Length: 20, Nullable: false},
+ {Name: "error_string", Type: DB_Text, Nullable: true},
+ {Name: "snapshot_uid", Type: DB_NVarchar, Length: 40, Nullable: false},
+ },
+ }
+
+ mg.AddMigration("create cloud_migration_resource table v1", NewAddTableMigration(migrationResourceTable))
+
+ // -- delete the snapshot result column while still in the experimental phase
+ mg.AddMigration("delete cloud_migration_snapshot.result column", NewRawSQLMigration("ALTER TABLE cloud_migration_snapshot DROP COLUMN result"))
}
diff --git a/pkg/services/ssosettings/strategies/saml_strategy.go b/pkg/services/ssosettings/strategies/saml_strategy.go
index fa37bb6b46b..e6e820474fc 100644
--- a/pkg/services/ssosettings/strategies/saml_strategy.go
+++ b/pkg/services/ssosettings/strategies/saml_strategy.go
@@ -63,6 +63,10 @@ func (s *SAMLStrategy) loadSAMLSettings() map[string]any {
"role_values_grafana_admin": section.KeyValue("role_values_grafana_admin").MustString(""),
"name_id_format": section.KeyValue("name_id_format").MustString(""),
"skip_org_role_sync": section.KeyValue("skip_org_role_sync").MustBool(false),
+ "client_id": section.KeyValue("client_id").MustString(""),
+ "client_secret": section.KeyValue("client_secret").MustString(""),
+ "token_url": section.KeyValue("token_url").MustString(""),
+ "force_use_graph_api": section.KeyValue("force_use_graph_api").MustBool(false),
}
return result
}
diff --git a/pkg/services/ssosettings/strategies/saml_strategy_test.go b/pkg/services/ssosettings/strategies/saml_strategy_test.go
index 489a3f1e7a7..fb61b54893e 100644
--- a/pkg/services/ssosettings/strategies/saml_strategy_test.go
+++ b/pkg/services/ssosettings/strategies/saml_strategy_test.go
@@ -45,6 +45,10 @@ var (
name_id_format = urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
skip_org_role_sync = false
role_values_none = guest disabled
+ token_url = http://localhost:8086/auth/realms/grafana/protocol/openid-connect/token
+ client_id = grafana
+ client_secret = grafana
+ force_use_graph_api = false
`
expectedSAMLInfo = map[string]any{
@@ -79,6 +83,10 @@ var (
"name_id_format": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
"skip_org_role_sync": false,
"role_values_none": "guest disabled",
+ "token_url": "http://localhost:8086/auth/realms/grafana/protocol/openid-connect/token",
+ "client_id": "grafana",
+ "client_secret": "grafana",
+ "force_use_graph_api": false,
}
)
diff --git a/pkg/services/temp_user/tempuserimpl/store.go b/pkg/services/temp_user/tempuserimpl/store.go
index ca6b14dc2b8..420ee61e710 100644
--- a/pkg/services/temp_user/tempuserimpl/store.go
+++ b/pkg/services/temp_user/tempuserimpl/store.go
@@ -26,7 +26,7 @@ type xormStore struct {
}
func (ss *xormStore) UpdateTempUserStatus(ctx context.Context, cmd *tempuser.UpdateTempUserStatusCommand) error {
- return ss.db.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
+ return ss.db.WithDbSession(ctx, func(sess *db.Session) error {
var rawSQL = "UPDATE temp_user SET status=? WHERE code=?"
_, err := sess.Exec(rawSQL, string(cmd.Status), cmd.Code)
return err
@@ -35,7 +35,7 @@ func (ss *xormStore) UpdateTempUserStatus(ctx context.Context, cmd *tempuser.Upd
func (ss *xormStore) CreateTempUser(ctx context.Context, cmd *tempuser.CreateTempUserCommand) (*tempuser.TempUser, error) {
var queryResult *tempuser.TempUser
- err := ss.db.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
+ err := ss.db.WithDbSession(ctx, func(sess *db.Session) error {
// create user
user := &tempuser.TempUser{
Email: cmd.Email,
@@ -66,7 +66,7 @@ func (ss *xormStore) CreateTempUser(ctx context.Context, cmd *tempuser.CreateTem
}
func (ss *xormStore) UpdateTempUserWithEmailSent(ctx context.Context, cmd *tempuser.UpdateTempUserWithEmailSentCommand) error {
- return ss.db.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
+ return ss.db.WithDbSession(ctx, func(sess *db.Session) error {
user := &tempuser.TempUser{
EmailSent: true,
EmailSentOn: time.Now(),
@@ -164,7 +164,7 @@ func (ss *xormStore) GetTempUserByCode(ctx context.Context, query *tempuser.GetT
}
func (ss *xormStore) ExpireOldUserInvites(ctx context.Context, cmd *tempuser.ExpireTempUsersCommand) error {
- return ss.db.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
+ return ss.db.WithDbSession(ctx, func(sess *db.Session) error {
var rawSQL = "UPDATE temp_user SET status = ?, updated = ? WHERE created <= ? AND status in (?, ?)"
if result, err := sess.Exec(rawSQL, string(tempuser.TmpUserExpired), time.Now().Unix(), cmd.OlderThan.Unix(), string(tempuser.TmpUserSignUpStarted), string(tempuser.TmpUserInvitePending)); err != nil {
return err
@@ -176,7 +176,7 @@ func (ss *xormStore) ExpireOldUserInvites(ctx context.Context, cmd *tempuser.Exp
}
func (ss *xormStore) ExpireOldVerifications(ctx context.Context, cmd *tempuser.ExpireTempUsersCommand) error {
- return ss.db.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
+ return ss.db.WithDbSession(ctx, func(sess *db.Session) error {
var rawSQL = "UPDATE temp_user SET status = ?, updated = ? WHERE created <= ? AND status = ?"
if result, err := sess.Exec(rawSQL, string(tempuser.TmpUserEmailUpdateExpired), time.Now().Unix(), cmd.OlderThan.Unix(), string(tempuser.TmpUserEmailUpdateStarted)); err != nil {
return err
@@ -188,7 +188,7 @@ func (ss *xormStore) ExpireOldVerifications(ctx context.Context, cmd *tempuser.E
}
func (ss *xormStore) ExpirePreviousVerifications(ctx context.Context, cmd *tempuser.ExpirePreviousVerificationsCommand) error {
- return ss.db.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
+ return ss.db.WithDbSession(ctx, func(sess *db.Session) error {
var rawSQL = "UPDATE temp_user SET status = ?, updated = ? WHERE invited_by_user_id = ? AND status = ?"
if result, err := sess.Exec(rawSQL, string(tempuser.TmpUserEmailUpdateExpired), time.Now().Unix(), cmd.InvitedByUserID, string(tempuser.TmpUserEmailUpdateStarted)); err != nil {
return err
diff --git a/pkg/services/user/userimpl/store.go b/pkg/services/user/userimpl/store.go
index 16a5876928d..1a722e6c92b 100644
--- a/pkg/services/user/userimpl/store.go
+++ b/pkg/services/user/userimpl/store.go
@@ -52,7 +52,7 @@ func ProvideStore(db db.DB, cfg *setting.Cfg) sqlStore {
func (ss *sqlStore) Insert(ctx context.Context, cmd *user.User) (int64, error) {
var err error
- err = ss.db.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
+ err = ss.db.WithDbSession(ctx, func(sess *db.Session) error {
sess.UseBool("is_admin")
if cmd.UID == "" {
cmd.UID = util.GenerateShortUID()
@@ -416,7 +416,7 @@ func validateOneAdminLeft(sess *db.Session) error {
}
func (ss *sqlStore) BatchDisableUsers(ctx context.Context, cmd *user.BatchDisableUsersCommand) error {
- return ss.db.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
+ return ss.db.WithDbSession(ctx, func(sess *db.Session) error {
userIds := cmd.UserIDs
if len(userIds) == 0 {
diff --git a/pkg/setting/setting_unified_alerting.go b/pkg/setting/setting_unified_alerting.go
index 1d205dc6faa..0f6a199bf5f 100644
--- a/pkg/setting/setting_unified_alerting.go
+++ b/pkg/setting/setting_unified_alerting.go
@@ -64,6 +64,7 @@ const (
stateHistoryDefaultEnabled = true
lokiDefaultMaxQueryLength = 721 * time.Hour // 30d1h, matches the default value in Loki
defaultRecordingRequestTimeout = 10 * time.Second
+ lokiDefaultMaxQuerySize = 65536 // 64kb
)
type UnifiedAlertingSettings struct {
@@ -160,6 +161,7 @@ type UnifiedAlertingStateHistorySettings struct {
LokiBasicAuthPassword string
LokiBasicAuthUsername string
LokiMaxQueryLength time.Duration
+ LokiMaxQuerySize int
MultiPrimary string
MultiSecondaries []string
ExternalLabels map[string]string
@@ -404,6 +406,7 @@ func (cfg *Cfg) ReadUnifiedAlertingSettings(iniFile *ini.File) error {
LokiBasicAuthUsername: stateHistory.Key("loki_basic_auth_username").MustString(""),
LokiBasicAuthPassword: stateHistory.Key("loki_basic_auth_password").MustString(""),
LokiMaxQueryLength: stateHistory.Key("loki_max_query_length").MustDuration(lokiDefaultMaxQueryLength),
+ LokiMaxQuerySize: stateHistory.Key("loki_max_query_size").MustInt(lokiDefaultMaxQuerySize),
MultiPrimary: stateHistory.Key("primary").MustString(""),
MultiSecondaries: splitTrim(stateHistory.Key("secondaries").MustString(""), ","),
ExternalLabels: stateHistoryLabels.KeysHash(),
diff --git a/public/api-enterprise-spec.json b/public/api-enterprise-spec.json
index de6c19c50b7..a2c5df56352 100644
--- a/public/api-enterprise-spec.json
+++ b/public/api-enterprise-spec.json
@@ -5382,7 +5382,9 @@
"type": "string",
"enum": [
"OK",
- "ERROR"
+ "ERROR",
+ "PENDING",
+ "UNKNOWN"
]
},
"type": {
diff --git a/public/api-merged.json b/public/api-merged.json
index 4a114b3fee3..e4aa026504a 100644
--- a/public/api-merged.json
+++ b/public/api-merged.json
@@ -2564,6 +2564,22 @@
"summary": "Get metadata about a snapshot, including where it is in its processing and final results.",
"operationId": "getSnapshot",
"parameters": [
+ {
+ "type": "integer",
+ "format": "int64",
+ "default": 1,
+ "description": "ResultPage is used for pagination with ResultLimit",
+ "name": "resultPage",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "format": "int64",
+ "default": 100,
+ "description": "Max limit for snapshot results returned.",
+ "name": "resultLimit",
+ "in": "query"
+ },
{
"type": "string",
"description": "Session UID of a session",
@@ -2694,9 +2710,9 @@
{
"type": "integer",
"format": "int64",
- "default": 0,
- "description": "Offset is used for pagination with limit",
- "name": "offset",
+ "default": 1,
+ "description": "Page is used for pagination with limit",
+ "name": "page",
"in": "query"
},
{
@@ -16874,7 +16890,9 @@
"type": "string",
"enum": [
"OK",
- "ERROR"
+ "ERROR",
+ "PENDING",
+ "UNKNOWN"
]
},
"type": {
diff --git a/public/app/AppWrapper.tsx b/public/app/AppWrapper.tsx
index 1e785c2cd4a..7c0997d7cea 100644
--- a/public/app/AppWrapper.tsx
+++ b/public/app/AppWrapper.tsx
@@ -1,5 +1,5 @@
import { Action, KBarProvider } from 'kbar';
-import React, { ComponentType } from 'react';
+import { Component, ComponentType } from 'react';
import { Provider } from 'react-redux';
import { Router, Redirect, Switch, RouteComponentProps } from 'react-router-dom';
import { CompatRouter, CompatRoute } from 'react-router-dom-v5-compat';
@@ -42,7 +42,7 @@ export function addPageBanner(fn: ComponentType) {
pageBanners.push(fn);
}
-export class AppWrapper extends React.Component {
+export class AppWrapper extends Component {
constructor(props: AppWrapperProps) {
super(props);
this.state = {};
diff --git a/public/app/angular/AngularRoot.tsx b/public/app/angular/AngularRoot.tsx
index ec3964a7b86..d780685c97c 100644
--- a/public/app/angular/AngularRoot.tsx
+++ b/public/app/angular/AngularRoot.tsx
@@ -1,6 +1,6 @@
-import React from 'react';
+import { forwardRef } from 'react';
-export const AngularRoot = React.forwardRef((props, ref) => {
+export const AngularRoot = forwardRef((props, ref) => {
return (
void;
}
-export const MegaMenu = React.memo(
+export const MegaMenu = memo(
forwardRef
(({ onClose, ...restProps }, ref) => {
const navTree = useSelector((state) => state.navBarTree);
const styles = useStyles2(getStyles);
diff --git a/public/app/core/components/AppChrome/MegaMenu/MegaMenuItem.tsx b/public/app/core/components/AppChrome/MegaMenu/MegaMenuItem.tsx
index 48504e5319f..aee471e961d 100644
--- a/public/app/core/components/AppChrome/MegaMenu/MegaMenuItem.tsx
+++ b/public/app/core/components/AppChrome/MegaMenu/MegaMenuItem.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { useEffect, useRef } from 'react';
+import { useEffect, useRef } from 'react';
+import * as React from 'react';
import { useLocation } from 'react-router-dom';
import { useLocalStorage } from 'react-use';
diff --git a/public/app/core/components/AppChrome/MegaMenu/MegaMenuItemText.tsx b/public/app/core/components/AppChrome/MegaMenu/MegaMenuItemText.tsx
index f05cbd54ee9..c6d15f4ab95 100644
--- a/public/app/core/components/AppChrome/MegaMenu/MegaMenuItemText.tsx
+++ b/public/app/core/components/AppChrome/MegaMenu/MegaMenuItemText.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/core/components/AppChrome/NavToolbar/NavToolbar.tsx b/public/app/core/components/AppChrome/NavToolbar/NavToolbar.tsx
index 7a15ebf85c7..95cb1a52058 100644
--- a/public/app/core/components/AppChrome/NavToolbar/NavToolbar.tsx
+++ b/public/app/core/components/AppChrome/NavToolbar/NavToolbar.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2, NavModelItem } from '@grafana/data';
import { Components } from '@grafana/e2e-selectors';
diff --git a/public/app/core/components/AppChrome/NavToolbar/NavToolbarSeparator.tsx b/public/app/core/components/AppChrome/NavToolbar/NavToolbarSeparator.tsx
index e801acd5d6c..928971a535a 100644
--- a/public/app/core/components/AppChrome/NavToolbar/NavToolbarSeparator.tsx
+++ b/public/app/core/components/AppChrome/NavToolbar/NavToolbarSeparator.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/core/components/AppChrome/News/NewsContainer.test.tsx b/public/app/core/components/AppChrome/News/NewsContainer.test.tsx
index 228b7c487cf..3b1ed747283 100644
--- a/public/app/core/components/AppChrome/News/NewsContainer.test.tsx
+++ b/public/app/core/components/AppChrome/News/NewsContainer.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { NewsContainer } from './NewsContainer';
diff --git a/public/app/core/components/AppChrome/News/NewsContainer.tsx b/public/app/core/components/AppChrome/News/NewsContainer.tsx
index 6dbe6ab2dff..2d4cec5a628 100644
--- a/public/app/core/components/AppChrome/News/NewsContainer.tsx
+++ b/public/app/core/components/AppChrome/News/NewsContainer.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { useToggle } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/core/components/AppChrome/News/NewsWrapper.tsx b/public/app/core/components/AppChrome/News/NewsWrapper.tsx
index f7a36884c8e..bfa3246f02b 100644
--- a/public/app/core/components/AppChrome/News/NewsWrapper.tsx
+++ b/public/app/core/components/AppChrome/News/NewsWrapper.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import { useMeasure } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/core/components/AppChrome/OrganizationSwitcher/OrganizationPicker.tsx b/public/app/core/components/AppChrome/OrganizationSwitcher/OrganizationPicker.tsx
index 80b2f1ae2f0..e5dba47920f 100644
--- a/public/app/core/components/AppChrome/OrganizationSwitcher/OrganizationPicker.tsx
+++ b/public/app/core/components/AppChrome/OrganizationSwitcher/OrganizationPicker.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { ValuePicker, useStyles2 } from '@grafana/ui';
diff --git a/public/app/core/components/AppChrome/OrganizationSwitcher/OrganizationSelect.tsx b/public/app/core/components/AppChrome/OrganizationSwitcher/OrganizationSelect.tsx
index 9ed55a571d2..c17f48bc4d9 100644
--- a/public/app/core/components/AppChrome/OrganizationSwitcher/OrganizationSelect.tsx
+++ b/public/app/core/components/AppChrome/OrganizationSwitcher/OrganizationSelect.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { SelectableValue, GrafanaTheme2 } from '@grafana/data';
import { Icon, Select, useStyles2 } from '@grafana/ui';
diff --git a/public/app/core/components/AppChrome/OrganizationSwitcher/OrganizationSwitcher.test.tsx b/public/app/core/components/AppChrome/OrganizationSwitcher/OrganizationSwitcher.test.tsx
index 20a5eb1db1c..74cb115e9f9 100644
--- a/public/app/core/components/AppChrome/OrganizationSwitcher/OrganizationSwitcher.test.tsx
+++ b/public/app/core/components/AppChrome/OrganizationSwitcher/OrganizationSwitcher.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { OrgRole } from '@grafana/data';
diff --git a/public/app/core/components/AppChrome/OrganizationSwitcher/OrganizationSwitcher.tsx b/public/app/core/components/AppChrome/OrganizationSwitcher/OrganizationSwitcher.tsx
index 4398ceb1097..afd5fd3d354 100644
--- a/public/app/core/components/AppChrome/OrganizationSwitcher/OrganizationSwitcher.tsx
+++ b/public/app/core/components/AppChrome/OrganizationSwitcher/OrganizationSwitcher.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { SelectableValue } from '@grafana/data';
import { locationService } from '@grafana/runtime';
diff --git a/public/app/core/components/AppChrome/QuickAdd/QuickAdd.test.tsx b/public/app/core/components/AppChrome/QuickAdd/QuickAdd.test.tsx
index 53b9099fff3..12f0f6a708c 100644
--- a/public/app/core/components/AppChrome/QuickAdd/QuickAdd.test.tsx
+++ b/public/app/core/components/AppChrome/QuickAdd/QuickAdd.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { NavModelItem } from '@grafana/data';
diff --git a/public/app/core/components/AppChrome/QuickAdd/QuickAdd.tsx b/public/app/core/components/AppChrome/QuickAdd/QuickAdd.tsx
index 65a9b92e498..f097d0073a1 100644
--- a/public/app/core/components/AppChrome/QuickAdd/QuickAdd.tsx
+++ b/public/app/core/components/AppChrome/QuickAdd/QuickAdd.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime';
diff --git a/public/app/core/components/AppChrome/ReturnToPrevious/DismissableButton.tsx b/public/app/core/components/AppChrome/ReturnToPrevious/DismissableButton.tsx
index a9fe92cdb24..fbc0dcc3803 100644
--- a/public/app/core/components/AppChrome/ReturnToPrevious/DismissableButton.tsx
+++ b/public/app/core/components/AppChrome/ReturnToPrevious/DismissableButton.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/core/components/AppChrome/ReturnToPrevious/ReturnToPrevious.test.tsx b/public/app/core/components/AppChrome/ReturnToPrevious/ReturnToPrevious.test.tsx
index b016e4ba626..d51fc6c9acc 100644
--- a/public/app/core/components/AppChrome/ReturnToPrevious/ReturnToPrevious.test.tsx
+++ b/public/app/core/components/AppChrome/ReturnToPrevious/ReturnToPrevious.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
diff --git a/public/app/core/components/AppChrome/ReturnToPrevious/ReturnToPrevious.tsx b/public/app/core/components/AppChrome/ReturnToPrevious/ReturnToPrevious.tsx
index 8d9ca18eabc..5d8cf0e1b4d 100644
--- a/public/app/core/components/AppChrome/ReturnToPrevious/ReturnToPrevious.tsx
+++ b/public/app/core/components/AppChrome/ReturnToPrevious/ReturnToPrevious.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/core/components/AppChrome/TopBar/SignInLink.tsx b/public/app/core/components/AppChrome/TopBar/SignInLink.tsx
index 19791612093..95f5006f507 100644
--- a/public/app/core/components/AppChrome/TopBar/SignInLink.tsx
+++ b/public/app/core/components/AppChrome/TopBar/SignInLink.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { useLocation } from 'react-router-dom';
import { GrafanaTheme2, locationUtil, textUtil } from '@grafana/data';
diff --git a/public/app/core/components/AppChrome/TopBar/TopNavBarMenu.tsx b/public/app/core/components/AppChrome/TopBar/TopNavBarMenu.tsx
index 1634f8fb8fb..27abaf86a77 100644
--- a/public/app/core/components/AppChrome/TopBar/TopNavBarMenu.tsx
+++ b/public/app/core/components/AppChrome/TopBar/TopNavBarMenu.tsx
@@ -1,6 +1,5 @@
import { css } from '@emotion/css';
import { cloneDeep } from 'lodash';
-import React from 'react';
import { GrafanaTheme2, NavModelItem } from '@grafana/data';
import { Menu, MenuItem, useStyles2 } from '@grafana/ui';
diff --git a/public/app/core/components/AppChrome/TopBar/TopSearchBar.tsx b/public/app/core/components/AppChrome/TopBar/TopSearchBar.tsx
index 727f0cec7ef..92ef3dd70ca 100644
--- a/public/app/core/components/AppChrome/TopBar/TopSearchBar.tsx
+++ b/public/app/core/components/AppChrome/TopBar/TopSearchBar.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { cloneDeep } from 'lodash';
-import React from 'react';
+import { memo } from 'react';
import { useLocation } from 'react-router-dom';
import { GrafanaTheme2, locationUtil, textUtil } from '@grafana/data';
@@ -21,7 +21,7 @@ import { TopNavBarMenu } from './TopNavBarMenu';
import { TopSearchBarCommandPaletteTrigger } from './TopSearchBarCommandPaletteTrigger';
import { TopSearchBarSection } from './TopSearchBarSection';
-export const TopSearchBar = React.memo(function TopSearchBar() {
+export const TopSearchBar = memo(function TopSearchBar() {
const styles = useStyles2(getStyles);
const navIndex = useSelector((state) => state.navIndex);
const location = useLocation();
diff --git a/public/app/core/components/AppChrome/TopBar/TopSearchBarCommandPaletteTrigger.tsx b/public/app/core/components/AppChrome/TopBar/TopSearchBarCommandPaletteTrigger.tsx
index 40d4e61e33d..8ad8eac711c 100644
--- a/public/app/core/components/AppChrome/TopBar/TopSearchBarCommandPaletteTrigger.tsx
+++ b/public/app/core/components/AppChrome/TopBar/TopSearchBarCommandPaletteTrigger.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { useKBar, VisualState } from 'kbar';
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { getInputStyles, Icon, Text, ToolbarButton, useStyles2, useTheme2 } from '@grafana/ui';
diff --git a/public/app/core/components/AppChrome/TopBar/TopSearchBarSection.test.tsx b/public/app/core/components/AppChrome/TopBar/TopSearchBarSection.test.tsx
index d883b0a32c8..51a70853828 100644
--- a/public/app/core/components/AppChrome/TopBar/TopSearchBarSection.test.tsx
+++ b/public/app/core/components/AppChrome/TopBar/TopSearchBarSection.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { TopSearchBarSection, TopSearchBarSectionProps } from './TopSearchBarSection';
diff --git a/public/app/core/components/AppChrome/TopBar/TopSearchBarSection.tsx b/public/app/core/components/AppChrome/TopBar/TopSearchBarSection.tsx
index 18ed008aa7e..ec9176039f0 100644
--- a/public/app/core/components/AppChrome/TopBar/TopSearchBarSection.tsx
+++ b/public/app/core/components/AppChrome/TopBar/TopSearchBarSection.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2, useTheme2 } from '@grafana/ui';
diff --git a/public/app/core/components/AppNotifications/AppNotificationItem.tsx b/public/app/core/components/AppNotifications/AppNotificationItem.tsx
index 167b2546009..291d68d3935 100644
--- a/public/app/core/components/AppNotifications/AppNotificationItem.tsx
+++ b/public/app/core/components/AppNotifications/AppNotificationItem.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { useEffectOnce } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/core/components/AppNotifications/AppNotificationList.tsx b/public/app/core/components/AppNotifications/AppNotificationList.tsx
index c9df5e95836..7b989214d45 100644
--- a/public/app/core/components/AppNotifications/AppNotificationList.tsx
+++ b/public/app/core/components/AppNotifications/AppNotificationList.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import { AppEvents, GrafanaTheme2 } from '@grafana/data';
import { useStyles2, Stack } from '@grafana/ui';
diff --git a/public/app/core/components/AppNotifications/StoredNotificationItem.tsx b/public/app/core/components/AppNotifications/StoredNotificationItem.tsx
index 3fa7325e27c..2592d978175 100644
--- a/public/app/core/components/AppNotifications/StoredNotificationItem.tsx
+++ b/public/app/core/components/AppNotifications/StoredNotificationItem.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { formatDistanceToNow } from 'date-fns';
-import React, { ReactNode } from 'react';
+import { ReactNode } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Card, Checkbox, useTheme2 } from '@grafana/ui';
diff --git a/public/app/core/components/BouncingLoader/BouncingLoader.tsx b/public/app/core/components/BouncingLoader/BouncingLoader.tsx
index e3273663af4..df69d10806a 100644
--- a/public/app/core/components/BouncingLoader/BouncingLoader.tsx
+++ b/public/app/core/components/BouncingLoader/BouncingLoader.tsx
@@ -1,5 +1,4 @@
import { css, keyframes } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/core/components/Branding/Branding.tsx b/public/app/core/components/Branding/Branding.tsx
index 15f37c694df..76352fe0eb4 100644
--- a/public/app/core/components/Branding/Branding.tsx
+++ b/public/app/core/components/Branding/Branding.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { FC } from 'react';
+import { FC } from 'react';
import { colorManipulator } from '@grafana/data';
import { useTheme2 } from '@grafana/ui';
diff --git a/public/app/core/components/Breadcrumbs/BreadcrumbItem.tsx b/public/app/core/components/Breadcrumbs/BreadcrumbItem.tsx
index 7dcdcc5ef4a..33b12b3de7f 100644
--- a/public/app/core/components/Breadcrumbs/BreadcrumbItem.tsx
+++ b/public/app/core/components/Breadcrumbs/BreadcrumbItem.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Components } from '@grafana/e2e-selectors';
diff --git a/public/app/core/components/Breadcrumbs/Breadcrumbs.test.tsx b/public/app/core/components/Breadcrumbs/Breadcrumbs.test.tsx
index 146ab7697db..43663ca80eb 100644
--- a/public/app/core/components/Breadcrumbs/Breadcrumbs.test.tsx
+++ b/public/app/core/components/Breadcrumbs/Breadcrumbs.test.tsx
@@ -1,5 +1,4 @@
import { render, screen, within } from '@testing-library/react';
-import React from 'react';
import { Breadcrumbs } from './Breadcrumbs';
import { Breadcrumb } from './types';
diff --git a/public/app/core/components/Breadcrumbs/Breadcrumbs.tsx b/public/app/core/components/Breadcrumbs/Breadcrumbs.tsx
index 8518ca70000..6f094d0f6e6 100644
--- a/public/app/core/components/Breadcrumbs/Breadcrumbs.tsx
+++ b/public/app/core/components/Breadcrumbs/Breadcrumbs.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/core/components/CardButton.tsx b/public/app/core/components/CardButton.tsx
index 2ed4eed360d..b3fe06bc932 100644
--- a/public/app/core/components/CardButton.tsx
+++ b/public/app/core/components/CardButton.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { HTMLAttributes } from 'react';
+import { HTMLAttributes } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Icon, IconName, useStyles2 } from '@grafana/ui';
diff --git a/public/app/core/components/CloseButton/CloseButton.tsx b/public/app/core/components/CloseButton/CloseButton.tsx
index a80a28f17f2..95ca3bcab18 100644
--- a/public/app/core/components/CloseButton/CloseButton.tsx
+++ b/public/app/core/components/CloseButton/CloseButton.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { IconButton, useStyles2 } from '@grafana/ui';
diff --git a/public/app/core/components/ColorScale/ColorScale.tsx b/public/app/core/components/ColorScale/ColorScale.tsx
index 5fd2039e1a8..5c97985ab87 100644
--- a/public/app/core/components/ColorScale/ColorScale.tsx
+++ b/public/app/core/components/ColorScale/ColorScale.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useState, useEffect } from 'react';
+import { useState, useEffect } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useTheme2 } from '@grafana/ui';
diff --git a/public/app/core/components/DynamicImports/SafeDynamicImport.tsx b/public/app/core/components/DynamicImports/SafeDynamicImport.tsx
index d8fe4c01722..146427370e1 100644
--- a/public/app/core/components/DynamicImports/SafeDynamicImport.tsx
+++ b/public/app/core/components/DynamicImports/SafeDynamicImport.tsx
@@ -1,5 +1,5 @@
-import React from 'react';
+import { lazy } from 'react';
import { GrafanaRouteComponent } from 'app/core/navigation/types';
-export const SafeDynamicImport = (loader: () => Promise): GrafanaRouteComponent => React.lazy(loader);
+export const SafeDynamicImport = (loader: () => Promise): GrafanaRouteComponent => lazy(loader);
diff --git a/public/app/core/components/EmptyListCTA/EmptyListCTA.test.tsx b/public/app/core/components/EmptyListCTA/EmptyListCTA.test.tsx
index 35d720e70cf..aae66d10754 100644
--- a/public/app/core/components/EmptyListCTA/EmptyListCTA.test.tsx
+++ b/public/app/core/components/EmptyListCTA/EmptyListCTA.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import EmptyListCTA from './EmptyListCTA';
diff --git a/public/app/core/components/EmptyListCTA/EmptyListCTA.tsx b/public/app/core/components/EmptyListCTA/EmptyListCTA.tsx
index ee31efcb2f9..6f6a667365a 100644
--- a/public/app/core/components/EmptyListCTA/EmptyListCTA.tsx
+++ b/public/app/core/components/EmptyListCTA/EmptyListCTA.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { MouseEvent } from 'react';
+import { MouseEvent } from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { Button, CallToActionCard, Icon, IconName, LinkButton } from '@grafana/ui';
diff --git a/public/app/core/components/FolderFilter/FolderFilter.tsx b/public/app/core/components/FolderFilter/FolderFilter.tsx
index ee1379085fc..069f583c342 100644
--- a/public/app/core/components/FolderFilter/FolderFilter.tsx
+++ b/public/app/core/components/FolderFilter/FolderFilter.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import debounce from 'debounce-promise';
-import React, { useCallback, useMemo, useState } from 'react';
+import { useCallback, useMemo, useState } from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { AsyncMultiSelect, Icon, Button, useStyles2 } from '@grafana/ui';
diff --git a/public/app/core/components/Footer/Footer.tsx b/public/app/core/components/Footer/Footer.tsx
index 56f1211c396..ed43848000c 100644
--- a/public/app/core/components/Footer/Footer.tsx
+++ b/public/app/core/components/Footer/Footer.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import { memo } from 'react';
import { GrafanaTheme2, LinkTarget } from '@grafana/data';
import { config } from '@grafana/runtime';
@@ -99,7 +99,7 @@ export interface Props {
hideEdition?: boolean;
}
-export const Footer = React.memo(({ customLinks, hideEdition }: Props) => {
+export const Footer = memo(({ customLinks, hideEdition }: Props) => {
const links = (customLinks || getFooterLinks()).concat(getVersionLinks(hideEdition));
const styles = useStyles2(getStyles);
diff --git a/public/app/core/components/ForgottenPassword/ChangePassword.tsx b/public/app/core/components/ForgottenPassword/ChangePassword.tsx
index 5561a227471..fe11f96ccf9 100644
--- a/public/app/core/components/ForgottenPassword/ChangePassword.tsx
+++ b/public/app/core/components/ForgottenPassword/ChangePassword.tsx
@@ -1,4 +1,4 @@
-import React, { SyntheticEvent, useState } from 'react';
+import { SyntheticEvent, useState } from 'react';
import { useForm } from 'react-hook-form';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/core/components/ForgottenPassword/ChangePasswordPage.test.tsx b/public/app/core/components/ForgottenPassword/ChangePasswordPage.test.tsx
index cc2a0cb6d35..4e0476fdc94 100644
--- a/public/app/core/components/ForgottenPassword/ChangePasswordPage.test.tsx
+++ b/public/app/core/components/ForgottenPassword/ChangePasswordPage.test.tsx
@@ -1,6 +1,5 @@
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps';
diff --git a/public/app/core/components/ForgottenPassword/ChangePasswordPage.tsx b/public/app/core/components/ForgottenPassword/ChangePasswordPage.tsx
index 5367119f087..5944ad3eea9 100644
--- a/public/app/core/components/ForgottenPassword/ChangePasswordPage.tsx
+++ b/public/app/core/components/ForgottenPassword/ChangePasswordPage.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
import LoginCtrl from '../Login/LoginCtrl';
diff --git a/public/app/core/components/ForgottenPassword/ForgottenPassword.tsx b/public/app/core/components/ForgottenPassword/ForgottenPassword.tsx
index 2cbf681224e..3b7a7cec970 100644
--- a/public/app/core/components/ForgottenPassword/ForgottenPassword.tsx
+++ b/public/app/core/components/ForgottenPassword/ForgottenPassword.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { useForm } from 'react-hook-form';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/core/components/ForgottenPassword/SendResetMailPage.test.tsx b/public/app/core/components/ForgottenPassword/SendResetMailPage.test.tsx
index 57da0cd1029..6ddd6b56cab 100644
--- a/public/app/core/components/ForgottenPassword/SendResetMailPage.test.tsx
+++ b/public/app/core/components/ForgottenPassword/SendResetMailPage.test.tsx
@@ -1,6 +1,5 @@
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { SendResetMailPage } from './SendResetMailPage';
diff --git a/public/app/core/components/ForgottenPassword/SendResetMailPage.tsx b/public/app/core/components/ForgottenPassword/SendResetMailPage.tsx
index 7a0938d3d9b..f4d69b6b881 100644
--- a/public/app/core/components/ForgottenPassword/SendResetMailPage.tsx
+++ b/public/app/core/components/ForgottenPassword/SendResetMailPage.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { LoginLayout, InnerBox } from '../Login/LoginLayout';
import { ForgottenPassword } from './ForgottenPassword';
diff --git a/public/app/core/components/Form/Form.tsx b/public/app/core/components/Form/Form.tsx
index 91ea061c975..d09e5797152 100644
--- a/public/app/core/components/Form/Form.tsx
+++ b/public/app/core/components/Form/Form.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { HTMLProps, useEffect } from 'react';
+import { HTMLProps, useEffect } from 'react';
+import * as React from 'react';
import {
useForm,
Mode,
diff --git a/public/app/core/components/FormPrompt/FormPrompt.tsx b/public/app/core/components/FormPrompt/FormPrompt.tsx
index 4339b7b89b0..dac60471129 100644
--- a/public/app/core/components/FormPrompt/FormPrompt.tsx
+++ b/public/app/core/components/FormPrompt/FormPrompt.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import history from 'history';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { Prompt, Redirect } from 'react-router-dom';
import { Button, Modal } from '@grafana/ui';
diff --git a/public/app/core/components/GraphNG/GraphNG.tsx b/public/app/core/components/GraphNG/GraphNG.tsx
index f2575110289..f096ab60afb 100644
--- a/public/app/core/components/GraphNG/GraphNG.tsx
+++ b/public/app/core/components/GraphNG/GraphNG.tsx
@@ -1,4 +1,5 @@
-import React, { Component } from 'react';
+import { Component } from 'react';
+import * as React from 'react';
import uPlot, { AlignedData } from 'uplot';
import {
diff --git a/public/app/core/components/Indent/Indent.tsx b/public/app/core/components/Indent/Indent.tsx
index 3f4647a4df3..237ed907984 100644
--- a/public/app/core/components/Indent/Indent.tsx
+++ b/public/app/core/components/Indent/Indent.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2, ThemeSpacingTokens } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/core/components/Layers/AddLayerButton.test.tsx b/public/app/core/components/Layers/AddLayerButton.test.tsx
index 0bdbf16f7fd..5ab15e2bcd3 100644
--- a/public/app/core/components/Layers/AddLayerButton.test.tsx
+++ b/public/app/core/components/Layers/AddLayerButton.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/core/components/Layers/AddLayerButton.tsx b/public/app/core/components/Layers/AddLayerButton.tsx
index b10c679ded9..8279593d547 100644
--- a/public/app/core/components/Layers/AddLayerButton.tsx
+++ b/public/app/core/components/Layers/AddLayerButton.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SelectableValue } from '@grafana/data';
import { ValuePicker } from '@grafana/ui';
diff --git a/public/app/core/components/Layers/LayerDragDropList.test.tsx b/public/app/core/components/Layers/LayerDragDropList.test.tsx
index 4d7ec105927..3f17393afb0 100644
--- a/public/app/core/components/Layers/LayerDragDropList.test.tsx
+++ b/public/app/core/components/Layers/LayerDragDropList.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { DATA_TEST_ID, LayerDragDropList, LayerDragDropListProps } from './LayerDragDropList';
diff --git a/public/app/core/components/Layers/LayerDragDropList.tsx b/public/app/core/components/Layers/LayerDragDropList.tsx
index 7589575c7f2..df98d434f15 100644
--- a/public/app/core/components/Layers/LayerDragDropList.tsx
+++ b/public/app/core/components/Layers/LayerDragDropList.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { DragDropContext, Draggable, Droppable, DropResult } from 'react-beautiful-dnd';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/core/components/Layers/LayerName.test.tsx b/public/app/core/components/Layers/LayerName.test.tsx
index 904f1102b64..7b26af6faef 100644
--- a/public/app/core/components/Layers/LayerName.test.tsx
+++ b/public/app/core/components/Layers/LayerName.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { LayerNameProps, LayerName } from './LayerName';
diff --git a/public/app/core/components/Layers/LayerName.tsx b/public/app/core/components/Layers/LayerName.tsx
index 2ef0a2981cd..761cc60aecf 100644
--- a/public/app/core/components/Layers/LayerName.tsx
+++ b/public/app/core/components/Layers/LayerName.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Icon, Input, FieldValidationMessage, useStyles2 } from '@grafana/ui';
diff --git a/public/app/core/components/LocalStorageValueProvider/LocalStorageValueProvider.tsx b/public/app/core/components/LocalStorageValueProvider/LocalStorageValueProvider.tsx
index d0558fe43ee..6d6804d5bba 100644
--- a/public/app/core/components/LocalStorageValueProvider/LocalStorageValueProvider.tsx
+++ b/public/app/core/components/LocalStorageValueProvider/LocalStorageValueProvider.tsx
@@ -1,4 +1,5 @@
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
+import * as React from 'react';
import store from '../../store';
diff --git a/public/app/core/components/Login/LoginCtrl.tsx b/public/app/core/components/Login/LoginCtrl.tsx
index 7adf963eed4..580c372ceab 100644
--- a/public/app/core/components/Login/LoginCtrl.tsx
+++ b/public/app/core/components/Login/LoginCtrl.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { FetchError, getBackendSrv, isFetchError } from '@grafana/runtime';
import config from 'app/core/config';
diff --git a/public/app/core/components/Login/LoginForm.tsx b/public/app/core/components/Login/LoginForm.tsx
index 4524e997442..17783e25fae 100644
--- a/public/app/core/components/Login/LoginForm.tsx
+++ b/public/app/core/components/Login/LoginForm.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { ReactElement, useId } from 'react';
+import { ReactElement, useId } from 'react';
import { useForm } from 'react-hook-form';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/core/components/Login/LoginLayout.tsx b/public/app/core/components/Login/LoginLayout.tsx
index c7ef7649be5..4a65789c6d7 100644
--- a/public/app/core/components/Login/LoginLayout.tsx
+++ b/public/app/core/components/Login/LoginLayout.tsx
@@ -1,5 +1,6 @@
import { cx, css, keyframes } from '@emotion/css';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/core/components/Login/LoginPage.test.tsx b/public/app/core/components/Login/LoginPage.test.tsx
index 17d6a0fd86f..6301119c9d6 100644
--- a/public/app/core/components/Login/LoginPage.test.tsx
+++ b/public/app/core/components/Login/LoginPage.test.tsx
@@ -1,6 +1,5 @@
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import * as runtimeMock from '@grafana/runtime';
diff --git a/public/app/core/components/Login/LoginPage.tsx b/public/app/core/components/Login/LoginPage.tsx
index 8c0c3d51044..109d6e9d818 100644
--- a/public/app/core/components/Login/LoginPage.tsx
+++ b/public/app/core/components/Login/LoginPage.tsx
@@ -1,6 +1,5 @@
// Libraries
import { css } from '@emotion/css';
-import React from 'react';
// Components
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/core/components/Login/LoginServiceButtons.tsx b/public/app/core/components/Login/LoginServiceButtons.tsx
index 157fe2e7e62..0cc28c6eb83 100644
--- a/public/app/core/components/Login/LoginServiceButtons.tsx
+++ b/public/app/core/components/Login/LoginServiceButtons.tsx
@@ -1,6 +1,5 @@
import { css, cx } from '@emotion/css';
import { pickBy } from 'lodash';
-import React from 'react';
import { GrafanaTheme2, DEFAULT_SAML_NAME } from '@grafana/data';
import { Icon, IconName, LinkButton, Stack, useStyles2, useTheme2 } from '@grafana/ui';
diff --git a/public/app/core/components/Login/UserSignup.tsx b/public/app/core/components/Login/UserSignup.tsx
index 148a07e3e92..7d729812592 100644
--- a/public/app/core/components/Login/UserSignup.tsx
+++ b/public/app/core/components/Login/UserSignup.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { LinkButton, Stack } from '@grafana/ui';
import { getConfig } from 'app/core/config';
diff --git a/public/app/core/components/NativeScrollbar.tsx b/public/app/core/components/NativeScrollbar.tsx
index 76d447f4311..3b60c1df7bc 100644
--- a/public/app/core/components/NativeScrollbar.tsx
+++ b/public/app/core/components/NativeScrollbar.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { useEffect, useRef } from 'react';
+import { useEffect, useRef } from 'react';
import { CustomScrollbar, useStyles2 } from '@grafana/ui';
diff --git a/public/app/core/components/NavLandingPage/NavLandingPage.test.tsx b/public/app/core/components/NavLandingPage/NavLandingPage.test.tsx
index 61ffd5a0fd9..caf11f3a48f 100644
--- a/public/app/core/components/NavLandingPage/NavLandingPage.test.tsx
+++ b/public/app/core/components/NavLandingPage/NavLandingPage.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { config } from '@grafana/runtime';
diff --git a/public/app/core/components/NavLandingPage/NavLandingPage.tsx b/public/app/core/components/NavLandingPage/NavLandingPage.tsx
index 9be82d67c7a..3e8d4683cfa 100644
--- a/public/app/core/components/NavLandingPage/NavLandingPage.tsx
+++ b/public/app/core/components/NavLandingPage/NavLandingPage.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/core/components/NavLandingPage/NavLandingPageCard.test.tsx b/public/app/core/components/NavLandingPage/NavLandingPageCard.test.tsx
index b15260c7708..0625f540233 100644
--- a/public/app/core/components/NavLandingPage/NavLandingPageCard.test.tsx
+++ b/public/app/core/components/NavLandingPage/NavLandingPageCard.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { NavLandingPageCard } from './NavLandingPageCard';
diff --git a/public/app/core/components/NavLandingPage/NavLandingPageCard.tsx b/public/app/core/components/NavLandingPage/NavLandingPageCard.tsx
index 23f582bdac3..0b24a12b524 100644
--- a/public/app/core/components/NavLandingPage/NavLandingPageCard.tsx
+++ b/public/app/core/components/NavLandingPage/NavLandingPageCard.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Card, useStyles2 } from '@grafana/ui';
diff --git a/public/app/core/components/NestedFolderPicker/NestedFolderList.tsx b/public/app/core/components/NestedFolderPicker/NestedFolderList.tsx
index 7de1643f74d..03105f84f73 100644
--- a/public/app/core/components/NestedFolderPicker/NestedFolderList.tsx
+++ b/public/app/core/components/NestedFolderPicker/NestedFolderList.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { useCallback, useId, useMemo, useRef } from 'react';
+import { useCallback, useId, useMemo, useRef } from 'react';
+import * as React from 'react';
import Skeleton from 'react-loading-skeleton';
import { FixedSizeList as List } from 'react-window';
import InfiniteLoader from 'react-window-infinite-loader';
diff --git a/public/app/core/components/NestedFolderPicker/NestedFolderPicker.test.tsx b/public/app/core/components/NestedFolderPicker/NestedFolderPicker.test.tsx
index e0b1602d6a6..caea1db92d3 100644
--- a/public/app/core/components/NestedFolderPicker/NestedFolderPicker.test.tsx
+++ b/public/app/core/components/NestedFolderPicker/NestedFolderPicker.test.tsx
@@ -2,7 +2,6 @@ import { fireEvent, render as rtlRender, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { HttpResponse, http } from 'msw';
import { SetupServer, setupServer } from 'msw/node';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { config } from '@grafana/runtime';
diff --git a/public/app/core/components/NestedFolderPicker/NestedFolderPicker.tsx b/public/app/core/components/NestedFolderPicker/NestedFolderPicker.tsx
index e9ee8eb9574..2d131f619ab 100644
--- a/public/app/core/components/NestedFolderPicker/NestedFolderPicker.tsx
+++ b/public/app/core/components/NestedFolderPicker/NestedFolderPicker.tsx
@@ -1,7 +1,8 @@
import { css } from '@emotion/css';
import { autoUpdate, flip, useClick, useDismiss, useFloating, useInteractions } from '@floating-ui/react';
import debounce from 'debounce-promise';
-import React, { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react';
+import { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { config } from '@grafana/runtime';
diff --git a/public/app/core/components/NestedFolderPicker/Trigger.tsx b/public/app/core/components/NestedFolderPicker/Trigger.tsx
index 8b25bd9b32f..ae1e5173f7b 100644
--- a/public/app/core/components/NestedFolderPicker/Trigger.tsx
+++ b/public/app/core/components/NestedFolderPicker/Trigger.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { forwardRef, ReactNode, ButtonHTMLAttributes } from 'react';
+import { forwardRef, ReactNode, ButtonHTMLAttributes } from 'react';
+import * as React from 'react';
import Skeleton from 'react-loading-skeleton';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/core/components/NestedFolderPicker/useTreeInteractions.ts b/public/app/core/components/NestedFolderPicker/useTreeInteractions.ts
index 393d35320e5..b1c7bdc8127 100644
--- a/public/app/core/components/NestedFolderPicker/useTreeInteractions.ts
+++ b/public/app/core/components/NestedFolderPicker/useTreeInteractions.ts
@@ -1,4 +1,5 @@
-import React, { useCallback, useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
+import * as React from 'react';
import { config } from '@grafana/runtime';
import { DashboardsTreeItem } from 'app/features/browse-dashboards/types';
diff --git a/public/app/core/components/OptionsUI/DashboardPicker.tsx b/public/app/core/components/OptionsUI/DashboardPicker.tsx
index 62b2a41e0f0..8869bf4aadb 100644
--- a/public/app/core/components/OptionsUI/DashboardPicker.tsx
+++ b/public/app/core/components/OptionsUI/DashboardPicker.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { SelectableValue, StandardEditorProps } from '@grafana/data';
import { DashboardPicker as BasePicker, DashboardPickerDTO } from 'app/core/components/Select/DashboardPicker';
diff --git a/public/app/core/components/OptionsUI/NumberInput.test.tsx b/public/app/core/components/OptionsUI/NumberInput.test.tsx
index 909d6f6c8f2..4bc7baa2fa0 100644
--- a/public/app/core/components/OptionsUI/NumberInput.test.tsx
+++ b/public/app/core/components/OptionsUI/NumberInput.test.tsx
@@ -1,5 +1,4 @@
import { render, screen, fireEvent } from '@testing-library/react';
-import React from 'react';
import { NumberInput } from './NumberInput';
diff --git a/public/app/core/components/OptionsUI/NumberInput.tsx b/public/app/core/components/OptionsUI/NumberInput.tsx
index a6da43a8f75..f5ba98492b7 100644
--- a/public/app/core/components/OptionsUI/NumberInput.tsx
+++ b/public/app/core/components/OptionsUI/NumberInput.tsx
@@ -1,5 +1,6 @@
import { debounce } from 'lodash';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
+import * as React from 'react';
import { Field, Input } from '@grafana/ui';
diff --git a/public/app/core/components/OptionsUI/color.tsx b/public/app/core/components/OptionsUI/color.tsx
index 3916c9b6ed6..f52ba1677f4 100644
--- a/public/app/core/components/OptionsUI/color.tsx
+++ b/public/app/core/components/OptionsUI/color.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useTheme2, useStyles2, ColorPicker, IconButton } from '@grafana/ui';
diff --git a/public/app/core/components/OptionsUI/fieldColor.test.tsx b/public/app/core/components/OptionsUI/fieldColor.test.tsx
index 316679ab359..67bc694c5c6 100644
--- a/public/app/core/components/OptionsUI/fieldColor.test.tsx
+++ b/public/app/core/components/OptionsUI/fieldColor.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { FieldColorEditor } from './fieldColor';
diff --git a/public/app/core/components/OptionsUI/fieldColor.tsx b/public/app/core/components/OptionsUI/fieldColor.tsx
index 77e67d73d11..f878c5fbc3d 100644
--- a/public/app/core/components/OptionsUI/fieldColor.tsx
+++ b/public/app/core/components/OptionsUI/fieldColor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { CSSProperties, FC } from 'react';
+import { CSSProperties, FC } from 'react';
import {
StandardEditorProps,
diff --git a/public/app/core/components/OptionsUI/links.tsx b/public/app/core/components/OptionsUI/links.tsx
index 31aa70e266a..1a73b41c477 100644
--- a/public/app/core/components/OptionsUI/links.tsx
+++ b/public/app/core/components/OptionsUI/links.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { DataLink, DataLinksFieldConfigSettings, StandardEditorProps, VariableSuggestionsScope } from '@grafana/data';
import { DataLinksInlineEditor } from '@grafana/ui';
diff --git a/public/app/core/components/OptionsUI/multiSelect.tsx b/public/app/core/components/OptionsUI/multiSelect.tsx
index 9550e352f4f..bf2b5b9e5eb 100644
--- a/public/app/core/components/OptionsUI/multiSelect.tsx
+++ b/public/app/core/components/OptionsUI/multiSelect.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
import { StandardEditorProps, SelectFieldConfigSettings, SelectableValue } from '@grafana/data';
import { MultiSelect } from '@grafana/ui';
@@ -14,7 +14,7 @@ type Props = StandardEditorProps>;
* MultiSelect for options UI
* @alpha
*/
-export class MultiSelectValueEditor extends React.PureComponent, State> {
+export class MultiSelectValueEditor extends PureComponent, State> {
state: State = {
isLoading: true,
options: [],
diff --git a/public/app/core/components/OptionsUI/number.tsx b/public/app/core/components/OptionsUI/number.tsx
index ff57e1e0c1e..e7b0db58bbe 100644
--- a/public/app/core/components/OptionsUI/number.tsx
+++ b/public/app/core/components/OptionsUI/number.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { StandardEditorProps, NumberFieldConfigSettings } from '@grafana/data';
diff --git a/public/app/core/components/OptionsUI/registry.tsx b/public/app/core/components/OptionsUI/registry.tsx
index 46e30f6bd60..481395d1744 100644
--- a/public/app/core/components/OptionsUI/registry.tsx
+++ b/public/app/core/components/OptionsUI/registry.tsx
@@ -1,5 +1,4 @@
import { BooleanFieldSettings } from '@react-awesome-query-builder/ui';
-import React from 'react';
import {
FieldConfigPropertyItem,
diff --git a/public/app/core/components/OptionsUI/select.tsx b/public/app/core/components/OptionsUI/select.tsx
index 006d83cc77b..f3fc4a5439b 100644
--- a/public/app/core/components/OptionsUI/select.tsx
+++ b/public/app/core/components/OptionsUI/select.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
import { StandardEditorProps, SelectFieldConfigSettings, SelectableValue } from '@grafana/data';
import { Select } from '@grafana/ui';
@@ -10,7 +10,7 @@ interface State {
type Props = StandardEditorProps>;
-export class SelectValueEditor extends React.PureComponent, State> {
+export class SelectValueEditor extends PureComponent, State> {
state: State = {
isLoading: true,
options: [],
diff --git a/public/app/core/components/OptionsUI/slider.tsx b/public/app/core/components/OptionsUI/slider.tsx
index a734cc99fac..74930dabcd9 100644
--- a/public/app/core/components/OptionsUI/slider.tsx
+++ b/public/app/core/components/OptionsUI/slider.tsx
@@ -1,7 +1,7 @@
import { css, cx } from '@emotion/css';
import { Global } from '@emotion/react';
import Slider from 'rc-slider';
-import React, { useCallback, useEffect, useRef, useState } from 'react';
+import { useCallback, useEffect, useRef, useState } from 'react';
import { StandardEditorProps, GrafanaTheme2, SliderFieldConfigSettings } from '@grafana/data';
import { useTheme2 } from '@grafana/ui';
diff --git a/public/app/core/components/OptionsUI/stats.tsx b/public/app/core/components/OptionsUI/stats.tsx
index 558d774e9a3..9fc63b2cec5 100644
--- a/public/app/core/components/OptionsUI/stats.tsx
+++ b/public/app/core/components/OptionsUI/stats.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { StandardEditorProps, StatsPickerConfigSettings } from '@grafana/data';
import { StatsPicker } from '@grafana/ui';
diff --git a/public/app/core/components/OptionsUI/string.tsx b/public/app/core/components/OptionsUI/string.tsx
index ef60d91d0ab..8001bf096af 100644
--- a/public/app/core/components/OptionsUI/string.tsx
+++ b/public/app/core/components/OptionsUI/string.tsx
@@ -1,4 +1,5 @@
-import React, { ReactNode, useCallback } from 'react';
+import { ReactNode, useCallback } from 'react';
+import * as React from 'react';
import { StandardEditorProps, StringFieldConfigSettings } from '@grafana/data';
import { Input, TextArea } from '@grafana/ui';
diff --git a/public/app/core/components/OptionsUI/strings.tsx b/public/app/core/components/OptionsUI/strings.tsx
index 244abc7ec47..77294b2314c 100644
--- a/public/app/core/components/OptionsUI/strings.tsx
+++ b/public/app/core/components/OptionsUI/strings.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { StandardEditorProps, StringFieldConfigSettings, GrafanaTheme2 } from '@grafana/data';
import { config } from '@grafana/runtime';
diff --git a/public/app/core/components/OptionsUI/units.tsx b/public/app/core/components/OptionsUI/units.tsx
index 4bf6d1e653c..0b2e0068506 100644
--- a/public/app/core/components/OptionsUI/units.tsx
+++ b/public/app/core/components/OptionsUI/units.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { StandardEditorProps, GrafanaTheme2, UnitFieldConfigSettings } from '@grafana/data';
import { IconButton, UnitPicker, useStyles2 } from '@grafana/ui';
diff --git a/public/app/core/components/Page/EditableTitle.test.tsx b/public/app/core/components/Page/EditableTitle.test.tsx
index fec1b44915b..81d164e857e 100644
--- a/public/app/core/components/Page/EditableTitle.test.tsx
+++ b/public/app/core/components/Page/EditableTitle.test.tsx
@@ -1,6 +1,5 @@
import { act, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { FetchError } from '@grafana/runtime';
diff --git a/public/app/core/components/Page/EditableTitle.tsx b/public/app/core/components/Page/EditableTitle.tsx
index 5076349caa9..79c46f368e9 100644
--- a/public/app/core/components/Page/EditableTitle.tsx
+++ b/public/app/core/components/Page/EditableTitle.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useCallback, useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { isFetchError } from '@grafana/runtime';
diff --git a/public/app/core/components/Page/Page.test.tsx b/public/app/core/components/Page/Page.test.tsx
index e7962be5cf1..92bf724b9e4 100644
--- a/public/app/core/components/Page/Page.test.tsx
+++ b/public/app/core/components/Page/Page.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
diff --git a/public/app/core/components/Page/Page.tsx b/public/app/core/components/Page/Page.tsx
index c588d17be1e..4ca28917377 100644
--- a/public/app/core/components/Page/Page.tsx
+++ b/public/app/core/components/Page/Page.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { useLayoutEffect } from 'react';
+import { useLayoutEffect } from 'react';
import { GrafanaTheme2, PageLayoutType } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/core/components/Page/PageContents.tsx b/public/app/core/components/Page/PageContents.tsx
index 1246443139a..cfb177c49e0 100644
--- a/public/app/core/components/Page/PageContents.tsx
+++ b/public/app/core/components/Page/PageContents.tsx
@@ -1,5 +1,5 @@
// Libraries
-import React from 'react';
+import * as React from 'react';
import PageLoader from '../PageLoader/PageLoader';
diff --git a/public/app/core/components/Page/PageHeader.tsx b/public/app/core/components/Page/PageHeader.tsx
index 23a7796c2c1..c83d3d9d101 100644
--- a/public/app/core/components/Page/PageHeader.tsx
+++ b/public/app/core/components/Page/PageHeader.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { NavModelItem, GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/core/components/Page/PageTabs.test.tsx b/public/app/core/components/Page/PageTabs.test.tsx
index 8ef76d655b2..fe2d4f291a1 100644
--- a/public/app/core/components/Page/PageTabs.test.tsx
+++ b/public/app/core/components/Page/PageTabs.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { NavModelItem } from '@grafana/data';
diff --git a/public/app/core/components/Page/PageTabs.tsx b/public/app/core/components/Page/PageTabs.tsx
index b25223d14e2..680ac9dda4f 100644
--- a/public/app/core/components/Page/PageTabs.tsx
+++ b/public/app/core/components/Page/PageTabs.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { NavModelItem, GrafanaTheme2 } from '@grafana/data';
import { useStyles2, TabsBar, Tab, toIconName } from '@grafana/ui';
diff --git a/public/app/core/components/Page/PluginPage.tsx b/public/app/core/components/Page/PluginPage.tsx
index 694c6729fa5..daab21037cf 100644
--- a/public/app/core/components/Page/PluginPage.tsx
+++ b/public/app/core/components/Page/PluginPage.tsx
@@ -1,4 +1,4 @@
-import React, { useContext } from 'react';
+import { useContext } from 'react';
import { PluginPageProps } from '@grafana/runtime';
import { PluginPageContext } from 'app/features/plugins/components/PluginPageContext';
diff --git a/public/app/core/components/Page/types.ts b/public/app/core/components/Page/types.ts
index 4705291cbc7..6c4e1294e34 100644
--- a/public/app/core/components/Page/types.ts
+++ b/public/app/core/components/Page/types.ts
@@ -1,4 +1,5 @@
-import React, { FC, HTMLAttributes, RefCallback } from 'react';
+import { FC, HTMLAttributes, RefCallback } from 'react';
+import * as React from 'react';
import { NavModel, NavModelItem, PageLayoutType } from '@grafana/data';
diff --git a/public/app/core/components/PageActionBar/PageActionBar.test.tsx b/public/app/core/components/PageActionBar/PageActionBar.test.tsx
index 8f27bcb8de9..7d92d2ccc4e 100644
--- a/public/app/core/components/PageActionBar/PageActionBar.test.tsx
+++ b/public/app/core/components/PageActionBar/PageActionBar.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import PageActionBar, { Props } from './PageActionBar';
diff --git a/public/app/core/components/PageActionBar/PageActionBar.tsx b/public/app/core/components/PageActionBar/PageActionBar.tsx
index 48fda4cc01f..88bab67b780 100644
--- a/public/app/core/components/PageActionBar/PageActionBar.tsx
+++ b/public/app/core/components/PageActionBar/PageActionBar.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { SelectableValue } from '@grafana/data';
import { LinkButton, FilterInput, InlineField } from '@grafana/ui';
diff --git a/public/app/core/components/PageInfo/PageInfo.test.tsx b/public/app/core/components/PageInfo/PageInfo.test.tsx
index 73aa06c8b3b..4dc754e7c6c 100644
--- a/public/app/core/components/PageInfo/PageInfo.test.tsx
+++ b/public/app/core/components/PageInfo/PageInfo.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { PageInfoItem } from '../Page/types';
diff --git a/public/app/core/components/PageInfo/PageInfo.tsx b/public/app/core/components/PageInfo/PageInfo.tsx
index 388853ca375..26cfdf4a1c7 100644
--- a/public/app/core/components/PageInfo/PageInfo.tsx
+++ b/public/app/core/components/PageInfo/PageInfo.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import { Fragment } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
@@ -16,13 +16,13 @@ export function PageInfo({ info }: Props) {
return (
{info.map((infoItem, index) => (
-
+
{infoItem.label}
{infoItem.value}
{index + 1 < info.length &&
}
-
+
))}
);
diff --git a/public/app/core/components/PageLoader/PageLoader.tsx b/public/app/core/components/PageLoader/PageLoader.tsx
index e6b133618db..78bd864482b 100644
--- a/public/app/core/components/PageLoader/PageLoader.tsx
+++ b/public/app/core/components/PageLoader/PageLoader.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Box, LoadingPlaceholder } from '@grafana/ui';
interface Props {
diff --git a/public/app/core/components/PageNotFound/EntityNotFound.tsx b/public/app/core/components/PageNotFound/EntityNotFound.tsx
index c749d30aa19..db969a8f236 100644
--- a/public/app/core/components/PageNotFound/EntityNotFound.tsx
+++ b/public/app/core/components/PageNotFound/EntityNotFound.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/core/components/PageNotFound/PageNotFound.tsx b/public/app/core/components/PageNotFound/PageNotFound.tsx
index 7135da5b81d..1ea82d68ff7 100644
--- a/public/app/core/components/PageNotFound/PageNotFound.tsx
+++ b/public/app/core/components/PageNotFound/PageNotFound.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PageLayoutType } from '@grafana/data';
import { Page } from '../Page/Page';
diff --git a/public/app/core/components/PanelTypeFilter/PanelTypeFilter.tsx b/public/app/core/components/PanelTypeFilter/PanelTypeFilter.tsx
index 9e852741f0e..e5320ba6f25 100644
--- a/public/app/core/components/PanelTypeFilter/PanelTypeFilter.tsx
+++ b/public/app/core/components/PanelTypeFilter/PanelTypeFilter.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useCallback, useMemo, useState } from 'react';
+import { useCallback, useMemo, useState } from 'react';
import { GrafanaTheme2, PanelPluginMeta, SelectableValue } from '@grafana/data';
import { config } from '@grafana/runtime';
diff --git a/public/app/core/components/PasswordField/PasswordField.test.tsx b/public/app/core/components/PasswordField/PasswordField.test.tsx
index 1e5ef302e75..618cad91752 100644
--- a/public/app/core/components/PasswordField/PasswordField.test.tsx
+++ b/public/app/core/components/PasswordField/PasswordField.test.tsx
@@ -1,5 +1,4 @@
import { fireEvent, render, screen } from '@testing-library/react';
-import React from 'react';
import { Field } from '@grafana/ui';
diff --git a/public/app/core/components/PasswordField/PasswordField.tsx b/public/app/core/components/PasswordField/PasswordField.tsx
index 0a91c8a9b50..c69873f4a5b 100644
--- a/public/app/core/components/PasswordField/PasswordField.tsx
+++ b/public/app/core/components/PasswordField/PasswordField.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { forwardRef, useState } from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { Input, IconButton } from '@grafana/ui';
@@ -6,7 +6,7 @@ import { Props as InputProps } from '@grafana/ui/src/components/Input/Input';
interface Props extends Omit {}
-export const PasswordField = React.forwardRef((props, ref) => {
+export const PasswordField = forwardRef((props, ref) => {
const [showPassword, setShowPassword] = useState(false);
return (
diff --git a/public/app/core/components/PluginHelp/PluginHelp.tsx b/public/app/core/components/PluginHelp/PluginHelp.tsx
index 4531abca50a..bd9436d26de 100644
--- a/public/app/core/components/PluginHelp/PluginHelp.tsx
+++ b/public/app/core/components/PluginHelp/PluginHelp.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useAsync } from 'react-use';
import { renderMarkdown } from '@grafana/data';
diff --git a/public/app/core/components/QueryOperationRow/OperationRowHelp.tsx b/public/app/core/components/QueryOperationRow/OperationRowHelp.tsx
index ea17c9ff423..16f69e2d1cd 100644
--- a/public/app/core/components/QueryOperationRow/OperationRowHelp.tsx
+++ b/public/app/core/components/QueryOperationRow/OperationRowHelp.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2, renderMarkdown } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/core/components/QueryOperationRow/QueryOperationAction.test.tsx b/public/app/core/components/QueryOperationRow/QueryOperationAction.test.tsx
index 5895d97c201..986e7a3e913 100644
--- a/public/app/core/components/QueryOperationRow/QueryOperationAction.test.tsx
+++ b/public/app/core/components/QueryOperationRow/QueryOperationAction.test.tsx
@@ -1,6 +1,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { ComponentPropsWithoutRef } from 'react';
+import { ComponentPropsWithoutRef } from 'react';
import { QueryOperationAction, QueryOperationToggleAction } from './QueryOperationAction';
diff --git a/public/app/core/components/QueryOperationRow/QueryOperationAction.tsx b/public/app/core/components/QueryOperationRow/QueryOperationAction.tsx
index c9a0bf2a543..f61344fd947 100644
--- a/public/app/core/components/QueryOperationRow/QueryOperationAction.tsx
+++ b/public/app/core/components/QueryOperationRow/QueryOperationAction.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/core/components/QueryOperationRow/QueryOperationRow.test.tsx b/public/app/core/components/QueryOperationRow/QueryOperationRow.test.tsx
index 2efdd6a2729..a6a672cea52 100644
--- a/public/app/core/components/QueryOperationRow/QueryOperationRow.test.tsx
+++ b/public/app/core/components/QueryOperationRow/QueryOperationRow.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { QueryOperationRow, QueryOperationRowProps } from './QueryOperationRow';
diff --git a/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx b/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx
index 5535d214861..547a9962d37 100644
--- a/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx
+++ b/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useCallback, useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
+import * as React from 'react';
import { Draggable } from 'react-beautiful-dnd';
import { useUpdateEffect } from 'react-use';
diff --git a/public/app/core/components/QueryOperationRow/QueryOperationRowHeader.test.tsx b/public/app/core/components/QueryOperationRow/QueryOperationRowHeader.test.tsx
index 7043bae11a0..ee610f13e2a 100644
--- a/public/app/core/components/QueryOperationRow/QueryOperationRowHeader.test.tsx
+++ b/public/app/core/components/QueryOperationRow/QueryOperationRowHeader.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { QueryOperationRowHeader, QueryOperationRowHeaderProps } from './QueryOperationRowHeader';
diff --git a/public/app/core/components/QueryOperationRow/QueryOperationRowHeader.tsx b/public/app/core/components/QueryOperationRow/QueryOperationRowHeader.tsx
index 0525cc9ca7f..51f5aff103f 100644
--- a/public/app/core/components/QueryOperationRow/QueryOperationRowHeader.tsx
+++ b/public/app/core/components/QueryOperationRow/QueryOperationRowHeader.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { MouseEventHandler } from 'react';
+import { MouseEventHandler } from 'react';
+import * as React from 'react';
import { DraggableProvided } from 'react-beautiful-dnd';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/core/components/RolePicker/BuiltinRoleSelector.tsx b/public/app/core/components/RolePicker/BuiltinRoleSelector.tsx
index 075c7491fd7..fe6e9581631 100644
--- a/public/app/core/components/RolePicker/BuiltinRoleSelector.tsx
+++ b/public/app/core/components/RolePicker/BuiltinRoleSelector.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SelectableValue } from '@grafana/data';
import { Icon, RadioButtonList, Tooltip, useStyles2, useTheme2, PopoverContent } from '@grafana/ui';
import { OrgRole } from 'app/types';
diff --git a/public/app/core/components/RolePicker/RoleMenuGroupOption.tsx b/public/app/core/components/RolePicker/RoleMenuGroupOption.tsx
index 6a7a1fef7cd..599b591dee3 100644
--- a/public/app/core/components/RolePicker/RoleMenuGroupOption.tsx
+++ b/public/app/core/components/RolePicker/RoleMenuGroupOption.tsx
@@ -1,5 +1,6 @@
import { cx } from '@emotion/css';
-import React, { FormEvent, memo } from 'react';
+import { FormEvent, memo } from 'react';
+import * as React from 'react';
import { Checkbox, Portal, useStyles2, useTheme2 } from '@grafana/ui';
import { getSelectStyles } from '@grafana/ui/src/components/Select/getSelectStyles';
diff --git a/public/app/core/components/RolePicker/RoleMenuGroupsSection.tsx b/public/app/core/components/RolePicker/RoleMenuGroupsSection.tsx
index 340b392cb2d..90695287595 100644
--- a/public/app/core/components/RolePicker/RoleMenuGroupsSection.tsx
+++ b/public/app/core/components/RolePicker/RoleMenuGroupsSection.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useState } from 'react';
+import { forwardRef, useCallback, useState } from 'react';
import { useStyles2, getSelectStyles, useTheme2 } from '@grafana/ui';
import { Role } from 'app/types';
@@ -29,7 +29,7 @@ interface RoleMenuGroupsSectionProps {
showOnLeftSubMenu?: boolean;
}
-export const RoleMenuGroupsSection = React.forwardRef(
+export const RoleMenuGroupsSection = forwardRef(
(
{
roles,
diff --git a/public/app/core/components/RolePicker/RoleMenuOption.tsx b/public/app/core/components/RolePicker/RoleMenuOption.tsx
index 0ee1c991c13..8fabb22eb8e 100644
--- a/public/app/core/components/RolePicker/RoleMenuOption.tsx
+++ b/public/app/core/components/RolePicker/RoleMenuOption.tsx
@@ -1,5 +1,5 @@
import { cx } from '@emotion/css';
-import React, { FormEvent } from 'react';
+import { forwardRef, FormEvent } from 'react';
import { Checkbox, Icon, Tooltip, useStyles2, useTheme2 } from '@grafana/ui';
import { getSelectStyles } from '@grafana/ui/src/components/Select/getSelectStyles';
@@ -16,7 +16,7 @@ interface RoleMenuOptionProps {
hideDescription?: boolean;
}
-export const RoleMenuOption = React.forwardRef>(
+export const RoleMenuOption = forwardRef>(
({ data, isFocused, isSelected, disabled, onChange, hideDescription }, ref) => {
const theme = useTheme2();
const styles = getSelectStyles(theme);
diff --git a/public/app/core/components/RolePicker/RolePicker.tsx b/public/app/core/components/RolePicker/RolePicker.tsx
index fe958e408c6..3df906a381c 100644
--- a/public/app/core/components/RolePicker/RolePicker.tsx
+++ b/public/app/core/components/RolePicker/RolePicker.tsx
@@ -1,4 +1,4 @@
-import React, { FormEvent, useCallback, useEffect, useState, useRef } from 'react';
+import { FormEvent, useCallback, useEffect, useState, useRef } from 'react';
import { ClickOutsideWrapper, Portal, useTheme2 } from '@grafana/ui';
import { Role, OrgRole } from 'app/types';
diff --git a/public/app/core/components/RolePicker/RolePickerInput.tsx b/public/app/core/components/RolePicker/RolePickerInput.tsx
index e5caab4b887..6bcf7b2e8b3 100644
--- a/public/app/core/components/RolePicker/RolePickerInput.tsx
+++ b/public/app/core/components/RolePicker/RolePickerInput.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { FormEvent, HTMLProps, useEffect, useRef } from 'react';
+import { FormEvent, HTMLProps, useEffect, useRef } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2, getInputStyles, sharedInputStyle, styleMixins, Tooltip, Icon, Spinner } from '@grafana/ui';
diff --git a/public/app/core/components/RolePicker/RolePickerMenu.tsx b/public/app/core/components/RolePicker/RolePickerMenu.tsx
index cb542c416ce..ed68be79f07 100644
--- a/public/app/core/components/RolePicker/RolePickerMenu.tsx
+++ b/public/app/core/components/RolePicker/RolePickerMenu.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { useEffect, useRef, useState } from 'react';
+import { useEffect, useRef, useState } from 'react';
import { Button, CustomScrollbar, Stack, TextLink, useStyles2, useTheme2 } from '@grafana/ui';
import { getSelectStyles } from '@grafana/ui/src/components/Select/getSelectStyles';
diff --git a/public/app/core/components/RolePicker/RolePickerSubMenu.tsx b/public/app/core/components/RolePicker/RolePickerSubMenu.tsx
index 2c5ba1b151f..7ea9bea52c7 100644
--- a/public/app/core/components/RolePicker/RolePickerSubMenu.tsx
+++ b/public/app/core/components/RolePicker/RolePickerSubMenu.tsx
@@ -1,5 +1,4 @@
import { cx } from '@emotion/css';
-import React from 'react';
import { Button, CustomScrollbar, Stack, useStyles2, useTheme2 } from '@grafana/ui';
import { getSelectStyles } from '@grafana/ui/src/components/Select/getSelectStyles';
diff --git a/public/app/core/components/RolePicker/TeamRolePicker.tsx b/public/app/core/components/RolePicker/TeamRolePicker.tsx
index f4f33871a53..83552236334 100644
--- a/public/app/core/components/RolePicker/TeamRolePicker.tsx
+++ b/public/app/core/components/RolePicker/TeamRolePicker.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import { useAsyncFn } from 'react-use';
import { contextSrv } from 'app/core/core';
diff --git a/public/app/core/components/RolePicker/UserRolePicker.tsx b/public/app/core/components/RolePicker/UserRolePicker.tsx
index 1b3bab63b71..5fa3c94286f 100644
--- a/public/app/core/components/RolePicker/UserRolePicker.tsx
+++ b/public/app/core/components/RolePicker/UserRolePicker.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import { useAsyncFn } from 'react-use';
import { contextSrv } from 'app/core/core';
diff --git a/public/app/core/components/RolePicker/ValueContainer.tsx b/public/app/core/components/RolePicker/ValueContainer.tsx
index f1a7d3848f4..ad3a7084c27 100644
--- a/public/app/core/components/RolePicker/ValueContainer.tsx
+++ b/public/app/core/components/RolePicker/ValueContainer.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { forwardRef, ReactNode } from 'react';
+import { forwardRef, ReactNode } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { getInputStyles, Icon, IconName, useStyles2, getSelectStyles } from '@grafana/ui';
diff --git a/public/app/core/components/SVG/SanitizedSVG.tsx b/public/app/core/components/SVG/SanitizedSVG.tsx
index b53bdccf5a1..1adf15b59e3 100644
--- a/public/app/core/components/SVG/SanitizedSVG.tsx
+++ b/public/app/core/components/SVG/SanitizedSVG.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import SVG, { Props } from 'react-inlinesvg';
import { textUtil } from '@grafana/data';
diff --git a/public/app/core/components/Select/DashboardPicker.tsx b/public/app/core/components/Select/DashboardPicker.tsx
index 047e0e59b14..bbce99e64c2 100644
--- a/public/app/core/components/Select/DashboardPicker.tsx
+++ b/public/app/core/components/Select/DashboardPicker.tsx
@@ -1,5 +1,5 @@
import debounce from 'debounce-promise';
-import React, { useCallback, useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
import { SelectableValue } from '@grafana/data';
import { AsyncSelectProps, AsyncSelect } from '@grafana/ui';
diff --git a/public/app/core/components/Select/FolderPicker.tsx b/public/app/core/components/Select/FolderPicker.tsx
index 39fbea56a38..e445d150615 100644
--- a/public/app/core/components/Select/FolderPicker.tsx
+++ b/public/app/core/components/Select/FolderPicker.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { config } from '@grafana/runtime';
diff --git a/public/app/core/components/Select/MetricSelect.test.tsx b/public/app/core/components/Select/MetricSelect.test.tsx
index d685b65c2b7..f0de2403d5e 100644
--- a/public/app/core/components/Select/MetricSelect.test.tsx
+++ b/public/app/core/components/Select/MetricSelect.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { select, openMenu } from 'react-select-event';
import { MetricSelect, Props } from './MetricSelect';
diff --git a/public/app/core/components/Select/MetricSelect.tsx b/public/app/core/components/Select/MetricSelect.tsx
index c1fca990418..771cf1aa6d2 100644
--- a/public/app/core/components/Select/MetricSelect.tsx
+++ b/public/app/core/components/Select/MetricSelect.tsx
@@ -1,5 +1,5 @@
import { flatten } from 'lodash';
-import React, { useCallback, useMemo } from 'react';
+import { useCallback, useMemo } from 'react';
import { SelectableValue } from '@grafana/data';
import { Select } from '@grafana/ui';
diff --git a/public/app/core/components/Select/OldFolderPicker.test.tsx b/public/app/core/components/Select/OldFolderPicker.test.tsx
index 3424c43be92..69fb67c5c9a 100644
--- a/public/app/core/components/Select/OldFolderPicker.test.tsx
+++ b/public/app/core/components/Select/OldFolderPicker.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import selectEvent from 'react-select-event';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/core/components/Select/OldFolderPicker.tsx b/public/app/core/components/Select/OldFolderPicker.tsx
index c144b30fba1..bb328f96434 100644
--- a/public/app/core/components/Select/OldFolderPicker.tsx
+++ b/public/app/core/components/Select/OldFolderPicker.tsx
@@ -1,6 +1,7 @@
import { css } from '@emotion/css';
import debounce from 'debounce-promise';
-import React, { FormEvent, useCallback, useEffect, useMemo, useState } from 'react';
+import { FormEvent, useCallback, useEffect, useMemo, useState } from 'react';
+import * as React from 'react';
import { useAsync } from 'react-use';
import { AppEvents, GrafanaTheme2, SelectableValue } from '@grafana/data';
diff --git a/public/app/core/components/Select/OrgPicker.test.tsx b/public/app/core/components/Select/OrgPicker.test.tsx
index 120d717dbfb..38344d1fd8a 100644
--- a/public/app/core/components/Select/OrgPicker.test.tsx
+++ b/public/app/core/components/Select/OrgPicker.test.tsx
@@ -1,6 +1,5 @@
import { screen, render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { OrgPicker } from './OrgPicker';
diff --git a/public/app/core/components/Select/OrgPicker.tsx b/public/app/core/components/Select/OrgPicker.tsx
index 27214d9f18e..596d69b2d6d 100644
--- a/public/app/core/components/Select/OrgPicker.tsx
+++ b/public/app/core/components/Select/OrgPicker.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import { useAsyncFn } from 'react-use';
import { SelectableValue } from '@grafana/data';
diff --git a/public/app/core/components/Select/ReadonlyFolderPicker/ReadonlyFolderPicker.test.tsx b/public/app/core/components/Select/ReadonlyFolderPicker/ReadonlyFolderPicker.test.tsx
index 9ccd2f3468f..6269aea909f 100644
--- a/public/app/core/components/Select/ReadonlyFolderPicker/ReadonlyFolderPicker.test.tsx
+++ b/public/app/core/components/Select/ReadonlyFolderPicker/ReadonlyFolderPicker.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { byTestId } from 'testing-library-selector';
import { SelectableValue } from '@grafana/data';
diff --git a/public/app/core/components/Select/ReadonlyFolderPicker/ReadonlyFolderPicker.tsx b/public/app/core/components/Select/ReadonlyFolderPicker/ReadonlyFolderPicker.tsx
index d60db50271c..170d6312031 100644
--- a/public/app/core/components/Select/ReadonlyFolderPicker/ReadonlyFolderPicker.tsx
+++ b/public/app/core/components/Select/ReadonlyFolderPicker/ReadonlyFolderPicker.tsx
@@ -1,5 +1,5 @@
import debouncePromise from 'debounce-promise';
-import React, { ReactElement, useCallback, useState } from 'react';
+import { ReactElement, useCallback, useState } from 'react';
import { SelectableValue } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/core/components/Select/ServiceAccountPicker.tsx b/public/app/core/components/Select/ServiceAccountPicker.tsx
index 4d88d316518..1cac0ebb600 100644
--- a/public/app/core/components/Select/ServiceAccountPicker.tsx
+++ b/public/app/core/components/Select/ServiceAccountPicker.tsx
@@ -1,5 +1,5 @@
import { debounce, DebouncedFuncLeading, isNil } from 'lodash';
-import React, { Component } from 'react';
+import { Component } from 'react';
import { SelectableValue } from '@grafana/data';
import { getBackendSrv } from '@grafana/runtime';
diff --git a/public/app/core/components/Select/SortPicker.tsx b/public/app/core/components/Select/SortPicker.tsx
index ec612c583a9..b07215156ce 100644
--- a/public/app/core/components/Select/SortPicker.tsx
+++ b/public/app/core/components/Select/SortPicker.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useAsync } from 'react-use';
import { SelectableValue } from '@grafana/data';
diff --git a/public/app/core/components/Select/TeamPicker.test.tsx b/public/app/core/components/Select/TeamPicker.test.tsx
index 1ade476e68b..9a822674471 100644
--- a/public/app/core/components/Select/TeamPicker.test.tsx
+++ b/public/app/core/components/Select/TeamPicker.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { TeamPicker } from './TeamPicker';
diff --git a/public/app/core/components/Select/TeamPicker.tsx b/public/app/core/components/Select/TeamPicker.tsx
index 345c0e55012..32ef82fc15d 100644
--- a/public/app/core/components/Select/TeamPicker.tsx
+++ b/public/app/core/components/Select/TeamPicker.tsx
@@ -1,5 +1,5 @@
import { debounce, DebouncedFuncLeading, isNil } from 'lodash';
-import React, { Component } from 'react';
+import { Component } from 'react';
import { SelectableValue } from '@grafana/data';
import { getBackendSrv } from '@grafana/runtime';
diff --git a/public/app/core/components/Select/UserPicker.test.tsx b/public/app/core/components/Select/UserPicker.test.tsx
index 00efa56b10f..6cb7009cb86 100644
--- a/public/app/core/components/Select/UserPicker.test.tsx
+++ b/public/app/core/components/Select/UserPicker.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { UserPicker } from './UserPicker';
diff --git a/public/app/core/components/Select/UserPicker.tsx b/public/app/core/components/Select/UserPicker.tsx
index c71bfa9af62..34857d7f0ec 100644
--- a/public/app/core/components/Select/UserPicker.tsx
+++ b/public/app/core/components/Select/UserPicker.tsx
@@ -1,5 +1,5 @@
import { debounce, DebouncedFuncLeading, isNil } from 'lodash';
-import React, { Component } from 'react';
+import { Component } from 'react';
import { SelectableValue } from '@grafana/data';
import { getBackendSrv } from '@grafana/runtime';
diff --git a/public/app/core/components/SharedPreferences/SharedPreferences.test.tsx b/public/app/core/components/SharedPreferences/SharedPreferences.test.tsx
index 8bf26101828..5b61d50da72 100644
--- a/public/app/core/components/SharedPreferences/SharedPreferences.test.tsx
+++ b/public/app/core/components/SharedPreferences/SharedPreferences.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { getSelectParent, selectOptionInTest } from 'test/helpers/selectOptionInTest';
import { Preferences as UserPreferencesDTO } from '@grafana/schema/src/raw/preferences/x/preferences_types.gen';
diff --git a/public/app/core/components/SharedPreferences/SharedPreferences.tsx b/public/app/core/components/SharedPreferences/SharedPreferences.tsx
index 57cc855855c..a294f78cd4e 100644
--- a/public/app/core/components/SharedPreferences/SharedPreferences.tsx
+++ b/public/app/core/components/SharedPreferences/SharedPreferences.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
+import * as React from 'react';
import { FeatureState, SelectableValue, getBuiltInThemes, ThemeRegistryItem } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/core/components/Signup/SignupPage.test.tsx b/public/app/core/components/Signup/SignupPage.test.tsx
index 96b4c84be49..167bd584491 100644
--- a/public/app/core/components/Signup/SignupPage.test.tsx
+++ b/public/app/core/components/Signup/SignupPage.test.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { render, fireEvent, screen, waitFor, userEvent } from 'test/test-utils';
import { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps';
diff --git a/public/app/core/components/Signup/SignupPage.tsx b/public/app/core/components/Signup/SignupPage.tsx
index c91cb364698..aecc1241955 100644
--- a/public/app/core/components/Signup/SignupPage.tsx
+++ b/public/app/core/components/Signup/SignupPage.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useForm } from 'react-hook-form';
import { getBackendSrv } from '@grafana/runtime';
diff --git a/public/app/core/components/Signup/VerifyEmail.tsx b/public/app/core/components/Signup/VerifyEmail.tsx
index cc255572863..9e6ce9577c7 100644
--- a/public/app/core/components/Signup/VerifyEmail.tsx
+++ b/public/app/core/components/Signup/VerifyEmail.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { useForm } from 'react-hook-form';
import { getBackendSrv } from '@grafana/runtime';
diff --git a/public/app/core/components/Signup/VerifyEmailPage.test.tsx b/public/app/core/components/Signup/VerifyEmailPage.test.tsx
index 424a7a6edd9..24f62c19d78 100644
--- a/public/app/core/components/Signup/VerifyEmailPage.test.tsx
+++ b/public/app/core/components/Signup/VerifyEmailPage.test.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { render, fireEvent, screen, waitFor, userEvent } from 'test/test-utils';
import { VerifyEmailPage } from './VerifyEmailPage';
diff --git a/public/app/core/components/Signup/VerifyEmailPage.tsx b/public/app/core/components/Signup/VerifyEmailPage.tsx
index 259965a177a..8fe86918d3f 100644
--- a/public/app/core/components/Signup/VerifyEmailPage.tsx
+++ b/public/app/core/components/Signup/VerifyEmailPage.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { LoginLayout, InnerBox } from '../Login/LoginLayout';
import { VerifyEmail } from './VerifyEmail';
diff --git a/public/app/core/components/SplitPaneWrapper/SplitPaneWrapper.tsx b/public/app/core/components/SplitPaneWrapper/SplitPaneWrapper.tsx
index 54691d44845..9ff66c518ee 100644
--- a/public/app/core/components/SplitPaneWrapper/SplitPaneWrapper.tsx
+++ b/public/app/core/components/SplitPaneWrapper/SplitPaneWrapper.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { createRef, MutableRefObject, PureComponent } from 'react';
+import { createRef, MutableRefObject, PureComponent } from 'react';
+import * as React from 'react';
import SplitPane, { Split } from 'react-split-pane';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/core/components/TagFilter/TagBadge.tsx b/public/app/core/components/TagFilter/TagBadge.tsx
index 204e5ed8ec4..c685d7c66e4 100644
--- a/public/app/core/components/TagFilter/TagBadge.tsx
+++ b/public/app/core/components/TagFilter/TagBadge.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { getTagColorsFromName, Icon } from '@grafana/ui';
diff --git a/public/app/core/components/TagFilter/TagFilter.tsx b/public/app/core/components/TagFilter/TagFilter.tsx
index f6148b7efab..98081dd6717 100644
--- a/public/app/core/components/TagFilter/TagFilter.tsx
+++ b/public/app/core/components/TagFilter/TagFilter.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useCallback, useEffect, useMemo, useState } from 'react';
+import { useCallback, useEffect, useMemo, useState } from 'react';
import { components, MultiValueRemoveProps } from 'react-select';
import { escapeStringForRegex, GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/core/components/TagFilter/TagOption.tsx b/public/app/core/components/TagFilter/TagOption.tsx
index 9a581e023d2..986d3f9ec7d 100644
--- a/public/app/core/components/TagFilter/TagOption.tsx
+++ b/public/app/core/components/TagFilter/TagOption.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { OptionProps } from 'react-select';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/core/components/TimePicker/TimePickerWithHistory.test.tsx b/public/app/core/components/TimePicker/TimePickerWithHistory.test.tsx
index 99883186c3e..8558e5764e5 100644
--- a/public/app/core/components/TimePicker/TimePickerWithHistory.test.tsx
+++ b/public/app/core/components/TimePicker/TimePickerWithHistory.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { getDefaultTimeRange, systemDateFormats } from '@grafana/data';
diff --git a/public/app/core/components/TimePicker/TimePickerWithHistory.tsx b/public/app/core/components/TimePicker/TimePickerWithHistory.tsx
index 570d2fb5780..64c08d31b67 100644
--- a/public/app/core/components/TimePicker/TimePickerWithHistory.tsx
+++ b/public/app/core/components/TimePicker/TimePickerWithHistory.tsx
@@ -1,5 +1,4 @@
import { uniqBy } from 'lodash';
-import React from 'react';
import { AppEvents, TimeRange, isDateTime, rangeUtil } from '@grafana/data';
import { TimeRangePickerProps, TimeRangePicker } from '@grafana/ui';
diff --git a/public/app/core/components/TimeSeries/TimeSeries.tsx b/public/app/core/components/TimeSeries/TimeSeries.tsx
index 45626aa2a18..197d468fc21 100644
--- a/public/app/core/components/TimeSeries/TimeSeries.tsx
+++ b/public/app/core/components/TimeSeries/TimeSeries.tsx
@@ -1,4 +1,4 @@
-import React, { Component } from 'react';
+import { Component } from 'react';
import { DataFrame, TimeRange } from '@grafana/data';
import { hasVisibleLegendSeries, PlotLegend } from '@grafana/ui/src/components/uPlot/PlotLegend';
diff --git a/public/app/core/components/TimelineChart/TimelineChart.tsx b/public/app/core/components/TimelineChart/TimelineChart.tsx
index 81ae09d2a7c..b6249657cca 100644
--- a/public/app/core/components/TimelineChart/TimelineChart.tsx
+++ b/public/app/core/components/TimelineChart/TimelineChart.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import { Component } from 'react';
import { DataFrame, FALLBACK_COLOR, FieldType, TimeRange } from '@grafana/data';
import { VisibilityMode, TimelineValueAlignment, TooltipDisplayMode, VizTooltipOptions } from '@grafana/schema';
@@ -23,7 +23,7 @@ export interface TimelineProps extends Omit {
+export class TimelineChart extends Component {
getValueColor = (frameIdx: number, fieldIdx: number, value: unknown) => {
const field = this.props.frames[frameIdx].fields[fieldIdx];
diff --git a/public/app/core/components/Upgrade/ProBadge.tsx b/public/app/core/components/Upgrade/ProBadge.tsx
index c886cc7e295..e8802c8f3bc 100644
--- a/public/app/core/components/Upgrade/ProBadge.tsx
+++ b/public/app/core/components/Upgrade/ProBadge.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { HTMLAttributes, useEffect } from 'react';
+import { HTMLAttributes, useEffect } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { reportExperimentView } from '@grafana/runtime';
diff --git a/public/app/core/components/Upgrade/UpgradeBox.tsx b/public/app/core/components/Upgrade/UpgradeBox.tsx
index 36f01e20ed5..e4bfb668273 100644
--- a/public/app/core/components/Upgrade/UpgradeBox.tsx
+++ b/public/app/core/components/Upgrade/UpgradeBox.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { HTMLAttributes, useEffect } from 'react';
+import { HTMLAttributes, useEffect } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { reportExperimentView } from '@grafana/runtime/src';
diff --git a/public/app/core/components/ValidationLabels/ValidationLabels.tsx b/public/app/core/components/ValidationLabels/ValidationLabels.tsx
index 20f50b36708..ee872bfaffa 100644
--- a/public/app/core/components/ValidationLabels/ValidationLabels.tsx
+++ b/public/app/core/components/ValidationLabels/ValidationLabels.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Box, Icon, Text, useStyles2 } from '@grafana/ui';
diff --git a/public/app/core/components/WithFeatureToggle.tsx b/public/app/core/components/WithFeatureToggle.tsx
index 8980535db5c..9f24edb36f0 100644
--- a/public/app/core/components/WithFeatureToggle.tsx
+++ b/public/app/core/components/WithFeatureToggle.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
export interface Props {
featureToggle: boolean;
diff --git a/public/app/core/components/help/HelpModal.tsx b/public/app/core/components/help/HelpModal.tsx
index e09721a0590..7f363828420 100644
--- a/public/app/core/components/help/HelpModal.tsx
+++ b/public/app/core/components/help/HelpModal.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Grid, Modal, useStyles2, Text } from '@grafana/ui';
diff --git a/public/app/core/context/GrafanaContext.ts b/public/app/core/context/GrafanaContext.ts
index b53788c23cc..1f3bf86372b 100644
--- a/public/app/core/context/GrafanaContext.ts
+++ b/public/app/core/context/GrafanaContext.ts
@@ -1,4 +1,4 @@
-import React, { useCallback, useContext } from 'react';
+import { createContext, useCallback, useContext } from 'react';
import { GrafanaConfig } from '@grafana/data';
import { LocationService, locationService, BackendSrv } from '@grafana/runtime';
@@ -16,7 +16,7 @@ export interface GrafanaContextType {
newAssetsChecker: NewFrontendAssetsChecker;
}
-export const GrafanaContext = React.createContext(undefined);
+export const GrafanaContext = createContext(undefined);
export function useGrafana(): GrafanaContextType {
const context = useContext(GrafanaContext);
diff --git a/public/app/core/context/ModalsContextProvider.tsx b/public/app/core/context/ModalsContextProvider.tsx
index 897588a7139..7566fc52d04 100644
--- a/public/app/core/context/ModalsContextProvider.tsx
+++ b/public/app/core/context/ModalsContextProvider.tsx
@@ -1,4 +1,5 @@
-import React, { useEffect, useMemo, useState } from 'react';
+import { useEffect, useMemo, useState } from 'react';
+import * as React from 'react';
import { textUtil } from '@grafana/data';
import { locationService } from '@grafana/runtime';
diff --git a/public/app/core/internationalization/index.test.tsx b/public/app/core/internationalization/index.test.tsx
index 6f83245b5b0..8eabddb6f15 100644
--- a/public/app/core/internationalization/index.test.tsx
+++ b/public/app/core/internationalization/index.test.tsx
@@ -1,5 +1,4 @@
import { render } from '@testing-library/react';
-import React from 'react';
import { Trans } from './index';
diff --git a/public/app/core/internationalization/index.tsx b/public/app/core/internationalization/index.tsx
index f111be88b98..895d7c58627 100644
--- a/public/app/core/internationalization/index.tsx
+++ b/public/app/core/internationalization/index.tsx
@@ -1,6 +1,5 @@
import i18n, { InitOptions, TFunction } from 'i18next';
import LanguageDetector, { DetectorOptions } from 'i18next-browser-languagedetector';
-import React from 'react';
import { Trans as I18NextTrans, initReactI18next } from 'react-i18next'; // eslint-disable-line no-restricted-imports
import { DEFAULT_LANGUAGE, NAMESPACES, VALID_LANGUAGES } from './constants';
diff --git a/public/app/core/navigation/GrafanaRoute.test.tsx b/public/app/core/navigation/GrafanaRoute.test.tsx
index d599a8479f2..301ccdae935 100644
--- a/public/app/core/navigation/GrafanaRoute.test.tsx
+++ b/public/app/core/navigation/GrafanaRoute.test.tsx
@@ -1,6 +1,6 @@
import { render, screen } from '@testing-library/react';
import { History, Location } from 'history';
-import React, { ComponentType } from 'react';
+import { lazy, ComponentType } from 'react';
import { match } from 'react-router-dom';
import { TestProvider } from 'test/helpers/TestProvider';
@@ -47,7 +47,7 @@ describe('GrafanaRoute', () => {
});
it('Shows loading on lazy load', async () => {
- const PageComponent = React.lazy(() => {
+ const PageComponent = lazy(() => {
return new Promise<{ default: ComponentType }>(() => {});
});
diff --git a/public/app/core/navigation/GrafanaRoute.tsx b/public/app/core/navigation/GrafanaRoute.tsx
index 7b40ea06d0f..f3718d09aaa 100644
--- a/public/app/core/navigation/GrafanaRoute.tsx
+++ b/public/app/core/navigation/GrafanaRoute.tsx
@@ -1,4 +1,4 @@
-import React, { Suspense, useEffect, useLayoutEffect } from 'react';
+import { Suspense, useEffect, useLayoutEffect } from 'react';
// @ts-ignore
import Drop from 'tether-drop';
diff --git a/public/app/core/navigation/GrafanaRouteError.tsx b/public/app/core/navigation/GrafanaRouteError.tsx
index 33c55654fb0..052df6bb0f7 100644
--- a/public/app/core/navigation/GrafanaRouteError.tsx
+++ b/public/app/core/navigation/GrafanaRouteError.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { ErrorInfo, useEffect } from 'react';
+import { ErrorInfo, useEffect } from 'react';
import { useLocation } from 'react-router-dom';
import { GrafanaTheme2, locationUtil, PageLayoutType } from '@grafana/data';
diff --git a/public/app/core/navigation/GrafanaRouteLoading.tsx b/public/app/core/navigation/GrafanaRouteLoading.tsx
index 01830aa7459..5ca45723fee 100644
--- a/public/app/core/navigation/GrafanaRouteLoading.tsx
+++ b/public/app/core/navigation/GrafanaRouteLoading.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/core/navigation/RouterDebugger.tsx b/public/app/core/navigation/RouterDebugger.tsx
index b033c5cc57a..abc6f9f66cc 100644
--- a/public/app/core/navigation/RouterDebugger.tsx
+++ b/public/app/core/navigation/RouterDebugger.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { Link } from 'react-router-dom';
import { getAppRoutes } from '../../routes/routes';
diff --git a/public/app/core/navigation/testRoutes.tsx b/public/app/core/navigation/testRoutes.tsx
index 82e5e5bec79..391d4dac3af 100644
--- a/public/app/core/navigation/testRoutes.tsx
+++ b/public/app/core/navigation/testRoutes.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { Link, NavLink } from 'react-router-dom';
import { RouterDebugger } from './RouterDebugger';
diff --git a/public/app/core/navigation/types.ts b/public/app/core/navigation/types.ts
index 9469221cb6d..8cae703857a 100644
--- a/public/app/core/navigation/types.ts
+++ b/public/app/core/navigation/types.ts
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { RouteComponentProps } from 'react-router';
import { UrlQueryMap } from '@grafana/data';
diff --git a/public/app/core/utils/ConfigProvider.tsx b/public/app/core/utils/ConfigProvider.tsx
index 7dafacffb78..53cdc1c3fc4 100644
--- a/public/app/core/utils/ConfigProvider.tsx
+++ b/public/app/core/utils/ConfigProvider.tsx
@@ -1,4 +1,5 @@
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
+import * as React from 'react';
import { SkeletonTheme } from 'react-loading-skeleton';
import { GrafanaTheme2, ThemeContext } from '@grafana/data';
diff --git a/public/app/core/utils/connectWithReduxStore.tsx b/public/app/core/utils/connectWithReduxStore.tsx
index 83f3b519fd3..6aef5e8711a 100644
--- a/public/app/core/utils/connectWithReduxStore.tsx
+++ b/public/app/core/utils/connectWithReduxStore.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { connect, Provider } from 'react-redux';
import { store } from '../../store/store';
diff --git a/public/app/core/utils/shortLinks.ts b/public/app/core/utils/shortLinks.ts
index 74ebbfbeb44..13d162967a2 100644
--- a/public/app/core/utils/shortLinks.ts
+++ b/public/app/core/utils/shortLinks.ts
@@ -9,6 +9,9 @@ import { DashboardScene } from 'app/features/dashboard-scene/scene/DashboardScen
import { getDashboardUrl } from 'app/features/dashboard-scene/utils/urlBuilders';
import { dispatch } from 'app/store/store';
+import { ShareLinkConfiguration } from '../../features/dashboard-scene/sharing/ShareButton/utils';
+import { t } from '../internationalization';
+
import { copyStringToClipboard } from './explore';
function buildHostUrl() {
@@ -42,20 +45,21 @@ export const createAndCopyShortLink = async (path: string) => {
}
};
-export const createAndCopyDashboardShortLink = async (
+export const createAndCopyShareDashboardLink = async (
dashboard: DashboardScene,
- opts: { useAbsoluteTimeRange: boolean; theme: string },
+ opts: ShareLinkConfiguration,
panel?: VizPanel
) => {
- const shareUrl = await createDashboardShareUrl(dashboard, opts, panel);
- await createAndCopyShortLink(shareUrl);
+ const shareUrl = createDashboardShareUrl(dashboard, opts, panel);
+ if (opts.useShortUrl) {
+ return await createAndCopyShortLink(shareUrl);
+ } else {
+ copyStringToClipboard(shareUrl);
+ dispatch(notifyApp(createSuccessNotification(t('link.share.copy-to-clipboard', 'Link copied to clipboard'))));
+ }
};
-export const createDashboardShareUrl = async (
- dashboard: DashboardScene,
- opts: { useAbsoluteTimeRange: boolean; theme: string },
- panel?: VizPanel
-) => {
+export const createDashboardShareUrl = (dashboard: DashboardScene, opts: ShareLinkConfiguration, panel?: VizPanel) => {
const location = locationService.getLocation();
const timeRange = sceneGraph.getTimeRange(panel ?? dashboard);
diff --git a/public/app/dev.ts b/public/app/dev.ts
index f228e80715a..8f72f1ab077 100644
--- a/public/app/dev.ts
+++ b/public/app/dev.ts
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
export async function initDevFeatures() {
// if why-render is in url enable why did you render react extension
diff --git a/public/app/features/admin/AdminEditOrgPage.tsx b/public/app/features/admin/AdminEditOrgPage.tsx
index 910bc855251..f83374d68b6 100644
--- a/public/app/features/admin/AdminEditOrgPage.tsx
+++ b/public/app/features/admin/AdminEditOrgPage.tsx
@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from 'react';
+import { useState, useEffect } from 'react';
import { useForm } from 'react-hook-form';
import { useAsyncFn } from 'react-use';
diff --git a/public/app/features/admin/AdminFeatureTogglesPage.tsx b/public/app/features/admin/AdminFeatureTogglesPage.tsx
index 0684405b3ee..92f7dd8df6c 100644
--- a/public/app/features/admin/AdminFeatureTogglesPage.tsx
+++ b/public/app/features/admin/AdminFeatureTogglesPage.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { useAsync } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/admin/AdminFeatureTogglesTable.tsx b/public/app/features/admin/AdminFeatureTogglesTable.tsx
index 3be88a6fe75..295b8bcacc7 100644
--- a/public/app/features/admin/AdminFeatureTogglesTable.tsx
+++ b/public/app/features/admin/AdminFeatureTogglesTable.tsx
@@ -1,4 +1,4 @@
-import React, { useState, useRef } from 'react';
+import { useState, useRef } from 'react';
import { Switch, InteractiveTable, Tooltip, type CellProps, Button, ConfirmModal, type SortByFn } from '@grafana/ui';
diff --git a/public/app/features/admin/AdminListOrgsPage.tsx b/public/app/features/admin/AdminListOrgsPage.tsx
index 6423924c004..f5fe2fe7fd4 100644
--- a/public/app/features/admin/AdminListOrgsPage.tsx
+++ b/public/app/features/admin/AdminListOrgsPage.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import useAsyncFn from 'react-use/lib/useAsyncFn';
import { getBackendSrv, isFetchError } from '@grafana/runtime';
diff --git a/public/app/features/admin/AdminOrgsTable.tsx b/public/app/features/admin/AdminOrgsTable.tsx
index 8f6cd87a571..6c99f023609 100644
--- a/public/app/features/admin/AdminOrgsTable.tsx
+++ b/public/app/features/admin/AdminOrgsTable.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import Skeleton from 'react-loading-skeleton';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/admin/AdminSettings.tsx b/public/app/features/admin/AdminSettings.tsx
index 4bd16ba2309..fd9a4abf5a9 100644
--- a/public/app/features/admin/AdminSettings.tsx
+++ b/public/app/features/admin/AdminSettings.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useAsync } from 'react-use';
import { getBackendSrv } from '@grafana/runtime';
diff --git a/public/app/features/admin/AdminSettingsTable.tsx b/public/app/features/admin/AdminSettingsTable.tsx
index 8825b98a45a..f5a016d0c11 100644
--- a/public/app/features/admin/AdminSettingsTable.tsx
+++ b/public/app/features/admin/AdminSettingsTable.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import { Fragment } from 'react';
import Skeleton from 'react-loading-skeleton';
import { Text } from '@grafana/ui';
@@ -15,7 +15,7 @@ const AdminSettingsTableComponent = ({ settings }: Props) => {
{Object.entries(settings).map(([sectionName, sectionSettings], i) => (
-
+
@@ -30,7 +30,7 @@ const AdminSettingsTableComponent = ({ settings }: Props) => {
{settingValue}
))}
-
+
))}
@@ -48,7 +48,7 @@ const AdminSettingsTableSkeleton: SkeletonComponent = ({ rootProps }) => {
const isSection = index === 0 || randomValue > 0.9;
return (
-
+
{isSection && (
@@ -65,7 +65,7 @@ const AdminSettingsTableSkeleton: SkeletonComponent = ({ rootProps }) => {
-
+
);
})}
diff --git a/public/app/features/admin/LicenseChrome.tsx b/public/app/features/admin/LicenseChrome.tsx
index 51ddfc7c337..dbd0b597fd9 100644
--- a/public/app/features/admin/LicenseChrome.tsx
+++ b/public/app/features/admin/LicenseChrome.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2, useTheme2 } from '@grafana/ui';
diff --git a/public/app/features/admin/OrgRolePicker.tsx b/public/app/features/admin/OrgRolePicker.tsx
index c123cbd1222..3e637d05e0a 100644
--- a/public/app/features/admin/OrgRolePicker.tsx
+++ b/public/app/features/admin/OrgRolePicker.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { OrgRole } from '@grafana/data';
import { Select } from '@grafana/ui';
diff --git a/public/app/features/admin/ServerStats.test.tsx b/public/app/features/admin/ServerStats.test.tsx
index 2a88bcb7fe5..a1343c5d6a7 100644
--- a/public/app/features/admin/ServerStats.test.tsx
+++ b/public/app/features/admin/ServerStats.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import config from 'app/core/config';
diff --git a/public/app/features/admin/ServerStats.tsx b/public/app/features/admin/ServerStats.tsx
index 8d366495457..9d0e0da9ae9 100644
--- a/public/app/features/admin/ServerStats.tsx
+++ b/public/app/features/admin/ServerStats.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { config, GrafanaBootConfig } from '@grafana/runtime';
diff --git a/public/app/features/admin/ServerStatsCard.tsx b/public/app/features/admin/ServerStatsCard.tsx
index 66fdabde6d8..ff78a5fba76 100644
--- a/public/app/features/admin/ServerStatsCard.tsx
+++ b/public/app/features/admin/ServerStatsCard.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import Skeleton from 'react-loading-skeleton';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/admin/UpgradePage.tsx b/public/app/features/admin/UpgradePage.tsx
index b6e7fc9ec85..2cfdf38f0e9 100644
--- a/public/app/features/admin/UpgradePage.tsx
+++ b/public/app/features/admin/UpgradePage.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { connect } from 'react-redux';
import { GrafanaTheme2, NavModel } from '@grafana/data';
diff --git a/public/app/features/admin/UserAdminPage.tsx b/public/app/features/admin/UserAdminPage.tsx
index 0d0109c520a..dc40a882c73 100644
--- a/public/app/features/admin/UserAdminPage.tsx
+++ b/public/app/features/admin/UserAdminPage.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { NavModelItem } from '@grafana/data';
diff --git a/public/app/features/admin/UserCreatePage.tsx b/public/app/features/admin/UserCreatePage.tsx
index 34bdee39089..b252c215edd 100644
--- a/public/app/features/admin/UserCreatePage.tsx
+++ b/public/app/features/admin/UserCreatePage.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { useForm } from 'react-hook-form';
import { useHistory } from 'react-router-dom';
diff --git a/public/app/features/admin/UserLdapSyncInfo.tsx b/public/app/features/admin/UserLdapSyncInfo.tsx
index 0ff189bb5d6..df2f270c620 100644
--- a/public/app/features/admin/UserLdapSyncInfo.tsx
+++ b/public/app/features/admin/UserLdapSyncInfo.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { dateTimeFormat } from '@grafana/data';
import { Button, LinkButton } from '@grafana/ui';
diff --git a/public/app/features/admin/UserListAdminPage.tsx b/public/app/features/admin/UserListAdminPage.tsx
index 6fbbc543a56..1456a8844f4 100644
--- a/public/app/features/admin/UserListAdminPage.tsx
+++ b/public/app/features/admin/UserListAdminPage.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { ComponentType, useEffect } from 'react';
+import { ComponentType, useEffect } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/admin/UserListAnonymousPage.tsx b/public/app/features/admin/UserListAnonymousPage.tsx
index 3d4355653a9..fe7405c0fbe 100644
--- a/public/app/features/admin/UserListAnonymousPage.tsx
+++ b/public/app/features/admin/UserListAnonymousPage.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/admin/UserListPage.test.tsx b/public/app/features/admin/UserListPage.test.tsx
index 274c15f4fdd..86e34581877 100644
--- a/public/app/features/admin/UserListPage.test.tsx
+++ b/public/app/features/admin/UserListPage.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src';
import { GrafanaBootConfig } from '@grafana/runtime/src';
diff --git a/public/app/features/admin/UserListPage.tsx b/public/app/features/admin/UserListPage.tsx
index d5bb089c62f..ffcf5a54944 100644
--- a/public/app/features/admin/UserListPage.tsx
+++ b/public/app/features/admin/UserListPage.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors as e2eSelectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/admin/UserListPublicDashboardPage/DashboardsListModalButton.tsx b/public/app/features/admin/UserListPublicDashboardPage/DashboardsListModalButton.tsx
index 625b4075679..3507d3bef02 100644
--- a/public/app/features/admin/UserListPublicDashboardPage/DashboardsListModalButton.tsx
+++ b/public/app/features/admin/UserListPublicDashboardPage/DashboardsListModalButton.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data/src';
import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src';
diff --git a/public/app/features/admin/UserListPublicDashboardPage/DeleteUserModalButton.tsx b/public/app/features/admin/UserListPublicDashboardPage/DeleteUserModalButton.tsx
index 90271933884..98d427d5569 100644
--- a/public/app/features/admin/UserListPublicDashboardPage/DeleteUserModalButton.tsx
+++ b/public/app/features/admin/UserListPublicDashboardPage/DeleteUserModalButton.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data/src';
import { Button, Modal, ModalsController, useStyles2 } from '@grafana/ui/src';
diff --git a/public/app/features/admin/UserListPublicDashboardPage/UserListPublicDashboardPage.tsx b/public/app/features/admin/UserListPublicDashboardPage/UserListPublicDashboardPage.tsx
index 655b80fcced..e2971cb1fbf 100644
--- a/public/app/features/admin/UserListPublicDashboardPage/UserListPublicDashboardPage.tsx
+++ b/public/app/features/admin/UserListPublicDashboardPage/UserListPublicDashboardPage.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src';
import { Icon, Stack, Tag, Tooltip } from '@grafana/ui/src';
import { Page } from 'app/core/components/Page/Page';
diff --git a/public/app/features/admin/UserOrgs.tsx b/public/app/features/admin/UserOrgs.tsx
index 2cfa498ebfd..66ecda8c441 100644
--- a/public/app/features/admin/UserOrgs.tsx
+++ b/public/app/features/admin/UserOrgs.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { PureComponent, ReactElement } from 'react';
+import { createRef, PureComponent, ReactElement } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import {
@@ -38,7 +38,7 @@ interface State {
}
export class UserOrgs extends PureComponent {
- addToOrgButtonRef = React.createRef();
+ addToOrgButtonRef = createRef();
state = {
showAddOrgModal: false,
};
diff --git a/public/app/features/admin/UserPermissions.tsx b/public/app/features/admin/UserPermissions.tsx
index 795223dfdc3..0ebd00f0366 100644
--- a/public/app/features/admin/UserPermissions.tsx
+++ b/public/app/features/admin/UserPermissions.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { ConfirmButton, RadioButtonGroup, Icon, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/admin/UserProfile.tsx b/public/app/features/admin/UserProfile.tsx
index 222fc27486c..34ee8a40cd0 100644
--- a/public/app/features/admin/UserProfile.tsx
+++ b/public/app/features/admin/UserProfile.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { PureComponent, useRef, useState } from 'react';
+import { PureComponent, useRef, useState } from 'react';
+import * as React from 'react';
import { Button, ConfirmButton, ConfirmModal, Input, LegacyInputStatus, Stack } from '@grafana/ui';
import { contextSrv } from 'app/core/core';
diff --git a/public/app/features/admin/UserSessions.tsx b/public/app/features/admin/UserSessions.tsx
index 91f8694998b..9197d962ce7 100644
--- a/public/app/features/admin/UserSessions.tsx
+++ b/public/app/features/admin/UserSessions.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { createRef, PureComponent } from 'react';
import { ConfirmButton, ConfirmModal, Button, Stack } from '@grafana/ui';
import { contextSrv } from 'app/core/core';
@@ -17,7 +17,7 @@ interface State {
}
class BaseUserSessions extends PureComponent {
- forceAllLogoutButton = React.createRef();
+ forceAllLogoutButton = createRef();
state: State = {
showLogoutModal: false,
};
diff --git a/public/app/features/admin/Users/AnonUsersTable.tsx b/public/app/features/admin/Users/AnonUsersTable.tsx
index 75c7f96aa78..22f5f5113db 100644
--- a/public/app/features/admin/Users/AnonUsersTable.tsx
+++ b/public/app/features/admin/Users/AnonUsersTable.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import {
Avatar,
diff --git a/public/app/features/admin/Users/OrgUnits.tsx b/public/app/features/admin/Users/OrgUnits.tsx
index 5da20ac22c3..5dc25622fed 100644
--- a/public/app/features/admin/Users/OrgUnits.tsx
+++ b/public/app/features/admin/Users/OrgUnits.tsx
@@ -1,4 +1,4 @@
-import React, { forwardRef, PropsWithChildren } from 'react';
+import { forwardRef, PropsWithChildren } from 'react';
import { IconName } from '@grafana/data';
import { Icon, Tooltip, Box, Stack } from '@grafana/ui';
diff --git a/public/app/features/admin/Users/OrgUsersTable.test.tsx b/public/app/features/admin/Users/OrgUsersTable.test.tsx
index 73f04d628f0..8652688ab6e 100644
--- a/public/app/features/admin/Users/OrgUsersTable.test.tsx
+++ b/public/app/features/admin/Users/OrgUsersTable.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { OrgUser } from '../../../types';
import { getMockUsers } from '../../users/__mocks__/userMocks';
diff --git a/public/app/features/admin/Users/OrgUsersTable.tsx b/public/app/features/admin/Users/OrgUsersTable.tsx
index 135413ae534..56550e1ea79 100644
--- a/public/app/features/admin/Users/OrgUsersTable.tsx
+++ b/public/app/features/admin/Users/OrgUsersTable.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useMemo, useState } from 'react';
+import { useEffect, useMemo, useState } from 'react';
import { OrgRole } from '@grafana/data';
import { selectors as e2eSelectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/admin/Users/UsersTable.tsx b/public/app/features/admin/Users/UsersTable.tsx
index 1c23998d5c5..5ee4f57509e 100644
--- a/public/app/features/admin/Users/UsersTable.tsx
+++ b/public/app/features/admin/Users/UsersTable.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { UseTableRowProps } from 'react-table';
import {
diff --git a/public/app/features/admin/ldap/LdapConnectionStatus.tsx b/public/app/features/admin/ldap/LdapConnectionStatus.tsx
index 2616a50436f..647688111f8 100644
--- a/public/app/features/admin/ldap/LdapConnectionStatus.tsx
+++ b/public/app/features/admin/ldap/LdapConnectionStatus.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { Alert, CellProps, Column, Icon, InteractiveTable, Stack, Text, Tooltip } from '@grafana/ui';
import { AppNotificationSeverity, LdapConnectionInfo, LdapServerInfo } from 'app/types';
diff --git a/public/app/features/admin/ldap/LdapPage.tsx b/public/app/features/admin/ldap/LdapPage.tsx
index d7bf34f6b87..d7eaade9b1a 100644
--- a/public/app/features/admin/ldap/LdapPage.tsx
+++ b/public/app/features/admin/ldap/LdapPage.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
import { useForm } from 'react-hook-form';
import { connect, ConnectedProps } from 'react-redux';
diff --git a/public/app/features/admin/ldap/LdapSyncInfo.tsx b/public/app/features/admin/ldap/LdapSyncInfo.tsx
index 6dc3dbcf56e..b51441d98e0 100644
--- a/public/app/features/admin/ldap/LdapSyncInfo.tsx
+++ b/public/app/features/admin/ldap/LdapSyncInfo.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { dateTimeFormat } from '@grafana/data';
import { InteractiveTable, Text } from '@grafana/ui';
import { SyncInfo } from 'app/types';
diff --git a/public/app/features/admin/ldap/LdapUserGroups.tsx b/public/app/features/admin/ldap/LdapUserGroups.tsx
index ced2acdab68..b5e35ea6285 100644
--- a/public/app/features/admin/ldap/LdapUserGroups.tsx
+++ b/public/app/features/admin/ldap/LdapUserGroups.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { Tooltip, Icon, InteractiveTable, type CellProps, Column } from '@grafana/ui';
import { LdapRole } from 'app/types';
diff --git a/public/app/features/admin/ldap/LdapUserInfo.tsx b/public/app/features/admin/ldap/LdapUserInfo.tsx
index 9f14a99f02f..115c41f78c0 100644
--- a/public/app/features/admin/ldap/LdapUserInfo.tsx
+++ b/public/app/features/admin/ldap/LdapUserInfo.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Box, Stack, Text } from '@grafana/ui';
import { LdapUser } from 'app/types';
diff --git a/public/app/features/admin/ldap/LdapUserMappingInfo.tsx b/public/app/features/admin/ldap/LdapUserMappingInfo.tsx
index c4989e4bf4d..534ea3cf0a7 100644
--- a/public/app/features/admin/ldap/LdapUserMappingInfo.tsx
+++ b/public/app/features/admin/ldap/LdapUserMappingInfo.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { InteractiveTable } from '@grafana/ui';
import { LdapUserInfo } from 'app/types';
diff --git a/public/app/features/admin/ldap/LdapUserPermissions.tsx b/public/app/features/admin/ldap/LdapUserPermissions.tsx
index d206ce2d03c..96071801be9 100644
--- a/public/app/features/admin/ldap/LdapUserPermissions.tsx
+++ b/public/app/features/admin/ldap/LdapUserPermissions.tsx
@@ -1,4 +1,5 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
+import * as React from 'react';
import { Column, Icon, InteractiveTable } from '@grafana/ui';
import { LdapPermissions } from 'app/types';
diff --git a/public/app/features/admin/ldap/LdapUserTeams.tsx b/public/app/features/admin/ldap/LdapUserTeams.tsx
index 0df5926099c..39f9f779710 100644
--- a/public/app/features/admin/ldap/LdapUserTeams.tsx
+++ b/public/app/features/admin/ldap/LdapUserTeams.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { Column, InteractiveTable, CellProps } from '@grafana/ui';
import { LdapTeam } from 'app/types';
diff --git a/public/app/features/alerting/unified/AlertGroups.test.tsx b/public/app/features/alerting/unified/AlertGroups.test.tsx
index 45066ea5de7..d82780dc266 100644
--- a/public/app/features/alerting/unified/AlertGroups.test.tsx
+++ b/public/app/features/alerting/unified/AlertGroups.test.tsx
@@ -1,6 +1,5 @@
import { render, waitFor, waitForElementToBeRemoved } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { byRole, byTestId, byText } from 'testing-library-selector';
diff --git a/public/app/features/alerting/unified/AlertGroups.tsx b/public/app/features/alerting/unified/AlertGroups.tsx
index 3aa683742eb..ec52313d5b9 100644
--- a/public/app/features/alerting/unified/AlertGroups.tsx
+++ b/public/app/features/alerting/unified/AlertGroups.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect } from 'react';
+import { Fragment, useEffect } from 'react';
import { Alert, LoadingPlaceholder, Text, Box } from '@grafana/ui';
import { useQueryParams } from 'app/core/hooks/useQueryParams';
@@ -71,7 +71,7 @@ const AlertGroups = () => {
{results &&
filteredAlertGroups.map((group, index) => {
return (
-
+
{((index === 1 && Object.keys(filteredAlertGroups[0].labels).length === 0) ||
(index === 0 && Object.keys(group.labels).length > 0)) && (
@@ -81,7 +81,7 @@ const AlertGroups = () => {
)}
-
+
);
})}
{results && !filteredAlertGroups.length && No results.
}
diff --git a/public/app/features/alerting/unified/AlertWarning.tsx b/public/app/features/alerting/unified/AlertWarning.tsx
index ab4ab0d2b7c..de5abeccf59 100644
--- a/public/app/features/alerting/unified/AlertWarning.tsx
+++ b/public/app/features/alerting/unified/AlertWarning.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Alert, LinkButton, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/AlertingNotEnabled.tsx b/public/app/features/alerting/unified/AlertingNotEnabled.tsx
index 7d2b89ae9e5..ca8a10aa487 100644
--- a/public/app/features/alerting/unified/AlertingNotEnabled.tsx
+++ b/public/app/features/alerting/unified/AlertingNotEnabled.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { NavModel } from '@grafana/data';
import { Page } from 'app/core/components/Page/Page';
diff --git a/public/app/features/alerting/unified/AlertsFolderView.test.tsx b/public/app/features/alerting/unified/AlertsFolderView.test.tsx
index 4ae40d245b4..ec1d3a27c5f 100644
--- a/public/app/features/alerting/unified/AlertsFolderView.test.tsx
+++ b/public/app/features/alerting/unified/AlertsFolderView.test.tsx
@@ -1,6 +1,5 @@
import { render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { byTestId } from 'testing-library-selector';
diff --git a/public/app/features/alerting/unified/AlertsFolderView.tsx b/public/app/features/alerting/unified/AlertsFolderView.tsx
index fac2797f1f7..1beb52abf25 100644
--- a/public/app/features/alerting/unified/AlertsFolderView.tsx
+++ b/public/app/features/alerting/unified/AlertsFolderView.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { orderBy } from 'lodash';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { useDebounce } from 'react-use';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/CloneRuleEditor.test.tsx b/public/app/features/alerting/unified/CloneRuleEditor.test.tsx
index 06d5354d0bd..211c66c1622 100644
--- a/public/app/features/alerting/unified/CloneRuleEditor.test.tsx
+++ b/public/app/features/alerting/unified/CloneRuleEditor.test.tsx
@@ -1,5 +1,5 @@
import { render, waitFor, waitForElementToBeRemoved, within } from '@testing-library/react';
-import React from 'react';
+import * as React from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { TestProvider } from 'test/helpers/TestProvider';
import { byRole, byTestId, byText } from 'testing-library-selector';
diff --git a/public/app/features/alerting/unified/CloneRuleEditor.tsx b/public/app/features/alerting/unified/CloneRuleEditor.tsx
index 1a70ee3348b..70a050b1ea9 100644
--- a/public/app/features/alerting/unified/CloneRuleEditor.tsx
+++ b/public/app/features/alerting/unified/CloneRuleEditor.tsx
@@ -1,5 +1,4 @@
import { cloneDeep } from 'lodash';
-import React from 'react';
import { locationService } from '@grafana/runtime/src';
import { Alert, LoadingPlaceholder } from '@grafana/ui/src';
diff --git a/public/app/features/alerting/unified/ExistingRuleEditor.tsx b/public/app/features/alerting/unified/ExistingRuleEditor.tsx
index df864f05287..17dc0d74753 100644
--- a/public/app/features/alerting/unified/ExistingRuleEditor.tsx
+++ b/public/app/features/alerting/unified/ExistingRuleEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Alert, LoadingPlaceholder } from '@grafana/ui';
import { RuleIdentifier } from 'app/types/unified-alerting';
diff --git a/public/app/features/alerting/unified/GrafanaRuleQueryViewer.test.tsx b/public/app/features/alerting/unified/GrafanaRuleQueryViewer.test.tsx
index b77aba3e2e3..0eee3f57c69 100644
--- a/public/app/features/alerting/unified/GrafanaRuleQueryViewer.test.tsx
+++ b/public/app/features/alerting/unified/GrafanaRuleQueryViewer.test.tsx
@@ -1,5 +1,4 @@
import { render, waitFor } from '@testing-library/react';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { DataSourceRef } from '@grafana/schema';
diff --git a/public/app/features/alerting/unified/GrafanaRuleQueryViewer.tsx b/public/app/features/alerting/unified/GrafanaRuleQueryViewer.tsx
index 8972f9c3cc9..0601d0b445b 100644
--- a/public/app/features/alerting/unified/GrafanaRuleQueryViewer.tsx
+++ b/public/app/features/alerting/unified/GrafanaRuleQueryViewer.tsx
@@ -1,6 +1,6 @@
import { css, cx } from '@emotion/css';
import { keyBy, startCase } from 'lodash';
-import React from 'react';
+import * as React from 'react';
import { DataSourceInstanceSettings, DataSourceRef, GrafanaTheme2, PanelData, urlUtil } from '@grafana/data';
import { secondsToHms } from '@grafana/data/src/datetime/rangeutil';
diff --git a/public/app/features/alerting/unified/MuteTimings.test.tsx b/public/app/features/alerting/unified/MuteTimings.test.tsx
index d52434ca228..dbd0d6f7cfc 100644
--- a/public/app/features/alerting/unified/MuteTimings.test.tsx
+++ b/public/app/features/alerting/unified/MuteTimings.test.tsx
@@ -1,6 +1,5 @@
import { fireEvent, render, waitFor, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { byRole, byTestId, byText } from 'testing-library-selector';
diff --git a/public/app/features/alerting/unified/MuteTimings.tsx b/public/app/features/alerting/unified/MuteTimings.tsx
index a49205c4774..8306c1eb724 100644
--- a/public/app/features/alerting/unified/MuteTimings.tsx
+++ b/public/app/features/alerting/unified/MuteTimings.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
import { Redirect, Route, Switch, useRouteMatch } from 'react-router-dom';
import { NavModelItem } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/NotificationPolicies.test.tsx b/public/app/features/alerting/unified/NotificationPolicies.test.tsx
index 258cab99483..e72488f1bf0 100644
--- a/public/app/features/alerting/unified/NotificationPolicies.test.tsx
+++ b/public/app/features/alerting/unified/NotificationPolicies.test.tsx
@@ -1,6 +1,5 @@
import { render, waitFor, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { selectOptionInTest } from 'test/helpers/selectOptionInTest';
import { byLabelText, byRole, byTestId, byText } from 'testing-library-selector';
diff --git a/public/app/features/alerting/unified/NotificationPolicies.tsx b/public/app/features/alerting/unified/NotificationPolicies.tsx
index 1bfdaccfa34..d09f48e8fb5 100644
--- a/public/app/features/alerting/unified/NotificationPolicies.tsx
+++ b/public/app/features/alerting/unified/NotificationPolicies.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useMemo, useState } from 'react';
+import { useEffect, useMemo, useState } from 'react';
import { useAsyncFn } from 'react-use';
import { GrafanaTheme2, UrlQueryMap } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/PanelAlertTab.tsx b/public/app/features/alerting/unified/PanelAlertTab.tsx
index 697fe405efc..95329e892dc 100644
--- a/public/app/features/alerting/unified/PanelAlertTab.tsx
+++ b/public/app/features/alerting/unified/PanelAlertTab.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Tab, TabProps } from '@grafana/ui';
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
diff --git a/public/app/features/alerting/unified/PanelAlertTabContent.test.tsx b/public/app/features/alerting/unified/PanelAlertTabContent.test.tsx
index 0eeddc37a2a..aaa604e5fb3 100644
--- a/public/app/features/alerting/unified/PanelAlertTabContent.test.tsx
+++ b/public/app/features/alerting/unified/PanelAlertTabContent.test.tsx
@@ -1,5 +1,4 @@
import { render } from '@testing-library/react';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { byTestId } from 'testing-library-selector';
diff --git a/public/app/features/alerting/unified/PanelAlertTabContent.tsx b/public/app/features/alerting/unified/PanelAlertTabContent.tsx
index 3dafb596575..e0be9d23f81 100644
--- a/public/app/features/alerting/unified/PanelAlertTabContent.tsx
+++ b/public/app/features/alerting/unified/PanelAlertTabContent.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/alerting/unified/Receivers.test.tsx b/public/app/features/alerting/unified/Receivers.test.tsx
index 982b4488eec..c7619e39f18 100644
--- a/public/app/features/alerting/unified/Receivers.test.tsx
+++ b/public/app/features/alerting/unified/Receivers.test.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { selectOptionInTest } from 'test/helpers/selectOptionInTest';
import { render, screen, waitFor, userEvent } from 'test/test-utils';
diff --git a/public/app/features/alerting/unified/Receivers.tsx b/public/app/features/alerting/unified/Receivers.tsx
index 367a1f21376..7e6fa953002 100644
--- a/public/app/features/alerting/unified/Receivers.tsx
+++ b/public/app/features/alerting/unified/Receivers.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { Route, Switch } from 'react-router-dom';
import { withErrorBoundary } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/RedirectToRuleViewer.test.tsx b/public/app/features/alerting/unified/RedirectToRuleViewer.test.tsx
index 5be4926cf12..9e71045b785 100644
--- a/public/app/features/alerting/unified/RedirectToRuleViewer.test.tsx
+++ b/public/app/features/alerting/unified/RedirectToRuleViewer.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { useLocation } from 'react-use';
import { TestProvider } from 'test/helpers/TestProvider';
diff --git a/public/app/features/alerting/unified/RedirectToRuleViewer.tsx b/public/app/features/alerting/unified/RedirectToRuleViewer.tsx
index 057c5c90782..9462ea4686f 100644
--- a/public/app/features/alerting/unified/RedirectToRuleViewer.tsx
+++ b/public/app/features/alerting/unified/RedirectToRuleViewer.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { Redirect } from 'react-router-dom';
import { useLocation } from 'react-use';
diff --git a/public/app/features/alerting/unified/RuleEditor.tsx b/public/app/features/alerting/unified/RuleEditor.tsx
index f2c82cf9187..5e58a5dd206 100644
--- a/public/app/features/alerting/unified/RuleEditor.tsx
+++ b/public/app/features/alerting/unified/RuleEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { useAsync } from 'react-use';
import { NavModelItem } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/RuleEditorCloudOnlyAllowed.test.tsx b/public/app/features/alerting/unified/RuleEditorCloudOnlyAllowed.test.tsx
index ea2a169d998..6db787d57ac 100644
--- a/public/app/features/alerting/unified/RuleEditorCloudOnlyAllowed.test.tsx
+++ b/public/app/features/alerting/unified/RuleEditorCloudOnlyAllowed.test.tsx
@@ -1,6 +1,5 @@
import { screen, waitForElementToBeRemoved } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { renderRuleEditor, ui } from 'test/helpers/alertingRuleEditor';
import { byText } from 'testing-library-selector';
diff --git a/public/app/features/alerting/unified/RuleEditorCloudRules.test.tsx b/public/app/features/alerting/unified/RuleEditorCloudRules.test.tsx
index 7868c5c3abe..ad3d0d70770 100644
--- a/public/app/features/alerting/unified/RuleEditorCloudRules.test.tsx
+++ b/public/app/features/alerting/unified/RuleEditorCloudRules.test.tsx
@@ -1,6 +1,6 @@
import { screen, waitFor, waitForElementToBeRemoved } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
+import * as React from 'react';
import { renderRuleEditor, ui } from 'test/helpers/alertingRuleEditor';
import { clickSelectOption } from 'test/helpers/selectOptionInTest';
diff --git a/public/app/features/alerting/unified/RuleEditorExisting.test.tsx b/public/app/features/alerting/unified/RuleEditorExisting.test.tsx
index 9fe2b5e35fc..e5c34d2288d 100644
--- a/public/app/features/alerting/unified/RuleEditorExisting.test.tsx
+++ b/public/app/features/alerting/unified/RuleEditorExisting.test.tsx
@@ -1,6 +1,6 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
+import * as React from 'react';
import { Route } from 'react-router-dom';
import { TestProvider } from 'test/helpers/TestProvider';
import { ui } from 'test/helpers/alertingRuleEditor';
diff --git a/public/app/features/alerting/unified/RuleEditorGrafanaRules.test.tsx b/public/app/features/alerting/unified/RuleEditorGrafanaRules.test.tsx
index 524d6be99cb..fa8ff6be0cf 100644
--- a/public/app/features/alerting/unified/RuleEditorGrafanaRules.test.tsx
+++ b/public/app/features/alerting/unified/RuleEditorGrafanaRules.test.tsx
@@ -1,6 +1,6 @@
import { screen, waitFor, waitForElementToBeRemoved } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
+import * as React from 'react';
import { renderRuleEditor, ui } from 'test/helpers/alertingRuleEditor';
import { clickSelectOption } from 'test/helpers/selectOptionInTest';
import { byRole } from 'testing-library-selector';
diff --git a/public/app/features/alerting/unified/RuleEditorRecordingRule.test.tsx b/public/app/features/alerting/unified/RuleEditorRecordingRule.test.tsx
index d8df9145395..5e02450bf44 100644
--- a/public/app/features/alerting/unified/RuleEditorRecordingRule.test.tsx
+++ b/public/app/features/alerting/unified/RuleEditorRecordingRule.test.tsx
@@ -1,6 +1,6 @@
import { screen, waitFor, waitForElementToBeRemoved } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
+import * as React from 'react';
import { renderRuleEditor, ui } from 'test/helpers/alertingRuleEditor';
import { clickSelectOption } from 'test/helpers/selectOptionInTest';
import { byText } from 'testing-library-selector';
diff --git a/public/app/features/alerting/unified/RuleList.test.tsx b/public/app/features/alerting/unified/RuleList.test.tsx
index 4c3b78d2cbb..ccb7523d8c7 100644
--- a/public/app/features/alerting/unified/RuleList.test.tsx
+++ b/public/app/features/alerting/unified/RuleList.test.tsx
@@ -1,7 +1,6 @@
import { SerializedError } from '@reduxjs/toolkit';
import userEvent from '@testing-library/user-event';
import { setupServer } from 'msw/node';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { prettyDOM, render, screen, waitFor, within } from 'test/test-utils';
import { byRole, byTestId, byText } from 'testing-library-selector';
diff --git a/public/app/features/alerting/unified/RuleList.tsx b/public/app/features/alerting/unified/RuleList.tsx
index 94dd35e71b5..54ed2487908 100644
--- a/public/app/features/alerting/unified/RuleList.tsx
+++ b/public/app/features/alerting/unified/RuleList.tsx
@@ -1,9 +1,9 @@
-import React, { Suspense } from 'react';
+import { lazy, Suspense } from 'react';
import { config } from '@grafana/runtime';
import RuleListV1 from './components/rule-list/RuleList.v1';
-const RuleListV2 = React.lazy(() => import('./components/rule-list/RuleList.v2'));
+const RuleListV2 = lazy(() => import('./components/rule-list/RuleList.v2'));
const RuleList = () => {
const newView = config.featureToggles.alertingListViewV2;
diff --git a/public/app/features/alerting/unified/RuleViewer.tsx b/public/app/features/alerting/unified/RuleViewer.tsx
index 32064616fa9..7e9aa0152b2 100644
--- a/public/app/features/alerting/unified/RuleViewer.tsx
+++ b/public/app/features/alerting/unified/RuleViewer.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import { useMemo } from 'react';
import { NavModelItem } from '@grafana/data';
import { isFetchError } from '@grafana/runtime';
@@ -8,7 +8,7 @@ import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
import { AlertingPageWrapper } from './components/AlertingPageWrapper';
import { AlertRuleProvider } from './components/rule-viewer/RuleContext';
-import DetailView from './components/rule-viewer/RuleViewer';
+import DetailView, { ActiveTab, useActiveTab } from './components/rule-viewer/RuleViewer';
import { useCombinedRule } from './hooks/useCombinedRule';
import { stringifyErrorLike } from './utils/misc';
import { getRuleIdFromPathname, parse as parseRuleId } from './utils/rule-id';
@@ -21,9 +21,16 @@ type RuleViewerProps = GrafanaRouteComponentProps<{
const RuleViewer = (props: RuleViewerProps): JSX.Element => {
const id = getRuleIdFromPathname(props.match.params);
+ const [activeTab] = useActiveTab();
+ const instancesTab = activeTab === ActiveTab.Instances;
+
+ // We will fetch no instances by default to speed up loading times and reduce memory footprint _unless_ we are visiting
+ // the "instances" tab. This optimization is only available for the Grafana-managed ruler.
+ const limitAlerts = instancesTab ? undefined : 0; // "0" means "do not include alert rule instances in the response"
+
// we convert the stringified ID to a rule identifier object which contains additional
// type and source information
- const identifier = React.useMemo(() => {
+ const identifier = useMemo(() => {
if (!id) {
throw new Error('Rule ID is required');
}
@@ -32,7 +39,7 @@ const RuleViewer = (props: RuleViewerProps): JSX.Element => {
}, [id]);
// we then fetch the rule from the correct API endpoint(s)
- const { loading, error, result: rule } = useCombinedRule({ ruleIdentifier: identifier });
+ const { loading, error, result: rule } = useCombinedRule({ ruleIdentifier: identifier, limitAlerts });
if (error) {
return (
diff --git a/public/app/features/alerting/unified/Settings.test.tsx b/public/app/features/alerting/unified/Settings.test.tsx
index 9d2ca68f3b2..892c5a35969 100644
--- a/public/app/features/alerting/unified/Settings.test.tsx
+++ b/public/app/features/alerting/unified/Settings.test.tsx
@@ -1,6 +1,5 @@
import { screen, waitFor, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { render } from 'test/test-utils';
import { byRole, byTestId, byText } from 'testing-library-selector';
diff --git a/public/app/features/alerting/unified/Settings.tsx b/public/app/features/alerting/unified/Settings.tsx
index 87a76606b6f..099bde572b0 100644
--- a/public/app/features/alerting/unified/Settings.tsx
+++ b/public/app/features/alerting/unified/Settings.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { LinkButton, Stack, Text } from '@grafana/ui';
import { AlertingPageWrapper } from './components/AlertingPageWrapper';
diff --git a/public/app/features/alerting/unified/Silences.test.tsx b/public/app/features/alerting/unified/Silences.test.tsx
index d3ce1e15afb..fb8fc89e6af 100644
--- a/public/app/features/alerting/unified/Silences.test.tsx
+++ b/public/app/features/alerting/unified/Silences.test.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { render, screen, userEvent, waitFor, within } from 'test/test-utils';
import { byLabelText, byPlaceholderText, byRole, byTestId, byText } from 'testing-library-selector';
diff --git a/public/app/features/alerting/unified/Silences.tsx b/public/app/features/alerting/unified/Silences.tsx
index 6fa311a6d01..fc8fd0c8ea4 100644
--- a/public/app/features/alerting/unified/Silences.tsx
+++ b/public/app/features/alerting/unified/Silences.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { Route, RouteChildrenProps, Switch } from 'react-router-dom';
import { withErrorBoundary } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/Templates.test.tsx b/public/app/features/alerting/unified/Templates.test.tsx
index 61e859042cf..2ffdcec94c1 100644
--- a/public/app/features/alerting/unified/Templates.test.tsx
+++ b/public/app/features/alerting/unified/Templates.test.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { render, screen, userEvent } from 'test/test-utils';
import { setupMswServer } from 'app/features/alerting/unified/mockApi';
diff --git a/public/app/features/alerting/unified/Templates.tsx b/public/app/features/alerting/unified/Templates.tsx
index b18a595b87e..f7aef31d9fc 100644
--- a/public/app/features/alerting/unified/Templates.tsx
+++ b/public/app/features/alerting/unified/Templates.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { Route, Switch } from 'react-router-dom';
import { withErrorBoundary } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/api/alertRuleApi.ts b/public/app/features/alerting/unified/api/alertRuleApi.ts
index 2192349a49c..001e950b53f 100644
--- a/public/app/features/alerting/unified/api/alertRuleApi.ts
+++ b/public/app/features/alerting/unified/api/alertRuleApi.ts
@@ -44,6 +44,13 @@ export interface Datasource {
export const PREVIEW_URL = '/api/v1/rule/test/grafana';
export const PROM_RULES_URL = 'api/prometheus/grafana/api/v1/rules';
+export enum PrometheusAPIFilters {
+ RuleGroup = 'rule_group',
+ Namespace = 'file',
+ FolderUID = 'folder_uid',
+ LimitAlerts = 'limit_alerts',
+}
+
export interface Data {
refId: string;
relativeTimeRange: RelativeTimeRange;
@@ -137,12 +144,12 @@ export const alertRuleApi = alertingApi.injectEndpoints({
// if we're fetching for Grafana managed rules, we should add a limit to the number of alert instances
// we do this because the response is large otherwise and we don't show all of them in the UI anyway.
if (limitAlerts) {
- searchParams.set('limit_alerts', String(limitAlerts));
+ searchParams.set(PrometheusAPIFilters.LimitAlerts, String(limitAlerts));
}
if (identifier && (isPrometheusRuleIdentifier(identifier) || isCloudRuleIdentifier(identifier))) {
- searchParams.set('file', identifier.namespace);
- searchParams.set('rule_group', identifier.groupName);
+ searchParams.set(PrometheusAPIFilters.Namespace, identifier.namespace);
+ searchParams.set(PrometheusAPIFilters.RuleGroup, identifier.groupName);
}
const params = prepareRulesFilterQueryParams(searchParams, filter);
@@ -163,9 +170,10 @@ export const alertRuleApi = alertingApi.injectEndpoints({
ruleName?: string;
dashboardUid?: string;
panelId?: number;
+ limitAlerts?: number;
}
>({
- query: ({ ruleSourceName, namespace, groupName, ruleName, dashboardUid, panelId }) => {
+ query: ({ ruleSourceName, namespace, groupName, ruleName, dashboardUid, panelId, limitAlerts }) => {
const queryParams: Record = {
rule_group: groupName,
rule_name: ruleName,
@@ -175,12 +183,16 @@ export const alertRuleApi = alertingApi.injectEndpoints({
if (namespace) {
if (isGrafanaRulesSource(ruleSourceName)) {
- set(queryParams, 'folder_uid', namespace);
+ set(queryParams, PrometheusAPIFilters.FolderUID, namespace);
} else {
- set(queryParams, 'file', namespace);
+ set(queryParams, PrometheusAPIFilters.Namespace, namespace);
}
}
+ if (limitAlerts !== undefined) {
+ set(queryParams, PrometheusAPIFilters.LimitAlerts, String(limitAlerts));
+ }
+
return {
url: `api/prometheus/${getDatasourceAPIUid(ruleSourceName)}/api/v1/rules`,
params: queryParams,
diff --git a/public/app/features/alerting/unified/api/alertingApi.ts b/public/app/features/alerting/unified/api/alertingApi.ts
index 906a9b12084..9f368f4f966 100644
--- a/public/app/features/alerting/unified/api/alertingApi.ts
+++ b/public/app/features/alerting/unified/api/alertingApi.ts
@@ -44,6 +44,7 @@ export const alertingApi = createApi({
'GrafanaLabels',
'CombinedAlertRule',
'GrafanaRulerRule',
+ 'GrafanaSlo',
],
endpoints: () => ({}),
});
diff --git a/public/app/features/alerting/unified/api/sloApi.ts b/public/app/features/alerting/unified/api/sloApi.ts
new file mode 100644
index 00000000000..86f26794cec
--- /dev/null
+++ b/public/app/features/alerting/unified/api/sloApi.ts
@@ -0,0 +1,35 @@
+import { SupportedPlugin } from '../types/pluginBridges';
+
+import { alertingApi } from './alertingApi';
+
+export interface Label {
+ key: string;
+ value: string;
+}
+
+export interface SloAlertingMetadata {
+ annotations?: Label[];
+ labels?: Label[];
+}
+
+export interface SloAlerting {
+ annotations?: Label[];
+ fastBurn?: SloAlertingMetadata;
+ labels?: Label[];
+ slowBurn?: SloAlertingMetadata;
+}
+
+export interface Slo {
+ alerting?: SloAlerting;
+}
+
+const SLO_API_PATH = `/api/plugins/${SupportedPlugin.Slo}/resources/v1`;
+
+export const sloApi = alertingApi.injectEndpoints({
+ endpoints: (build) => ({
+ getSlos: build.query<{ slos: Slo[] }, void>({
+ query: () => ({ url: `${SLO_API_PATH}/slo`, showErrorAlert: false }),
+ providesTags: ['GrafanaSlo'],
+ }),
+ }),
+});
diff --git a/public/app/features/alerting/unified/components/AlertLabel.tsx b/public/app/features/alerting/unified/components/AlertLabel.tsx
index 21f5a542230..1288e7d56e7 100644
--- a/public/app/features/alerting/unified/components/AlertLabel.tsx
+++ b/public/app/features/alerting/unified/components/AlertLabel.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { IconButton, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/AlertLabelDropdown.tsx b/public/app/features/alerting/unified/components/AlertLabelDropdown.tsx
index 9b9faf828ee..0f7a535cd39 100644
--- a/public/app/features/alerting/unified/components/AlertLabelDropdown.tsx
+++ b/public/app/features/alerting/unified/components/AlertLabelDropdown.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { FC } from 'react';
+import { forwardRef, FC } from 'react';
import { createFilter, GroupBase, OptionsOrGroups } from 'react-select';
import { SelectableValue } from '@grafana/data';
@@ -34,7 +34,7 @@ const handleIsValidNewOption = (
return !Boolean(exactValueExists) && Boolean(valueIsNotEmpty);
};
-const AlertLabelDropdown: FC = React.forwardRef(
+const AlertLabelDropdown: FC = forwardRef(
function LabelPicker({ onChange, options, defaultValue, type, onOpenMenu = () => {} }, ref) {
const styles = useStyles2(getStyles);
diff --git a/public/app/features/alerting/unified/components/AlertLabels.test.tsx b/public/app/features/alerting/unified/components/AlertLabels.test.tsx
index 47eab5467bd..0e8efab0186 100644
--- a/public/app/features/alerting/unified/components/AlertLabels.test.tsx
+++ b/public/app/features/alerting/unified/components/AlertLabels.test.tsx
@@ -1,6 +1,5 @@
import { screen, render, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { AlertLabels } from './AlertLabels';
diff --git a/public/app/features/alerting/unified/components/AlertLabels.tsx b/public/app/features/alerting/unified/components/AlertLabels.tsx
index 40801357372..5083e7c6f29 100644
--- a/public/app/features/alerting/unified/components/AlertLabels.tsx
+++ b/public/app/features/alerting/unified/components/AlertLabels.tsx
@@ -1,7 +1,7 @@
import { css } from '@emotion/css';
import { chain } from 'lodash';
import pluralize from 'pluralize';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Button, getTagColorsFromName, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/AlertManagerPicker.tsx b/public/app/features/alerting/unified/components/AlertManagerPicker.tsx
index a18fb39981e..75bc97f6512 100644
--- a/public/app/features/alerting/unified/components/AlertManagerPicker.tsx
+++ b/public/app/features/alerting/unified/components/AlertManagerPicker.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { InlineField, Select, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/AlertStateDot.tsx b/public/app/features/alerting/unified/components/AlertStateDot.tsx
index fb2b1f30f67..e966e80ea95 100644
--- a/public/app/features/alerting/unified/components/AlertStateDot.tsx
+++ b/public/app/features/alerting/unified/components/AlertStateDot.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Stack, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/AlertingPageWrapper.tsx b/public/app/features/alerting/unified/components/AlertingPageWrapper.tsx
index 62f9069b8db..68b011d7d22 100644
--- a/public/app/features/alerting/unified/components/AlertingPageWrapper.tsx
+++ b/public/app/features/alerting/unified/components/AlertingPageWrapper.tsx
@@ -1,4 +1,4 @@
-import React, { PropsWithChildren } from 'react';
+import { PropsWithChildren } from 'react';
import { useLocation } from 'react-use';
import { Page } from 'app/core/components/Page/Page';
diff --git a/public/app/features/alerting/unified/components/AnnotationDetailsField.tsx b/public/app/features/alerting/unified/components/AnnotationDetailsField.tsx
index f197caead2a..ca49efd6dd6 100644
--- a/public/app/features/alerting/unified/components/AnnotationDetailsField.tsx
+++ b/public/app/features/alerting/unified/components/AnnotationDetailsField.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { TextLink, Tooltip, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/Authorize.tsx b/public/app/features/alerting/unified/components/Authorize.tsx
index cf83b38fdb4..339dd7bea0c 100644
--- a/public/app/features/alerting/unified/components/Authorize.tsx
+++ b/public/app/features/alerting/unified/components/Authorize.tsx
@@ -1,5 +1,5 @@
import { chain, filter } from 'lodash';
-import React, { PropsWithChildren } from 'react';
+import { PropsWithChildren } from 'react';
import {
Abilities,
diff --git a/public/app/features/alerting/unified/components/CollapseToggle.test.tsx b/public/app/features/alerting/unified/components/CollapseToggle.test.tsx
index 9bdb1cf191b..03c2b6e5187 100644
--- a/public/app/features/alerting/unified/components/CollapseToggle.test.tsx
+++ b/public/app/features/alerting/unified/components/CollapseToggle.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import { noop } from 'lodash';
-import React from 'react';
import { CollapseToggle } from './CollapseToggle';
diff --git a/public/app/features/alerting/unified/components/CollapseToggle.tsx b/public/app/features/alerting/unified/components/CollapseToggle.tsx
index b11e871afa4..7150f3a5f3a 100644
--- a/public/app/features/alerting/unified/components/CollapseToggle.tsx
+++ b/public/app/features/alerting/unified/components/CollapseToggle.tsx
@@ -1,4 +1,4 @@
-import React, { HTMLAttributes } from 'react';
+import { HTMLAttributes } from 'react';
import { IconSize, Button } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/ConditionalWrap.tsx b/public/app/features/alerting/unified/components/ConditionalWrap.tsx
index 3a5308b7da1..5a02dcf9686 100644
--- a/public/app/features/alerting/unified/components/ConditionalWrap.tsx
+++ b/public/app/features/alerting/unified/components/ConditionalWrap.tsx
@@ -1,4 +1,4 @@
-import React, { forwardRef, Ref } from 'react';
+import { cloneElement, forwardRef, Ref } from 'react';
interface ConditionalWrapProps {
shouldWrap: boolean;
@@ -7,7 +7,7 @@ interface ConditionalWrapProps {
}
function ConditionalWrap({ children, shouldWrap, wrap }: ConditionalWrapProps, _ref: Ref) {
- return shouldWrap ? React.cloneElement(wrap(children)) : children;
+ return shouldWrap ? cloneElement(wrap(children)) : children;
}
export default forwardRef(ConditionalWrap);
diff --git a/public/app/features/alerting/unified/components/DetailsField.tsx b/public/app/features/alerting/unified/components/DetailsField.tsx
index 9d229a4f546..756a203ce26 100644
--- a/public/app/features/alerting/unified/components/DetailsField.tsx
+++ b/public/app/features/alerting/unified/components/DetailsField.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/DynamicTable.tsx b/public/app/features/alerting/unified/components/DynamicTable.tsx
index 959a402f032..608ce517b92 100644
--- a/public/app/features/alerting/unified/components/DynamicTable.tsx
+++ b/public/app/features/alerting/unified/components/DynamicTable.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { ReactNode, useState } from 'react';
+import { ReactNode, useState } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/alerting/unified/components/DynamicTableWithGuidelines.tsx b/public/app/features/alerting/unified/components/DynamicTableWithGuidelines.tsx
index ce843c7e849..4678adecbeb 100644
--- a/public/app/features/alerting/unified/components/DynamicTableWithGuidelines.tsx
+++ b/public/app/features/alerting/unified/components/DynamicTableWithGuidelines.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/EmptyArea.tsx b/public/app/features/alerting/unified/components/EmptyArea.tsx
index 97a1b6a2781..d3a90d42acf 100644
--- a/public/app/features/alerting/unified/components/EmptyArea.tsx
+++ b/public/app/features/alerting/unified/components/EmptyArea.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/EmptyAreaWithCTA.tsx b/public/app/features/alerting/unified/components/EmptyAreaWithCTA.tsx
index ae960a5db0b..7f0bd202b7d 100644
--- a/public/app/features/alerting/unified/components/EmptyAreaWithCTA.tsx
+++ b/public/app/features/alerting/unified/components/EmptyAreaWithCTA.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { ButtonHTMLAttributes } from 'react';
+import { ButtonHTMLAttributes } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Button, ButtonVariant, IconName, LinkButton, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/Expression.tsx b/public/app/features/alerting/unified/components/Expression.tsx
index b085b0a399e..3ad6efb380a 100644
--- a/public/app/features/alerting/unified/components/Expression.tsx
+++ b/public/app/features/alerting/unified/components/Expression.tsx
@@ -1,6 +1,6 @@
import { css, cx } from '@emotion/css';
import { languages as prismLanguages } from 'prismjs';
-import React, { FC, useMemo } from 'react';
+import { FC, useMemo } from 'react';
import { Editor } from 'slate-react';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/GrafanaAlertmanagerDeliveryWarning.test.tsx b/public/app/features/alerting/unified/components/GrafanaAlertmanagerDeliveryWarning.test.tsx
index 340bdd52ae7..6ed7a2a7aab 100644
--- a/public/app/features/alerting/unified/components/GrafanaAlertmanagerDeliveryWarning.test.tsx
+++ b/public/app/features/alerting/unified/components/GrafanaAlertmanagerDeliveryWarning.test.tsx
@@ -1,5 +1,4 @@
import { render, screen, waitFor } from '@testing-library/react';
-import React from 'react';
import { Provider } from 'react-redux';
import { setupMswServer } from 'app/features/alerting/unified/mockApi';
diff --git a/public/app/features/alerting/unified/components/GrafanaAlertmanagerDeliveryWarning.tsx b/public/app/features/alerting/unified/components/GrafanaAlertmanagerDeliveryWarning.tsx
index 38016674de7..913001ffe66 100644
--- a/public/app/features/alerting/unified/components/GrafanaAlertmanagerDeliveryWarning.tsx
+++ b/public/app/features/alerting/unified/components/GrafanaAlertmanagerDeliveryWarning.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data/src';
import { Alert, useStyles2 } from '@grafana/ui/src';
diff --git a/public/app/features/alerting/unified/components/HoverCard.tsx b/public/app/features/alerting/unified/components/HoverCard.tsx
index 9d20a32fd60..0572cfa7794 100644
--- a/public/app/features/alerting/unified/components/HoverCard.tsx
+++ b/public/app/features/alerting/unified/components/HoverCard.tsx
@@ -1,7 +1,7 @@
import { css } from '@emotion/css';
import { Placement } from '@popperjs/core';
import classnames from 'classnames';
-import React, { ReactElement, ReactNode, useRef } from 'react';
+import { cloneElement, ReactElement, ReactNode, useRef } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Popover as GrafanaPopover, PopoverController, useStyles2, Stack } from '@grafana/ui';
@@ -63,7 +63,7 @@ export const HoverCard = ({
/>
)}
- {React.cloneElement(children, {
+ {cloneElement(children, {
ref: popoverRef,
onMouseEnter: showPopper,
onMouseLeave: hidePopper,
diff --git a/public/app/features/alerting/unified/components/InfoIcon.tsx b/public/app/features/alerting/unified/components/InfoIcon.tsx
index e4653b441ca..ce4690a4b10 100644
--- a/public/app/features/alerting/unified/components/InfoIcon.tsx
+++ b/public/app/features/alerting/unified/components/InfoIcon.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Icon, Tooltip } from '@grafana/ui';
export function InfoIcon({ text }: { text: string }) {
diff --git a/public/app/features/alerting/unified/components/InfoPausedRule.tsx b/public/app/features/alerting/unified/components/InfoPausedRule.tsx
index f111f4917a7..52df56f1289 100644
--- a/public/app/features/alerting/unified/components/InfoPausedRule.tsx
+++ b/public/app/features/alerting/unified/components/InfoPausedRule.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Alert } from '@grafana/ui';
const InfoPausedRule = () => {
diff --git a/public/app/features/alerting/unified/components/InvalidIntervalWarning.tsx b/public/app/features/alerting/unified/components/InvalidIntervalWarning.tsx
index 9dc4673336b..56703f75cf7 100644
--- a/public/app/features/alerting/unified/components/InvalidIntervalWarning.tsx
+++ b/public/app/features/alerting/unified/components/InvalidIntervalWarning.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { config } from '@grafana/runtime';
import { Alert } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/Label.tsx b/public/app/features/alerting/unified/components/Label.tsx
index bef7c86d408..577b8e7ddf3 100644
--- a/public/app/features/alerting/unified/components/Label.tsx
+++ b/public/app/features/alerting/unified/components/Label.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { CSSProperties, ReactNode } from 'react';
+import { CSSProperties, ReactNode } from 'react';
import tinycolor2 from 'tinycolor2';
import { GrafanaTheme2, IconName } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/MenuItemPauseRule.tsx b/public/app/features/alerting/unified/components/MenuItemPauseRule.tsx
index f520b6a1ef2..74b52754c85 100644
--- a/public/app/features/alerting/unified/components/MenuItemPauseRule.tsx
+++ b/public/app/features/alerting/unified/components/MenuItemPauseRule.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Menu } from '@grafana/ui';
import { useAppNotification } from 'app/core/copy/appNotification';
import {
diff --git a/public/app/features/alerting/unified/components/MetaText.tsx b/public/app/features/alerting/unified/components/MetaText.tsx
index 4615d5ca2ac..5f890cbcba9 100644
--- a/public/app/features/alerting/unified/components/MetaText.tsx
+++ b/public/app/features/alerting/unified/components/MetaText.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { ComponentProps, HTMLAttributes } from 'react';
+import { ComponentProps, HTMLAttributes } from 'react';
import { Icon, IconName, useStyles2, Text, Stack } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/MoreButton.tsx b/public/app/features/alerting/unified/components/MoreButton.tsx
index 7b41fe61fda..a1cc69f2346 100644
--- a/public/app/features/alerting/unified/components/MoreButton.tsx
+++ b/public/app/features/alerting/unified/components/MoreButton.tsx
@@ -1,4 +1,4 @@
-import React, { forwardRef, Ref } from 'react';
+import { forwardRef, Ref } from 'react';
import { Button, ButtonProps, Icon, Stack } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/NoAlertManagerWarning.tsx b/public/app/features/alerting/unified/components/NoAlertManagerWarning.tsx
index cea1106b01d..3c769164350 100644
--- a/public/app/features/alerting/unified/components/NoAlertManagerWarning.tsx
+++ b/public/app/features/alerting/unified/components/NoAlertManagerWarning.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Alert } from '@grafana/ui';
import { AlertManagerDataSource } from '../utils/datasource';
diff --git a/public/app/features/alerting/unified/components/PluginBridge.test.tsx b/public/app/features/alerting/unified/components/PluginBridge.test.tsx
index 96026d3944f..4252b0f99c6 100644
--- a/public/app/features/alerting/unified/components/PluginBridge.test.tsx
+++ b/public/app/features/alerting/unified/components/PluginBridge.test.tsx
@@ -1,5 +1,4 @@
import { screen, render } from '@testing-library/react';
-import React from 'react';
import { setBackendSrv } from '@grafana/runtime';
import { backendSrv } from 'app/core/services/backend_srv';
diff --git a/public/app/features/alerting/unified/components/PluginBridge.tsx b/public/app/features/alerting/unified/components/PluginBridge.tsx
index 564231580f9..061cf62280a 100644
--- a/public/app/features/alerting/unified/components/PluginBridge.tsx
+++ b/public/app/features/alerting/unified/components/PluginBridge.tsx
@@ -1,4 +1,5 @@
-import React, { ReactElement } from 'react';
+import { ReactElement } from 'react';
+import * as React from 'react';
import { usePluginBridge } from '../hooks/usePluginBridge';
import { SupportedPlugin } from '../types/pluginBridges';
diff --git a/public/app/features/alerting/unified/components/Provisioning.tsx b/public/app/features/alerting/unified/components/Provisioning.tsx
index 78a7c28ac08..15dc2fe6ad7 100644
--- a/public/app/features/alerting/unified/components/Provisioning.tsx
+++ b/public/app/features/alerting/unified/components/Provisioning.tsx
@@ -1,4 +1,4 @@
-import React, { ComponentPropsWithoutRef } from 'react';
+import { ComponentPropsWithoutRef } from 'react';
import { Alert, Badge } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/RuleLocation.tsx b/public/app/features/alerting/unified/components/RuleLocation.tsx
index 9b3dd5cd770..6b3f144d053 100644
--- a/public/app/features/alerting/unified/components/RuleLocation.tsx
+++ b/public/app/features/alerting/unified/components/RuleLocation.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Icon, Text } from '@grafana/ui';
interface Props {
diff --git a/public/app/features/alerting/unified/components/Spacer.tsx b/public/app/features/alerting/unified/components/Spacer.tsx
index 8ecc46ec22d..8d0f00f4528 100644
--- a/public/app/features/alerting/unified/components/Spacer.tsx
+++ b/public/app/features/alerting/unified/components/Spacer.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
/**
* A simple "flex: 1;" component you can use in combination with the Stack component(s), like so
diff --git a/public/app/features/alerting/unified/components/StateColoredText.tsx b/public/app/features/alerting/unified/components/StateColoredText.tsx
index ababfef016b..6831ff39189 100644
--- a/public/app/features/alerting/unified/components/StateColoredText.tsx
+++ b/public/app/features/alerting/unified/components/StateColoredText.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/StateTag.tsx b/public/app/features/alerting/unified/components/StateTag.tsx
index 81204cd0193..e73b1d6c53c 100644
--- a/public/app/features/alerting/unified/components/StateTag.tsx
+++ b/public/app/features/alerting/unified/components/StateTag.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { forwardRef } from 'react';
+import { forwardRef } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/Tokenize.tsx b/public/app/features/alerting/unified/components/Tokenize.tsx
index 1c7574c650d..7802f2d3c26 100644
--- a/public/app/features/alerting/unified/components/Tokenize.tsx
+++ b/public/app/features/alerting/unified/components/Tokenize.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Badge, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/Well.tsx b/public/app/features/alerting/unified/components/Well.tsx
index a4e40102d7a..97cdaf44d8f 100644
--- a/public/app/features/alerting/unified/components/Well.tsx
+++ b/public/app/features/alerting/unified/components/Well.tsx
@@ -1,5 +1,5 @@
import { cx, css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/WithReturnButton.tsx b/public/app/features/alerting/unified/components/WithReturnButton.tsx
index 5d8ef8c8e34..6b266949e1b 100644
--- a/public/app/features/alerting/unified/components/WithReturnButton.tsx
+++ b/public/app/features/alerting/unified/components/WithReturnButton.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { cloneElement, useCallback } from 'react';
import { useReturnToPrevious } from '@grafana/runtime';
@@ -15,5 +15,5 @@ export const WithReturnButton = ({ component, title = 'previous page' }: WithRet
returnToPrevious(title);
}, [returnToPrevious, title]);
- return React.cloneElement(component, { onClick: returnToThisURL });
+ return cloneElement(component, { onClick: returnToThisURL });
};
diff --git a/public/app/features/alerting/unified/components/alert-groups/AlertDetails.tsx b/public/app/features/alerting/unified/components/alert-groups/AlertDetails.tsx
index 04359da10fe..30757d16fa0 100644
--- a/public/app/features/alerting/unified/components/alert-groups/AlertDetails.tsx
+++ b/public/app/features/alerting/unified/components/alert-groups/AlertDetails.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { LinkButton, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/alert-groups/AlertGroup.tsx b/public/app/features/alerting/unified/components/alert-groups/AlertGroup.tsx
index 0c3d7232ac1..7c5169f930b 100644
--- a/public/app/features/alerting/unified/components/alert-groups/AlertGroup.tsx
+++ b/public/app/features/alerting/unified/components/alert-groups/AlertGroup.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2, Stack, TextLink } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/alert-groups/AlertGroupAlertsTable.tsx b/public/app/features/alerting/unified/components/alert-groups/AlertGroupAlertsTable.tsx
index 3a7a08f8635..93404167dae 100644
--- a/public/app/features/alerting/unified/components/alert-groups/AlertGroupAlertsTable.tsx
+++ b/public/app/features/alerting/unified/components/alert-groups/AlertGroupAlertsTable.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { GrafanaTheme2, intervalToAbbreviatedDurationString } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/alert-groups/AlertGroupFilter.tsx b/public/app/features/alerting/unified/components/alert-groups/AlertGroupFilter.tsx
index bb7c5569f7e..f5c1be52139 100644
--- a/public/app/features/alerting/unified/components/alert-groups/AlertGroupFilter.tsx
+++ b/public/app/features/alerting/unified/components/alert-groups/AlertGroupFilter.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Button, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/alert-groups/AlertGroupHeader.tsx b/public/app/features/alerting/unified/components/alert-groups/AlertGroupHeader.tsx
index 6a4b7a2ca22..c9d6be97f8c 100644
--- a/public/app/features/alerting/unified/components/alert-groups/AlertGroupHeader.tsx
+++ b/public/app/features/alerting/unified/components/alert-groups/AlertGroupHeader.tsx
@@ -1,5 +1,4 @@
import pluralize from 'pluralize';
-import React from 'react';
import { useStyles2 } from '@grafana/ui';
import { AlertmanagerGroup, AlertState } from 'app/plugins/datasource/alertmanager/types';
diff --git a/public/app/features/alerting/unified/components/alert-groups/AlertStateFilter.tsx b/public/app/features/alerting/unified/components/alert-groups/AlertStateFilter.tsx
index d94e2c36b0e..68bf6860bae 100644
--- a/public/app/features/alerting/unified/components/alert-groups/AlertStateFilter.tsx
+++ b/public/app/features/alerting/unified/components/alert-groups/AlertStateFilter.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SelectableValue } from '@grafana/data';
import { RadioButtonGroup, Label } from '@grafana/ui';
import { AlertState } from 'app/plugins/datasource/alertmanager/types';
diff --git a/public/app/features/alerting/unified/components/alert-groups/GroupBy.tsx b/public/app/features/alerting/unified/components/alert-groups/GroupBy.tsx
index 5cd7443478e..130f7018b94 100644
--- a/public/app/features/alerting/unified/components/alert-groups/GroupBy.tsx
+++ b/public/app/features/alerting/unified/components/alert-groups/GroupBy.tsx
@@ -1,5 +1,4 @@
import { uniq } from 'lodash';
-import React from 'react';
import { SelectableValue } from '@grafana/data';
import { Icon, Label, MultiSelect } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/alert-groups/MatcherFilter.test.tsx b/public/app/features/alerting/unified/components/alert-groups/MatcherFilter.test.tsx
index cc019e7c86c..a51b96925b9 100644
--- a/public/app/features/alerting/unified/components/alert-groups/MatcherFilter.test.tsx
+++ b/public/app/features/alerting/unified/components/alert-groups/MatcherFilter.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import * as analytics from '../../Analytics';
diff --git a/public/app/features/alerting/unified/components/alert-groups/MatcherFilter.tsx b/public/app/features/alerting/unified/components/alert-groups/MatcherFilter.tsx
index b53fbf6425e..8643ac99555 100644
--- a/public/app/features/alerting/unified/components/alert-groups/MatcherFilter.tsx
+++ b/public/app/features/alerting/unified/components/alert-groups/MatcherFilter.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import { useState } from 'react';
import { useDebounce } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
@@ -16,7 +16,7 @@ interface Props {
export const MatcherFilter = ({ onFilterChange, defaultQueryString }: Props) => {
const styles = useStyles2(getStyles);
- const [filterQuery, setFilterQuery] = React.useState(defaultQueryString ?? '');
+ const [filterQuery, setFilterQuery] = useState(defaultQueryString ?? '');
useDebounce(
() => {
diff --git a/public/app/features/alerting/unified/components/bridges/DeclareIncidentButton.tsx b/public/app/features/alerting/unified/components/bridges/DeclareIncidentButton.tsx
index fab8db3c9d5..1625cb449f7 100644
--- a/public/app/features/alerting/unified/components/bridges/DeclareIncidentButton.tsx
+++ b/public/app/features/alerting/unified/components/bridges/DeclareIncidentButton.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Button, LinkButton, Menu, Tooltip } from '@grafana/ui';
import { usePluginBridge } from '../../hooks/usePluginBridge';
diff --git a/public/app/features/alerting/unified/components/contact-points/ContactPoints.test.tsx b/public/app/features/alerting/unified/components/contact-points/ContactPoints.test.tsx
index 1eb47c7ae96..e82566ad970 100644
--- a/public/app/features/alerting/unified/components/contact-points/ContactPoints.test.tsx
+++ b/public/app/features/alerting/unified/components/contact-points/ContactPoints.test.tsx
@@ -1,7 +1,7 @@
import { render, screen, waitFor, waitForElementToBeRemoved } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { noop } from 'lodash';
-import React, { ComponentProps, PropsWithChildren } from 'react';
+import { ComponentProps, PropsWithChildren } from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/alerting/unified/components/contact-points/ContactPoints.tsx b/public/app/features/alerting/unified/components/contact-points/ContactPoints.tsx
index 4bcc0428a68..ac651588dbe 100644
--- a/public/app/features/alerting/unified/components/contact-points/ContactPoints.tsx
+++ b/public/app/features/alerting/unified/components/contact-points/ContactPoints.tsx
@@ -3,7 +3,8 @@ import uFuzzy from '@leeoniya/ufuzzy';
import { SerializedError } from '@reduxjs/toolkit';
import { groupBy, size, uniq, upperFirst } from 'lodash';
import pluralize from 'pluralize';
-import React, { Fragment, ReactNode, useCallback, useMemo, useState } from 'react';
+import { Fragment, ReactNode, useCallback, useMemo, useState } from 'react';
+import * as React from 'react';
import { useToggle } from 'react-use';
import { dateTime, GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/contact-points/DuplicateMessageTemplate.tsx b/public/app/features/alerting/unified/components/contact-points/DuplicateMessageTemplate.tsx
index 5fe9e5a40d1..9050df7a085 100644
--- a/public/app/features/alerting/unified/components/contact-points/DuplicateMessageTemplate.tsx
+++ b/public/app/features/alerting/unified/components/contact-points/DuplicateMessageTemplate.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { RouteChildrenProps } from 'react-router-dom';
import { EntityNotFound } from 'app/core/components/PageNotFound/EntityNotFound';
diff --git a/public/app/features/alerting/unified/components/contact-points/EditContactPoint.tsx b/public/app/features/alerting/unified/components/contact-points/EditContactPoint.tsx
index a9cfa2f865b..a21ec2c47eb 100644
--- a/public/app/features/alerting/unified/components/contact-points/EditContactPoint.tsx
+++ b/public/app/features/alerting/unified/components/contact-points/EditContactPoint.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { RouteChildrenProps } from 'react-router-dom';
import { Alert } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/contact-points/EditMessageTemplate.tsx b/public/app/features/alerting/unified/components/contact-points/EditMessageTemplate.tsx
index 51b10f92c98..502752f368e 100644
--- a/public/app/features/alerting/unified/components/contact-points/EditMessageTemplate.tsx
+++ b/public/app/features/alerting/unified/components/contact-points/EditMessageTemplate.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { RouteChildrenProps } from 'react-router-dom';
import { Alert } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/contact-points/NewContactPoint.test.tsx b/public/app/features/alerting/unified/components/contact-points/NewContactPoint.test.tsx
index 2269eede098..bde239feebe 100644
--- a/public/app/features/alerting/unified/components/contact-points/NewContactPoint.test.tsx
+++ b/public/app/features/alerting/unified/components/contact-points/NewContactPoint.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { byLabelText, byPlaceholderText, byRole, byTestId } from 'testing-library-selector';
diff --git a/public/app/features/alerting/unified/components/contact-points/NewContactPoint.tsx b/public/app/features/alerting/unified/components/contact-points/NewContactPoint.tsx
index 0151e262768..64e496c1fc0 100644
--- a/public/app/features/alerting/unified/components/contact-points/NewContactPoint.tsx
+++ b/public/app/features/alerting/unified/components/contact-points/NewContactPoint.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Alert } from '@grafana/ui';
import { useAlertmanagerConfig } from '../../hooks/useAlertmanagerConfig';
diff --git a/public/app/features/alerting/unified/components/contact-points/NewMessageTemplate.tsx b/public/app/features/alerting/unified/components/contact-points/NewMessageTemplate.tsx
index fce6ff95057..042da972d17 100644
--- a/public/app/features/alerting/unified/components/contact-points/NewMessageTemplate.tsx
+++ b/public/app/features/alerting/unified/components/contact-points/NewMessageTemplate.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Alert } from '@grafana/ui';
import { useAlertmanagerConfig } from '../../hooks/useAlertmanagerConfig';
diff --git a/public/app/features/alerting/unified/components/contact-points/NotificationTemplates.tsx b/public/app/features/alerting/unified/components/contact-points/NotificationTemplates.tsx
index 67077810fa9..51fd67657b7 100644
--- a/public/app/features/alerting/unified/components/contact-points/NotificationTemplates.tsx
+++ b/public/app/features/alerting/unified/components/contact-points/NotificationTemplates.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Alert } from '@grafana/ui';
import { useAlertmanagerConfig } from '../../hooks/useAlertmanagerConfig';
diff --git a/public/app/features/alerting/unified/components/contact-points/components/ContactPointsFilter.tsx b/public/app/features/alerting/unified/components/contact-points/components/ContactPointsFilter.tsx
index f1d6ee5c31a..990352f0fcc 100644
--- a/public/app/features/alerting/unified/components/contact-points/components/ContactPointsFilter.tsx
+++ b/public/app/features/alerting/unified/components/contact-points/components/ContactPointsFilter.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useCallback, useState } from 'react';
+import { useCallback, useState } from 'react';
import { useDebounce } from 'react-use';
import { Stack } from '@grafana/experimental';
diff --git a/public/app/features/alerting/unified/components/contact-points/components/GlobalConfig.tsx b/public/app/features/alerting/unified/components/contact-points/components/GlobalConfig.tsx
index 1d493119eb6..da56a3f5148 100644
--- a/public/app/features/alerting/unified/components/contact-points/components/GlobalConfig.tsx
+++ b/public/app/features/alerting/unified/components/contact-points/components/GlobalConfig.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Alert } from '@grafana/ui';
import { useAlertmanagerConfig } from '../../../hooks/useAlertmanagerConfig';
diff --git a/public/app/features/alerting/unified/components/contact-points/components/GlobalConfigAlert.tsx b/public/app/features/alerting/unified/components/contact-points/components/GlobalConfigAlert.tsx
index e277b007ac6..de37af9227f 100644
--- a/public/app/features/alerting/unified/components/contact-points/components/GlobalConfigAlert.tsx
+++ b/public/app/features/alerting/unified/components/contact-points/components/GlobalConfigAlert.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Alert, LinkButton } from '@grafana/ui';
import { AlertmanagerAction } from '../../../hooks/useAbilities';
diff --git a/public/app/features/alerting/unified/components/contact-points/components/Modals.tsx b/public/app/features/alerting/unified/components/contact-points/components/Modals.tsx
index 371f4c860d4..ca395fe9be8 100644
--- a/public/app/features/alerting/unified/components/contact-points/components/Modals.tsx
+++ b/public/app/features/alerting/unified/components/contact-points/components/Modals.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useMemo, useState } from 'react';
+import { useCallback, useMemo, useState } from 'react';
import { Button, Modal, ModalProps } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/contact-points/components/UnusedBadge.tsx b/public/app/features/alerting/unified/components/contact-points/components/UnusedBadge.tsx
index 8d459985ee4..7406ed7d515 100644
--- a/public/app/features/alerting/unified/components/contact-points/components/UnusedBadge.tsx
+++ b/public/app/features/alerting/unified/components/contact-points/components/UnusedBadge.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Badge } from '@grafana/ui';
export const UnusedContactPointBadge = () => (
diff --git a/public/app/features/alerting/unified/components/contact-points/templates/EditorColumnHeader.tsx b/public/app/features/alerting/unified/components/contact-points/templates/EditorColumnHeader.tsx
index f60257d79ac..63369188507 100644
--- a/public/app/features/alerting/unified/components/contact-points/templates/EditorColumnHeader.tsx
+++ b/public/app/features/alerting/unified/components/contact-points/templates/EditorColumnHeader.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Label, Stack, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/contact-points/useContactPoints.test.tsx b/public/app/features/alerting/unified/components/contact-points/useContactPoints.test.tsx
index a4188d51789..52a059e835d 100644
--- a/public/app/features/alerting/unified/components/contact-points/useContactPoints.test.tsx
+++ b/public/app/features/alerting/unified/components/contact-points/useContactPoints.test.tsx
@@ -1,5 +1,4 @@
import { renderHook, waitFor } from '@testing-library/react';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import alertmanagerMock from 'app/features/alerting/unified/components/contact-points/__mocks__/alertmanager.config.mock.json';
diff --git a/public/app/features/alerting/unified/components/export/FileExportPreview.tsx b/public/app/features/alerting/unified/components/export/FileExportPreview.tsx
index dad58ab4aa7..cc68516160a 100644
--- a/public/app/features/alerting/unified/components/export/FileExportPreview.tsx
+++ b/public/app/features/alerting/unified/components/export/FileExportPreview.tsx
@@ -1,6 +1,7 @@
import { css } from '@emotion/css';
import saveAs from 'file-saver';
-import React, { useCallback, useMemo } from 'react';
+import { useCallback, useMemo } from 'react';
+import * as React from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/export/GrafanaExportDrawer.tsx b/public/app/features/alerting/unified/components/export/GrafanaExportDrawer.tsx
index 80daa8cdb8a..660258b1888 100644
--- a/public/app/features/alerting/unified/components/export/GrafanaExportDrawer.tsx
+++ b/public/app/features/alerting/unified/components/export/GrafanaExportDrawer.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { Drawer } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/export/GrafanaModifyExport.test.tsx b/public/app/features/alerting/unified/components/export/GrafanaModifyExport.test.tsx
index 5a2bae664b2..02d7a9a442c 100644
--- a/public/app/features/alerting/unified/components/export/GrafanaModifyExport.test.tsx
+++ b/public/app/features/alerting/unified/components/export/GrafanaModifyExport.test.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { Route } from 'react-router-dom';
import { Props } from 'react-virtualized-auto-sizer';
import { render, waitFor, waitForElementToBeRemoved, userEvent } from 'test/test-utils';
diff --git a/public/app/features/alerting/unified/components/export/GrafanaMuteTimingsExporter.tsx b/public/app/features/alerting/unified/components/export/GrafanaMuteTimingsExporter.tsx
index 7225337458c..3ebf00a2dd5 100644
--- a/public/app/features/alerting/unified/components/export/GrafanaMuteTimingsExporter.tsx
+++ b/public/app/features/alerting/unified/components/export/GrafanaMuteTimingsExporter.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { LoadingPlaceholder } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/export/GrafanaPoliciesExporter.tsx b/public/app/features/alerting/unified/components/export/GrafanaPoliciesExporter.tsx
index c0cf2e0083b..bcc82d50030 100644
--- a/public/app/features/alerting/unified/components/export/GrafanaPoliciesExporter.tsx
+++ b/public/app/features/alerting/unified/components/export/GrafanaPoliciesExporter.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { LoadingPlaceholder } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/export/GrafanaReceiverExporter.tsx b/public/app/features/alerting/unified/components/export/GrafanaReceiverExporter.tsx
index 6a90aca6918..c894333c5ab 100644
--- a/public/app/features/alerting/unified/components/export/GrafanaReceiverExporter.tsx
+++ b/public/app/features/alerting/unified/components/export/GrafanaReceiverExporter.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { LoadingPlaceholder } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/export/GrafanaReceiversExporter.tsx b/public/app/features/alerting/unified/components/export/GrafanaReceiversExporter.tsx
index e0f0037f676..86767c1b56d 100644
--- a/public/app/features/alerting/unified/components/export/GrafanaReceiversExporter.tsx
+++ b/public/app/features/alerting/unified/components/export/GrafanaReceiversExporter.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { LoadingPlaceholder } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/export/GrafanaRuleExporter.tsx b/public/app/features/alerting/unified/components/export/GrafanaRuleExporter.tsx
index 20347d656c8..391024f7d15 100644
--- a/public/app/features/alerting/unified/components/export/GrafanaRuleExporter.tsx
+++ b/public/app/features/alerting/unified/components/export/GrafanaRuleExporter.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { LoadingPlaceholder } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/export/GrafanaRuleFolderExporter.tsx b/public/app/features/alerting/unified/components/export/GrafanaRuleFolderExporter.tsx
index f7832957c01..572dcef609e 100644
--- a/public/app/features/alerting/unified/components/export/GrafanaRuleFolderExporter.tsx
+++ b/public/app/features/alerting/unified/components/export/GrafanaRuleFolderExporter.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { LoadingPlaceholder } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/export/GrafanaRuleGroupExporter.tsx b/public/app/features/alerting/unified/components/export/GrafanaRuleGroupExporter.tsx
index ab7286c82f4..678cf2b9337 100644
--- a/public/app/features/alerting/unified/components/export/GrafanaRuleGroupExporter.tsx
+++ b/public/app/features/alerting/unified/components/export/GrafanaRuleGroupExporter.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { LoadingPlaceholder } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/export/GrafanaRulesExporter.tsx b/public/app/features/alerting/unified/components/export/GrafanaRulesExporter.tsx
index 4d4a2db0193..425c6aaa5ca 100644
--- a/public/app/features/alerting/unified/components/export/GrafanaRulesExporter.tsx
+++ b/public/app/features/alerting/unified/components/export/GrafanaRulesExporter.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { LoadingPlaceholder } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/expressions/Expression.test.tsx b/public/app/features/alerting/unified/components/expressions/Expression.test.tsx
index 3c502ac4370..7f87e514ba6 100644
--- a/public/app/features/alerting/unified/components/expressions/Expression.test.tsx
+++ b/public/app/features/alerting/unified/components/expressions/Expression.test.tsx
@@ -1,7 +1,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { times } from 'lodash';
-import React from 'react';
import { DataFrame, toDataFrame } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/expressions/Expression.tsx b/public/app/features/alerting/unified/components/expressions/Expression.tsx
index b61434d6b5f..9db3be0c830 100644
--- a/public/app/features/alerting/unified/components/expressions/Expression.tsx
+++ b/public/app/features/alerting/unified/components/expressions/Expression.tsx
@@ -1,6 +1,6 @@
import { css, cx } from '@emotion/css';
import { uniqueId } from 'lodash';
-import React, { FC, useCallback, useState } from 'react';
+import { FC, useCallback, useState } from 'react';
import { useFormContext } from 'react-hook-form';
import { DataFrame, dateTimeFormat, GrafanaTheme2, isTimeSeriesFrames, LoadingState, PanelData } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/expressions/ExpressionStatusIndicator.test.tsx b/public/app/features/alerting/unified/components/expressions/ExpressionStatusIndicator.test.tsx
index bab68c9c6dc..b1cdd614864 100644
--- a/public/app/features/alerting/unified/components/expressions/ExpressionStatusIndicator.test.tsx
+++ b/public/app/features/alerting/unified/components/expressions/ExpressionStatusIndicator.test.tsx
@@ -1,5 +1,4 @@
import { screen, render } from '@testing-library/react';
-import React from 'react';
import { ExpressionStatusIndicator } from './ExpressionStatusIndicator';
diff --git a/public/app/features/alerting/unified/components/expressions/ExpressionStatusIndicator.tsx b/public/app/features/alerting/unified/components/expressions/ExpressionStatusIndicator.tsx
index 867972f26c1..e147d477907 100644
--- a/public/app/features/alerting/unified/components/expressions/ExpressionStatusIndicator.tsx
+++ b/public/app/features/alerting/unified/components/expressions/ExpressionStatusIndicator.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Badge, clearButtonStyles, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/extensions/AlertInstanceExtensionPoint.tsx b/public/app/features/alerting/unified/components/extensions/AlertInstanceExtensionPoint.tsx
index a75f70af622..ffb42258520 100644
--- a/public/app/features/alerting/unified/components/extensions/AlertInstanceExtensionPoint.tsx
+++ b/public/app/features/alerting/unified/components/extensions/AlertInstanceExtensionPoint.tsx
@@ -1,4 +1,4 @@
-import React, { ReactElement, useMemo, useState } from 'react';
+import { ReactElement, useMemo, useState } from 'react';
import { PluginExtensionLink, PluginExtensionPoints } from '@grafana/data';
import { usePluginLinkExtensions } from '@grafana/runtime';
diff --git a/public/app/features/alerting/unified/components/mute-timings/MuteTimingForm.tsx b/public/app/features/alerting/unified/components/mute-timings/MuteTimingForm.tsx
index 3d668ab947f..f7b2c65fc8c 100644
--- a/public/app/features/alerting/unified/components/mute-timings/MuteTimingForm.tsx
+++ b/public/app/features/alerting/unified/components/mute-timings/MuteTimingForm.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/mute-timings/MuteTimingTimeInterval.tsx b/public/app/features/alerting/unified/components/mute-timings/MuteTimingTimeInterval.tsx
index 479d3ea924a..0781bc3902e 100644
--- a/public/app/features/alerting/unified/components/mute-timings/MuteTimingTimeInterval.tsx
+++ b/public/app/features/alerting/unified/components/mute-timings/MuteTimingTimeInterval.tsx
@@ -1,6 +1,6 @@
import { css, cx } from '@emotion/css';
import { concat, uniq, upperFirst, without } from 'lodash';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { useFieldArray, useFormContext } from 'react-hook-form';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/mute-timings/MuteTimingTimeRange.tsx b/public/app/features/alerting/unified/components/mute-timings/MuteTimingTimeRange.tsx
index 9b2707645d9..130e06bc7d9 100644
--- a/public/app/features/alerting/unified/components/mute-timings/MuteTimingTimeRange.tsx
+++ b/public/app/features/alerting/unified/components/mute-timings/MuteTimingTimeRange.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { useFieldArray, useFormContext } from 'react-hook-form';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/mute-timings/MuteTimingsTable.test.tsx b/public/app/features/alerting/unified/components/mute-timings/MuteTimingsTable.test.tsx
index 17976633b01..6ceffac48e0 100644
--- a/public/app/features/alerting/unified/components/mute-timings/MuteTimingsTable.test.tsx
+++ b/public/app/features/alerting/unified/components/mute-timings/MuteTimingsTable.test.tsx
@@ -1,5 +1,4 @@
import { render, waitFor } from '@testing-library/react';
-import React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
diff --git a/public/app/features/alerting/unified/components/mute-timings/MuteTimingsTable.tsx b/public/app/features/alerting/unified/components/mute-timings/MuteTimingsTable.tsx
index a2b621b27c7..f846ec57380 100644
--- a/public/app/features/alerting/unified/components/mute-timings/MuteTimingsTable.tsx
+++ b/public/app/features/alerting/unified/components/mute-timings/MuteTimingsTable.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useCallback, useMemo, useState } from 'react';
+import { useCallback, useMemo, useState } from 'react';
import { useToggle } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/mute-timings/timezones.tsx b/public/app/features/alerting/unified/components/mute-timings/timezones.tsx
index 9e0ca1e8a1a..5c87bb4fce2 100644
--- a/public/app/features/alerting/unified/components/mute-timings/timezones.tsx
+++ b/public/app/features/alerting/unified/components/mute-timings/timezones.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SelectableValue } from '@grafana/data';
import { Select, SelectCommonProps } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/mute-timings/util.tsx b/public/app/features/alerting/unified/components/mute-timings/util.tsx
index 00a52f5e8ff..8ca6a4ee31b 100644
--- a/public/app/features/alerting/unified/components/mute-timings/util.tsx
+++ b/public/app/features/alerting/unified/components/mute-timings/util.tsx
@@ -1,5 +1,5 @@
import moment from 'moment';
-import React from 'react';
+import { Fragment } from 'react';
import { AlertmanagerConfig, MuteTimeInterval } from 'app/plugins/datasource/alertmanager/types';
@@ -63,12 +63,12 @@ function renderTimeIntervals(muteTiming: MuteTimeInterval) {
const yearsString = getYearsString(years);
return (
-
+
{`${timeString} ${weekdayString}`}
{[daysString, monthsString, yearsString].join(' | ')}
-
+
);
});
}
diff --git a/public/app/features/alerting/unified/components/notification-policies/AlertGroupsSummary.tsx b/public/app/features/alerting/unified/components/notification-policies/AlertGroupsSummary.tsx
index 29daa987f22..bdc6641f252 100644
--- a/public/app/features/alerting/unified/components/notification-policies/AlertGroupsSummary.tsx
+++ b/public/app/features/alerting/unified/components/notification-policies/AlertGroupsSummary.tsx
@@ -1,5 +1,6 @@
import pluralize from 'pluralize';
-import React, { Fragment } from 'react';
+import { Fragment } from 'react';
+import * as React from 'react';
import { Badge, Stack } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/notification-policies/ContactPointSelector.tsx b/public/app/features/alerting/unified/components/notification-policies/ContactPointSelector.tsx
index a5d96772876..7e71aa703a7 100644
--- a/public/app/features/alerting/unified/components/notification-policies/ContactPointSelector.tsx
+++ b/public/app/features/alerting/unified/components/notification-policies/ContactPointSelector.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SelectableValue } from '@grafana/data';
import { Select, SelectCommonProps, Text, Stack } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/notification-policies/EditDefaultPolicyForm.test.tsx b/public/app/features/alerting/unified/components/notification-policies/EditDefaultPolicyForm.test.tsx
index e6e046c66b0..58d6d2be5f5 100644
--- a/public/app/features/alerting/unified/components/notification-policies/EditDefaultPolicyForm.test.tsx
+++ b/public/app/features/alerting/unified/components/notification-policies/EditDefaultPolicyForm.test.tsx
@@ -1,7 +1,6 @@
import { render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { noop } from 'lodash';
-import React from 'react';
import { byRole } from 'testing-library-selector';
import { Button } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/notification-policies/EditDefaultPolicyForm.tsx b/public/app/features/alerting/unified/components/notification-policies/EditDefaultPolicyForm.tsx
index 2ae8f5f58d7..4c48f4c1a3a 100644
--- a/public/app/features/alerting/unified/components/notification-policies/EditDefaultPolicyForm.tsx
+++ b/public/app/features/alerting/unified/components/notification-policies/EditDefaultPolicyForm.tsx
@@ -1,4 +1,4 @@
-import React, { ReactNode, useState } from 'react';
+import { ReactNode, useState } from 'react';
import { useForm, Controller } from 'react-hook-form';
import { Collapse, Field, Link, MultiSelect, Select, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/notification-policies/EditNotificationPolicyForm.test.tsx b/public/app/features/alerting/unified/components/notification-policies/EditNotificationPolicyForm.test.tsx
index a0196a35dfe..e84ea06f48a 100644
--- a/public/app/features/alerting/unified/components/notification-policies/EditNotificationPolicyForm.test.tsx
+++ b/public/app/features/alerting/unified/components/notification-policies/EditNotificationPolicyForm.test.tsx
@@ -1,7 +1,6 @@
import { render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { noop } from 'lodash';
-import React from 'react';
import { byRole } from 'testing-library-selector';
import { Button } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/notification-policies/EditNotificationPolicyForm.tsx b/public/app/features/alerting/unified/components/notification-policies/EditNotificationPolicyForm.tsx
index 1940e575ea9..d12470c37b6 100644
--- a/public/app/features/alerting/unified/components/notification-policies/EditNotificationPolicyForm.tsx
+++ b/public/app/features/alerting/unified/components/notification-policies/EditNotificationPolicyForm.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { ReactNode, useState } from 'react';
+import { ReactNode, useState } from 'react';
import { useForm, Controller, useFieldArray } from 'react-hook-form';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/notification-policies/Filters.tsx b/public/app/features/alerting/unified/components/notification-policies/Filters.tsx
index df7c51040cd..1352563ed67 100644
--- a/public/app/features/alerting/unified/components/notification-policies/Filters.tsx
+++ b/public/app/features/alerting/unified/components/notification-policies/Filters.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { debounce, isEqual } from 'lodash';
-import React, { useCallback, useEffect, useRef } from 'react';
+import { useCallback, useEffect, useRef } from 'react';
import { SelectableValue } from '@grafana/data';
import { Button, Field, Icon, Input, Label, Select, Stack, Text, Tooltip, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/notification-policies/Matchers.tsx b/public/app/features/alerting/unified/components/notification-policies/Matchers.tsx
index 4a528648f05..26929327c08 100644
--- a/public/app/features/alerting/unified/components/notification-policies/Matchers.tsx
+++ b/public/app/features/alerting/unified/components/notification-policies/Matchers.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { take, takeRight, uniqueId } from 'lodash';
-import React, { FC } from 'react';
+import { FC } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { getTagColorsFromName, useStyles2, Stack } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/notification-policies/Modals.tsx b/public/app/features/alerting/unified/components/notification-policies/Modals.tsx
index 43338fdbdcf..08b9b8d3aa4 100644
--- a/public/app/features/alerting/unified/components/notification-policies/Modals.tsx
+++ b/public/app/features/alerting/unified/components/notification-policies/Modals.tsx
@@ -1,5 +1,5 @@
import { groupBy } from 'lodash';
-import React, { FC, useCallback, useMemo, useState } from 'react';
+import { FC, useCallback, useMemo, useState } from 'react';
import { Button, Icon, Modal, ModalProps, Spinner, Stack } from '@grafana/ui';
import {
diff --git a/public/app/features/alerting/unified/components/notification-policies/Policy.test.tsx b/public/app/features/alerting/unified/components/notification-policies/Policy.test.tsx
index 88e43ab5a71..00a1c7acc9d 100644
--- a/public/app/features/alerting/unified/components/notification-policies/Policy.test.tsx
+++ b/public/app/features/alerting/unified/components/notification-policies/Policy.test.tsx
@@ -1,7 +1,6 @@
import { render, renderHook, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { noop } from 'lodash';
-import React from 'react';
import { Router } from 'react-router-dom';
import { config, locationService } from '@grafana/runtime';
diff --git a/public/app/features/alerting/unified/components/notification-policies/Policy.tsx b/public/app/features/alerting/unified/components/notification-policies/Policy.tsx
index 5d5c129bb2c..8923768799b 100644
--- a/public/app/features/alerting/unified/components/notification-policies/Policy.tsx
+++ b/public/app/features/alerting/unified/components/notification-policies/Policy.tsx
@@ -1,7 +1,8 @@
import { css } from '@emotion/css';
import { defaults, groupBy, isArray, sumBy, uniqueId, upperFirst } from 'lodash';
import pluralize from 'pluralize';
-import React, { FC, Fragment, ReactNode, useState } from 'react';
+import { FC, Fragment, ReactNode, useState } from 'react';
+import * as React from 'react';
import { useToggle } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/notification-policies/PromDurationDocs.tsx b/public/app/features/alerting/unified/components/notification-policies/PromDurationDocs.tsx
index 148944219f5..ad0ccbca300 100644
--- a/public/app/features/alerting/unified/components/notification-policies/PromDurationDocs.tsx
+++ b/public/app/features/alerting/unified/components/notification-policies/PromDurationDocs.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/notification-policies/PromDurationInput.tsx b/public/app/features/alerting/unified/components/notification-policies/PromDurationInput.tsx
index 5c873ee6563..697f49531b0 100644
--- a/public/app/features/alerting/unified/components/notification-policies/PromDurationInput.tsx
+++ b/public/app/features/alerting/unified/components/notification-policies/PromDurationInput.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import { forwardRef } from 'react';
import { Icon, Input } from '@grafana/ui';
@@ -6,20 +6,18 @@ import { HoverCard } from '../HoverCard';
import { PromDurationDocs } from './PromDurationDocs';
-export const PromDurationInput = React.forwardRef>(
- (props, ref) => {
- return (
- } disabled={false}>
-
-
- }
- {...props}
- ref={ref}
- />
- );
- }
-);
+export const PromDurationInput = forwardRef>((props, ref) => {
+ return (
+ } disabled={false}>
+
+
+ }
+ {...props}
+ ref={ref}
+ />
+ );
+});
PromDurationInput.displayName = 'PromDurationInput';
diff --git a/public/app/features/alerting/unified/components/panel-alerts-tab/NewRuleFromPanelButton.test.tsx b/public/app/features/alerting/unified/components/panel-alerts-tab/NewRuleFromPanelButton.test.tsx
index eac3ccdf927..1db7c0c5c0a 100644
--- a/public/app/features/alerting/unified/components/panel-alerts-tab/NewRuleFromPanelButton.test.tsx
+++ b/public/app/features/alerting/unified/components/panel-alerts-tab/NewRuleFromPanelButton.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { PanelModel } from 'app/features/dashboard/state';
import { createDashboardModelFixture } from 'app/features/dashboard/state/__fixtures__/dashboardFixtures';
diff --git a/public/app/features/alerting/unified/components/panel-alerts-tab/NewRuleFromPanelButton.tsx b/public/app/features/alerting/unified/components/panel-alerts-tab/NewRuleFromPanelButton.tsx
index 4ab427e8341..a07e0b2d054 100644
--- a/public/app/features/alerting/unified/components/panel-alerts-tab/NewRuleFromPanelButton.tsx
+++ b/public/app/features/alerting/unified/components/panel-alerts-tab/NewRuleFromPanelButton.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useLocation } from 'react-router-dom';
import { useAsync } from 'react-use';
diff --git a/public/app/features/alerting/unified/components/receivers/AlertInstanceModalSelector.tsx b/public/app/features/alerting/unified/components/receivers/AlertInstanceModalSelector.tsx
index 08a026664eb..bb32d6d8f15 100644
--- a/public/app/features/alerting/unified/components/receivers/AlertInstanceModalSelector.tsx
+++ b/public/app/features/alerting/unified/components/receivers/AlertInstanceModalSelector.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { CSSProperties, useCallback, useMemo, useState } from 'react';
+import { CSSProperties, useCallback, useMemo, useState } from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
import { FixedSizeList } from 'react-window';
diff --git a/public/app/features/alerting/unified/components/receivers/DuplicateTemplateView.tsx b/public/app/features/alerting/unified/components/receivers/DuplicateTemplateView.tsx
index 91f28e94c79..e6f55163d1e 100644
--- a/public/app/features/alerting/unified/components/receivers/DuplicateTemplateView.tsx
+++ b/public/app/features/alerting/unified/components/receivers/DuplicateTemplateView.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Alert } from '@grafana/ui';
import { AlertManagerCortexConfig } from 'app/plugins/datasource/alertmanager/types';
diff --git a/public/app/features/alerting/unified/components/receivers/EditReceiverView.tsx b/public/app/features/alerting/unified/components/receivers/EditReceiverView.tsx
index 0a3dcf095e5..636e2944cbb 100644
--- a/public/app/features/alerting/unified/components/receivers/EditReceiverView.tsx
+++ b/public/app/features/alerting/unified/components/receivers/EditReceiverView.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Alert } from '@grafana/ui';
import { AlertManagerCortexConfig } from 'app/plugins/datasource/alertmanager/types';
diff --git a/public/app/features/alerting/unified/components/receivers/EditTemplateView.tsx b/public/app/features/alerting/unified/components/receivers/EditTemplateView.tsx
index 062d2f58bec..210a021936d 100644
--- a/public/app/features/alerting/unified/components/receivers/EditTemplateView.tsx
+++ b/public/app/features/alerting/unified/components/receivers/EditTemplateView.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Alert } from '@grafana/ui';
import { AlertManagerCortexConfig } from 'app/plugins/datasource/alertmanager/types';
diff --git a/public/app/features/alerting/unified/components/receivers/GlobalConfigForm.tsx b/public/app/features/alerting/unified/components/receivers/GlobalConfigForm.tsx
index 7974cf27a8a..928ea1327de 100644
--- a/public/app/features/alerting/unified/components/receivers/GlobalConfigForm.tsx
+++ b/public/app/features/alerting/unified/components/receivers/GlobalConfigForm.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useForm, FormProvider } from 'react-hook-form';
import { Alert, Button, Stack, LinkButton } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/receivers/NewReceiverView.tsx b/public/app/features/alerting/unified/components/receivers/NewReceiverView.tsx
index 0fe5ed33a61..5941336fe35 100644
--- a/public/app/features/alerting/unified/components/receivers/NewReceiverView.tsx
+++ b/public/app/features/alerting/unified/components/receivers/NewReceiverView.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { AlertManagerCortexConfig } from 'app/plugins/datasource/alertmanager/types';
import { GRAFANA_RULES_SOURCE_NAME } from '../../utils/datasource';
diff --git a/public/app/features/alerting/unified/components/receivers/NewTemplateView.tsx b/public/app/features/alerting/unified/components/receivers/NewTemplateView.tsx
index 0daac5b222b..00d3d788333 100644
--- a/public/app/features/alerting/unified/components/receivers/NewTemplateView.tsx
+++ b/public/app/features/alerting/unified/components/receivers/NewTemplateView.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { AlertManagerCortexConfig } from 'app/plugins/datasource/alertmanager/types';
import { TemplateForm } from './TemplateForm';
diff --git a/public/app/features/alerting/unified/components/receivers/PayloadEditor.test.tsx b/public/app/features/alerting/unified/components/receivers/PayloadEditor.test.tsx
index c4ad73cf9c0..2feb251e8b6 100644
--- a/public/app/features/alerting/unified/components/receivers/PayloadEditor.test.tsx
+++ b/public/app/features/alerting/unified/components/receivers/PayloadEditor.test.tsx
@@ -1,6 +1,6 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import { default as React, useState } from 'react';
+import { useState } from 'react';
import { Props } from 'react-virtualized-auto-sizer';
import { TestProvider } from 'test/helpers/TestProvider';
diff --git a/public/app/features/alerting/unified/components/receivers/PayloadEditor.tsx b/public/app/features/alerting/unified/components/receivers/PayloadEditor.tsx
index ef4065992a7..9c2966adbcb 100644
--- a/public/app/features/alerting/unified/components/receivers/PayloadEditor.tsx
+++ b/public/app/features/alerting/unified/components/receivers/PayloadEditor.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
+import * as React from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/receivers/ReceiversSection.tsx b/public/app/features/alerting/unified/components/receivers/ReceiversSection.tsx
index 94a010c7d72..a8c9a2591e8 100644
--- a/public/app/features/alerting/unified/components/receivers/ReceiversSection.tsx
+++ b/public/app/features/alerting/unified/components/receivers/ReceiversSection.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { Link } from 'react-router-dom';
import { useToggle } from 'react-use';
diff --git a/public/app/features/alerting/unified/components/receivers/TemplateDataDocs.tsx b/public/app/features/alerting/unified/components/receivers/TemplateDataDocs.tsx
index 610bc2150d6..cb6caa193b3 100644
--- a/public/app/features/alerting/unified/components/receivers/TemplateDataDocs.tsx
+++ b/public/app/features/alerting/unified/components/receivers/TemplateDataDocs.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2, Stack } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/receivers/TemplateEditor.tsx b/public/app/features/alerting/unified/components/receivers/TemplateEditor.tsx
index e09b1f94efa..4a5270a1662 100644
--- a/public/app/features/alerting/unified/components/receivers/TemplateEditor.tsx
+++ b/public/app/features/alerting/unified/components/receivers/TemplateEditor.tsx
@@ -4,7 +4,7 @@
* It includes auto-complete for template data and syntax highlighting
*/
import { editor, IDisposable } from 'monaco-editor';
-import React, { useEffect, useRef } from 'react';
+import { useEffect, useRef } from 'react';
import { CodeEditor } from '@grafana/ui';
import { CodeEditorProps } from '@grafana/ui/src/components/Monaco/types';
diff --git a/public/app/features/alerting/unified/components/receivers/TemplateForm.tsx b/public/app/features/alerting/unified/components/receivers/TemplateForm.tsx
index abbc2dd34f9..31e25736564 100644
--- a/public/app/features/alerting/unified/components/receivers/TemplateForm.tsx
+++ b/public/app/features/alerting/unified/components/receivers/TemplateForm.tsx
@@ -1,7 +1,7 @@
import { css, cx } from '@emotion/css';
import { addMinutes, subDays, subHours } from 'date-fns';
import { Location } from 'history';
-import React, { useRef, useState } from 'react';
+import { useRef, useState } from 'react';
import { FormProvider, useForm, Validate } from 'react-hook-form';
import { useToggle } from 'react-use';
import AutoSizer from 'react-virtualized-auto-sizer';
diff --git a/public/app/features/alerting/unified/components/receivers/TemplatePreview.tsx b/public/app/features/alerting/unified/components/receivers/TemplatePreview.tsx
index cab1322c2d4..df2b601334a 100644
--- a/public/app/features/alerting/unified/components/receivers/TemplatePreview.tsx
+++ b/public/app/features/alerting/unified/components/receivers/TemplatePreview.tsx
@@ -1,6 +1,6 @@
import { css, cx } from '@emotion/css';
import { compact, uniqueId } from 'lodash';
-import React from 'react';
+import * as React from 'react';
import { useFormContext } from 'react-hook-form';
import AutoSizer from 'react-virtualized-auto-sizer';
diff --git a/public/app/features/alerting/unified/components/receivers/TemplatesTable.test.tsx b/public/app/features/alerting/unified/components/receivers/TemplatesTable.test.tsx
index b173d5387c6..e47d08dfda7 100644
--- a/public/app/features/alerting/unified/components/receivers/TemplatesTable.test.tsx
+++ b/public/app/features/alerting/unified/components/receivers/TemplatesTable.test.tsx
@@ -1,5 +1,4 @@
import { render, screen, within } from '@testing-library/react';
-import React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
diff --git a/public/app/features/alerting/unified/components/receivers/TemplatesTable.tsx b/public/app/features/alerting/unified/components/receivers/TemplatesTable.tsx
index f38bf7442ca..8982cdfcac1 100644
--- a/public/app/features/alerting/unified/components/receivers/TemplatesTable.tsx
+++ b/public/app/features/alerting/unified/components/receivers/TemplatesTable.tsx
@@ -1,4 +1,4 @@
-import React, { Fragment, useMemo, useState } from 'react';
+import { Fragment, useMemo, useState } from 'react';
import { ConfirmModal, useStyles2 } from '@grafana/ui';
import { AlertManagerCortexConfig } from 'app/plugins/datasource/alertmanager/types';
diff --git a/public/app/features/alerting/unified/components/receivers/form/ChannelOptions.tsx b/public/app/features/alerting/unified/components/receivers/form/ChannelOptions.tsx
index 57f58f13271..eb57f14c55c 100644
--- a/public/app/features/alerting/unified/components/receivers/form/ChannelOptions.tsx
+++ b/public/app/features/alerting/unified/components/receivers/form/ChannelOptions.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { useFormContext, FieldError, FieldErrors, DeepMap } from 'react-hook-form';
import { Button, Field, Input } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/receivers/form/ChannelSubForm.tsx b/public/app/features/alerting/unified/components/receivers/form/ChannelSubForm.tsx
index 8a9050c6355..c3650654a41 100644
--- a/public/app/features/alerting/unified/components/receivers/form/ChannelSubForm.tsx
+++ b/public/app/features/alerting/unified/components/receivers/form/ChannelSubForm.tsx
@@ -1,6 +1,7 @@
import { css } from '@emotion/css';
import { sortBy } from 'lodash';
-import React, { useCallback, useEffect, useMemo, useState } from 'react';
+import { useCallback, useEffect, useMemo, useState } from 'react';
+import * as React from 'react';
import { Controller, FieldErrors, FieldValues, useFormContext } from 'react-hook-form';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
@@ -192,7 +193,7 @@ export function ChannelSubForm({
{isTelegram && !isParseModeNone && (
{
setShowTemplates(true);
trackEditInputWithTemplate();
@@ -117,14 +117,14 @@ interface TemplateSelectorProps {
function TemplateSelector({ onSelect, onClose, option, valueInForm }: TemplateSelectorProps) {
const styles = useStyles2(getStyles);
const useGetDefaultTemplatesQuery = templatesApi.endpoints.getDefaultTemplates.useQuery;
- const [template, setTemplate] = React.useState(undefined);
- const [inputToUpdate, setInputToUpdate] = React.useState('');
- const [inputToUpdateCustom, setInputToUpdateCustom] = React.useState(valueInForm);
+ const [template, setTemplate] = useState(undefined);
+ const [inputToUpdate, setInputToUpdate] = useState('');
+ const [inputToUpdateCustom, setInputToUpdateCustom] = useState(valueInForm);
const { selectedAlertmanager } = useAlertmanager();
const { data, error } = useAlertmanagerConfig(selectedAlertmanager);
const { data: defaultTemplates } = useGetDefaultTemplatesQuery();
- const [templateOption, setTemplateOption] = React.useState('Existing');
+ const [templateOption, setTemplateOption] = useState('Existing');
const [_, copyToClipboard] = useCopyToClipboard();
const templateOptions: Array> = [
diff --git a/public/app/features/alerting/unified/components/receivers/grafanaAppReceivers/ReceiverMetadataBadge.tsx b/public/app/features/alerting/unified/components/receivers/grafanaAppReceivers/ReceiverMetadataBadge.tsx
index 41101cf21c1..7a40e88b465 100644
--- a/public/app/features/alerting/unified/components/receivers/grafanaAppReceivers/ReceiverMetadataBadge.tsx
+++ b/public/app/features/alerting/unified/components/receivers/grafanaAppReceivers/ReceiverMetadataBadge.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Icon, LinkButton, Tooltip, useStyles2, Stack } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/receivers/grafanaAppReceivers/types.ts b/public/app/features/alerting/unified/components/receivers/grafanaAppReceivers/types.ts
index 6b65cc39322..8a316af702d 100644
--- a/public/app/features/alerting/unified/components/receivers/grafanaAppReceivers/types.ts
+++ b/public/app/features/alerting/unified/components/receivers/grafanaAppReceivers/types.ts
@@ -12,4 +12,5 @@ export const GRAFANA_APP_RECEIVERS_SOURCE_IMAGE: Record
[SupportedPlugin.Incident]: '',
[SupportedPlugin.MachineLearning]: '',
[SupportedPlugin.Labels]: '',
+ [SupportedPlugin.Slo]: '',
};
diff --git a/public/app/features/alerting/unified/components/rule-editor/AlertRuleNameInput.tsx b/public/app/features/alerting/unified/components/rule-editor/AlertRuleNameInput.tsx
index ffa4a09b4b1..983d6c781e2 100644
--- a/public/app/features/alerting/unified/components/rule-editor/AlertRuleNameInput.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/AlertRuleNameInput.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useFormContext } from 'react-hook-form';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/alerting/unified/components/rule-editor/AnnotationHeaderField.tsx b/public/app/features/alerting/unified/components/rule-editor/AnnotationHeaderField.tsx
index a939d86c984..0884eea135b 100644
--- a/public/app/features/alerting/unified/components/rule-editor/AnnotationHeaderField.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/AnnotationHeaderField.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { FieldArrayWithId, useFormContext, Controller } from 'react-hook-form';
import { Text, Stack } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rule-editor/AnnotationKeyInput.tsx b/public/app/features/alerting/unified/components/rule-editor/AnnotationKeyInput.tsx
index 864ddacb515..1c8ff70734f 100644
--- a/public/app/features/alerting/unified/components/rule-editor/AnnotationKeyInput.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/AnnotationKeyInput.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { SelectableValue } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rule-editor/AnnotationsStep.test.tsx b/public/app/features/alerting/unified/components/rule-editor/AnnotationsStep.test.tsx
index 5f380de38fd..559b4d45de9 100644
--- a/public/app/features/alerting/unified/components/rule-editor/AnnotationsStep.test.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/AnnotationsStep.test.tsx
@@ -1,7 +1,6 @@
import { findByRole, findByText, findByTitle, getByTestId, queryByText, render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { setupServer } from 'msw/node';
-import React from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { TestProvider } from 'test/helpers/TestProvider';
import { byRole, byTestId } from 'testing-library-selector';
diff --git a/public/app/features/alerting/unified/components/rule-editor/AnnotationsStep.tsx b/public/app/features/alerting/unified/components/rule-editor/AnnotationsStep.tsx
index f24b2a06909..df6d82009c1 100644
--- a/public/app/features/alerting/unified/components/rule-editor/AnnotationsStep.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/AnnotationsStep.tsx
@@ -1,6 +1,6 @@
import { css, cx } from '@emotion/css';
import { produce } from 'immer';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { useFieldArray, useFormContext } from 'react-hook-form';
import { useToggle } from 'react-use';
diff --git a/public/app/features/alerting/unified/components/rule-editor/CloudAlertPreview.tsx b/public/app/features/alerting/unified/components/rule-editor/CloudAlertPreview.tsx
index 06a2c63afce..67e447f29a6 100644
--- a/public/app/features/alerting/unified/components/rule-editor/CloudAlertPreview.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/CloudAlertPreview.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { DataFrame, GrafanaTheme2 } from '@grafana/data/src';
import { Icon, TagList, Tooltip, useStyles2 } from '@grafana/ui/src';
diff --git a/public/app/features/alerting/unified/components/rule-editor/CloudEvaluationBehavior.tsx b/public/app/features/alerting/unified/components/rule-editor/CloudEvaluationBehavior.tsx
index 53d5cc17033..4a223311b00 100644
--- a/public/app/features/alerting/unified/components/rule-editor/CloudEvaluationBehavior.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/CloudEvaluationBehavior.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { useFormContext, Controller } from 'react-hook-form';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rule-editor/CloudRulesSourcePicker.tsx b/public/app/features/alerting/unified/components/rule-editor/CloudRulesSourcePicker.tsx
index cf90e30003e..4155d51a3f4 100644
--- a/public/app/features/alerting/unified/components/rule-editor/CloudRulesSourcePicker.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/CloudRulesSourcePicker.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { useAsync } from 'react-use';
import { DataSourceInstanceSettings } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rule-editor/CustomAnnotationHeaderField.tsx b/public/app/features/alerting/unified/components/rule-editor/CustomAnnotationHeaderField.tsx
index 94e0421a77d..6b9765870e4 100644
--- a/public/app/features/alerting/unified/components/rule-editor/CustomAnnotationHeaderField.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/CustomAnnotationHeaderField.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Input, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rule-editor/DashboardAnnotationField.tsx b/public/app/features/alerting/unified/components/rule-editor/DashboardAnnotationField.tsx
index cc105d1fae0..94a7ce84ba2 100644
--- a/public/app/features/alerting/unified/components/rule-editor/DashboardAnnotationField.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/DashboardAnnotationField.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Icon, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rule-editor/DashboardPicker.test.tsx b/public/app/features/alerting/unified/components/rule-editor/DashboardPicker.test.tsx
index 7532f9b7376..5d49288dbb7 100644
--- a/public/app/features/alerting/unified/components/rule-editor/DashboardPicker.test.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/DashboardPicker.test.tsx
@@ -1,6 +1,5 @@
import { render, waitFor } from '@testing-library/react';
import { noop } from 'lodash';
-import React from 'react';
import { Props } from 'react-virtualized-auto-sizer';
import { byRole } from 'testing-library-selector';
diff --git a/public/app/features/alerting/unified/components/rule-editor/DashboardPicker.tsx b/public/app/features/alerting/unified/components/rule-editor/DashboardPicker.tsx
index bbba23164d3..becc633ca1d 100644
--- a/public/app/features/alerting/unified/components/rule-editor/DashboardPicker.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/DashboardPicker.tsx
@@ -1,6 +1,6 @@
import { css, cx } from '@emotion/css';
import { noop } from 'lodash';
-import React, { CSSProperties, useCallback, useMemo, useState } from 'react';
+import { CSSProperties, useCallback, useMemo, useState } from 'react';
import { useDebounce } from 'react-use';
import AutoSizer from 'react-virtualized-auto-sizer';
import { FixedSizeList } from 'react-window';
diff --git a/public/app/features/alerting/unified/components/rule-editor/EvaluationGroupQuickPick.test.tsx b/public/app/features/alerting/unified/components/rule-editor/EvaluationGroupQuickPick.test.tsx
index ec9b1ceb0ef..d1a927fbbdf 100644
--- a/public/app/features/alerting/unified/components/rule-editor/EvaluationGroupQuickPick.test.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/EvaluationGroupQuickPick.test.tsx
@@ -1,7 +1,6 @@
import { screen } from '@testing-library/dom';
import { render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { getEvaluationGroupOptions, EvaluationGroupQuickPick } from './EvaluationGroupQuickPick';
diff --git a/public/app/features/alerting/unified/components/rule-editor/EvaluationGroupQuickPick.tsx b/public/app/features/alerting/unified/components/rule-editor/EvaluationGroupQuickPick.tsx
index a92c2826676..6de3a7bb081 100644
--- a/public/app/features/alerting/unified/components/rule-editor/EvaluationGroupQuickPick.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/EvaluationGroupQuickPick.tsx
@@ -1,5 +1,4 @@
import { last, times } from 'lodash';
-import React from 'react';
import { config } from '@grafana/runtime';
import { Button, Stack } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rule-editor/ExpressionEditor.tsx b/public/app/features/alerting/unified/components/rule-editor/ExpressionEditor.tsx
index 93db08e9fd6..66d191dce5a 100644
--- a/public/app/features/alerting/unified/components/rule-editor/ExpressionEditor.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/ExpressionEditor.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { noop } from 'lodash';
-import React, { useCallback, useMemo } from 'react';
+import { useCallback, useMemo } from 'react';
import { useAsync } from 'react-use';
import { CoreApp, DataQuery, DataSourcePluginContextProvider, GrafanaTheme2, LoadingState } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rule-editor/ExpressionsEditor.tsx b/public/app/features/alerting/unified/components/rule-editor/ExpressionsEditor.tsx
index fcea75c2823..a9708fc79cd 100644
--- a/public/app/features/alerting/unified/components/rule-editor/ExpressionsEditor.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/ExpressionsEditor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { GrafanaTheme2, PanelData } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rule-editor/FolderAndGroup.tsx b/public/app/features/alerting/unified/components/rule-editor/FolderAndGroup.tsx
index 6a505fa06ee..d0cdc0b5ab9 100644
--- a/public/app/features/alerting/unified/components/rule-editor/FolderAndGroup.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/FolderAndGroup.tsx
@@ -1,6 +1,7 @@
import { css } from '@emotion/css';
import { debounce, take, uniqueId } from 'lodash';
-import React, { useCallback, useMemo, useState } from 'react';
+import { useCallback, useMemo, useState } from 'react';
+import * as React from 'react';
import { FormProvider, useForm, useFormContext, Controller } from 'react-hook-form';
import { AppEvents, GrafanaTheme2, SelectableValue } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rule-editor/GrafanaAlertStatePicker.tsx b/public/app/features/alerting/unified/components/rule-editor/GrafanaAlertStatePicker.tsx
index 2da0a1e8a8f..ed4ef5c481b 100644
--- a/public/app/features/alerting/unified/components/rule-editor/GrafanaAlertStatePicker.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/GrafanaAlertStatePicker.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { SelectableValue } from '@grafana/data';
import { Select } from '@grafana/ui';
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 93833664bb4..b98c50e6c40 100644
--- a/public/app/features/alerting/unified/components/rule-editor/GrafanaEvaluationBehavior.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/GrafanaEvaluationBehavior.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useCallback, useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
import { Controller, RegisterOptions, useFormContext } from 'react-hook-form';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rule-editor/GroupAndNamespaceFields.tsx b/public/app/features/alerting/unified/components/rule-editor/GroupAndNamespaceFields.tsx
index 1f46cb06088..541a7b6780a 100644
--- a/public/app/features/alerting/unified/components/rule-editor/GroupAndNamespaceFields.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/GroupAndNamespaceFields.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useMemo } from 'react';
+import { useEffect, useMemo } from 'react';
import { useFormContext, Controller } from 'react-hook-form';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rule-editor/NeedHelpInfo.tsx b/public/app/features/alerting/unified/components/rule-editor/NeedHelpInfo.tsx
index bed39ec01f1..8fe7112ae7a 100644
--- a/public/app/features/alerting/unified/components/rule-editor/NeedHelpInfo.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/NeedHelpInfo.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Icon, Text, Toggletip, useStyles2, Stack } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rule-editor/NotificationsStep.tsx b/public/app/features/alerting/unified/components/rule-editor/NotificationsStep.tsx
index f4d8c1ad097..c8ffbcead25 100644
--- a/public/app/features/alerting/unified/components/rule-editor/NotificationsStep.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/NotificationsStep.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { useFormContext } from 'react-hook-form';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rule-editor/PendingPeriodQuickPick.test.tsx b/public/app/features/alerting/unified/components/rule-editor/PendingPeriodQuickPick.test.tsx
index be299bee8d0..d77c2f74426 100644
--- a/public/app/features/alerting/unified/components/rule-editor/PendingPeriodQuickPick.test.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/PendingPeriodQuickPick.test.tsx
@@ -1,7 +1,6 @@
import { screen } from '@testing-library/dom';
import { render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { PendingPeriodQuickPick } from './PendingPeriodQuickPick';
diff --git a/public/app/features/alerting/unified/components/rule-editor/PendingPeriodQuickPick.tsx b/public/app/features/alerting/unified/components/rule-editor/PendingPeriodQuickPick.tsx
index 11015a643a6..5ee59437c06 100644
--- a/public/app/features/alerting/unified/components/rule-editor/PendingPeriodQuickPick.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/PendingPeriodQuickPick.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Button, Stack } from '@grafana/ui';
import { formatPrometheusDuration, safeParsePrometheusDuration } from '../../utils/time';
diff --git a/public/app/features/alerting/unified/components/rule-editor/PreviewRule.tsx b/public/app/features/alerting/unified/components/rule-editor/PreviewRule.tsx
index 65f5f17cf7d..170b849e030 100644
--- a/public/app/features/alerting/unified/components/rule-editor/PreviewRule.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/PreviewRule.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useCallback, useState } from 'react';
+import { useCallback, useState } from 'react';
+import * as React from 'react';
import { useFormContext } from 'react-hook-form';
import { useMountedState } from 'react-use';
import { takeWhile } from 'rxjs/operators';
diff --git a/public/app/features/alerting/unified/components/rule-editor/PreviewRuleResult.tsx b/public/app/features/alerting/unified/components/rule-editor/PreviewRuleResult.tsx
index 355ee4bd43d..7fc0af00cfb 100644
--- a/public/app/features/alerting/unified/components/rule-editor/PreviewRuleResult.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/PreviewRuleResult.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
import { FieldConfigSource, FieldMatcherID, GrafanaTheme2, LoadingState } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rule-editor/QueryEditor.tsx b/public/app/features/alerting/unified/components/rule-editor/QueryEditor.tsx
index 4a8d582f0b0..3f3a8fa9d71 100644
--- a/public/app/features/alerting/unified/components/rule-editor/QueryEditor.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/QueryEditor.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2, PanelData } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rule-editor/QueryOptions.tsx b/public/app/features/alerting/unified/components/rule-editor/QueryOptions.tsx
index d375aadacce..eb382117227 100644
--- a/public/app/features/alerting/unified/components/rule-editor/QueryOptions.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/QueryOptions.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { dateTime, getDefaultRelativeTimeRange, GrafanaTheme2, RelativeTimeRange } from '@grafana/data';
import { relativeToTimeRange } from '@grafana/data/src/datetime/rangeutil';
diff --git a/public/app/features/alerting/unified/components/rule-editor/QueryRows.tsx b/public/app/features/alerting/unified/components/rule-editor/QueryRows.tsx
index 55cb20a1dac..d8e1d43b7a9 100644
--- a/public/app/features/alerting/unified/components/rule-editor/QueryRows.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/QueryRows.tsx
@@ -1,5 +1,5 @@
import { omit } from 'lodash';
-import React, { PureComponent, useState } from 'react';
+import { PureComponent, useState } from 'react';
import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd';
import {
diff --git a/public/app/features/alerting/unified/components/rule-editor/QueryWrapper.tsx b/public/app/features/alerting/unified/components/rule-editor/QueryWrapper.tsx
index c449e07b446..7a6dfba30bb 100644
--- a/public/app/features/alerting/unified/components/rule-editor/QueryWrapper.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/QueryWrapper.tsx
@@ -1,6 +1,7 @@
import { css } from '@emotion/css';
import { cloneDeep } from 'lodash';
-import React, { ChangeEvent, useState } from 'react';
+import { ChangeEvent, useState } from 'react';
+import * as React from 'react';
import {
CoreApp,
diff --git a/public/app/features/alerting/unified/components/rule-editor/RecordingRuleEditor.tsx b/public/app/features/alerting/unified/components/rule-editor/RecordingRuleEditor.tsx
index d51e0b429e9..7e3167768f5 100644
--- a/public/app/features/alerting/unified/components/rule-editor/RecordingRuleEditor.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/RecordingRuleEditor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { FC, useEffect, useState } from 'react';
+import { FC, useEffect, useState } from 'react';
import { useAsync } from 'react-use';
import { PanelData, CoreApp, GrafanaTheme2, LoadingState } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rule-editor/RecordingRulesNameSpaceAndGroupStep.tsx b/public/app/features/alerting/unified/components/rule-editor/RecordingRulesNameSpaceAndGroupStep.tsx
index ad1af3184cd..f512af4c3b2 100644
--- a/public/app/features/alerting/unified/components/rule-editor/RecordingRulesNameSpaceAndGroupStep.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/RecordingRulesNameSpaceAndGroupStep.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useFormContext } from 'react-hook-form';
import { RuleFormValues } from '../../types/rule-form';
diff --git a/public/app/features/alerting/unified/components/rule-editor/RuleEditorSection.tsx b/public/app/features/alerting/unified/components/rule-editor/RuleEditorSection.tsx
index 7016078e775..200e1bc8583 100644
--- a/public/app/features/alerting/unified/components/rule-editor/RuleEditorSection.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/RuleEditorSection.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { ReactElement } from 'react';
+import { ReactElement } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { FieldSet, Text, useStyles2, Stack } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rule-editor/RuleFolderPicker.tsx b/public/app/features/alerting/unified/components/rule-editor/RuleFolderPicker.tsx
index 4020136a56f..8d56e50778b 100644
--- a/public/app/features/alerting/unified/components/rule-editor/RuleFolderPicker.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/RuleFolderPicker.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Icon, Stack, Tooltip, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rule-editor/RuleInspector.tsx b/public/app/features/alerting/unified/components/rule-editor/RuleInspector.tsx
index fe8711a7d1d..2a94349d177 100644
--- a/public/app/features/alerting/unified/components/rule-editor/RuleInspector.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/RuleInspector.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { dump, load } from 'js-yaml';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { useFormContext } from 'react-hook-form';
import AutoSizer from 'react-virtualized-auto-sizer';
diff --git a/public/app/features/alerting/unified/components/rule-editor/SelectWIthAdd.tsx b/public/app/features/alerting/unified/components/rule-editor/SelectWIthAdd.tsx
index 8bc85bc91b6..d4bc62757bc 100644
--- a/public/app/features/alerting/unified/components/rule-editor/SelectWIthAdd.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/SelectWIthAdd.tsx
@@ -1,4 +1,5 @@
-import React, { useEffect, useMemo, useRef, useState } from 'react';
+import { useEffect, useMemo, useRef, useState } from 'react';
+import * as React from 'react';
import { SelectableValue } from '@grafana/data';
import { Input, Select } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rule-editor/VizWrapper.tsx b/public/app/features/alerting/unified/components/rule-editor/VizWrapper.tsx
index c252c92a2ee..62529714a59 100644
--- a/public/app/features/alerting/unified/components/rule-editor/VizWrapper.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/VizWrapper.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
import { GrafanaTheme2, isTimeSeriesFrames, PanelData, ThresholdsConfig } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/AlertRuleForm.tsx b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/AlertRuleForm.tsx
index 6b60c525c7c..13bf7edcfdc 100644
--- a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/AlertRuleForm.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/AlertRuleForm.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useMemo, useState } from 'react';
+import { useEffect, useMemo, useState } from 'react';
import { FormProvider, SubmitErrorHandler, UseFormWatch, useForm } from 'react-hook-form';
import { Link, useParams } from 'react-router-dom';
diff --git a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/ModifyExportRuleForm.tsx b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/ModifyExportRuleForm.tsx
index 29b118a52ac..3efe5311328 100644
--- a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/ModifyExportRuleForm.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/ModifyExportRuleForm.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useEffect, useMemo, useState } from 'react';
+import { memo, useCallback, useEffect, useMemo, useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { useAsync } from 'react-use';
@@ -214,27 +214,25 @@ interface GrafanaRuleDesignExporterProps {
uid: string;
}
-export const GrafanaRuleDesignExporter = React.memo(
- ({ onClose, exportValues, uid }: GrafanaRuleDesignExporterProps) => {
- const [activeTab, setActiveTab] = useState('yaml');
+export const GrafanaRuleDesignExporter = memo(({ onClose, exportValues, uid }: GrafanaRuleDesignExporterProps) => {
+ const [activeTab, setActiveTab] = useState('yaml');
- return (
-
+
-
-
- );
- }
-);
+ exportValues={exportValues}
+ uid={uid}
+ />
+
+ );
+});
GrafanaRuleDesignExporter.displayName = 'GrafanaRuleDesignExporter';
diff --git a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/AlertManagerRouting.tsx b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/AlertManagerRouting.tsx
index 82c7f3ae907..55751a9db97 100644
--- a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/AlertManagerRouting.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/AlertManagerRouting.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { useFormContext } from 'react-hook-form';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/SimplifiedRouting.tsx b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/SimplifiedRouting.tsx
index 5b15982411e..177c6f1bc69 100644
--- a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/SimplifiedRouting.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/SimplifiedRouting.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { useFormContext } from 'react-hook-form';
import { AlertmanagerProvider } from 'app/features/alerting/unified/state/AlertmanagerContext';
diff --git a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/SimplifiedRuleEditor.test.tsx b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/SimplifiedRuleEditor.test.tsx
index 0cae6f92809..a85a98f60e8 100644
--- a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/SimplifiedRuleEditor.test.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/SimplifiedRuleEditor.test.tsx
@@ -1,6 +1,6 @@
import { render, screen, waitFor, waitForElementToBeRemoved } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
+import * as React from 'react';
import { Route } from 'react-router-dom';
import { TestProvider } from 'test/helpers/TestProvider';
import { ui } from 'test/helpers/alertingRuleEditor';
diff --git a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/contactPoint/ContactPointDetails.tsx b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/contactPoint/ContactPointDetails.tsx
index 251b6a6095e..6b2a949117b 100644
--- a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/contactPoint/ContactPointDetails.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/contactPoint/ContactPointDetails.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Stack } from '@grafana/ui';
import { ContactPointReceiverTitleRow } from '../../../../contact-points/ContactPoints';
diff --git a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/contactPoint/ContactPointSelector.tsx b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/contactPoint/ContactPointSelector.tsx
index 8b5abe2c7c4..3a62bf35584 100644
--- a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/contactPoint/ContactPointSelector.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/contactPoint/ContactPointSelector.tsx
@@ -1,5 +1,6 @@
import { css, cx, keyframes } from '@emotion/css';
-import React, { useCallback, useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
+import * as React from 'react';
import { useFormContext, Controller } from 'react-hook-form';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/route-settings/MuteTimingFields.tsx b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/route-settings/MuteTimingFields.tsx
index d52230f4e94..bf73daa8b11 100644
--- a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/route-settings/MuteTimingFields.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/route-settings/MuteTimingFields.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useFormContext, Controller } from 'react-hook-form';
import { SelectableValue } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/route-settings/RouteSettings.tsx b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/route-settings/RouteSettings.tsx
index 82861c08d0e..cfbc879842a 100644
--- a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/route-settings/RouteSettings.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/route-settings/RouteSettings.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
+import * as React from 'react';
import { useFormContext, Controller } from 'react-hook-form';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/route-settings/RouteTimings.tsx b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/route-settings/RouteTimings.tsx
index 02eb7e4ede4..df8d3539ec3 100644
--- a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/route-settings/RouteTimings.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/route-settings/RouteTimings.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useFormContext } from 'react-hook-form';
import { Field, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rule-editor/labels/LabelsButtons.tsx b/public/app/features/alerting/unified/components/rule-editor/labels/LabelsButtons.tsx
index c7f9683bec6..8ef2687ff82 100644
--- a/public/app/features/alerting/unified/components/rule-editor/labels/LabelsButtons.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/labels/LabelsButtons.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { UseFieldArrayRemove } from 'react-hook-form';
import { Button } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rule-editor/labels/LabelsEditorModal.tsx b/public/app/features/alerting/unified/components/rule-editor/labels/LabelsEditorModal.tsx
index 3b6d5675fb5..a98ad871b49 100644
--- a/public/app/features/alerting/unified/components/rule-editor/labels/LabelsEditorModal.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/labels/LabelsEditorModal.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Modal } from '@grafana/ui';
import { LabelsSubForm } from './LabelsField';
diff --git a/public/app/features/alerting/unified/components/rule-editor/labels/LabelsField.test.tsx b/public/app/features/alerting/unified/components/rule-editor/labels/LabelsField.test.tsx
index 3f279087e5b..c1b3ab3286e 100644
--- a/public/app/features/alerting/unified/components/rule-editor/labels/LabelsField.test.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/labels/LabelsField.test.tsx
@@ -1,6 +1,6 @@
import { render, screen, waitFor, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
+import * as React from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { TestProvider } from 'test/helpers/TestProvider';
diff --git a/public/app/features/alerting/unified/components/rule-editor/labels/LabelsField.tsx b/public/app/features/alerting/unified/components/rule-editor/labels/LabelsField.tsx
index 3573f37ef6c..bcbdcdbd65f 100644
--- a/public/app/features/alerting/unified/components/rule-editor/labels/LabelsField.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/labels/LabelsField.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { FC, useCallback, useEffect, useMemo, useState } from 'react';
+import { FC, useCallback, useEffect, useMemo, useState } from 'react';
import { Controller, FormProvider, useFieldArray, useForm, useFormContext } from 'react-hook-form';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rule-editor/labels/LabelsFieldInForm.tsx b/public/app/features/alerting/unified/components/rule-editor/labels/LabelsFieldInForm.tsx
index 14d7319b088..3bfaa4fe6e0 100644
--- a/public/app/features/alerting/unified/components/rule-editor/labels/LabelsFieldInForm.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/labels/LabelsFieldInForm.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useFormContext } from 'react-hook-form';
import { Button, Stack, Text } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPolicyMatchers.tsx b/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPolicyMatchers.tsx
index 47b2091d5a9..b6643b0253f 100644
--- a/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPolicyMatchers.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPolicyMatchers.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPreview.test.tsx b/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPreview.test.tsx
index c6655a898da..cb8c46a04f1 100644
--- a/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPreview.test.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPreview.test.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { render, screen, waitFor, within, userEvent } from 'test/test-utils';
import { byRole, byTestId, byText } from 'testing-library-selector';
diff --git a/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPreview.tsx b/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPreview.tsx
index 8040157bd18..632b5192e6c 100644
--- a/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPreview.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPreview.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { compact } from 'lodash';
-import React, { lazy, Suspense } from 'react';
+import { lazy, Suspense } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Button, LoadingPlaceholder, Text, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPreviewByAlertManager.tsx b/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPreviewByAlertManager.tsx
index 13e2cf81dc8..f437f80df74 100644
--- a/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPreviewByAlertManager.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPreviewByAlertManager.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Alert, LoadingPlaceholder, useStyles2, withErrorBoundary } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationRoute.tsx b/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationRoute.tsx
index db0cfbddd19..8c114ddcfb5 100644
--- a/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationRoute.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationRoute.tsx
@@ -1,7 +1,7 @@
import { css, cx } from '@emotion/css';
import { uniqueId } from 'lodash';
import pluralize from 'pluralize';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { useToggle } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationRouteDetailsModal.tsx b/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationRouteDetailsModal.tsx
index 52c7f80cd4c..42e0bc67804 100644
--- a/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationRouteDetailsModal.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationRouteDetailsModal.tsx
@@ -1,6 +1,5 @@
import { css, cx } from '@emotion/css';
import { compact } from 'lodash';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Button, Icon, Modal, Stack, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/CloudDataSourceSelector.tsx b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/CloudDataSourceSelector.tsx
index 263c3e07a02..85deb7eb620 100644
--- a/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/CloudDataSourceSelector.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/CloudDataSourceSelector.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { useFormContext, Controller } from 'react-hook-form';
import { DataSourceInstanceSettings, GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/QueryAndExpressionsStep.tsx b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/QueryAndExpressionsStep.tsx
index 7da5af1f8c6..39c3123c0b8 100644
--- a/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/QueryAndExpressionsStep.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/QueryAndExpressionsStep.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { cloneDeep } from 'lodash';
-import React, { useCallback, useEffect, useMemo, useReducer, useState } from 'react';
+import { useCallback, useEffect, useMemo, useReducer, useState } from 'react';
import { useFormContext, Controller } from 'react-hook-form';
import { getDefaultRelativeTimeRange, GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/SmartAlertTypeDetector.tsx b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/SmartAlertTypeDetector.tsx
index d123b01ef52..b1f83b217aa 100644
--- a/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/SmartAlertTypeDetector.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/SmartAlertTypeDetector.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useFormContext } from 'react-hook-form';
import { DataSourceInstanceSettings } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rule-editor/rule-types/DisabledTooltip.tsx b/public/app/features/alerting/unified/components/rule-editor/rule-types/DisabledTooltip.tsx
index bd72f7619b4..ffbffcfa635 100644
--- a/public/app/features/alerting/unified/components/rule-editor/rule-types/DisabledTooltip.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/rule-types/DisabledTooltip.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { Tooltip } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rule-editor/rule-types/GrafanaManagedAlert.tsx b/public/app/features/alerting/unified/components/rule-editor/rule-types/GrafanaManagedAlert.tsx
index ce10238a329..49443375d5f 100644
--- a/public/app/features/alerting/unified/components/rule-editor/rule-types/GrafanaManagedAlert.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/rule-types/GrafanaManagedAlert.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { RuleFormType } from '../../../types/rule-form';
import { RuleType, SharedProps } from './RuleType';
diff --git a/public/app/features/alerting/unified/components/rule-editor/rule-types/MimirOrLokiAlert.tsx b/public/app/features/alerting/unified/components/rule-editor/rule-types/MimirOrLokiAlert.tsx
index 652fc9b8a20..e1c1adb3981 100644
--- a/public/app/features/alerting/unified/components/rule-editor/rule-types/MimirOrLokiAlert.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/rule-types/MimirOrLokiAlert.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { RuleFormType } from '../../../types/rule-form';
import { DisabledTooltip } from './DisabledTooltip';
diff --git a/public/app/features/alerting/unified/components/rule-editor/rule-types/MimirOrLokiRecordingRule.tsx b/public/app/features/alerting/unified/components/rule-editor/rule-types/MimirOrLokiRecordingRule.tsx
index 0f16884199b..de899b0a690 100644
--- a/public/app/features/alerting/unified/components/rule-editor/rule-types/MimirOrLokiRecordingRule.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/rule-types/MimirOrLokiRecordingRule.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { RuleFormType } from '../../../types/rule-form';
import { DisabledTooltip } from './DisabledTooltip';
diff --git a/public/app/features/alerting/unified/components/rule-editor/rule-types/RuleType.tsx b/public/app/features/alerting/unified/components/rule-editor/rule-types/RuleType.tsx
index d36e916345a..3568fa5985c 100644
--- a/public/app/features/alerting/unified/components/rule-editor/rule-types/RuleType.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/rule-types/RuleType.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { ReactNode } from 'react';
+import { ReactNode } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Card, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rule-editor/rule-types/RuleTypePicker.tsx b/public/app/features/alerting/unified/components/rule-editor/rule-types/RuleTypePicker.tsx
index 505b6b39b31..82c777ae2ed 100644
--- a/public/app/features/alerting/unified/components/rule-editor/rule-types/RuleTypePicker.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/rule-types/RuleTypePicker.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { isEmpty } from 'lodash';
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import { GrafanaTheme2 } from '@grafana/data/src';
import { useStyles2, Stack } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rule-list/AlertRuleListItem.tsx b/public/app/features/alerting/unified/components/rule-list/AlertRuleListItem.tsx
index 05fc5d7b965..59d42a6b80f 100644
--- a/public/app/features/alerting/unified/components/rule-list/AlertRuleListItem.tsx
+++ b/public/app/features/alerting/unified/components/rule-list/AlertRuleListItem.tsx
@@ -1,7 +1,6 @@
import { css } from '@emotion/css';
import { isEmpty } from 'lodash';
import pluralize from 'pluralize';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2, Stack, Text, TextLink, Dropdown, Button, Menu, Alert } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rule-list/EvaluationGroup.tsx b/public/app/features/alerting/unified/components/rule-list/EvaluationGroup.tsx
index 68419674e94..15969398870 100644
--- a/public/app/features/alerting/unified/components/rule-list/EvaluationGroup.tsx
+++ b/public/app/features/alerting/unified/components/rule-list/EvaluationGroup.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { PropsWithChildren } from 'react';
+import { PropsWithChildren } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2, Badge, Button, Dropdown, Menu, Stack, Text, Icon } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rule-list/EvaluationGroupWithRules.tsx b/public/app/features/alerting/unified/components/rule-list/EvaluationGroupWithRules.tsx
index 0b00e839e94..36da6c9a1de 100644
--- a/public/app/features/alerting/unified/components/rule-list/EvaluationGroupWithRules.tsx
+++ b/public/app/features/alerting/unified/components/rule-list/EvaluationGroupWithRules.tsx
@@ -1,5 +1,4 @@
import { size } from 'lodash';
-import React from 'react';
import { useToggle } from 'react-use';
import { CombinedRuleGroup, RulesSource } from 'app/types/unified-alerting';
diff --git a/public/app/features/alerting/unified/components/rule-list/Namespace.tsx b/public/app/features/alerting/unified/components/rule-list/Namespace.tsx
index 71ba016ff41..a84ebe9c05e 100644
--- a/public/app/features/alerting/unified/components/rule-list/Namespace.tsx
+++ b/public/app/features/alerting/unified/components/rule-list/Namespace.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { PropsWithChildren } from 'react';
+import { PropsWithChildren } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2, Stack, TextLink, Icon } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rule-list/RuleList.v1.tsx b/public/app/features/alerting/unified/components/rule-list/RuleList.v1.tsx
index f2a0409de11..5e56084b6d6 100644
--- a/public/app/features/alerting/unified/components/rule-list/RuleList.v1.tsx
+++ b/public/app/features/alerting/unified/components/rule-list/RuleList.v1.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useCallback, useEffect, useMemo, useState } from 'react';
+import { useCallback, useEffect, useMemo, useState } from 'react';
import { useLocation } from 'react-router-dom';
import { useAsyncFn, useInterval } from 'react-use';
diff --git a/public/app/features/alerting/unified/components/rule-list/RuleList.v2.tsx b/public/app/features/alerting/unified/components/rule-list/RuleList.v2.tsx
index be189d2ede5..21271c658c9 100644
--- a/public/app/features/alerting/unified/components/rule-list/RuleList.v2.tsx
+++ b/public/app/features/alerting/unified/components/rule-list/RuleList.v2.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useCallback, useEffect, useMemo, useState } from 'react';
+import { useCallback, useEffect, useMemo, useState } from 'react';
import { useLocation } from 'react-router-dom';
import { useAsyncFn, useInterval, useMeasure } from 'react-use';
diff --git a/public/app/features/alerting/unified/components/rule-list/RuleListIcon.tsx b/public/app/features/alerting/unified/components/rule-list/RuleListIcon.tsx
index 9de3d974638..bbecda09ebe 100644
--- a/public/app/features/alerting/unified/components/rule-list/RuleListIcon.tsx
+++ b/public/app/features/alerting/unified/components/rule-list/RuleListIcon.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import type { RequireAtLeastOne } from 'type-fest';
import { Tooltip, type IconName, Text, Icon } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rule-viewer/AlertRuleMenu.tsx b/public/app/features/alerting/unified/components/rule-viewer/AlertRuleMenu.tsx
index ef4bd8106a2..0f19f5a5b41 100644
--- a/public/app/features/alerting/unified/components/rule-viewer/AlertRuleMenu.tsx
+++ b/public/app/features/alerting/unified/components/rule-viewer/AlertRuleMenu.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { AppEvents } from '@grafana/data';
import { ComponentSize, Dropdown, Menu } from '@grafana/ui';
import appEvents from 'app/core/app_events';
diff --git a/public/app/features/alerting/unified/components/rule-viewer/DeleteModal.tsx b/public/app/features/alerting/unified/components/rule-viewer/DeleteModal.tsx
index 5e234b9e1fa..0af821c048d 100644
--- a/public/app/features/alerting/unified/components/rule-viewer/DeleteModal.tsx
+++ b/public/app/features/alerting/unified/components/rule-viewer/DeleteModal.tsx
@@ -1,4 +1,4 @@
-import React, { useState, useCallback, useMemo } from 'react';
+import { useState, useCallback, useMemo } from 'react';
import { locationService } from '@grafana/runtime';
import { ConfirmModal } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rule-viewer/FederatedRuleWarning.tsx b/public/app/features/alerting/unified/components/rule-viewer/FederatedRuleWarning.tsx
index 76bf9317abf..a90066f3c6e 100644
--- a/public/app/features/alerting/unified/components/rule-viewer/FederatedRuleWarning.tsx
+++ b/public/app/features/alerting/unified/components/rule-viewer/FederatedRuleWarning.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Alert, Button, Stack } from '@grafana/ui';
export function FederatedRuleWarning() {
diff --git a/public/app/features/alerting/unified/components/rule-viewer/PausedBadge.tsx b/public/app/features/alerting/unified/components/rule-viewer/PausedBadge.tsx
index 1bb27750bc8..5db7647869e 100644
--- a/public/app/features/alerting/unified/components/rule-viewer/PausedBadge.tsx
+++ b/public/app/features/alerting/unified/components/rule-viewer/PausedBadge.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Icon, Stack, Text } from '@grafana/ui';
export default function PausedBadge() {
diff --git a/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.test.tsx b/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.test.tsx
index fb11d3591a0..f077544ebb2 100644
--- a/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.test.tsx
+++ b/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.test.tsx
@@ -1,5 +1,4 @@
import { within } from '@testing-library/react';
-import React from 'react';
import { render, waitFor, screen, userEvent } from 'test/test-utils';
import { byText, byRole } from 'testing-library-selector';
diff --git a/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.tsx b/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.tsx
index e6900d976b4..0ff7c324605 100644
--- a/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.tsx
+++ b/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
-import { isEmpty, truncate } from 'lodash';
-import React, { useState } from 'react';
+import { chain, isEmpty, truncate } from 'lodash';
+import { useState } from 'react';
import { NavModelItem, UrlQueryValue } from '@grafana/data';
import { Alert, LinkButton, Stack, TabContent, Text, TextLink, useStyles2 } from '@grafana/ui';
@@ -8,7 +8,7 @@ import { PageInfoItem } from 'app/core/components/Page/types';
import { useQueryParams } from 'app/core/hooks/useQueryParams';
import InfoPausedRule from 'app/features/alerting/unified/components/InfoPausedRule';
import { RuleActionsButtons } from 'app/features/alerting/unified/components/rules/RuleActionsButtons';
-import { CombinedRule, RuleHealth, RuleIdentifier } from 'app/types/unified-alerting';
+import { AlertInstanceTotalState, CombinedRule, RuleHealth, RuleIdentifier } from 'app/types/unified-alerting';
import { PromAlertingRuleState, PromRuleType } from 'app/types/unified-alerting-dto';
import { defaultPageNav } from '../../RuleViewer';
@@ -42,7 +42,7 @@ import { InstancesList } from './tabs/Instances';
import { QueryResults } from './tabs/Query';
import { Routing } from './tabs/Routing';
-enum ActiveTab {
+export enum ActiveTab {
Query = 'query',
Instances = 'instances',
History = 'history',
@@ -251,7 +251,7 @@ export const Title = ({ name, paused = false, state, health, ruleType, ruleOrigi
export const isErrorHealth = (health?: RuleHealth) => health === 'error' || health === 'err';
-function useActiveTab(): [ActiveTab, (tab: ActiveTab) => void] {
+export function useActiveTab(): [ActiveTab, (tab: ActiveTab) => void] {
const [queryParams, setQueryParams] = useQueryParams();
const tabFromQuery = queryParams['tab'];
@@ -277,7 +277,7 @@ function usePageNav(rule: CombinedRule) {
const summary = annotations[Annotation.summary];
const isAlertType = isAlertingRule(promRule);
- const numberOfInstance = isAlertType ? (promRule.alerts ?? []).length : undefined;
+ const numberOfInstance = isAlertType ? calculateTotalInstances(rule.instanceTotals) : undefined;
const namespaceName = decodeGrafanaNamespace(rule.namespace).name;
const groupName = rule.group.name;
@@ -343,6 +343,14 @@ function usePageNav(rule: CombinedRule) {
};
}
+const calculateTotalInstances = (stats: CombinedRule['instanceTotals']) => {
+ return chain(stats)
+ .pick([AlertInstanceTotalState.Alerting, AlertInstanceTotalState.Pending, AlertInstanceTotalState.Normal])
+ .values()
+ .sum()
+ .value();
+};
+
const getStyles = () => ({
title: css({
display: 'flex',
diff --git a/public/app/features/alerting/unified/components/rule-viewer/RuleViewerLayout.tsx b/public/app/features/alerting/unified/components/rule-viewer/RuleViewerLayout.tsx
index 9e781793a5e..1f61f10e640 100644
--- a/public/app/features/alerting/unified/components/rule-viewer/RuleViewerLayout.tsx
+++ b/public/app/features/alerting/unified/components/rule-viewer/RuleViewerLayout.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2, NavModelItem } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rule-viewer/RuleViewerVisualization.tsx b/public/app/features/alerting/unified/components/rule-viewer/RuleViewerVisualization.tsx
index 7cba1c7386d..c55b01c6d16 100644
--- a/public/app/features/alerting/unified/components/rule-viewer/RuleViewerVisualization.tsx
+++ b/public/app/features/alerting/unified/components/rule-viewer/RuleViewerVisualization.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PanelData } from '@grafana/data';
import { VizWrapper } from '../rule-editor/VizWrapper';
diff --git a/public/app/features/alerting/unified/components/rule-viewer/StateBadges.tsx b/public/app/features/alerting/unified/components/rule-viewer/StateBadges.tsx
index 8c478be41de..a2c620d0659 100644
--- a/public/app/features/alerting/unified/components/rule-viewer/StateBadges.tsx
+++ b/public/app/features/alerting/unified/components/rule-viewer/StateBadges.tsx
@@ -1,4 +1,4 @@
-import React, { ReactNode } from 'react';
+import { ReactNode } from 'react';
import { Stack, Text } from '@grafana/ui';
import { RuleHealth } from 'app/types/unified-alerting';
diff --git a/public/app/features/alerting/unified/components/rule-viewer/tabs/Details.tsx b/public/app/features/alerting/unified/components/rule-viewer/tabs/Details.tsx
index a23aada798f..e4757c8b993 100644
--- a/public/app/features/alerting/unified/components/rule-viewer/tabs/Details.tsx
+++ b/public/app/features/alerting/unified/components/rule-viewer/tabs/Details.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { formatDistanceToNowStrict } from 'date-fns';
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Text, Stack, useStyles2, ClipboardButton, TextLink } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rule-viewer/tabs/History.tsx b/public/app/features/alerting/unified/components/rule-viewer/tabs/History.tsx
index e2843dab278..c2f6910e08c 100644
--- a/public/app/features/alerting/unified/components/rule-viewer/tabs/History.tsx
+++ b/public/app/features/alerting/unified/components/rule-viewer/tabs/History.tsx
@@ -1,4 +1,4 @@
-import React, { lazy, Suspense } from 'react';
+import { lazy, Suspense } from 'react';
import { config } from '@grafana/runtime';
import { RulerGrafanaRuleDTO } from 'app/types/unified-alerting-dto';
diff --git a/public/app/features/alerting/unified/components/rule-viewer/tabs/Instances.tsx b/public/app/features/alerting/unified/components/rule-viewer/tabs/Instances.tsx
index 3ad8da071f9..23440609478 100644
--- a/public/app/features/alerting/unified/components/rule-viewer/tabs/Instances.tsx
+++ b/public/app/features/alerting/unified/components/rule-viewer/tabs/Instances.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { DEFAULT_PER_PAGE_PAGINATION } from 'app/core/constants';
import { CombinedRule } from 'app/types/unified-alerting';
diff --git a/public/app/features/alerting/unified/components/rule-viewer/tabs/Query.tsx b/public/app/features/alerting/unified/components/rule-viewer/tabs/Query.tsx
index 8988d3a6d99..390c8acf677 100644
--- a/public/app/features/alerting/unified/components/rule-viewer/tabs/Query.tsx
+++ b/public/app/features/alerting/unified/components/rule-viewer/tabs/Query.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useEffect, useMemo } from 'react';
+import { useCallback, useEffect, useMemo } from 'react';
import { useObservable } from 'react-use';
import { LoadingState, PanelData } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rule-viewer/tabs/Query/DataSourceModelPreview.tsx b/public/app/features/alerting/unified/components/rule-viewer/tabs/Query/DataSourceModelPreview.tsx
index c0349bb88dc..7ce8533705d 100644
--- a/public/app/features/alerting/unified/components/rule-viewer/tabs/Query/DataSourceModelPreview.tsx
+++ b/public/app/features/alerting/unified/components/rule-viewer/tabs/Query/DataSourceModelPreview.tsx
@@ -1,5 +1,5 @@
import { dump } from 'js-yaml';
-import React from 'react';
+import * as React from 'react';
import { DataSourceInstanceSettings } from '@grafana/data';
import { AlertDataQuery } from 'app/types/unified-alerting-dto';
diff --git a/public/app/features/alerting/unified/components/rule-viewer/tabs/Query/LokiQueryPreview.tsx b/public/app/features/alerting/unified/components/rule-viewer/tabs/Query/LokiQueryPreview.tsx
index 123f15c5582..03d2053a380 100644
--- a/public/app/features/alerting/unified/components/rule-viewer/tabs/Query/LokiQueryPreview.tsx
+++ b/public/app/features/alerting/unified/components/rule-viewer/tabs/Query/LokiQueryPreview.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { RawQuery } from '@grafana/experimental';
import lokiGrammar from 'app/plugins/datasource/loki/syntax';
diff --git a/public/app/features/alerting/unified/components/rule-viewer/tabs/Query/PrometheusQueryPreview.tsx b/public/app/features/alerting/unified/components/rule-viewer/tabs/Query/PrometheusQueryPreview.tsx
index 6db93b7e358..446d8a08720 100644
--- a/public/app/features/alerting/unified/components/rule-viewer/tabs/Query/PrometheusQueryPreview.tsx
+++ b/public/app/features/alerting/unified/components/rule-viewer/tabs/Query/PrometheusQueryPreview.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { RawQuery } from '@grafana/experimental';
import { promqlGrammar } from '@grafana/prometheus';
diff --git a/public/app/features/alerting/unified/components/rule-viewer/tabs/Query/SQLQueryPreview.tsx b/public/app/features/alerting/unified/components/rule-viewer/tabs/Query/SQLQueryPreview.tsx
index d491690980e..1bec7174f77 100644
--- a/public/app/features/alerting/unified/components/rule-viewer/tabs/Query/SQLQueryPreview.tsx
+++ b/public/app/features/alerting/unified/components/rule-viewer/tabs/Query/SQLQueryPreview.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { ReactMonacoEditor } from '@grafana/ui';
import { AlertDataQuery } from 'app/types/unified-alerting-dto';
diff --git a/public/app/features/alerting/unified/components/rule-viewer/tabs/Routing.tsx b/public/app/features/alerting/unified/components/rule-viewer/tabs/Routing.tsx
index 799d95d43b7..fefc1d02da1 100644
--- a/public/app/features/alerting/unified/components/rule-viewer/tabs/Routing.tsx
+++ b/public/app/features/alerting/unified/components/rule-viewer/tabs/Routing.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
const Routing = () => <>Routing>;
export { Routing };
diff --git a/public/app/features/alerting/unified/components/rules/ActionButton.tsx b/public/app/features/alerting/unified/components/rules/ActionButton.tsx
index 44d6fbcfc54..2613be36cb1 100644
--- a/public/app/features/alerting/unified/components/rules/ActionButton.tsx
+++ b/public/app/features/alerting/unified/components/rules/ActionButton.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rules/ActionIcon.tsx b/public/app/features/alerting/unified/components/rules/ActionIcon.tsx
index 355f9883f07..cd4b27a9cd3 100644
--- a/public/app/features/alerting/unified/components/rules/ActionIcon.tsx
+++ b/public/app/features/alerting/unified/components/rules/ActionIcon.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { IconName, Tooltip, LinkButton, Button } from '@grafana/ui';
import { PopoverContent, TooltipPlacement } from '@grafana/ui/src/components/Tooltip';
diff --git a/public/app/features/alerting/unified/components/rules/AlertInstanceDetails.tsx b/public/app/features/alerting/unified/components/rules/AlertInstanceDetails.tsx
index c680e46ce86..f84cee2a4d9 100644
--- a/public/app/features/alerting/unified/components/rules/AlertInstanceDetails.tsx
+++ b/public/app/features/alerting/unified/components/rules/AlertInstanceDetails.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Alert } from 'app/types/unified-alerting';
import { useAnnotationLinks, useCleanAnnotations } from '../../utils/annotations';
diff --git a/public/app/features/alerting/unified/components/rules/AlertInstanceStateFilter.tsx b/public/app/features/alerting/unified/components/rules/AlertInstanceStateFilter.tsx
index bbcdaa61ca5..97cf310a478 100644
--- a/public/app/features/alerting/unified/components/rules/AlertInstanceStateFilter.tsx
+++ b/public/app/features/alerting/unified/components/rules/AlertInstanceStateFilter.tsx
@@ -1,6 +1,5 @@
import { css } from '@emotion/css';
import { capitalize } from 'lodash';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data/src';
import { Label, RadioButtonGroup, Tag, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rules/AlertInstancesTable.tsx b/public/app/features/alerting/unified/components/rules/AlertInstancesTable.tsx
index fd32c83574f..6df5d74ed40 100644
--- a/public/app/features/alerting/unified/components/rules/AlertInstancesTable.tsx
+++ b/public/app/features/alerting/unified/components/rules/AlertInstancesTable.tsx
@@ -1,4 +1,5 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
+import * as React from 'react';
import { PluginExtensionPoints, dateTime, findCommonLabels } from '@grafana/data';
import { Alert, CombinedRule, PaginationProps } from 'app/types/unified-alerting';
diff --git a/public/app/features/alerting/unified/components/rules/AlertStateTag.tsx b/public/app/features/alerting/unified/components/rules/AlertStateTag.tsx
index 142ec8b0e1c..e05d76bab8b 100644
--- a/public/app/features/alerting/unified/components/rules/AlertStateTag.tsx
+++ b/public/app/features/alerting/unified/components/rules/AlertStateTag.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import { memo } from 'react';
import { AlertState } from '@grafana/data';
import { Icon, Tooltip } from '@grafana/ui';
@@ -13,7 +13,7 @@ interface Props {
muted?: boolean;
}
-export const AlertStateTag = React.memo(({ state, isPaused = false, size = 'md', muted = false }: Props) => {
+export const AlertStateTag = memo(({ state, isPaused = false, size = 'md', muted = false }: Props) => {
if (isPaused) {
return (
diff --git a/public/app/features/alerting/unified/components/rules/CloneRule.tsx b/public/app/features/alerting/unified/components/rules/CloneRule.tsx
index d8cd6af4e88..646aace7945 100644
--- a/public/app/features/alerting/unified/components/rules/CloneRule.tsx
+++ b/public/app/features/alerting/unified/components/rules/CloneRule.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { forwardRef, useState } from 'react';
import { Redirect, useLocation } from 'react-router-dom';
import { Button, ConfirmModal } from '@grafana/ui';
@@ -65,7 +65,7 @@ interface CloneRuleButtonProps {
className?: string;
}
-export const CloneRuleButton = React.forwardRef(
+export const CloneRuleButton = forwardRef(
({ text, ruleIdentifier, isProvisioned, className }, ref) => {
const [redirectToClone, setRedirectToClone] = useState(false);
diff --git a/public/app/features/alerting/unified/components/rules/CloudRules.tsx b/public/app/features/alerting/unified/components/rules/CloudRules.tsx
index a19716bb57f..54cb3493cce 100644
--- a/public/app/features/alerting/unified/components/rules/CloudRules.tsx
+++ b/public/app/features/alerting/unified/components/rules/CloudRules.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import pluralize from 'pluralize';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { useLocation } from 'react-router-dom';
import { GrafanaTheme2, urlUtil } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rules/EditRuleGroupModal.test.tsx b/public/app/features/alerting/unified/components/rules/EditRuleGroupModal.test.tsx
index 5e916d86781..99facc65e27 100644
--- a/public/app/features/alerting/unified/components/rules/EditRuleGroupModal.test.tsx
+++ b/public/app/features/alerting/unified/components/rules/EditRuleGroupModal.test.tsx
@@ -1,5 +1,5 @@
import { render } from '@testing-library/react';
-import React from 'react';
+import * as React from 'react';
import { Provider } from 'react-redux';
import { byLabelText, byTestId, byText, byTitle } from 'testing-library-selector';
diff --git a/public/app/features/alerting/unified/components/rules/EditRuleGroupModal.tsx b/public/app/features/alerting/unified/components/rules/EditRuleGroupModal.tsx
index 70f2e4cc730..91e47148d8e 100644
--- a/public/app/features/alerting/unified/components/rules/EditRuleGroupModal.tsx
+++ b/public/app/features/alerting/unified/components/rules/EditRuleGroupModal.tsx
@@ -1,6 +1,7 @@
import { css } from '@emotion/css';
import { compact } from 'lodash';
-import React, { useEffect, useMemo } from 'react';
+import { useEffect, useMemo } from 'react';
+import * as React from 'react';
import { FormProvider, RegisterOptions, useForm, useFormContext } from 'react-hook-form';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rules/GrafanaRules.tsx b/public/app/features/alerting/unified/components/rules/GrafanaRules.tsx
index 2257f02218e..3cf53dc6e6a 100644
--- a/public/app/features/alerting/unified/components/rules/GrafanaRules.tsx
+++ b/public/app/features/alerting/unified/components/rules/GrafanaRules.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { useToggle } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rules/MultipleDataSourcePicker.tsx b/public/app/features/alerting/unified/components/rules/MultipleDataSourcePicker.tsx
index 72124081a5a..9502e573b75 100644
--- a/public/app/features/alerting/unified/components/rules/MultipleDataSourcePicker.tsx
+++ b/public/app/features/alerting/unified/components/rules/MultipleDataSourcePicker.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { PopValueActionMeta, RemoveValueActionMeta } from 'react-select';
import {
diff --git a/public/app/features/alerting/unified/components/rules/NoRulesCTA.tsx b/public/app/features/alerting/unified/components/rules/NoRulesCTA.tsx
index 9c4c1d72fb5..0e635b2dbd7 100644
--- a/public/app/features/alerting/unified/components/rules/NoRulesCTA.tsx
+++ b/public/app/features/alerting/unified/components/rules/NoRulesCTA.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data/src/themes';
import { CallToActionCard, useStyles2, Stack } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rules/ReorderRuleGroupModal.tsx b/public/app/features/alerting/unified/components/rules/ReorderRuleGroupModal.tsx
index 28da1fffde6..e8a6e71e83c 100644
--- a/public/app/features/alerting/unified/components/rules/ReorderRuleGroupModal.tsx
+++ b/public/app/features/alerting/unified/components/rules/ReorderRuleGroupModal.tsx
@@ -1,7 +1,8 @@
import { css } from '@emotion/css';
import cx from 'classnames';
import { compact } from 'lodash';
-import React, { useCallback, useState } from 'react';
+import { useCallback, useState } from 'react';
+import * as React from 'react';
import {
DragDropContext,
Draggable,
diff --git a/public/app/features/alerting/unified/components/rules/RuleActionsButtons.test.tsx b/public/app/features/alerting/unified/components/rules/RuleActionsButtons.test.tsx
index ee989f9fdf9..8c992e53a4c 100644
--- a/public/app/features/alerting/unified/components/rules/RuleActionsButtons.test.tsx
+++ b/public/app/features/alerting/unified/components/rules/RuleActionsButtons.test.tsx
@@ -1,5 +1,4 @@
import { produce } from 'immer';
-import React from 'react';
import { render, screen, userEvent } from 'test/test-utils';
import { byLabelText, byRole } from 'testing-library-selector';
diff --git a/public/app/features/alerting/unified/components/rules/RuleActionsButtons.tsx b/public/app/features/alerting/unified/components/rules/RuleActionsButtons.tsx
index 08d4c84ef61..2d7b45ba56b 100644
--- a/public/app/features/alerting/unified/components/rules/RuleActionsButtons.tsx
+++ b/public/app/features/alerting/unified/components/rules/RuleActionsButtons.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { useLocation } from 'react-router-dom';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rules/RuleConfigStatus.tsx b/public/app/features/alerting/unified/components/rules/RuleConfigStatus.tsx
index 99ee72c4b85..2309f946e78 100644
--- a/public/app/features/alerting/unified/components/rules/RuleConfigStatus.tsx
+++ b/public/app/features/alerting/unified/components/rules/RuleConfigStatus.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { GrafanaTheme2 } from '@grafana/data/src';
import { config } from '@grafana/runtime/src';
diff --git a/public/app/features/alerting/unified/components/rules/RuleDetails.test.tsx b/public/app/features/alerting/unified/components/rules/RuleDetails.test.tsx
index 3db77807348..a81ac310b6a 100644
--- a/public/app/features/alerting/unified/components/rules/RuleDetails.test.tsx
+++ b/public/app/features/alerting/unified/components/rules/RuleDetails.test.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { render } from 'test/test-utils';
import { byRole } from 'testing-library-selector';
diff --git a/public/app/features/alerting/unified/components/rules/RuleDetails.tsx b/public/app/features/alerting/unified/components/rules/RuleDetails.tsx
index a0ea4f9d851..db62f8e624f 100644
--- a/public/app/features/alerting/unified/components/rules/RuleDetails.tsx
+++ b/public/app/features/alerting/unified/components/rules/RuleDetails.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2, dateTime, dateTimeFormat } from '@grafana/data';
import { useStyles2, Tooltip } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rules/RuleDetailsAnnotations.tsx b/public/app/features/alerting/unified/components/rules/RuleDetailsAnnotations.tsx
index f9e4920a4be..b2ff856a498 100644
--- a/public/app/features/alerting/unified/components/rules/RuleDetailsAnnotations.tsx
+++ b/public/app/features/alerting/unified/components/rules/RuleDetailsAnnotations.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rules/RuleDetailsButtons.tsx b/public/app/features/alerting/unified/components/rules/RuleDetailsButtons.tsx
index 71184ae8b0f..558ae99315c 100644
--- a/public/app/features/alerting/unified/components/rules/RuleDetailsButtons.tsx
+++ b/public/app/features/alerting/unified/components/rules/RuleDetailsButtons.tsx
@@ -1,4 +1,4 @@
-import React, { Fragment } from 'react';
+import { Fragment } from 'react';
import { textUtil } from '@grafana/data';
import { useReturnToPrevious } from '@grafana/runtime';
diff --git a/public/app/features/alerting/unified/components/rules/RuleDetailsDataSources.tsx b/public/app/features/alerting/unified/components/rules/RuleDetailsDataSources.tsx
index 907e01fa05c..9f6ea6c1dcc 100644
--- a/public/app/features/alerting/unified/components/rules/RuleDetailsDataSources.tsx
+++ b/public/app/features/alerting/unified/components/rules/RuleDetailsDataSources.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { getDataSourceSrv } from '@grafana/runtime';
diff --git a/public/app/features/alerting/unified/components/rules/RuleDetailsExpression.tsx b/public/app/features/alerting/unified/components/rules/RuleDetailsExpression.tsx
index 5099ab12de8..e5b3c7891e1 100644
--- a/public/app/features/alerting/unified/components/rules/RuleDetailsExpression.tsx
+++ b/public/app/features/alerting/unified/components/rules/RuleDetailsExpression.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { CombinedRule, RulesSource } from 'app/types/unified-alerting';
diff --git a/public/app/features/alerting/unified/components/rules/RuleDetailsFederatedSources.tsx b/public/app/features/alerting/unified/components/rules/RuleDetailsFederatedSources.tsx
index ab1304c2fee..5aacd449bfd 100644
--- a/public/app/features/alerting/unified/components/rules/RuleDetailsFederatedSources.tsx
+++ b/public/app/features/alerting/unified/components/rules/RuleDetailsFederatedSources.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { CombinedRuleGroup } from 'app/types/unified-alerting';
import { DetailsField } from '../DetailsField';
diff --git a/public/app/features/alerting/unified/components/rules/RuleDetailsMatchingInstances.test.tsx b/public/app/features/alerting/unified/components/rules/RuleDetailsMatchingInstances.test.tsx
index 0770a0e184a..6406d0badd2 100644
--- a/public/app/features/alerting/unified/components/rules/RuleDetailsMatchingInstances.test.tsx
+++ b/public/app/features/alerting/unified/components/rules/RuleDetailsMatchingInstances.test.tsx
@@ -1,7 +1,6 @@
import { render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { times } from 'lodash';
-import React from 'react';
import { byLabelText, byRole, byTestId } from 'testing-library-selector';
import { PluginExtensionTypes } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rules/RuleDetailsMatchingInstances.tsx b/public/app/features/alerting/unified/components/rules/RuleDetailsMatchingInstances.tsx
index fc757422f0c..80ae03c9e10 100644
--- a/public/app/features/alerting/unified/components/rules/RuleDetailsMatchingInstances.tsx
+++ b/public/app/features/alerting/unified/components/rules/RuleDetailsMatchingInstances.tsx
@@ -1,6 +1,7 @@
import { css, cx } from '@emotion/css';
import { countBy, sum } from 'lodash';
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { LinkButton, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rules/RuleHealth.tsx b/public/app/features/alerting/unified/components/rules/RuleHealth.tsx
index 75869675e3b..f72054a9e62 100644
--- a/public/app/features/alerting/unified/components/rules/RuleHealth.tsx
+++ b/public/app/features/alerting/unified/components/rules/RuleHealth.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Icon, Tooltip, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rules/RuleListErrors.tsx b/public/app/features/alerting/unified/components/rules/RuleListErrors.tsx
index 298e3214e5f..39148ab5415 100644
--- a/public/app/features/alerting/unified/components/rules/RuleListErrors.tsx
+++ b/public/app/features/alerting/unified/components/rules/RuleListErrors.tsx
@@ -1,7 +1,7 @@
import { css } from '@emotion/css';
import { SerializedError } from '@reduxjs/toolkit';
import pluralize from 'pluralize';
-import React, { useMemo, ReactElement, useState, FC } from 'react';
+import { useMemo, ReactElement, useState, FC } from 'react';
import { useLocalStorage } from 'react-use';
import { DataSourceInstanceSettings, GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rules/RuleListGroupView.test.tsx b/public/app/features/alerting/unified/components/rules/RuleListGroupView.test.tsx
index 0c51d4ccbb9..f6c2e092c68 100644
--- a/public/app/features/alerting/unified/components/rules/RuleListGroupView.test.tsx
+++ b/public/app/features/alerting/unified/components/rules/RuleListGroupView.test.tsx
@@ -1,5 +1,4 @@
import { render, waitFor } from '@testing-library/react';
-import React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
import { byRole } from 'testing-library-selector';
diff --git a/public/app/features/alerting/unified/components/rules/RuleListGroupView.tsx b/public/app/features/alerting/unified/components/rules/RuleListGroupView.tsx
index a1438fc383b..59ff6b16264 100644
--- a/public/app/features/alerting/unified/components/rules/RuleListGroupView.tsx
+++ b/public/app/features/alerting/unified/components/rules/RuleListGroupView.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useMemo } from 'react';
+import { useEffect, useMemo } from 'react';
import { CombinedRuleNamespace } from 'app/types/unified-alerting';
diff --git a/public/app/features/alerting/unified/components/rules/RuleListStateSection.tsx b/public/app/features/alerting/unified/components/rules/RuleListStateSection.tsx
index ae9fab19b17..3a2ee432dba 100644
--- a/public/app/features/alerting/unified/components/rules/RuleListStateSection.tsx
+++ b/public/app/features/alerting/unified/components/rules/RuleListStateSection.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rules/RuleListStateView.tsx b/public/app/features/alerting/unified/components/rules/RuleListStateView.tsx
index f3f6022d3e8..00460715009 100644
--- a/public/app/features/alerting/unified/components/rules/RuleListStateView.tsx
+++ b/public/app/features/alerting/unified/components/rules/RuleListStateView.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { useQueryParams } from 'app/core/hooks/useQueryParams';
import { CombinedRule, CombinedRuleNamespace } from 'app/types/unified-alerting';
diff --git a/public/app/features/alerting/unified/components/rules/RuleState.tsx b/public/app/features/alerting/unified/components/rules/RuleState.tsx
index b853708c5c4..975093f1448 100644
--- a/public/app/features/alerting/unified/components/rules/RuleState.tsx
+++ b/public/app/features/alerting/unified/components/rules/RuleState.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { GrafanaTheme2, intervalToAbbreviatedDurationString } from '@grafana/data';
import { Spinner, useStyles2, Stack } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rules/RuleStats.tsx b/public/app/features/alerting/unified/components/rules/RuleStats.tsx
index bde656c18b9..d772d6843a7 100644
--- a/public/app/features/alerting/unified/components/rules/RuleStats.tsx
+++ b/public/app/features/alerting/unified/components/rules/RuleStats.tsx
@@ -1,6 +1,7 @@
import { isUndefined, omitBy, pick, sum } from 'lodash';
import pluralize from 'pluralize';
-import React, { Fragment } from 'react';
+import { Fragment } from 'react';
+import * as React from 'react';
import { Badge, Stack } from '@grafana/ui';
import {
diff --git a/public/app/features/alerting/unified/components/rules/RulesFilter.test.tsx b/public/app/features/alerting/unified/components/rules/RulesFilter.test.tsx
index 058e0a61f25..83c02716c9c 100644
--- a/public/app/features/alerting/unified/components/rules/RulesFilter.test.tsx
+++ b/public/app/features/alerting/unified/components/rules/RulesFilter.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { byLabelText, byRole } from 'testing-library-selector';
diff --git a/public/app/features/alerting/unified/components/rules/RulesFilter.tsx b/public/app/features/alerting/unified/components/rules/RulesFilter.tsx
index 983273389d0..204c7c6930a 100644
--- a/public/app/features/alerting/unified/components/rules/RulesFilter.tsx
+++ b/public/app/features/alerting/unified/components/rules/RulesFilter.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useRef, useState } from 'react';
+import { useEffect, useRef, useState } from 'react';
import { useForm } from 'react-hook-form';
import { DataSourceInstanceSettings, GrafanaTheme2, SelectableValue } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rules/RulesGroup.test.tsx b/public/app/features/alerting/unified/components/rules/RulesGroup.test.tsx
index 3093caf579c..097ecefce1f 100644
--- a/public/app/features/alerting/unified/components/rules/RulesGroup.test.tsx
+++ b/public/app/features/alerting/unified/components/rules/RulesGroup.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { Provider } from 'react-redux';
import { Props } from 'react-virtualized-auto-sizer';
import { byRole, byTestId, byText } from 'testing-library-selector';
diff --git a/public/app/features/alerting/unified/components/rules/RulesGroup.tsx b/public/app/features/alerting/unified/components/rules/RulesGroup.tsx
index e76c2fe2bb2..bb66ef6421e 100644
--- a/public/app/features/alerting/unified/components/rules/RulesGroup.tsx
+++ b/public/app/features/alerting/unified/components/rules/RulesGroup.tsx
@@ -1,6 +1,7 @@
import { css } from '@emotion/css';
import pluralize from 'pluralize';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/alerting/unified/components/rules/RulesTable.test.tsx b/public/app/features/alerting/unified/components/rules/RulesTable.test.tsx
index 4f25c55f8e6..a13c5e1e864 100644
--- a/public/app/features/alerting/unified/components/rules/RulesTable.test.tsx
+++ b/public/app/features/alerting/unified/components/rules/RulesTable.test.tsx
@@ -1,6 +1,5 @@
import { render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { Provider } from 'react-redux';
import { MemoryRouter } from 'react-router-dom';
import { byRole } from 'testing-library-selector';
diff --git a/public/app/features/alerting/unified/components/rules/RulesTable.tsx b/public/app/features/alerting/unified/components/rules/RulesTable.tsx
index bf94dcfaa7a..8712d292fa9 100644
--- a/public/app/features/alerting/unified/components/rules/RulesTable.tsx
+++ b/public/app/features/alerting/unified/components/rules/RulesTable.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2, Tooltip } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/rules/central-state-history/CentralAlertHistory.tsx b/public/app/features/alerting/unified/components/rules/central-state-history/CentralAlertHistory.tsx
index e01bb4f6a02..26b6db879ce 100644
--- a/public/app/features/alerting/unified/components/rules/central-state-history/CentralAlertHistory.tsx
+++ b/public/app/features/alerting/unified/components/rules/central-state-history/CentralAlertHistory.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useCallback, useState } from 'react';
+import { forwardRef, useCallback, useState } from 'react';
import { useForm } from 'react-hook-form';
import { useMeasure } from 'react-use';
@@ -133,7 +133,7 @@ interface SearchFieldInputProps {
showClearFilterSuffix: boolean;
onClearFilterClick: () => void;
}
-const SearchFieldInput = React.forwardRef(
+const SearchFieldInput = forwardRef(
({ showClearFilterSuffix, onClearFilterClick, ...rest }: SearchFieldInputProps, ref) => {
const placeholder = t('central-alert-history.filter.placeholder', 'Filter events in the list with labels');
return (
diff --git a/public/app/features/alerting/unified/components/rules/central-state-history/CentralAlertHistoryPage.tsx b/public/app/features/alerting/unified/components/rules/central-state-history/CentralAlertHistoryPage.tsx
index 0ab57f508d4..eb767a1df2f 100644
--- a/public/app/features/alerting/unified/components/rules/central-state-history/CentralAlertHistoryPage.tsx
+++ b/public/app/features/alerting/unified/components/rules/central-state-history/CentralAlertHistoryPage.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { withErrorBoundary } from '@grafana/ui';
import { AlertingPageWrapper } from '../../AlertingPageWrapper';
diff --git a/public/app/features/alerting/unified/components/rules/central-state-history/CentralAlertHistoryScene.tsx b/public/app/features/alerting/unified/components/rules/central-state-history/CentralAlertHistoryScene.tsx
index 0cd75c05a4b..066ba2fb546 100644
--- a/public/app/features/alerting/unified/components/rules/central-state-history/CentralAlertHistoryScene.tsx
+++ b/public/app/features/alerting/unified/components/rules/central-state-history/CentralAlertHistoryScene.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { getDataSourceSrv } from '@grafana/runtime';
import {
EmbeddedScene,
diff --git a/public/app/features/alerting/unified/components/rules/state-history/LogRecordViewer.test.tsx b/public/app/features/alerting/unified/components/rules/state-history/LogRecordViewer.test.tsx
index 48bd6548508..6ff72a88fb8 100644
--- a/public/app/features/alerting/unified/components/rules/state-history/LogRecordViewer.test.tsx
+++ b/public/app/features/alerting/unified/components/rules/state-history/LogRecordViewer.test.tsx
@@ -1,5 +1,4 @@
import { getByTestId, render } from '@testing-library/react';
-import React from 'react';
import { byRole } from 'testing-library-selector';
import { LogRecordViewerByTimestamp } from './LogRecordViewer';
diff --git a/public/app/features/alerting/unified/components/rules/state-history/LogRecordViewer.tsx b/public/app/features/alerting/unified/components/rules/state-history/LogRecordViewer.tsx
index 60c3fa07a80..ea841a95bfb 100644
--- a/public/app/features/alerting/unified/components/rules/state-history/LogRecordViewer.tsx
+++ b/public/app/features/alerting/unified/components/rules/state-history/LogRecordViewer.tsx
@@ -1,7 +1,7 @@
import { css } from '@emotion/css';
import { formatDistanceToNowStrict } from 'date-fns';
import { groupBy, uniqueId } from 'lodash';
-import React, { useEffect } from 'react';
+import { memo, Fragment, useEffect } from 'react';
import { dateTimeFormat, GrafanaTheme2 } from '@grafana/data';
import { Icon, TagList, useStyles2, Stack } from '@grafana/ui';
@@ -34,7 +34,7 @@ function groupRecordsByTimestamp(records: LogRecord[]) {
return new Map([...groupedLines].sort((a, b) => b[0] - a[0]));
}
-export const LogRecordViewerByTimestamp = React.memo(
+export const LogRecordViewerByTimestamp = memo(
({ records, commonLabels, onLabelClick, onRecordsRendered }: LogRecordViewerProps) => {
const styles = useStyles2(getStyles);
@@ -59,7 +59,7 @@ export const LogRecordViewerByTimestamp = React.memo(
{records.map(({ line }) => (
-
+
@@ -74,7 +74,7 @@ export const LogRecordViewerByTimestamp = React.memo(
/>
)}
-
+
))}
@@ -142,7 +142,7 @@ const Timestamp = ({ time }: TimestampProps) => {
);
};
-const AlertInstanceValues = React.memo(({ record }: { record: Record }) => {
+const AlertInstanceValues = memo(({ record }: { record: Record }) => {
const values = Object.entries(record);
return (
diff --git a/public/app/features/alerting/unified/components/rules/state-history/LogTimelineViewer.tsx b/public/app/features/alerting/unified/components/rules/state-history/LogTimelineViewer.tsx
index 4703fb4c912..510a856210e 100644
--- a/public/app/features/alerting/unified/components/rules/state-history/LogTimelineViewer.tsx
+++ b/public/app/features/alerting/unified/components/rules/state-history/LogTimelineViewer.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import { memo } from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
import { DataFrame, InterpolateFunction, TimeRange } from '@grafana/data';
@@ -15,7 +15,7 @@ interface LogTimelineViewerProps {
// noop
const replaceVariables: InterpolateFunction = (v) => v;
-export const LogTimelineViewer = React.memo(({ frames, timeRange }: LogTimelineViewerProps) => {
+export const LogTimelineViewer = memo(({ frames, timeRange }: LogTimelineViewerProps) => {
const theme = useTheme2();
return (
diff --git a/public/app/features/alerting/unified/components/rules/state-history/LokiStateHistory.test.tsx b/public/app/features/alerting/unified/components/rules/state-history/LokiStateHistory.test.tsx
index 44cc923b06b..3513084d7cc 100644
--- a/public/app/features/alerting/unified/components/rules/state-history/LokiStateHistory.test.tsx
+++ b/public/app/features/alerting/unified/components/rules/state-history/LokiStateHistory.test.tsx
@@ -1,7 +1,6 @@
import { render, waitFor } from '@testing-library/react';
import { http, HttpResponse } from 'msw';
import { setupServer } from 'msw/node';
-import React from 'react';
import { Props } from 'react-virtualized-auto-sizer';
import { byRole, byTestId, byText } from 'testing-library-selector';
diff --git a/public/app/features/alerting/unified/components/rules/state-history/LokiStateHistory.tsx b/public/app/features/alerting/unified/components/rules/state-history/LokiStateHistory.tsx
index 9c9ea58eabe..eefaa9ec794 100644
--- a/public/app/features/alerting/unified/components/rules/state-history/LokiStateHistory.tsx
+++ b/public/app/features/alerting/unified/components/rules/state-history/LokiStateHistory.tsx
@@ -1,6 +1,7 @@
import { css } from '@emotion/css';
import { fromPairs, isEmpty, sortBy, take, uniq } from 'lodash';
-import React, { useCallback, useMemo, useRef, useState } from 'react';
+import { useCallback, useMemo, useRef, useState } from 'react';
+import * as React from 'react';
import { useForm } from 'react-hook-form';
import { DataFrame, dateTime, GrafanaTheme2, TimeRange } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/rules/state-history/StateHistory.tsx b/public/app/features/alerting/unified/components/rules/state-history/StateHistory.tsx
index 88a25cda460..5a198918da9 100644
--- a/public/app/features/alerting/unified/components/rules/state-history/StateHistory.tsx
+++ b/public/app/features/alerting/unified/components/rules/state-history/StateHistory.tsx
@@ -1,6 +1,7 @@
import { css } from '@emotion/css';
import { groupBy } from 'lodash';
-import React, { FormEvent, useCallback, useState } from 'react';
+import { FormEvent, useCallback, useState } from 'react';
+import * as React from 'react';
import { AlertState, dateTimeFormat, GrafanaTheme2 } from '@grafana/data';
import { Alert, Field, Icon, Input, Label, LoadingPlaceholder, Tooltip, useStyles2, Stack } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/settings/AlertmanagerCard.test.tsx b/public/app/features/alerting/unified/components/settings/AlertmanagerCard.test.tsx
index 4aecd7844cd..b3629c4d4f6 100644
--- a/public/app/features/alerting/unified/components/settings/AlertmanagerCard.test.tsx
+++ b/public/app/features/alerting/unified/components/settings/AlertmanagerCard.test.tsx
@@ -1,6 +1,5 @@
import { screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { render } from 'test/test-utils';
import { ConnectionStatus } from '../../hooks/useExternalAmSelector';
diff --git a/public/app/features/alerting/unified/components/settings/AlertmanagerCard.tsx b/public/app/features/alerting/unified/components/settings/AlertmanagerCard.tsx
index 8e79e0282bc..0bd121ac622 100644
--- a/public/app/features/alerting/unified/components/settings/AlertmanagerCard.tsx
+++ b/public/app/features/alerting/unified/components/settings/AlertmanagerCard.tsx
@@ -1,5 +1,4 @@
import { capitalize } from 'lodash';
-import React from 'react';
import { Badge, Button, Card, Stack, Text, TextLink } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/settings/AlertmanagerConfig.test.tsx b/public/app/features/alerting/unified/components/settings/AlertmanagerConfig.test.tsx
index dd1af8d3380..c5865159778 100644
--- a/public/app/features/alerting/unified/components/settings/AlertmanagerConfig.test.tsx
+++ b/public/app/features/alerting/unified/components/settings/AlertmanagerConfig.test.tsx
@@ -1,6 +1,5 @@
import { waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { render } from 'test/test-utils';
import { byRole, byTestId } from 'testing-library-selector';
diff --git a/public/app/features/alerting/unified/components/settings/AlertmanagerConfig.tsx b/public/app/features/alerting/unified/components/settings/AlertmanagerConfig.tsx
index 109116f96b9..f721ace329d 100644
--- a/public/app/features/alerting/unified/components/settings/AlertmanagerConfig.tsx
+++ b/public/app/features/alerting/unified/components/settings/AlertmanagerConfig.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { useForm } from 'react-hook-form';
import AutoSizer from 'react-virtualized-auto-sizer';
diff --git a/public/app/features/alerting/unified/components/settings/ConfigurationDrawer.tsx b/public/app/features/alerting/unified/components/settings/ConfigurationDrawer.tsx
index 92a8d587d3e..26d1a67e33d 100644
--- a/public/app/features/alerting/unified/components/settings/ConfigurationDrawer.tsx
+++ b/public/app/features/alerting/unified/components/settings/ConfigurationDrawer.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useMemo, useState } from 'react';
+import { useCallback, useMemo, useState } from 'react';
import { Drawer, Tab, TabsBar } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/settings/ExternalAlertmanagers.tsx b/public/app/features/alerting/unified/components/settings/ExternalAlertmanagers.tsx
index f39dff4e469..07bf9314061 100644
--- a/public/app/features/alerting/unified/components/settings/ExternalAlertmanagers.tsx
+++ b/public/app/features/alerting/unified/components/settings/ExternalAlertmanagers.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Stack } from '@grafana/ui';
import { DATASOURCES_ROUTES } from 'app/features/datasources/constants';
import { AlertmanagerChoice } from 'app/plugins/datasource/alertmanager/types';
diff --git a/public/app/features/alerting/unified/components/settings/InternalAlertmanager.tsx b/public/app/features/alerting/unified/components/settings/InternalAlertmanager.tsx
index cea3396cadb..add2e0f852d 100644
--- a/public/app/features/alerting/unified/components/settings/InternalAlertmanager.tsx
+++ b/public/app/features/alerting/unified/components/settings/InternalAlertmanager.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { ConnectionStatus } from '../../hooks/useExternalAmSelector';
import { GRAFANA_RULES_SOURCE_NAME } from '../../utils/datasource';
import { isInternalAlertmanagerInterestedInAlerts } from '../../utils/settings';
diff --git a/public/app/features/alerting/unified/components/settings/SettingsContext.tsx b/public/app/features/alerting/unified/components/settings/SettingsContext.tsx
index 20ff037adf8..03fc283a8f1 100644
--- a/public/app/features/alerting/unified/components/settings/SettingsContext.tsx
+++ b/public/app/features/alerting/unified/components/settings/SettingsContext.tsx
@@ -1,5 +1,5 @@
import { debounce, union, without } from 'lodash';
-import React, { PropsWithChildren, useEffect, useRef } from 'react';
+import { createContext, useContext, PropsWithChildren, useEffect, useRef } from 'react';
import { AppEvents } from '@grafana/data';
import { config, getAppEvents } from '@grafana/runtime';
@@ -39,7 +39,7 @@ interface Context {
forwardingDisabled: boolean;
}
-const SettingsContext = React.createContext(undefined);
+const SettingsContext = createContext(undefined);
const isInternalAlertmanager = (uid: string) => uid === GRAFANA_RULES_SOURCE_NAME;
export const SettingsProvider = (props: PropsWithChildren) => {
@@ -163,7 +163,7 @@ function determineDeliveryMode(interestedAlertmanagers: string[]): AlertmanagerC
}
export function useSettings() {
- const context = React.useContext(SettingsContext);
+ const context = useContext(SettingsContext);
if (context === undefined) {
throw new Error('useSettings must be used within a SettingsContext');
diff --git a/public/app/features/alerting/unified/components/settings/VersionManager.tsx b/public/app/features/alerting/unified/components/settings/VersionManager.tsx
index d84b00185b8..e7a122e0441 100644
--- a/public/app/features/alerting/unified/components/settings/VersionManager.tsx
+++ b/public/app/features/alerting/unified/components/settings/VersionManager.tsx
@@ -1,7 +1,7 @@
import { css } from '@emotion/css';
import { chain, omit } from 'lodash';
import moment from 'moment';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import {
diff --git a/public/app/features/alerting/unified/components/silences/AmAlertStateTag.tsx b/public/app/features/alerting/unified/components/silences/AmAlertStateTag.tsx
index acc02a02d74..68e78528040 100644
--- a/public/app/features/alerting/unified/components/silences/AmAlertStateTag.tsx
+++ b/public/app/features/alerting/unified/components/silences/AmAlertStateTag.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { AlertState } from 'app/plugins/datasource/alertmanager/types';
import { State, StateTag } from '../StateTag';
diff --git a/public/app/features/alerting/unified/components/silences/Matchers.tsx b/public/app/features/alerting/unified/components/silences/Matchers.tsx
index 9726277256f..4cd16affe87 100644
--- a/public/app/features/alerting/unified/components/silences/Matchers.tsx
+++ b/public/app/features/alerting/unified/components/silences/Matchers.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { TagList, useStyles2 } from '@grafana/ui';
import { Matcher } from 'app/plugins/datasource/alertmanager/types';
diff --git a/public/app/features/alerting/unified/components/silences/MatchersField.tsx b/public/app/features/alerting/unified/components/silences/MatchersField.tsx
index 6070bdcaa7c..e241e76300e 100644
--- a/public/app/features/alerting/unified/components/silences/MatchersField.tsx
+++ b/public/app/features/alerting/unified/components/silences/MatchersField.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import { useFormContext, useFieldArray, Controller } from 'react-hook-form';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/silences/NoSilencesCTA.tsx b/public/app/features/alerting/unified/components/silences/NoSilencesCTA.tsx
index fd42325863a..720cdd9e960 100644
--- a/public/app/features/alerting/unified/components/silences/NoSilencesCTA.tsx
+++ b/public/app/features/alerting/unified/components/silences/NoSilencesCTA.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { CallToActionCard, EmptyState, LinkButton } from '@grafana/ui';
import { Trans, t } from 'app/core/internationalization';
import { contextSrv } from 'app/core/services/context_srv';
diff --git a/public/app/features/alerting/unified/components/silences/SilenceDetails.tsx b/public/app/features/alerting/unified/components/silences/SilenceDetails.tsx
index 2a8865a0f54..bb88e909128 100644
--- a/public/app/features/alerting/unified/components/silences/SilenceDetails.tsx
+++ b/public/app/features/alerting/unified/components/silences/SilenceDetails.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { dateMath, GrafanaTheme2, intervalToAbbreviatedDurationString } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/silences/SilenceGrafanaRuleDrawer.tsx b/public/app/features/alerting/unified/components/silences/SilenceGrafanaRuleDrawer.tsx
index 302a2151e79..d86779f722e 100644
--- a/public/app/features/alerting/unified/components/silences/SilenceGrafanaRuleDrawer.tsx
+++ b/public/app/features/alerting/unified/components/silences/SilenceGrafanaRuleDrawer.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Drawer, Stack } from '@grafana/ui';
import { SilencesEditor } from 'app/features/alerting/unified/components/silences/SilencesEditor';
import { getDefaultSilenceFormValues } from 'app/features/alerting/unified/components/silences/utils';
diff --git a/public/app/features/alerting/unified/components/silences/SilencePeriod.tsx b/public/app/features/alerting/unified/components/silences/SilencePeriod.tsx
index 6da7b0e2927..3a3b3375b8d 100644
--- a/public/app/features/alerting/unified/components/silences/SilencePeriod.tsx
+++ b/public/app/features/alerting/unified/components/silences/SilencePeriod.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { useController, useFormContext } from 'react-hook-form';
import { dateTime } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/silences/SilenceStateTag.tsx b/public/app/features/alerting/unified/components/silences/SilenceStateTag.tsx
index 4c7768e889e..63f6cea3d3b 100644
--- a/public/app/features/alerting/unified/components/silences/SilenceStateTag.tsx
+++ b/public/app/features/alerting/unified/components/silences/SilenceStateTag.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SilenceState } from 'app/plugins/datasource/alertmanager/types';
import { State, StateTag } from '../StateTag';
diff --git a/public/app/features/alerting/unified/components/silences/SilencedAlertsTable.tsx b/public/app/features/alerting/unified/components/silences/SilencedAlertsTable.tsx
index 7a59cd56005..2e18459f5b5 100644
--- a/public/app/features/alerting/unified/components/silences/SilencedAlertsTable.tsx
+++ b/public/app/features/alerting/unified/components/silences/SilencedAlertsTable.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/silences/SilencedAlertsTableRow.tsx b/public/app/features/alerting/unified/components/silences/SilencedAlertsTableRow.tsx
index 64ac0bee461..9ccafe8402f 100644
--- a/public/app/features/alerting/unified/components/silences/SilencedAlertsTableRow.tsx
+++ b/public/app/features/alerting/unified/components/silences/SilencedAlertsTableRow.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { intervalToAbbreviatedDurationString } from '@grafana/data';
import { AlertmanagerAlert } from 'app/plugins/datasource/alertmanager/types';
diff --git a/public/app/features/alerting/unified/components/silences/SilencedInstancesPreview.tsx b/public/app/features/alerting/unified/components/silences/SilencedInstancesPreview.tsx
index f527bf76a3d..49235dd22e4 100644
--- a/public/app/features/alerting/unified/components/silences/SilencedInstancesPreview.tsx
+++ b/public/app/features/alerting/unified/components/silences/SilencedInstancesPreview.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { useDebounce, useDeepCompareEffect } from 'react-use';
import { dateTime, GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/components/silences/SilencesEditor.tsx b/public/app/features/alerting/unified/components/silences/SilencesEditor.tsx
index 969d048e92e..56e1f533e76 100644
--- a/public/app/features/alerting/unified/components/silences/SilencesEditor.tsx
+++ b/public/app/features/alerting/unified/components/silences/SilencesEditor.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { pickBy } from 'lodash';
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { useDebounce } from 'react-use';
diff --git a/public/app/features/alerting/unified/components/silences/SilencesFilter.tsx b/public/app/features/alerting/unified/components/silences/SilencesFilter.tsx
index 24acc9924bb..7cb57c91055 100644
--- a/public/app/features/alerting/unified/components/silences/SilencesFilter.tsx
+++ b/public/app/features/alerting/unified/components/silences/SilencesFilter.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { debounce, uniqueId } from 'lodash';
-import React, { FormEvent, useState } from 'react';
+import { FormEvent, useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Button, Field, Icon, Input, Label, Tooltip, useStyles2, Stack } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/components/silences/SilencesTable.tsx b/public/app/features/alerting/unified/components/silences/SilencesTable.tsx
index f590cc4565a..bde51494412 100644
--- a/public/app/features/alerting/unified/components/silences/SilencesTable.tsx
+++ b/public/app/features/alerting/unified/components/silences/SilencesTable.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { GrafanaTheme2, dateMath } from '@grafana/data';
import {
diff --git a/public/app/features/alerting/unified/home/GettingStarted.tsx b/public/app/features/alerting/unified/home/GettingStarted.tsx
index 1087fda355c..b0be37de447 100644
--- a/public/app/features/alerting/unified/home/GettingStarted.tsx
+++ b/public/app/features/alerting/unified/home/GettingStarted.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import SVG from 'react-inlinesvg';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/home/Home.tsx b/public/app/features/alerting/unified/home/Home.tsx
index d036a8e9f3a..616f73acff3 100644
--- a/public/app/features/alerting/unified/home/Home.tsx
+++ b/public/app/features/alerting/unified/home/Home.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { config } from '@grafana/runtime';
import { Box, Stack, Tab, TabContent, TabsBar } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/home/Insights.tsx b/public/app/features/alerting/unified/home/Insights.tsx
index 29fed164d73..a374edbf9dd 100644
--- a/public/app/features/alerting/unified/home/Insights.tsx
+++ b/public/app/features/alerting/unified/home/Insights.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { DataSourceInstanceSettings, DataSourceJsonData } from '@grafana/data';
import { getDataSourceSrv } from '@grafana/runtime';
import {
diff --git a/public/app/features/alerting/unified/home/PluginIntegrations.tsx b/public/app/features/alerting/unified/home/PluginIntegrations.tsx
index dda9dd0f3b2..ced46dc7e28 100644
--- a/public/app/features/alerting/unified/home/PluginIntegrations.tsx
+++ b/public/app/features/alerting/unified/home/PluginIntegrations.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data/';
import { Stack, Text } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/hooks/useAbilities.test.tsx b/public/app/features/alerting/unified/hooks/useAbilities.test.tsx
index b5c60260426..ddea4463b14 100644
--- a/public/app/features/alerting/unified/hooks/useAbilities.test.tsx
+++ b/public/app/features/alerting/unified/hooks/useAbilities.test.tsx
@@ -1,6 +1,6 @@
import { renderHook, waitFor } from '@testing-library/react';
import { createBrowserHistory } from 'history';
-import React, { PropsWithChildren } from 'react';
+import { PropsWithChildren } from 'react';
import { Router } from 'react-router-dom';
import { TestProvider } from 'test/helpers/TestProvider';
import { render, screen } from 'test/test-utils';
diff --git a/public/app/features/alerting/unified/hooks/useCombinedRule.ts b/public/app/features/alerting/unified/hooks/useCombinedRule.ts
index e4afe097cab..d2f24516cac 100644
--- a/public/app/features/alerting/unified/hooks/useCombinedRule.ts
+++ b/public/app/features/alerting/unified/hooks/useCombinedRule.ts
@@ -171,10 +171,15 @@ interface RequestState {
error?: unknown;
}
+interface Props {
+ ruleIdentifier: RuleIdentifier;
+ limitAlerts?: number;
+}
+
// Many places still use the old way of fetching code so synchronizing cache expiration is difficult
// Hence, this hook fetches a fresh version of a rule most of the time
// Due to enabled filtering for Prometheus and Ruler rules it shouldn't be a problem
-export function useCombinedRule({ ruleIdentifier }: { ruleIdentifier: RuleIdentifier }): RequestState {
+export function useCombinedRule({ ruleIdentifier, limitAlerts }: Props): RequestState {
const { ruleSourceName } = ruleIdentifier;
const ruleSource = getRulesSourceFromIdentifier(ruleIdentifier);
@@ -195,6 +200,7 @@ export function useCombinedRule({ ruleIdentifier }: { ruleIdentifier: RuleIdenti
namespace: ruleLocation?.namespace,
groupName: ruleLocation?.group,
ruleName: ruleLocation?.ruleName,
+ limitAlerts,
},
{
skip: !ruleLocation || isLoadingRuleLocation,
diff --git a/public/app/features/alerting/unified/hooks/useIsRuleEditable.test.tsx b/public/app/features/alerting/unified/hooks/useIsRuleEditable.test.tsx
index f58f2c24f58..77bee61a162 100644
--- a/public/app/features/alerting/unified/hooks/useIsRuleEditable.test.tsx
+++ b/public/app/features/alerting/unified/hooks/useIsRuleEditable.test.tsx
@@ -1,5 +1,5 @@
import { renderHook, waitFor } from '@testing-library/react';
-import React from 'react';
+import * as React from 'react';
import { Provider } from 'react-redux';
import { contextSrv } from 'app/core/services/context_srv';
diff --git a/public/app/features/alerting/unified/hooks/useProduceNewRuleGroup.test.tsx b/public/app/features/alerting/unified/hooks/useProduceNewRuleGroup.test.tsx
index c8c6ec7cf92..8f9433a8378 100644
--- a/public/app/features/alerting/unified/hooks/useProduceNewRuleGroup.test.tsx
+++ b/public/app/features/alerting/unified/hooks/useProduceNewRuleGroup.test.tsx
@@ -1,5 +1,4 @@
import { HttpResponse } from 'msw';
-import React from 'react';
import { render, userEvent } from 'test/test-utils';
import { byRole, byText } from 'testing-library-selector';
diff --git a/public/app/features/alerting/unified/hooks/useSilenceNavData.test.tsx b/public/app/features/alerting/unified/hooks/useSilenceNavData.test.tsx
index 090f4f5fb22..3ba43193666 100644
--- a/public/app/features/alerting/unified/hooks/useSilenceNavData.test.tsx
+++ b/public/app/features/alerting/unified/hooks/useSilenceNavData.test.tsx
@@ -1,5 +1,4 @@
import { render } from '@testing-library/react';
-import React from 'react';
import { useRouteMatch } from 'react-router-dom';
import { useSilenceNavData } from './useSilenceNavData';
diff --git a/public/app/features/alerting/unified/hooks/useStateHistoryModal.tsx b/public/app/features/alerting/unified/hooks/useStateHistoryModal.tsx
index 807132087bc..ef3e9ba5439 100644
--- a/public/app/features/alerting/unified/hooks/useStateHistoryModal.tsx
+++ b/public/app/features/alerting/unified/hooks/useStateHistoryModal.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { lazy, Suspense, useCallback, useMemo, useState } from 'react';
+import { lazy, Suspense, useCallback, useMemo, useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { config } from '@grafana/runtime';
diff --git a/public/app/features/alerting/unified/initAlerting.tsx b/public/app/features/alerting/unified/initAlerting.tsx
index 92e593e4361..2b294f68a7b 100644
--- a/public/app/features/alerting/unified/initAlerting.tsx
+++ b/public/app/features/alerting/unified/initAlerting.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import { lazy, Suspense } from 'react';
import { config } from '@grafana/runtime';
import { contextSrv } from 'app/core/services/context_srv';
@@ -8,7 +8,7 @@ import { addCustomRightAction } from '../../dashboard/components/DashNav/DashNav
import { getRulesPermissions } from './utils/access-control';
import { GRAFANA_RULES_SOURCE_NAME } from './utils/datasource';
-const AlertRulesToolbarButton = React.lazy(
+const AlertRulesToolbarButton = lazy(
() => import(/* webpackChunkName: "alert-rules-toolbar-button" */ './integration/AlertRulesToolbarButton')
);
@@ -21,9 +21,9 @@ export function initAlerting() {
show: () => alertingEnabled,
component: ({ dashboard }) =>
alertingEnabled ? (
-
+
{dashboard && }
-
+
) : null,
index: -2,
});
diff --git a/public/app/features/alerting/unified/insights/DataSourcesInfo.tsx b/public/app/features/alerting/unified/insights/DataSourcesInfo.tsx
index 764cdc9fd44..bb3831c689b 100644
--- a/public/app/features/alerting/unified/insights/DataSourcesInfo.tsx
+++ b/public/app/features/alerting/unified/insights/DataSourcesInfo.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data/src/themes';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/insights/RatingModal.tsx b/public/app/features/alerting/unified/insights/RatingModal.tsx
index 3ae9bc69f67..0dd41eb7a61 100644
--- a/public/app/features/alerting/unified/insights/RatingModal.tsx
+++ b/public/app/features/alerting/unified/insights/RatingModal.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data/src/themes';
import { Button, Dropdown, Icon, IconButton, Menu, Modal, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/insights/SectionFooter.tsx b/public/app/features/alerting/unified/insights/SectionFooter.tsx
index 337352ea18c..560b562abff 100644
--- a/public/app/features/alerting/unified/insights/SectionFooter.tsx
+++ b/public/app/features/alerting/unified/insights/SectionFooter.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data/src/themes';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/insights/SectionSubheader.tsx b/public/app/features/alerting/unified/insights/SectionSubheader.tsx
index 3490ed2a01c..302a391129d 100644
--- a/public/app/features/alerting/unified/insights/SectionSubheader.tsx
+++ b/public/app/features/alerting/unified/insights/SectionSubheader.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data/src/themes';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/insights/grafana/Active.tsx b/public/app/features/alerting/unified/insights/grafana/Active.tsx
index 636780cce3b..46528c23d69 100644
--- a/public/app/features/alerting/unified/insights/grafana/Active.tsx
+++ b/public/app/features/alerting/unified/insights/grafana/Active.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { ThresholdsMode } from '@grafana/data';
import { PanelBuilders, SceneFlexItem, SceneQueryRunner } from '@grafana/scenes';
import { DataSourceRef } from '@grafana/schema';
diff --git a/public/app/features/alerting/unified/insights/grafana/AlertsByStateScene.tsx b/public/app/features/alerting/unified/insights/grafana/AlertsByStateScene.tsx
index 96de8f16a2e..55ec514c57c 100644
--- a/public/app/features/alerting/unified/insights/grafana/AlertsByStateScene.tsx
+++ b/public/app/features/alerting/unified/insights/grafana/AlertsByStateScene.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PanelBuilders, SceneDataTransformer, SceneFlexItem, SceneQueryRunner } from '@grafana/scenes';
import { DataSourceRef, GraphDrawStyle, TooltipDisplayMode } from '@grafana/schema';
diff --git a/public/app/features/alerting/unified/insights/grafana/EvalSuccessVsFailuresScene.tsx b/public/app/features/alerting/unified/insights/grafana/EvalSuccessVsFailuresScene.tsx
index 9382f40a671..b3d9921660f 100644
--- a/public/app/features/alerting/unified/insights/grafana/EvalSuccessVsFailuresScene.tsx
+++ b/public/app/features/alerting/unified/insights/grafana/EvalSuccessVsFailuresScene.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PanelBuilders, SceneFlexItem, SceneQueryRunner } from '@grafana/scenes';
import { DataSourceRef, GraphDrawStyle, TooltipDisplayMode } from '@grafana/schema';
diff --git a/public/app/features/alerting/unified/insights/grafana/InstanceStatusScene.tsx b/public/app/features/alerting/unified/insights/grafana/InstanceStatusScene.tsx
index b561a30f39d..647c27c00ff 100644
--- a/public/app/features/alerting/unified/insights/grafana/InstanceStatusScene.tsx
+++ b/public/app/features/alerting/unified/insights/grafana/InstanceStatusScene.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PanelBuilders, SceneFlexItem, SceneQueryRunner } from '@grafana/scenes';
import { DataSourceRef } from '@grafana/schema';
diff --git a/public/app/features/alerting/unified/insights/grafana/MissedIterationsScene.tsx b/public/app/features/alerting/unified/insights/grafana/MissedIterationsScene.tsx
index 1b37c2f2783..7c1976df590 100644
--- a/public/app/features/alerting/unified/insights/grafana/MissedIterationsScene.tsx
+++ b/public/app/features/alerting/unified/insights/grafana/MissedIterationsScene.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { Observable, map } from 'rxjs';
import { DataFrame } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/insights/grafana/MostFiredInstancesTable.tsx b/public/app/features/alerting/unified/insights/grafana/MostFiredInstancesTable.tsx
index d3b63ab5d8c..817318db695 100644
--- a/public/app/features/alerting/unified/insights/grafana/MostFiredInstancesTable.tsx
+++ b/public/app/features/alerting/unified/insights/grafana/MostFiredInstancesTable.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { Observable, map } from 'rxjs';
import { DataFrame, Field, GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/alerting/unified/insights/grafana/Paused.tsx b/public/app/features/alerting/unified/insights/grafana/Paused.tsx
index 9d5b9a58c4e..eb7b1abb851 100644
--- a/public/app/features/alerting/unified/insights/grafana/Paused.tsx
+++ b/public/app/features/alerting/unified/insights/grafana/Paused.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { ThresholdsMode } from '@grafana/data';
import { PanelBuilders, SceneFlexItem, SceneQueryRunner } from '@grafana/scenes';
import { DataSourceRef } from '@grafana/schema';
diff --git a/public/app/features/alerting/unified/insights/grafana/RulesByEvaluation.tsx b/public/app/features/alerting/unified/insights/grafana/RulesByEvaluation.tsx
index c5726fb77b2..57d9bb90cc8 100644
--- a/public/app/features/alerting/unified/insights/grafana/RulesByEvaluation.tsx
+++ b/public/app/features/alerting/unified/insights/grafana/RulesByEvaluation.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PanelBuilders, SceneFlexItem, SceneQueryRunner } from '@grafana/scenes';
import { DataSourceRef, GraphDrawStyle, TooltipDisplayMode } from '@grafana/schema';
diff --git a/public/app/features/alerting/unified/insights/grafana/RulesByEvaluationPercentage.tsx b/public/app/features/alerting/unified/insights/grafana/RulesByEvaluationPercentage.tsx
index 0749765c30f..a6728f14953 100644
--- a/public/app/features/alerting/unified/insights/grafana/RulesByEvaluationPercentage.tsx
+++ b/public/app/features/alerting/unified/insights/grafana/RulesByEvaluationPercentage.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PanelBuilders, SceneFlexItem, SceneQueryRunner } from '@grafana/scenes';
import { DataSourceRef, GraphDrawStyle, TooltipDisplayMode } from '@grafana/schema';
diff --git a/public/app/features/alerting/unified/insights/grafana/alertmanager/AlertsByState.tsx b/public/app/features/alerting/unified/insights/grafana/alertmanager/AlertsByState.tsx
index 6ee7175abd6..0796b90a644 100644
--- a/public/app/features/alerting/unified/insights/grafana/alertmanager/AlertsByState.tsx
+++ b/public/app/features/alerting/unified/insights/grafana/alertmanager/AlertsByState.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PanelBuilders, SceneFlexItem, SceneQueryRunner } from '@grafana/scenes';
import { DataSourceRef, GraphDrawStyle, TooltipDisplayMode } from '@grafana/schema';
diff --git a/public/app/features/alerting/unified/insights/grafana/alertmanager/NotificationsScene.tsx b/public/app/features/alerting/unified/insights/grafana/alertmanager/NotificationsScene.tsx
index da4b51d0e13..27f542f91b5 100644
--- a/public/app/features/alerting/unified/insights/grafana/alertmanager/NotificationsScene.tsx
+++ b/public/app/features/alerting/unified/insights/grafana/alertmanager/NotificationsScene.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PanelBuilders, SceneFlexItem, SceneQueryRunner } from '@grafana/scenes';
import { DataSourceRef, GraphDrawStyle, TooltipDisplayMode } from '@grafana/schema';
diff --git a/public/app/features/alerting/unified/insights/grafana/alertmanager/SilencesByStateScene.tsx b/public/app/features/alerting/unified/insights/grafana/alertmanager/SilencesByStateScene.tsx
index e710b591fb3..a1b68a0e0ed 100644
--- a/public/app/features/alerting/unified/insights/grafana/alertmanager/SilencesByStateScene.tsx
+++ b/public/app/features/alerting/unified/insights/grafana/alertmanager/SilencesByStateScene.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PanelBuilders, SceneFlexItem, SceneQueryRunner } from '@grafana/scenes';
import { DataSourceRef, GraphDrawStyle, TooltipDisplayMode } from '@grafana/schema';
diff --git a/public/app/features/alerting/unified/insights/mimir/AlertsByState.tsx b/public/app/features/alerting/unified/insights/mimir/AlertsByState.tsx
index b0b725f6bba..415423fb212 100644
--- a/public/app/features/alerting/unified/insights/mimir/AlertsByState.tsx
+++ b/public/app/features/alerting/unified/insights/mimir/AlertsByState.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PanelBuilders, SceneFlexItem, SceneQueryRunner } from '@grafana/scenes';
import { DataSourceRef, GraphDrawStyle, TooltipDisplayMode } from '@grafana/schema';
diff --git a/public/app/features/alerting/unified/insights/mimir/InvalidConfig.tsx b/public/app/features/alerting/unified/insights/mimir/InvalidConfig.tsx
index 5705fd0ff84..dba5a5b7ae3 100644
--- a/public/app/features/alerting/unified/insights/mimir/InvalidConfig.tsx
+++ b/public/app/features/alerting/unified/insights/mimir/InvalidConfig.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PanelBuilders, SceneFlexItem, SceneQueryRunner } from '@grafana/scenes';
import { BigValueGraphMode, DataSourceRef } from '@grafana/schema';
diff --git a/public/app/features/alerting/unified/insights/mimir/Notifications.tsx b/public/app/features/alerting/unified/insights/mimir/Notifications.tsx
index d7cc629dcbe..ca7576f8e22 100644
--- a/public/app/features/alerting/unified/insights/mimir/Notifications.tsx
+++ b/public/app/features/alerting/unified/insights/mimir/Notifications.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PanelBuilders, SceneFlexItem, SceneQueryRunner } from '@grafana/scenes';
import { DataSourceRef, GraphDrawStyle, TooltipDisplayMode } from '@grafana/schema';
diff --git a/public/app/features/alerting/unified/insights/mimir/Silences.tsx b/public/app/features/alerting/unified/insights/mimir/Silences.tsx
index 97398bcf404..01646a5cefe 100644
--- a/public/app/features/alerting/unified/insights/mimir/Silences.tsx
+++ b/public/app/features/alerting/unified/insights/mimir/Silences.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PanelBuilders, SceneFlexItem, SceneQueryRunner } from '@grafana/scenes';
import { DataSourceRef, GraphDrawStyle, TooltipDisplayMode } from '@grafana/schema';
diff --git a/public/app/features/alerting/unified/insights/mimir/perGroup/RuleGroupEvaluationDurationIntervalRatioScene.tsx b/public/app/features/alerting/unified/insights/mimir/perGroup/RuleGroupEvaluationDurationIntervalRatioScene.tsx
index b80b17779cb..bfca1bbaada 100644
--- a/public/app/features/alerting/unified/insights/mimir/perGroup/RuleGroupEvaluationDurationIntervalRatioScene.tsx
+++ b/public/app/features/alerting/unified/insights/mimir/perGroup/RuleGroupEvaluationDurationIntervalRatioScene.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PanelBuilders, SceneFlexItem, SceneQueryRunner } from '@grafana/scenes';
import { DataSourceRef, GraphDrawStyle, ThresholdsMode, TooltipDisplayMode } from '@grafana/schema';
diff --git a/public/app/features/alerting/unified/insights/mimir/perGroup/RuleGroupEvaluationDurationScene.tsx b/public/app/features/alerting/unified/insights/mimir/perGroup/RuleGroupEvaluationDurationScene.tsx
index 86761697725..db28b864fba 100644
--- a/public/app/features/alerting/unified/insights/mimir/perGroup/RuleGroupEvaluationDurationScene.tsx
+++ b/public/app/features/alerting/unified/insights/mimir/perGroup/RuleGroupEvaluationDurationScene.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PanelBuilders, SceneFlexItem, SceneQueryRunner } from '@grafana/scenes';
import { DataSourceRef, GraphDrawStyle, TooltipDisplayMode } from '@grafana/schema';
diff --git a/public/app/features/alerting/unified/insights/mimir/perGroup/RuleGroupEvaluationsScene.tsx b/public/app/features/alerting/unified/insights/mimir/perGroup/RuleGroupEvaluationsScene.tsx
index 33a0fea7c45..5c872356be6 100644
--- a/public/app/features/alerting/unified/insights/mimir/perGroup/RuleGroupEvaluationsScene.tsx
+++ b/public/app/features/alerting/unified/insights/mimir/perGroup/RuleGroupEvaluationsScene.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PanelBuilders, SceneFlexItem, SceneQueryRunner } from '@grafana/scenes';
import { DataSourceRef, GraphDrawStyle, TooltipDisplayMode } from '@grafana/schema';
diff --git a/public/app/features/alerting/unified/insights/mimir/perGroup/RuleGroupIntervalScene.tsx b/public/app/features/alerting/unified/insights/mimir/perGroup/RuleGroupIntervalScene.tsx
index a576a6f9429..ced1d761532 100644
--- a/public/app/features/alerting/unified/insights/mimir/perGroup/RuleGroupIntervalScene.tsx
+++ b/public/app/features/alerting/unified/insights/mimir/perGroup/RuleGroupIntervalScene.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PanelBuilders, SceneFlexItem, SceneQueryRunner } from '@grafana/scenes';
import { BigValueGraphMode, DataSourceRef } from '@grafana/schema';
diff --git a/public/app/features/alerting/unified/insights/mimir/perGroup/RulesPerGroupScene.tsx b/public/app/features/alerting/unified/insights/mimir/perGroup/RulesPerGroupScene.tsx
index 437366c9550..33c77d319db 100644
--- a/public/app/features/alerting/unified/insights/mimir/perGroup/RulesPerGroupScene.tsx
+++ b/public/app/features/alerting/unified/insights/mimir/perGroup/RulesPerGroupScene.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PanelBuilders, SceneFlexItem, SceneQueryRunner } from '@grafana/scenes';
import { BigValueGraphMode, DataSourceRef } from '@grafana/schema';
diff --git a/public/app/features/alerting/unified/insights/mimir/rules/EvalSuccessVsFailuresScene.tsx b/public/app/features/alerting/unified/insights/mimir/rules/EvalSuccessVsFailuresScene.tsx
index 363c39364be..28722367a73 100644
--- a/public/app/features/alerting/unified/insights/mimir/rules/EvalSuccessVsFailuresScene.tsx
+++ b/public/app/features/alerting/unified/insights/mimir/rules/EvalSuccessVsFailuresScene.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PanelBuilders, SceneFlexItem, SceneQueryRunner } from '@grafana/scenes';
import { DataSourceRef, GraphDrawStyle, TooltipDisplayMode } from '@grafana/schema';
diff --git a/public/app/features/alerting/unified/insights/mimir/rules/Firing.tsx b/public/app/features/alerting/unified/insights/mimir/rules/Firing.tsx
index 46547869bf0..0d35c6d4ec3 100644
--- a/public/app/features/alerting/unified/insights/mimir/rules/Firing.tsx
+++ b/public/app/features/alerting/unified/insights/mimir/rules/Firing.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { ThresholdsMode } from '@grafana/data';
import { PanelBuilders, SceneFlexItem, SceneQueryRunner } from '@grafana/scenes';
import { DataSourceRef } from '@grafana/schema';
diff --git a/public/app/features/alerting/unified/insights/mimir/rules/InstancesByState.tsx b/public/app/features/alerting/unified/insights/mimir/rules/InstancesByState.tsx
index 42ab455b650..b054a358c98 100644
--- a/public/app/features/alerting/unified/insights/mimir/rules/InstancesByState.tsx
+++ b/public/app/features/alerting/unified/insights/mimir/rules/InstancesByState.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PanelBuilders, SceneFlexItem, SceneQueryRunner } from '@grafana/scenes';
import { DataSourceRef, GraphDrawStyle, TooltipDisplayMode } from '@grafana/schema';
diff --git a/public/app/features/alerting/unified/insights/mimir/rules/InstancesPercentageByState.tsx b/public/app/features/alerting/unified/insights/mimir/rules/InstancesPercentageByState.tsx
index d23b001b6fd..91cfb75801a 100644
--- a/public/app/features/alerting/unified/insights/mimir/rules/InstancesPercentageByState.tsx
+++ b/public/app/features/alerting/unified/insights/mimir/rules/InstancesPercentageByState.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PanelBuilders, SceneFlexItem, SceneQueryRunner } from '@grafana/scenes';
import { DataSourceRef, GraphDrawStyle, TooltipDisplayMode } from '@grafana/schema';
diff --git a/public/app/features/alerting/unified/insights/mimir/rules/MissedIterationsScene.tsx b/public/app/features/alerting/unified/insights/mimir/rules/MissedIterationsScene.tsx
index eb8b4d37dcb..59721817c19 100644
--- a/public/app/features/alerting/unified/insights/mimir/rules/MissedIterationsScene.tsx
+++ b/public/app/features/alerting/unified/insights/mimir/rules/MissedIterationsScene.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PanelBuilders, SceneFlexItem, SceneQueryRunner } from '@grafana/scenes';
import { DataSourceRef, GraphDrawStyle, TooltipDisplayMode } from '@grafana/schema';
diff --git a/public/app/features/alerting/unified/insights/mimir/rules/MostFiredRules.tsx b/public/app/features/alerting/unified/insights/mimir/rules/MostFiredRules.tsx
index 402042c01d3..339c7b03651 100644
--- a/public/app/features/alerting/unified/insights/mimir/rules/MostFiredRules.tsx
+++ b/public/app/features/alerting/unified/insights/mimir/rules/MostFiredRules.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PanelBuilders, SceneDataTransformer, SceneFlexItem, SceneQueryRunner } from '@grafana/scenes';
import { DataSourceRef } from '@grafana/schema';
diff --git a/public/app/features/alerting/unified/insights/mimir/rules/Pending.tsx b/public/app/features/alerting/unified/insights/mimir/rules/Pending.tsx
index a792f31ce43..7667300015a 100644
--- a/public/app/features/alerting/unified/insights/mimir/rules/Pending.tsx
+++ b/public/app/features/alerting/unified/insights/mimir/rules/Pending.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { ThresholdsMode } from '@grafana/data';
import { PanelBuilders, SceneFlexItem, SceneQueryRunner } from '@grafana/scenes';
import { DataSourceRef } from '@grafana/schema';
diff --git a/public/app/features/alerting/unified/integration/AlertRulesDrawer.tsx b/public/app/features/alerting/unified/integration/AlertRulesDrawer.tsx
index d22ac005efd..ab5386974c0 100644
--- a/public/app/features/alerting/unified/integration/AlertRulesDrawer.tsx
+++ b/public/app/features/alerting/unified/integration/AlertRulesDrawer.tsx
@@ -1,11 +1,11 @@
-import React from 'react';
+import { lazy, Suspense } from 'react';
import { Drawer, LoadingPlaceholder, Stack, TextLink } from '@grafana/ui';
import { t } from '../../../../core/internationalization';
import { createUrl } from '../utils/url';
-const AlertRulesDrawerContent = React.lazy(
+const AlertRulesDrawerContent = lazy(
() => import(/* webpackChunkName: "alert-rules-drawer-content" */ './AlertRulesDrawerContent')
);
@@ -17,9 +17,9 @@ interface Props {
export function AlertRulesDrawer({ dashboardUid, onDismiss }: Props) {
return (
} onClose={onDismiss} size="lg">
- }>
+ }>
-
+
);
}
diff --git a/public/app/features/alerting/unified/integration/AlertRulesDrawerContent.tsx b/public/app/features/alerting/unified/integration/AlertRulesDrawerContent.tsx
index fd0ff6823b7..11cba57fff8 100644
--- a/public/app/features/alerting/unified/integration/AlertRulesDrawerContent.tsx
+++ b/public/app/features/alerting/unified/integration/AlertRulesDrawerContent.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { LoadingPlaceholder } from '@grafana/ui';
import { RulesTable } from '../components/rules/RulesTable';
diff --git a/public/app/features/alerting/unified/integration/AlertRulesToolbarButton.tsx b/public/app/features/alerting/unified/integration/AlertRulesToolbarButton.tsx
index d7f4b18b857..8acbed408c1 100644
--- a/public/app/features/alerting/unified/integration/AlertRulesToolbarButton.tsx
+++ b/public/app/features/alerting/unified/integration/AlertRulesToolbarButton.tsx
@@ -1,4 +1,4 @@
-import React, { useContext } from 'react';
+import { useContext } from 'react';
import { ModalsContext, ToolbarButton } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/plugins/PluginOriginBadge.tsx b/public/app/features/alerting/unified/plugins/PluginOriginBadge.tsx
index 437d56fd192..64967c68adf 100644
--- a/public/app/features/alerting/unified/plugins/PluginOriginBadge.tsx
+++ b/public/app/features/alerting/unified/plugins/PluginOriginBadge.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useAsync } from 'react-use';
import { Badge, Tooltip } from '@grafana/ui';
diff --git a/public/app/features/alerting/unified/state/AlertmanagerContext.test.tsx b/public/app/features/alerting/unified/state/AlertmanagerContext.test.tsx
index 719dedfd30e..adcba4180b1 100644
--- a/public/app/features/alerting/unified/state/AlertmanagerContext.test.tsx
+++ b/public/app/features/alerting/unified/state/AlertmanagerContext.test.tsx
@@ -1,6 +1,6 @@
import { renderHook } from '@testing-library/react';
import { createMemoryHistory } from 'history';
-import React from 'react';
+import * as React from 'react';
import { MemoryRouter, Router } from 'react-router-dom';
import store from 'app/core/store';
diff --git a/public/app/features/alerting/unified/types/pluginBridges.ts b/public/app/features/alerting/unified/types/pluginBridges.ts
index fbe809743b6..926a75ff41d 100644
--- a/public/app/features/alerting/unified/types/pluginBridges.ts
+++ b/public/app/features/alerting/unified/types/pluginBridges.ts
@@ -3,4 +3,5 @@ export enum SupportedPlugin {
OnCall = 'grafana-oncall-app',
MachineLearning = 'grafana-ml-app',
Labels = 'grafana-labels-app',
+ Slo = 'grafana-slo-app',
}
diff --git a/public/app/features/alerting/unified/types/receiver-form.ts b/public/app/features/alerting/unified/types/receiver-form.ts
index d896f03f3f3..419c94fa93f 100644
--- a/public/app/features/alerting/unified/types/receiver-form.ts
+++ b/public/app/features/alerting/unified/types/receiver-form.ts
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { GrafanaManagedReceiverConfig } from 'app/plugins/datasource/alertmanager/types';
import { CloudNotifierType, NotifierType } from 'app/types';
diff --git a/public/app/features/annotations/components/AnnotationResultMapper.tsx b/public/app/features/annotations/components/AnnotationResultMapper.tsx
index a229769a247..973a4071044 100644
--- a/public/app/features/annotations/components/AnnotationResultMapper.tsx
+++ b/public/app/features/annotations/components/AnnotationResultMapper.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import {
SelectableValue,
diff --git a/public/app/features/annotations/components/StandardAnnotationQueryEditor.test.tsx b/public/app/features/annotations/components/StandardAnnotationQueryEditor.test.tsx
index a840ae1641c..c347a069369 100644
--- a/public/app/features/annotations/components/StandardAnnotationQueryEditor.test.tsx
+++ b/public/app/features/annotations/components/StandardAnnotationQueryEditor.test.tsx
@@ -1,5 +1,4 @@
import { render } from '@testing-library/react';
-import React from 'react';
import { AnnotationQuery, DataSourceApi, DataSourceInstanceSettings } from '@grafana/data/src';
diff --git a/public/app/features/annotations/components/StandardAnnotationQueryEditor.tsx b/public/app/features/annotations/components/StandardAnnotationQueryEditor.tsx
index b07d7843759..dd9ba29a735 100644
--- a/public/app/features/annotations/components/StandardAnnotationQueryEditor.tsx
+++ b/public/app/features/annotations/components/StandardAnnotationQueryEditor.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent, ReactElement } from 'react';
+import { PureComponent, ReactElement } from 'react';
import { lastValueFrom } from 'rxjs';
import {
diff --git a/public/app/features/api-keys/ApiKeysActionBar.tsx b/public/app/features/api-keys/ApiKeysActionBar.tsx
index f8c6470a7b6..e5edff671ac 100644
--- a/public/app/features/api-keys/ApiKeysActionBar.tsx
+++ b/public/app/features/api-keys/ApiKeysActionBar.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { FilterInput, InlineField } from '@grafana/ui';
interface Props {
diff --git a/public/app/features/api-keys/ApiKeysPage.test.tsx b/public/app/features/api-keys/ApiKeysPage.test.tsx
index c28791ea4ff..728508a14e8 100644
--- a/public/app/features/api-keys/ApiKeysPage.test.tsx
+++ b/public/app/features/api-keys/ApiKeysPage.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, within } from '@testing-library/react';
import userEvent, { PointerEventsCheckLevel } from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { ApiKey, OrgRole } from 'app/types';
diff --git a/public/app/features/api-keys/ApiKeysPage.tsx b/public/app/features/api-keys/ApiKeysPage.tsx
index ea9d42c8c71..1f3e769e86b 100644
--- a/public/app/features/api-keys/ApiKeysPage.tsx
+++ b/public/app/features/api-keys/ApiKeysPage.tsx
@@ -1,4 +1,5 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
+import * as React from 'react';
import { connect, ConnectedProps } from 'react-redux';
// Utils
diff --git a/public/app/features/api-keys/ApiKeysTable.tsx b/public/app/features/api-keys/ApiKeysTable.tsx
index 452aa370e94..20a118bdd21 100644
--- a/public/app/features/api-keys/ApiKeysTable.tsx
+++ b/public/app/features/api-keys/ApiKeysTable.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { dateTimeFormat, GrafanaTheme2, TimeZone } from '@grafana/data';
import { Button, DeleteButton, Icon, Stack, Tooltip, useTheme2 } from '@grafana/ui';
diff --git a/public/app/features/api-keys/MigrateToServiceAccountsCard.tsx b/public/app/features/api-keys/MigrateToServiceAccountsCard.tsx
index 78a8d258104..042e126eafd 100644
--- a/public/app/features/api-keys/MigrateToServiceAccountsCard.tsx
+++ b/public/app/features/api-keys/MigrateToServiceAccountsCard.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Alert, Button, ConfirmModal, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/auth-config/AuthDrawer.test.tsx b/public/app/features/auth-config/AuthDrawer.test.tsx
index 9578d7a777d..b5a16c41fb4 100644
--- a/public/app/features/auth-config/AuthDrawer.test.tsx
+++ b/public/app/features/auth-config/AuthDrawer.test.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { render, screen } from 'test/test-utils';
import { AuthDrawerUnconnected, Props } from './AuthDrawer';
diff --git a/public/app/features/auth-config/AuthDrawer.tsx b/public/app/features/auth-config/AuthDrawer.tsx
index bd66222ee78..a9530e92d9f 100644
--- a/public/app/features/auth-config/AuthDrawer.tsx
+++ b/public/app/features/auth-config/AuthDrawer.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { JSX } from 'react';
+import { JSX } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/auth-config/AuthProvidersListPage.tsx b/public/app/features/auth-config/AuthProvidersListPage.tsx
index ceece9d32ea..171666929be 100644
--- a/public/app/features/auth-config/AuthProvidersListPage.tsx
+++ b/public/app/features/auth-config/AuthProvidersListPage.tsx
@@ -1,4 +1,4 @@
-import React, { JSX, useEffect, useState } from 'react';
+import { JSX, useEffect, useState } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { GrafanaEdition } from '@grafana/data/src/types/config';
diff --git a/public/app/features/auth-config/ErrorContainer.tsx b/public/app/features/auth-config/ErrorContainer.tsx
index e237aa629f0..79cf6514569 100644
--- a/public/app/features/auth-config/ErrorContainer.tsx
+++ b/public/app/features/auth-config/ErrorContainer.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { Alert } from '@grafana/ui';
diff --git a/public/app/features/auth-config/FieldRenderer.tsx b/public/app/features/auth-config/FieldRenderer.tsx
index 856ac56b252..56ef4c5526a 100644
--- a/public/app/features/auth-config/FieldRenderer.tsx
+++ b/public/app/features/auth-config/FieldRenderer.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { UseFormReturn, Controller } from 'react-hook-form';
import { Checkbox, Field, Input, SecretInput, Select, Switch, useTheme2 } from '@grafana/ui';
diff --git a/public/app/features/auth-config/ProviderConfigForm.test.tsx b/public/app/features/auth-config/ProviderConfigForm.test.tsx
index a59f15d821f..ad1b87ec39a 100644
--- a/public/app/features/auth-config/ProviderConfigForm.test.tsx
+++ b/public/app/features/auth-config/ProviderConfigForm.test.tsx
@@ -1,6 +1,6 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { JSX } from 'react';
+import { JSX } from 'react';
import { reportInteraction } from '@grafana/runtime';
diff --git a/public/app/features/auth-config/ProviderConfigForm.tsx b/public/app/features/auth-config/ProviderConfigForm.tsx
index 74dfffaf1f6..bdaeb1e0bc7 100644
--- a/public/app/features/auth-config/ProviderConfigForm.tsx
+++ b/public/app/features/auth-config/ProviderConfigForm.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { useForm } from 'react-hook-form';
import { AppEvents } from '@grafana/data';
diff --git a/public/app/features/auth-config/ProviderConfigPage.tsx b/public/app/features/auth-config/ProviderConfigPage.tsx
index c42956c7aee..12aef8a2cab 100644
--- a/public/app/features/auth-config/ProviderConfigPage.tsx
+++ b/public/app/features/auth-config/ProviderConfigPage.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { NavModelItem } from '@grafana/data';
diff --git a/public/app/features/auth-config/components/ConfigureAuthCTA.tsx b/public/app/features/auth-config/components/ConfigureAuthCTA.tsx
index c493aee5e51..904bf725950 100644
--- a/public/app/features/auth-config/components/ConfigureAuthCTA.tsx
+++ b/public/app/features/auth-config/components/ConfigureAuthCTA.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Icon, Stack, Text, TextLink, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/auth-config/components/ProviderCard.tsx b/public/app/features/auth-config/components/ProviderCard.tsx
index e7ddee44561..f255a3bc1d7 100644
--- a/public/app/features/auth-config/components/ProviderCard.tsx
+++ b/public/app/features/auth-config/components/ProviderCard.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { isIconName } from '@grafana/data';
import { Badge, Card, Icon } from '@grafana/ui';
diff --git a/public/app/features/auth-config/fields.tsx b/public/app/features/auth-config/fields.tsx
index 952e3af3e7b..6b34468b22b 100644
--- a/public/app/features/auth-config/fields.tsx
+++ b/public/app/features/auth-config/fields.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { validate as uuidValidate } from 'uuid';
import { config } from '@grafana/runtime';
diff --git a/public/app/features/browse-dashboards/BrowseDashboardsPage.test.tsx b/public/app/features/browse-dashboards/BrowseDashboardsPage.test.tsx
index bf815c72dc4..7269e217afa 100644
--- a/public/app/features/browse-dashboards/BrowseDashboardsPage.test.tsx
+++ b/public/app/features/browse-dashboards/BrowseDashboardsPage.test.tsx
@@ -2,7 +2,8 @@ import { render as rtlRender, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { HttpResponse, http } from 'msw';
import { setupServer, SetupServer } from 'msw/node';
-import React, { ComponentProps } from 'react';
+import { ComponentProps } from 'react';
+import * as React from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
import { TestProvider } from 'test/helpers/TestProvider';
diff --git a/public/app/features/browse-dashboards/BrowseDashboardsPage.tsx b/public/app/features/browse-dashboards/BrowseDashboardsPage.tsx
index 5e5e588a903..0bc5416047b 100644
--- a/public/app/features/browse-dashboards/BrowseDashboardsPage.tsx
+++ b/public/app/features/browse-dashboards/BrowseDashboardsPage.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { memo, useEffect, useMemo } from 'react';
+import { memo, useEffect, useMemo } from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/browse-dashboards/BrowseFolderAlertingPage.test.tsx b/public/app/features/browse-dashboards/BrowseFolderAlertingPage.test.tsx
index 7c88338fc55..69b22171aba 100644
--- a/public/app/features/browse-dashboards/BrowseFolderAlertingPage.test.tsx
+++ b/public/app/features/browse-dashboards/BrowseFolderAlertingPage.test.tsx
@@ -1,7 +1,6 @@
import { render as rtlRender, screen } from '@testing-library/react';
import { http, HttpResponse } from 'msw';
import { SetupServer, setupServer } from 'msw/node';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { contextSrv } from 'app/core/core';
diff --git a/public/app/features/browse-dashboards/BrowseFolderAlertingPage.tsx b/public/app/features/browse-dashboards/BrowseFolderAlertingPage.tsx
index 54908ba4d15..4c137afff9b 100644
--- a/public/app/features/browse-dashboards/BrowseFolderAlertingPage.tsx
+++ b/public/app/features/browse-dashboards/BrowseFolderAlertingPage.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { Page } from 'app/core/components/Page/Page';
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
diff --git a/public/app/features/browse-dashboards/BrowseFolderLibraryPanelsPage.test.tsx b/public/app/features/browse-dashboards/BrowseFolderLibraryPanelsPage.test.tsx
index fc48cd50672..bb758e875e8 100644
--- a/public/app/features/browse-dashboards/BrowseFolderLibraryPanelsPage.test.tsx
+++ b/public/app/features/browse-dashboards/BrowseFolderLibraryPanelsPage.test.tsx
@@ -1,7 +1,6 @@
import { render as rtlRender, screen } from '@testing-library/react';
import { http, HttpResponse } from 'msw';
import { SetupServer, setupServer } from 'msw/node';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { contextSrv } from 'app/core/core';
diff --git a/public/app/features/browse-dashboards/BrowseFolderLibraryPanelsPage.tsx b/public/app/features/browse-dashboards/BrowseFolderLibraryPanelsPage.tsx
index 4c52890a54f..48caa971c62 100644
--- a/public/app/features/browse-dashboards/BrowseFolderLibraryPanelsPage.tsx
+++ b/public/app/features/browse-dashboards/BrowseFolderLibraryPanelsPage.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
import { Page } from 'app/core/components/Page/Page';
diff --git a/public/app/features/browse-dashboards/RecentlyDeletedPage.tsx b/public/app/features/browse-dashboards/RecentlyDeletedPage.tsx
index ee0579fbead..0b952cead08 100644
--- a/public/app/features/browse-dashboards/RecentlyDeletedPage.tsx
+++ b/public/app/features/browse-dashboards/RecentlyDeletedPage.tsx
@@ -1,7 +1,9 @@
-import React, { memo, useEffect } from 'react';
+import { memo, useEffect } from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
+import { EmptyState } from '@grafana/ui';
import { Page } from 'app/core/components/Page/Page';
+import { t } from 'app/core/internationalization';
import { ActionRow } from 'app/features/search/page/components/ActionRow';
import { getGrafanaSearcher } from 'app/features/search/service';
@@ -33,33 +35,50 @@ const RecentlyDeletedPage = memo(() => {
);
}, [dispatch, stateManager]);
+ if (searchState.loading === false && searchState.result?.totalRows === 0) {
+ return (
+
+
+
+
+
+ );
+ }
+
return (
-
-
-
- {({ width, height }) => (
-
+
- )}
-
+
+
+ {({ width, height }) => (
+
+ )}
+
+ >
+ )}
);
diff --git a/public/app/features/browse-dashboards/components/BrowseActions/BrowseActions.test.tsx b/public/app/features/browse-dashboards/components/BrowseActions/BrowseActions.test.tsx
index 376600e007d..e94c48a00b9 100644
--- a/public/app/features/browse-dashboards/components/BrowseActions/BrowseActions.test.tsx
+++ b/public/app/features/browse-dashboards/components/BrowseActions/BrowseActions.test.tsx
@@ -1,5 +1,4 @@
import { render as rtlRender, screen } from '@testing-library/react';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { BrowseActions } from './BrowseActions';
diff --git a/public/app/features/browse-dashboards/components/BrowseActions/BrowseActions.tsx b/public/app/features/browse-dashboards/components/BrowseActions/BrowseActions.tsx
index a3478cb4669..c9f3f46dfe9 100644
--- a/public/app/features/browse-dashboards/components/BrowseActions/BrowseActions.tsx
+++ b/public/app/features/browse-dashboards/components/BrowseActions/BrowseActions.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { config, reportInteraction } from '@grafana/runtime';
diff --git a/public/app/features/browse-dashboards/components/BrowseActions/DeleteModal.test.tsx b/public/app/features/browse-dashboards/components/BrowseActions/DeleteModal.test.tsx
index fac6515b04b..07a11c34724 100644
--- a/public/app/features/browse-dashboards/components/BrowseActions/DeleteModal.test.tsx
+++ b/public/app/features/browse-dashboards/components/BrowseActions/DeleteModal.test.tsx
@@ -1,6 +1,5 @@
import { render as rtlRender, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { DeleteModal, Props } from './DeleteModal';
diff --git a/public/app/features/browse-dashboards/components/BrowseActions/DeleteModal.tsx b/public/app/features/browse-dashboards/components/BrowseActions/DeleteModal.tsx
index 937da5d0924..090ccd9ef79 100644
--- a/public/app/features/browse-dashboards/components/BrowseActions/DeleteModal.tsx
+++ b/public/app/features/browse-dashboards/components/BrowseActions/DeleteModal.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { config } from '@grafana/runtime';
import { Alert, ConfirmModal, Text, Space } from '@grafana/ui';
@@ -18,7 +18,7 @@ export interface Props {
export const DeleteModal = ({ onConfirm, onDismiss, selectedItems, ...props }: Props) => {
const { data } = useGetAffectedItemsQuery(selectedItems);
- const deleteIsInvalid = !config.featureToggles.nestedFolders && data && (data.alertRule || data.libraryPanel);
+ const deleteIsInvalid = Boolean(data && (data.alertRule || data.libraryPanel));
const [isDeleting, setIsDeleting] = useState(false);
const onDelete = async () => {
setIsDeleting(true);
@@ -80,6 +80,7 @@ export const DeleteModal = ({ onConfirm, onDismiss, selectedItems, ...props }: P
onConfirm={onDelete}
title={t('browse-dashboards.action.delete-modal-title', 'Delete')}
{...props}
+ disabled={deleteIsInvalid}
/>
);
};
diff --git a/public/app/features/browse-dashboards/components/BrowseActions/DescendantCount.tsx b/public/app/features/browse-dashboards/components/BrowseActions/DescendantCount.tsx
index 114c35a4dd8..50a1de533a5 100644
--- a/public/app/features/browse-dashboards/components/BrowseActions/DescendantCount.tsx
+++ b/public/app/features/browse-dashboards/components/BrowseActions/DescendantCount.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import Skeleton from 'react-loading-skeleton';
import { Alert, Text } from '@grafana/ui';
diff --git a/public/app/features/browse-dashboards/components/BrowseActions/MoveModal.test.tsx b/public/app/features/browse-dashboards/components/BrowseActions/MoveModal.test.tsx
index 3c049270947..d6a9172a347 100644
--- a/public/app/features/browse-dashboards/components/BrowseActions/MoveModal.test.tsx
+++ b/public/app/features/browse-dashboards/components/BrowseActions/MoveModal.test.tsx
@@ -1,6 +1,5 @@
import { render as rtlRender, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { selectOptionInTest } from 'test/helpers/selectOptionInTest';
diff --git a/public/app/features/browse-dashboards/components/BrowseActions/MoveModal.tsx b/public/app/features/browse-dashboards/components/BrowseActions/MoveModal.tsx
index 366d3c3208c..b5f2f488eb9 100644
--- a/public/app/features/browse-dashboards/components/BrowseActions/MoveModal.tsx
+++ b/public/app/features/browse-dashboards/components/BrowseActions/MoveModal.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { Alert, Button, Field, Modal, Text, Space } from '@grafana/ui';
import { FolderPicker } from 'app/core/components/Select/FolderPicker';
diff --git a/public/app/features/browse-dashboards/components/BrowseFilters.tsx b/public/app/features/browse-dashboards/components/BrowseFilters.tsx
index 2e339fbd012..f7f8554d731 100644
--- a/public/app/features/browse-dashboards/components/BrowseFilters.tsx
+++ b/public/app/features/browse-dashboards/components/BrowseFilters.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { ActionRow } from 'app/features/search/page/components/ActionRow';
import { getGrafanaSearcher } from 'app/features/search/service';
import { useSearchStateManager } from 'app/features/search/state/SearchStateManager';
diff --git a/public/app/features/browse-dashboards/components/BrowseView.test.tsx b/public/app/features/browse-dashboards/components/BrowseView.test.tsx
index a083f8374c5..6cbabd17d6f 100644
--- a/public/app/features/browse-dashboards/components/BrowseView.test.tsx
+++ b/public/app/features/browse-dashboards/components/BrowseView.test.tsx
@@ -1,6 +1,5 @@
import { getByLabelText, render as rtlRender, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/browse-dashboards/components/BrowseView.tsx b/public/app/features/browse-dashboards/components/BrowseView.tsx
index b9cc1ea5a2d..8c9ab64cde0 100644
--- a/public/app/features/browse-dashboards/components/BrowseView.tsx
+++ b/public/app/features/browse-dashboards/components/BrowseView.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { CallToActionCard, EmptyState, LinkButton, TextLink } from '@grafana/ui';
import { Trans, t } from 'app/core/internationalization';
diff --git a/public/app/features/browse-dashboards/components/CheckboxCell.tsx b/public/app/features/browse-dashboards/components/CheckboxCell.tsx
index fb8ffebfe20..26325c23f49 100644
--- a/public/app/features/browse-dashboards/components/CheckboxCell.tsx
+++ b/public/app/features/browse-dashboards/components/CheckboxCell.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/browse-dashboards/components/CheckboxHeaderCell.tsx b/public/app/features/browse-dashboards/components/CheckboxHeaderCell.tsx
index d31dbdce500..e35347db415 100644
--- a/public/app/features/browse-dashboards/components/CheckboxHeaderCell.tsx
+++ b/public/app/features/browse-dashboards/components/CheckboxHeaderCell.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Checkbox } from '@grafana/ui';
import { t } from 'app/core/internationalization';
diff --git a/public/app/features/browse-dashboards/components/CreateNewButton.test.tsx b/public/app/features/browse-dashboards/components/CreateNewButton.test.tsx
index dfa6c6f415b..902f3b0ef2a 100644
--- a/public/app/features/browse-dashboards/components/CreateNewButton.test.tsx
+++ b/public/app/features/browse-dashboards/components/CreateNewButton.test.tsx
@@ -1,6 +1,5 @@
import { render as rtlRender, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { FolderDTO } from 'app/types';
diff --git a/public/app/features/browse-dashboards/components/CreateNewButton.tsx b/public/app/features/browse-dashboards/components/CreateNewButton.tsx
index 97af7819b7b..b50fed9f669 100644
--- a/public/app/features/browse-dashboards/components/CreateNewButton.tsx
+++ b/public/app/features/browse-dashboards/components/CreateNewButton.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { useLocation } from 'react-router-dom';
import { config, reportInteraction } from '@grafana/runtime';
diff --git a/public/app/features/browse-dashboards/components/DashboardsTree.test.tsx b/public/app/features/browse-dashboards/components/DashboardsTree.test.tsx
index caa039829bd..bc2bebe5cce 100644
--- a/public/app/features/browse-dashboards/components/DashboardsTree.test.tsx
+++ b/public/app/features/browse-dashboards/components/DashboardsTree.test.tsx
@@ -1,6 +1,5 @@
import { render as rtlRender, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { assertIsDefined } from 'test/helpers/asserts';
diff --git a/public/app/features/browse-dashboards/components/DashboardsTree.tsx b/public/app/features/browse-dashboards/components/DashboardsTree.tsx
index 94d16c5ba77..4250fc7a479 100644
--- a/public/app/features/browse-dashboards/components/DashboardsTree.tsx
+++ b/public/app/features/browse-dashboards/components/DashboardsTree.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { useCallback, useEffect, useId, useMemo, useRef } from 'react';
+import { useCallback, useEffect, useId, useMemo, useRef } from 'react';
+import * as React from 'react';
import { TableInstance, useTable } from 'react-table';
import { VariableSizeList as List } from 'react-window';
import InfiniteLoader from 'react-window-infinite-loader';
diff --git a/public/app/features/browse-dashboards/components/FolderActionsButton.test.tsx b/public/app/features/browse-dashboards/components/FolderActionsButton.test.tsx
index d6a4a134ad5..535be61f806 100644
--- a/public/app/features/browse-dashboards/components/FolderActionsButton.test.tsx
+++ b/public/app/features/browse-dashboards/components/FolderActionsButton.test.tsx
@@ -1,6 +1,5 @@
import { render as rtlRender, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { config } from '@grafana/runtime';
diff --git a/public/app/features/browse-dashboards/components/FolderActionsButton.tsx b/public/app/features/browse-dashboards/components/FolderActionsButton.tsx
index fc22f19b37f..1c4f3984d86 100644
--- a/public/app/features/browse-dashboards/components/FolderActionsButton.tsx
+++ b/public/app/features/browse-dashboards/components/FolderActionsButton.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { config, locationService, reportInteraction } from '@grafana/runtime';
import { Button, Drawer, Dropdown, Icon, Menu, MenuItem } from '@grafana/ui';
diff --git a/public/app/features/browse-dashboards/components/NameCell.tsx b/public/app/features/browse-dashboards/components/NameCell.tsx
index 086d3a4d5cc..dbdc60eba51 100644
--- a/public/app/features/browse-dashboards/components/NameCell.tsx
+++ b/public/app/features/browse-dashboards/components/NameCell.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import Skeleton from 'react-loading-skeleton';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/browse-dashboards/components/NewFolderForm.tsx b/public/app/features/browse-dashboards/components/NewFolderForm.tsx
index a31594be7f3..de926dc753a 100644
--- a/public/app/features/browse-dashboards/components/NewFolderForm.tsx
+++ b/public/app/features/browse-dashboards/components/NewFolderForm.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useForm } from 'react-hook-form';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/browse-dashboards/components/PermanentlyDeleteModal.tsx b/public/app/features/browse-dashboards/components/PermanentlyDeleteModal.tsx
index 0c0b89cb708..961898a4fc2 100644
--- a/public/app/features/browse-dashboards/components/PermanentlyDeleteModal.tsx
+++ b/public/app/features/browse-dashboards/components/PermanentlyDeleteModal.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { ConfirmModal, Text } from '@grafana/ui';
import { Trans, t } from '../../../core/internationalization';
diff --git a/public/app/features/browse-dashboards/components/RecentlyDeletedActions.tsx b/public/app/features/browse-dashboards/components/RecentlyDeletedActions.tsx
index b2f23879ab6..a34fef11edc 100644
--- a/public/app/features/browse-dashboards/components/RecentlyDeletedActions.tsx
+++ b/public/app/features/browse-dashboards/components/RecentlyDeletedActions.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { GrafanaTheme2 } from '@grafana/data/';
import { Button, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/browse-dashboards/components/RestoreModal.tsx b/public/app/features/browse-dashboards/components/RestoreModal.tsx
index 9b16765b963..6d4c0686e11 100644
--- a/public/app/features/browse-dashboards/components/RestoreModal.tsx
+++ b/public/app/features/browse-dashboards/components/RestoreModal.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { ConfirmModal, Text } from '@grafana/ui';
import { Trans, t } from '../../../core/internationalization';
diff --git a/public/app/features/browse-dashboards/components/SearchView.tsx b/public/app/features/browse-dashboards/components/SearchView.tsx
index 54253546200..2893f0abea6 100644
--- a/public/app/features/browse-dashboards/components/SearchView.tsx
+++ b/public/app/features/browse-dashboards/components/SearchView.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { DataFrameView, toDataFrame } from '@grafana/data';
import { Button, EmptyState } from '@grafana/ui';
diff --git a/public/app/features/browse-dashboards/components/TagsCell.tsx b/public/app/features/browse-dashboards/components/TagsCell.tsx
index a97d03f4dbd..7ac29e08008 100644
--- a/public/app/features/browse-dashboards/components/TagsCell.tsx
+++ b/public/app/features/browse-dashboards/components/TagsCell.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { CellProps } from 'react-table';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/canvas/elements/button.tsx b/public/app/features/canvas/elements/button.tsx
index f08bdb450df..eb926056ace 100644
--- a/public/app/features/canvas/elements/button.tsx
+++ b/public/app/features/canvas/elements/button.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import { useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { PluginState } from '@grafana/data/src';
@@ -42,7 +42,7 @@ export const defaultStyleConfig: ButtonStyleConfig = {
const ButtonDisplay = ({ data }: CanvasElementProps) => {
const styles = useStyles2(getStyles, data);
- const [isLoading, setIsLoading] = React.useState(false);
+ const [isLoading, setIsLoading] = useState(false);
const updateLoadingStateCallback = (loading: boolean) => {
setIsLoading(loading);
diff --git a/public/app/features/canvas/elements/cloud.tsx b/public/app/features/canvas/elements/cloud.tsx
index 1d48f43a35c..64313248f28 100644
--- a/public/app/features/canvas/elements/cloud.tsx
+++ b/public/app/features/canvas/elements/cloud.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { v4 as uuidv4 } from 'uuid';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/canvas/elements/droneFront.tsx b/public/app/features/canvas/elements/droneFront.tsx
index 031df8af28b..ab46e80214f 100644
--- a/public/app/features/canvas/elements/droneFront.tsx
+++ b/public/app/features/canvas/elements/droneFront.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { ScalarDimensionConfig } from '@grafana/schema';
diff --git a/public/app/features/canvas/elements/droneSide.tsx b/public/app/features/canvas/elements/droneSide.tsx
index a82b11d3ff1..49ca76ca309 100644
--- a/public/app/features/canvas/elements/droneSide.tsx
+++ b/public/app/features/canvas/elements/droneSide.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { ScalarDimensionConfig } from '@grafana/schema';
diff --git a/public/app/features/canvas/elements/droneTop.tsx b/public/app/features/canvas/elements/droneTop.tsx
index 31584b00583..fefb56ea841 100644
--- a/public/app/features/canvas/elements/droneTop.tsx
+++ b/public/app/features/canvas/elements/droneTop.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { ScalarDimensionConfig } from '@grafana/schema';
diff --git a/public/app/features/canvas/elements/ellipse.tsx b/public/app/features/canvas/elements/ellipse.tsx
index b15b5908610..67e5a68285f 100644
--- a/public/app/features/canvas/elements/ellipse.tsx
+++ b/public/app/features/canvas/elements/ellipse.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { v4 as uuidv4 } from 'uuid';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/canvas/elements/icon.tsx b/public/app/features/canvas/elements/icon.tsx
index 0bf7642206f..6de414257a0 100644
--- a/public/app/features/canvas/elements/icon.tsx
+++ b/public/app/features/canvas/elements/icon.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { isString } from 'lodash';
-import React, { CSSProperties } from 'react';
+import { CSSProperties } from 'react';
import { LinkModel } from '@grafana/data';
import { ColorDimensionConfig, ResourceDimensionConfig, ResourceDimensionMode } from '@grafana/schema';
diff --git a/public/app/features/canvas/elements/metricValue.tsx b/public/app/features/canvas/elements/metricValue.tsx
index 2f5f1a0894e..181033505b9 100644
--- a/public/app/features/canvas/elements/metricValue.tsx
+++ b/public/app/features/canvas/elements/metricValue.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { useObservable } from 'react-use';
import { of } from 'rxjs';
diff --git a/public/app/features/canvas/elements/notFound.tsx b/public/app/features/canvas/elements/notFound.tsx
index a0502d28d58..8aafc4951c8 100644
--- a/public/app/features/canvas/elements/notFound.tsx
+++ b/public/app/features/canvas/elements/notFound.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { CanvasElementItem, CanvasElementProps } from '../element';
diff --git a/public/app/features/canvas/elements/parallelogram.tsx b/public/app/features/canvas/elements/parallelogram.tsx
index 61c4b8531fa..7bccfd0c813 100644
--- a/public/app/features/canvas/elements/parallelogram.tsx
+++ b/public/app/features/canvas/elements/parallelogram.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { v4 as uuidv4 } from 'uuid';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/canvas/elements/rectangle.tsx b/public/app/features/canvas/elements/rectangle.tsx
index fcadaddc857..e89b7e448e7 100644
--- a/public/app/features/canvas/elements/rectangle.tsx
+++ b/public/app/features/canvas/elements/rectangle.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { stylesFactory } from '@grafana/ui';
diff --git a/public/app/features/canvas/elements/server/server.tsx b/public/app/features/canvas/elements/server/server.tsx
index cdb69ea7fbd..d84211ffe0e 100644
--- a/public/app/features/canvas/elements/server/server.tsx
+++ b/public/app/features/canvas/elements/server/server.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2, LinkModel } from '@grafana/data';
import { ColorDimensionConfig, ScalarDimensionConfig } from '@grafana/schema';
diff --git a/public/app/features/canvas/elements/server/types/database.tsx b/public/app/features/canvas/elements/server/types/database.tsx
index f2a48c723cd..4ca6794b50c 100644
--- a/public/app/features/canvas/elements/server/types/database.tsx
+++ b/public/app/features/canvas/elements/server/types/database.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { useStyles2 } from '@grafana/ui';
import { getServerStyles, ServerData } from '../server';
diff --git a/public/app/features/canvas/elements/server/types/single.tsx b/public/app/features/canvas/elements/server/types/single.tsx
index a779a1a71fe..62d8ec42ea0 100644
--- a/public/app/features/canvas/elements/server/types/single.tsx
+++ b/public/app/features/canvas/elements/server/types/single.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { useStyles2 } from '@grafana/ui';
import { getServerStyles, ServerData } from '../server';
diff --git a/public/app/features/canvas/elements/server/types/stack.tsx b/public/app/features/canvas/elements/server/types/stack.tsx
index 1eb71cbdf2d..d5a5807e967 100644
--- a/public/app/features/canvas/elements/server/types/stack.tsx
+++ b/public/app/features/canvas/elements/server/types/stack.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { useStyles2 } from '@grafana/ui';
import { getServerStyles, ServerData } from '../server';
diff --git a/public/app/features/canvas/elements/server/types/terminal.tsx b/public/app/features/canvas/elements/server/types/terminal.tsx
index f13241f5c64..9f3ee636de3 100644
--- a/public/app/features/canvas/elements/server/types/terminal.tsx
+++ b/public/app/features/canvas/elements/server/types/terminal.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { useStyles2 } from '@grafana/ui';
import { getServerStyles, ServerData } from '../server';
diff --git a/public/app/features/canvas/elements/text.tsx b/public/app/features/canvas/elements/text.tsx
index 7c2af4da6fd..b5cabfdc107 100644
--- a/public/app/features/canvas/elements/text.tsx
+++ b/public/app/features/canvas/elements/text.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useCallback, useEffect, useRef } from 'react';
+import { useCallback, useEffect, useRef } from 'react';
+import * as React from 'react';
import { useObservable } from 'react-use';
import { of } from 'rxjs';
diff --git a/public/app/features/canvas/elements/triangle.tsx b/public/app/features/canvas/elements/triangle.tsx
index 9a46e7f3dd5..84093278df1 100644
--- a/public/app/features/canvas/elements/triangle.tsx
+++ b/public/app/features/canvas/elements/triangle.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { v4 as uuidv4 } from 'uuid';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/canvas/elements/windTurbine.tsx b/public/app/features/canvas/elements/windTurbine.tsx
index 94f33c9628e..c4c1e38844d 100644
--- a/public/app/features/canvas/elements/windTurbine.tsx
+++ b/public/app/features/canvas/elements/windTurbine.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2, LinkModel } from '@grafana/data';
import { ScalarDimensionConfig } from '@grafana/schema';
diff --git a/public/app/features/canvas/runtime/SceneTransformWrapper.tsx b/public/app/features/canvas/runtime/SceneTransformWrapper.tsx
index 52ae32fa5f2..eed1b429193 100644
--- a/public/app/features/canvas/runtime/SceneTransformWrapper.tsx
+++ b/public/app/features/canvas/runtime/SceneTransformWrapper.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { TransformWrapper, TransformComponent, ReactZoomPanPinchRef } from 'react-zoom-pan-pinch';
import { config } from '@grafana/runtime';
diff --git a/public/app/features/canvas/runtime/element.tsx b/public/app/features/canvas/runtime/element.tsx
index 30dfcf01f01..96d099ac52f 100644
--- a/public/app/features/canvas/runtime/element.tsx
+++ b/public/app/features/canvas/runtime/element.tsx
@@ -1,4 +1,5 @@
-import React, { CSSProperties } from 'react';
+import { CSSProperties } from 'react';
+import * as React from 'react';
import { OnDrag, OnResize, OnRotate } from 'react-moveable/declaration/types';
import { LayerElement } from 'app/core/components/Layers/types';
diff --git a/public/app/features/canvas/runtime/frame.tsx b/public/app/features/canvas/runtime/frame.tsx
index 7307fdb5513..8ed68e62b2f 100644
--- a/public/app/features/canvas/runtime/frame.tsx
+++ b/public/app/features/canvas/runtime/frame.tsx
@@ -1,5 +1,4 @@
import { cloneDeep } from 'lodash';
-import React from 'react';
import { notFoundItem } from 'app/features/canvas/elements/notFound';
import { DimensionContext } from 'app/features/dimensions';
diff --git a/public/app/features/canvas/runtime/root.tsx b/public/app/features/canvas/runtime/root.tsx
index 33e3551b8c8..4a1e8a207c8 100644
--- a/public/app/features/canvas/runtime/root.tsx
+++ b/public/app/features/canvas/runtime/root.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { CanvasFrameOptions } from '../frame';
import { FrameState } from './frame';
diff --git a/public/app/features/canvas/runtime/scene.tsx b/public/app/features/canvas/runtime/scene.tsx
index 5df905d1dd8..764b6d81eda 100644
--- a/public/app/features/canvas/runtime/scene.tsx
+++ b/public/app/features/canvas/runtime/scene.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import Moveable from 'moveable';
-import React, { createRef, CSSProperties, RefObject } from 'react';
+import { createRef, CSSProperties, RefObject } from 'react';
import { ReactZoomPanPinchContentRef } from 'react-zoom-pan-pinch';
import { BehaviorSubject, ReplaySubject, Subject, Subscription } from 'rxjs';
import Selecto from 'selecto';
diff --git a/public/app/features/commandPalette/CommandPalette.tsx b/public/app/features/commandPalette/CommandPalette.tsx
index 38f268eb71b..783f6c06a81 100644
--- a/public/app/features/commandPalette/CommandPalette.tsx
+++ b/public/app/features/commandPalette/CommandPalette.tsx
@@ -12,7 +12,7 @@ import {
useKBar,
ActionImpl,
} from 'kbar';
-import React, { useEffect, useMemo, useRef } from 'react';
+import { useEffect, useMemo, useRef } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime';
diff --git a/public/app/features/commandPalette/ResultItem.tsx b/public/app/features/commandPalette/ResultItem.tsx
index 544781a39d1..75e68b3b3d0 100644
--- a/public/app/features/commandPalette/ResultItem.tsx
+++ b/public/app/features/commandPalette/ResultItem.tsx
@@ -1,6 +1,6 @@
import { css, cx } from '@emotion/css';
import { ActionId, ActionImpl } from 'kbar';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/connections/Connections.test.tsx b/public/app/features/connections/Connections.test.tsx
index c246c7f6630..ad70acaa15c 100644
--- a/public/app/features/connections/Connections.test.tsx
+++ b/public/app/features/connections/Connections.test.tsx
@@ -1,5 +1,4 @@
import { render, RenderResult, screen } from '@testing-library/react';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { locationService } from '@grafana/runtime';
diff --git a/public/app/features/connections/Connections.tsx b/public/app/features/connections/Connections.tsx
index bf96adbfac0..600dbb958c0 100644
--- a/public/app/features/connections/Connections.tsx
+++ b/public/app/features/connections/Connections.tsx
@@ -1,4 +1,3 @@
-import * as React from 'react';
import { Redirect, Route, Switch, useLocation } from 'react-router-dom';
import { DataSourcesRoutesContext } from 'app/features/datasources/state';
diff --git a/public/app/features/connections/components/ConnectionsRedirectNotice/ConnectionsRedirectNotice.tsx b/public/app/features/connections/components/ConnectionsRedirectNotice/ConnectionsRedirectNotice.tsx
index fc49117c918..c5aabc6a2f3 100644
--- a/public/app/features/connections/components/ConnectionsRedirectNotice/ConnectionsRedirectNotice.tsx
+++ b/public/app/features/connections/components/ConnectionsRedirectNotice/ConnectionsRedirectNotice.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Alert, LinkButton, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/connections/pages/AddNewConnectionPage.tsx b/public/app/features/connections/pages/AddNewConnectionPage.tsx
index 84af4f0ea99..bb81e688c8e 100644
--- a/public/app/features/connections/pages/AddNewConnectionPage.tsx
+++ b/public/app/features/connections/pages/AddNewConnectionPage.tsx
@@ -1,5 +1,3 @@
-import * as React from 'react';
-
import { Page } from 'app/core/components/Page/Page';
import { AddNewConnection } from '../tabs/ConnectData';
diff --git a/public/app/features/connections/pages/DataSourceDashboardsPage.tsx b/public/app/features/connections/pages/DataSourceDashboardsPage.tsx
index 14ed508dfbf..ecda29195d7 100644
--- a/public/app/features/connections/pages/DataSourceDashboardsPage.tsx
+++ b/public/app/features/connections/pages/DataSourceDashboardsPage.tsx
@@ -1,4 +1,3 @@
-import * as React from 'react';
import { useParams } from 'react-router-dom';
import { Page } from 'app/core/components/Page/Page';
diff --git a/public/app/features/connections/pages/DataSourceDetailsPage.tsx b/public/app/features/connections/pages/DataSourceDetailsPage.tsx
index 1380efd0a30..9a72ddb5783 100644
--- a/public/app/features/connections/pages/DataSourceDetailsPage.tsx
+++ b/public/app/features/connections/pages/DataSourceDetailsPage.tsx
@@ -1,4 +1,3 @@
-import * as React from 'react';
import { useParams } from 'react-router-dom';
import { Alert, Badge } from '@grafana/ui';
diff --git a/public/app/features/connections/pages/DataSourcesListPage.tsx b/public/app/features/connections/pages/DataSourcesListPage.tsx
index 7c75b08d039..29f24b7e548 100644
--- a/public/app/features/connections/pages/DataSourcesListPage.tsx
+++ b/public/app/features/connections/pages/DataSourcesListPage.tsx
@@ -1,5 +1,3 @@
-import * as React from 'react';
-
import { Page } from 'app/core/components/Page/Page';
import { DataSourceAddButton } from 'app/features/datasources/components/DataSourceAddButton';
import { DataSourcesList } from 'app/features/datasources/components/DataSourcesList';
diff --git a/public/app/features/connections/pages/EditDataSourcePage.tsx b/public/app/features/connections/pages/EditDataSourcePage.tsx
index bc4053609d7..be105116ca0 100644
--- a/public/app/features/connections/pages/EditDataSourcePage.tsx
+++ b/public/app/features/connections/pages/EditDataSourcePage.tsx
@@ -1,4 +1,3 @@
-import * as React from 'react';
import { useLocation, useParams } from 'react-router-dom';
import DataSourceTabPage from 'app/features/datasources/components/DataSourceTabPage';
diff --git a/public/app/features/connections/pages/NewDataSourcePage.tsx b/public/app/features/connections/pages/NewDataSourcePage.tsx
index c2228d6835b..43bb54bb096 100644
--- a/public/app/features/connections/pages/NewDataSourcePage.tsx
+++ b/public/app/features/connections/pages/NewDataSourcePage.tsx
@@ -1,5 +1,3 @@
-import * as React from 'react';
-
import { Page } from 'app/core/components/Page/Page';
import { NewDataSource } from 'app/features/datasources/components/NewDataSource';
diff --git a/public/app/features/connections/tabs/ConnectData/CardGrid/CardGrid.tsx b/public/app/features/connections/tabs/ConnectData/CardGrid/CardGrid.tsx
index 23f45f749b9..07cdde766ae 100644
--- a/public/app/features/connections/tabs/ConnectData/CardGrid/CardGrid.tsx
+++ b/public/app/features/connections/tabs/ConnectData/CardGrid/CardGrid.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Card, Grid, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/connections/tabs/ConnectData/CategoryHeader/CategoryHeader.tsx b/public/app/features/connections/tabs/ConnectData/CategoryHeader/CategoryHeader.tsx
index ae9a97f85ad..f483e5f9741 100644
--- a/public/app/features/connections/tabs/ConnectData/CategoryHeader/CategoryHeader.tsx
+++ b/public/app/features/connections/tabs/ConnectData/CategoryHeader/CategoryHeader.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2, IconName } from '@grafana/data';
import { Icon, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/connections/tabs/ConnectData/ConnectData.test.tsx b/public/app/features/connections/tabs/ConnectData/ConnectData.test.tsx
index 2b18442fcf3..78ac0623cc0 100644
--- a/public/app/features/connections/tabs/ConnectData/ConnectData.test.tsx
+++ b/public/app/features/connections/tabs/ConnectData/ConnectData.test.tsx
@@ -1,6 +1,5 @@
import { render, RenderResult, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { PluginType } from '@grafana/data';
diff --git a/public/app/features/connections/tabs/ConnectData/ConnectData.tsx b/public/app/features/connections/tabs/ConnectData/ConnectData.tsx
index ef8b788f2eb..1ea3c727a48 100644
--- a/public/app/features/connections/tabs/ConnectData/ConnectData.tsx
+++ b/public/app/features/connections/tabs/ConnectData/ConnectData.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
+import * as React from 'react';
import { GrafanaTheme2, PluginType } from '@grafana/data';
import { useStyles2, LoadingPlaceholder, EmptyState } from '@grafana/ui';
diff --git a/public/app/features/connections/tabs/ConnectData/NoAccessModal/NoAccessModal.tsx b/public/app/features/connections/tabs/ConnectData/NoAccessModal/NoAccessModal.tsx
index c6e6c6f5dd6..9206a40e602 100644
--- a/public/app/features/connections/tabs/ConnectData/NoAccessModal/NoAccessModal.tsx
+++ b/public/app/features/connections/tabs/ConnectData/NoAccessModal/NoAccessModal.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2, Modal, Icon, Button } from '@grafana/ui';
diff --git a/public/app/features/connections/tabs/ConnectData/Search/Search.tsx b/public/app/features/connections/tabs/ConnectData/Search/Search.tsx
index bddb9f0579f..6cd79c7f9f3 100644
--- a/public/app/features/connections/tabs/ConnectData/Search/Search.tsx
+++ b/public/app/features/connections/tabs/ConnectData/Search/Search.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Icon, Input, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/correlations/CorrelationsFeatureToggle.tsx b/public/app/features/correlations/CorrelationsFeatureToggle.tsx
index 8f4631a3243..c91bb8c12fe 100644
--- a/public/app/features/correlations/CorrelationsFeatureToggle.tsx
+++ b/public/app/features/correlations/CorrelationsFeatureToggle.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Page } from 'app/core/components/Page/Page';
import { Trans } from 'app/core/internationalization';
diff --git a/public/app/features/correlations/CorrelationsPage.test.tsx b/public/app/features/correlations/CorrelationsPage.test.tsx
index f127acf5b0a..e3745b45cfd 100644
--- a/public/app/features/correlations/CorrelationsPage.test.tsx
+++ b/public/app/features/correlations/CorrelationsPage.test.tsx
@@ -1,7 +1,6 @@
import { render, waitFor, screen, within, Matcher, getByRole } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { merge, uniqueId } from 'lodash';
-import React from 'react';
import { openMenu } from 'react-select-event';
import { Observable } from 'rxjs';
import { TestProvider } from 'test/helpers/TestProvider';
diff --git a/public/app/features/correlations/CorrelationsPage.tsx b/public/app/features/correlations/CorrelationsPage.tsx
index 0fa75853cf6..ea85765eae5 100644
--- a/public/app/features/correlations/CorrelationsPage.tsx
+++ b/public/app/features/correlations/CorrelationsPage.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { negate } from 'lodash';
-import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
+import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { isFetchError, reportInteraction } from '@grafana/runtime';
diff --git a/public/app/features/correlations/Forms/AddCorrelationForm.tsx b/public/app/features/correlations/Forms/AddCorrelationForm.tsx
index 21664725530..09f7f74584b 100644
--- a/public/app/features/correlations/Forms/AddCorrelationForm.tsx
+++ b/public/app/features/correlations/Forms/AddCorrelationForm.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { PanelContainer, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/correlations/Forms/ConfigureCorrelationBasicInfoForm.tsx b/public/app/features/correlations/Forms/ConfigureCorrelationBasicInfoForm.tsx
index fdf12eca094..1f870024d24 100644
--- a/public/app/features/correlations/Forms/ConfigureCorrelationBasicInfoForm.tsx
+++ b/public/app/features/correlations/Forms/ConfigureCorrelationBasicInfoForm.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { useFormContext } from 'react-hook-form';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/correlations/Forms/ConfigureCorrelationSourceForm.tsx b/public/app/features/correlations/Forms/ConfigureCorrelationSourceForm.tsx
index f62050a1874..51bedf03b7b 100644
--- a/public/app/features/correlations/Forms/ConfigureCorrelationSourceForm.tsx
+++ b/public/app/features/correlations/Forms/ConfigureCorrelationSourceForm.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { Controller, useFormContext } from 'react-hook-form';
import { DataSourceInstanceSettings, GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/correlations/Forms/ConfigureCorrelationTargetForm.tsx b/public/app/features/correlations/Forms/ConfigureCorrelationTargetForm.tsx
index f8f4c59104f..f0f36c4dcfd 100644
--- a/public/app/features/correlations/Forms/ConfigureCorrelationTargetForm.tsx
+++ b/public/app/features/correlations/Forms/ConfigureCorrelationTargetForm.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { Controller, useFormContext, useWatch } from 'react-hook-form';
import { DataSourceInstanceSettings } from '@grafana/data';
diff --git a/public/app/features/correlations/Forms/CorrelationFormNavigation.tsx b/public/app/features/correlations/Forms/CorrelationFormNavigation.tsx
index 95d6d56fc24..1c16f42a741 100644
--- a/public/app/features/correlations/Forms/CorrelationFormNavigation.tsx
+++ b/public/app/features/correlations/Forms/CorrelationFormNavigation.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Button, Stack } from '@grafana/ui';
import { Trans, t } from 'app/core/internationalization';
diff --git a/public/app/features/correlations/Forms/EditCorrelationForm.tsx b/public/app/features/correlations/Forms/EditCorrelationForm.tsx
index b24885aeec2..55417f4fad0 100644
--- a/public/app/features/correlations/Forms/EditCorrelationForm.tsx
+++ b/public/app/features/correlations/Forms/EditCorrelationForm.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import { Wizard } from '../components/Wizard';
import { Correlation } from '../types';
diff --git a/public/app/features/correlations/Forms/QueryEditorField.test.tsx b/public/app/features/correlations/Forms/QueryEditorField.test.tsx
index e9884198705..bb4b4d33a52 100644
--- a/public/app/features/correlations/Forms/QueryEditorField.test.tsx
+++ b/public/app/features/correlations/Forms/QueryEditorField.test.tsx
@@ -1,5 +1,5 @@
import { render, screen } from '@testing-library/react';
-import React, { ReactNode } from 'react';
+import { ReactNode } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { MockDataSourceApi } from 'test/mocks/datasource_srv';
diff --git a/public/app/features/correlations/Forms/QueryEditorField.tsx b/public/app/features/correlations/Forms/QueryEditorField.tsx
index b4cb893b1ae..b2e9a55127c 100644
--- a/public/app/features/correlations/Forms/QueryEditorField.tsx
+++ b/public/app/features/correlations/Forms/QueryEditorField.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { Controller } from 'react-hook-form';
import { useAsync } from 'react-use';
diff --git a/public/app/features/correlations/Forms/TransformationEditorRow.tsx b/public/app/features/correlations/Forms/TransformationEditorRow.tsx
index 8c549c8709f..e3294aa0d8c 100644
--- a/public/app/features/correlations/Forms/TransformationEditorRow.tsx
+++ b/public/app/features/correlations/Forms/TransformationEditorRow.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { useFormContext, useWatch } from 'react-hook-form';
import { Field, Icon, IconButton, Input, Label, Select, Stack, Tooltip, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/correlations/Forms/TransformationsEditor.tsx b/public/app/features/correlations/Forms/TransformationsEditor.tsx
index 3d83c43126d..1bfcf94e767 100644
--- a/public/app/features/correlations/Forms/TransformationsEditor.tsx
+++ b/public/app/features/correlations/Forms/TransformationsEditor.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useFormContext, useFieldArray } from 'react-hook-form';
import { Button, Stack, Text } from '@grafana/ui';
diff --git a/public/app/features/correlations/Forms/correlationsFormContext.tsx b/public/app/features/correlations/Forms/correlationsFormContext.tsx
index ec689966ab9..0f96fecd893 100644
--- a/public/app/features/correlations/Forms/correlationsFormContext.tsx
+++ b/public/app/features/correlations/Forms/correlationsFormContext.tsx
@@ -1,4 +1,4 @@
-import React, { createContext, PropsWithChildren, useContext } from 'react';
+import { createContext, PropsWithChildren, useContext } from 'react';
import { Correlation } from '../types';
diff --git a/public/app/features/correlations/components/EmptyCorrelationsCTA.tsx b/public/app/features/correlations/components/EmptyCorrelationsCTA.tsx
index b4f020295ce..64f61b32ca1 100644
--- a/public/app/features/correlations/components/EmptyCorrelationsCTA.tsx
+++ b/public/app/features/correlations/components/EmptyCorrelationsCTA.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Button, Card, EmptyState } from '@grafana/ui';
import { Trans, t } from 'app/core/internationalization';
diff --git a/public/app/features/correlations/components/Wizard/Wizard.test.tsx b/public/app/features/correlations/components/Wizard/Wizard.test.tsx
index 22760c45c04..50db3dbf1eb 100644
--- a/public/app/features/correlations/components/Wizard/Wizard.test.tsx
+++ b/public/app/features/correlations/components/Wizard/Wizard.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { Wizard } from './Wizard';
diff --git a/public/app/features/correlations/components/Wizard/Wizard.tsx b/public/app/features/correlations/components/Wizard/Wizard.tsx
index 38634a934b5..89ec9ca4799 100644
--- a/public/app/features/correlations/components/Wizard/Wizard.tsx
+++ b/public/app/features/correlations/components/Wizard/Wizard.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useForm, FormProvider, FieldValues } from 'react-hook-form';
import { WizardContent } from './WizardContent';
diff --git a/public/app/features/correlations/components/Wizard/WizardContent.tsx b/public/app/features/correlations/components/Wizard/WizardContent.tsx
index 2053c40d931..6073222cf9a 100644
--- a/public/app/features/correlations/components/Wizard/WizardContent.tsx
+++ b/public/app/features/correlations/components/Wizard/WizardContent.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { useFormContext } from 'react-hook-form';
import { useWizardContext } from './wizardContext';
diff --git a/public/app/features/correlations/components/Wizard/wizardContext.tsx b/public/app/features/correlations/components/Wizard/wizardContext.tsx
index 74b42e0e025..f59510e9721 100644
--- a/public/app/features/correlations/components/Wizard/wizardContext.tsx
+++ b/public/app/features/correlations/components/Wizard/wizardContext.tsx
@@ -1,4 +1,5 @@
-import React, { createContext, PropsWithChildren, useContext, useState } from 'react';
+import { createContext, PropsWithChildren, useContext, useState } from 'react';
+import * as React from 'react';
import { FieldValues } from 'react-hook-form';
export type WizardContextProps = {
diff --git a/public/app/features/dashboard-scene/embedding/EmbeddedDashboard.tsx b/public/app/features/dashboard-scene/embedding/EmbeddedDashboard.tsx
index 14390c35a8c..11a7859df4f 100644
--- a/public/app/features/dashboard-scene/embedding/EmbeddedDashboard.tsx
+++ b/public/app/features/dashboard-scene/embedding/EmbeddedDashboard.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { GrafanaTheme2, urlUtil } from '@grafana/data';
import { EmbeddedDashboardProps } from '@grafana/runtime';
diff --git a/public/app/features/dashboard-scene/embedding/EmbeddedDashboardLazy.tsx b/public/app/features/dashboard-scene/embedding/EmbeddedDashboardLazy.tsx
index b52299cb9bc..d6df473101b 100644
--- a/public/app/features/dashboard-scene/embedding/EmbeddedDashboardLazy.tsx
+++ b/public/app/features/dashboard-scene/embedding/EmbeddedDashboardLazy.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import { lazy } from 'react';
import { EmbeddedDashboardProps } from '@grafana/runtime';
@@ -6,7 +6,7 @@ export function EmbeddedDashboardLazy(props: EmbeddedDashboardProps) {
return ;
}
-const Component = React.lazy(async () => {
+const Component = lazy(async () => {
const { EmbeddedDashboard } = await import(/* webpackChunkName: "EmbeddedDashboard" */ './EmbeddedDashboard');
return { default: EmbeddedDashboard };
});
diff --git a/public/app/features/dashboard-scene/embedding/EmbeddedDashboardTestPage.tsx b/public/app/features/dashboard-scene/embedding/EmbeddedDashboardTestPage.tsx
index 747979ea6e3..8be07e4a0bb 100644
--- a/public/app/features/dashboard-scene/embedding/EmbeddedDashboardTestPage.tsx
+++ b/public/app/features/dashboard-scene/embedding/EmbeddedDashboardTestPage.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { PageLayoutType } from '@grafana/data';
import { Box } from '@grafana/ui';
diff --git a/public/app/features/dashboard-scene/inspect/HelpWizard/HelpWizard.test.tsx b/public/app/features/dashboard-scene/inspect/HelpWizard/HelpWizard.test.tsx
index 70b6d361137..e217fbd6d35 100644
--- a/public/app/features/dashboard-scene/inspect/HelpWizard/HelpWizard.test.tsx
+++ b/public/app/features/dashboard-scene/inspect/HelpWizard/HelpWizard.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { FieldType, getDefaultTimeRange, LoadingState, toDataFrame } from '@grafana/data';
import { getPanelPlugin } from '@grafana/data/test/__mocks__/pluginMocks';
diff --git a/public/app/features/dashboard-scene/inspect/HelpWizard/HelpWizard.tsx b/public/app/features/dashboard-scene/inspect/HelpWizard/HelpWizard.tsx
index 4b903c05b93..59662f7c513 100644
--- a/public/app/features/dashboard-scene/inspect/HelpWizard/HelpWizard.tsx
+++ b/public/app/features/dashboard-scene/inspect/HelpWizard/HelpWizard.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo, useEffect } from 'react';
+import { useMemo, useEffect } from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
import { GrafanaTheme2, FeatureState } from '@grafana/data';
diff --git a/public/app/features/dashboard-scene/inspect/InspectDataTab.tsx b/public/app/features/dashboard-scene/inspect/InspectDataTab.tsx
index 7e9d7d52b08..3e835a1c0af 100644
--- a/public/app/features/dashboard-scene/inspect/InspectDataTab.tsx
+++ b/public/app/features/dashboard-scene/inspect/InspectDataTab.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { LoadingState } from '@grafana/data';
import {
SceneComponentProps,
diff --git a/public/app/features/dashboard-scene/inspect/InspectJsonTab.tsx b/public/app/features/dashboard-scene/inspect/InspectJsonTab.tsx
index e43ac6f5d0f..8091daf5d8a 100644
--- a/public/app/features/dashboard-scene/inspect/InspectJsonTab.tsx
+++ b/public/app/features/dashboard-scene/inspect/InspectJsonTab.tsx
@@ -1,5 +1,4 @@
import { isEqual } from 'lodash';
-import React from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
import { SelectableValue } from '@grafana/data';
diff --git a/public/app/features/dashboard-scene/inspect/InspectMetaDataTab.tsx b/public/app/features/dashboard-scene/inspect/InspectMetaDataTab.tsx
index 61ead1e25cc..692f15b7faa 100644
--- a/public/app/features/dashboard-scene/inspect/InspectMetaDataTab.tsx
+++ b/public/app/features/dashboard-scene/inspect/InspectMetaDataTab.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { DataSourceApi } from '@grafana/data';
import {
SceneComponentProps,
diff --git a/public/app/features/dashboard-scene/inspect/InspectQueryTab.tsx b/public/app/features/dashboard-scene/inspect/InspectQueryTab.tsx
index 2099a9ba9f6..686563f15de 100644
--- a/public/app/features/dashboard-scene/inspect/InspectQueryTab.tsx
+++ b/public/app/features/dashboard-scene/inspect/InspectQueryTab.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import {
SceneComponentProps,
sceneGraph,
diff --git a/public/app/features/dashboard-scene/inspect/InspectStatsTab.tsx b/public/app/features/dashboard-scene/inspect/InspectStatsTab.tsx
index 3fd8c8f6c08..194d4d4241d 100644
--- a/public/app/features/dashboard-scene/inspect/InspectStatsTab.tsx
+++ b/public/app/features/dashboard-scene/inspect/InspectStatsTab.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import {
SceneComponentProps,
sceneGraph,
diff --git a/public/app/features/dashboard-scene/inspect/PanelInspectDrawer.tsx b/public/app/features/dashboard-scene/inspect/PanelInspectDrawer.tsx
index 319798559ec..7024aca1ebd 100644
--- a/public/app/features/dashboard-scene/inspect/PanelInspectDrawer.tsx
+++ b/public/app/features/dashboard-scene/inspect/PanelInspectDrawer.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useLocation } from 'react-router-dom';
import { locationUtil } from '@grafana/data';
diff --git a/public/app/features/dashboard-scene/pages/DashboardScenePage.test.tsx b/public/app/features/dashboard-scene/pages/DashboardScenePage.test.tsx
index 51777c2fd7a..0aebf3fe3d2 100644
--- a/public/app/features/dashboard-scene/pages/DashboardScenePage.test.tsx
+++ b/public/app/features/dashboard-scene/pages/DashboardScenePage.test.tsx
@@ -1,7 +1,6 @@
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { cloneDeep } from 'lodash';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
diff --git a/public/app/features/dashboard-scene/pages/DashboardScenePage.tsx b/public/app/features/dashboard-scene/pages/DashboardScenePage.tsx
index 7159235f8c1..d64bf5975ce 100644
--- a/public/app/features/dashboard-scene/pages/DashboardScenePage.tsx
+++ b/public/app/features/dashboard-scene/pages/DashboardScenePage.tsx
@@ -1,5 +1,5 @@
// Libraries
-import React, { useEffect, useMemo } from 'react';
+import { useEffect, useMemo } from 'react';
import { PageLayoutType } from '@grafana/data';
import { UrlSyncContextProvider } from '@grafana/scenes';
diff --git a/public/app/features/dashboard-scene/pages/PublicDashboardScenePage.test.tsx b/public/app/features/dashboard-scene/pages/PublicDashboardScenePage.test.tsx
index cbcd8909ad6..2824025d1e6 100644
--- a/public/app/features/dashboard-scene/pages/PublicDashboardScenePage.test.tsx
+++ b/public/app/features/dashboard-scene/pages/PublicDashboardScenePage.test.tsx
@@ -1,5 +1,4 @@
import { render, screen, waitForElementToBeRemoved } from '@testing-library/react';
-import React from 'react';
import { of } from 'rxjs';
import { TestProvider } from 'test/helpers/TestProvider';
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
diff --git a/public/app/features/dashboard-scene/pages/PublicDashboardScenePage.tsx b/public/app/features/dashboard-scene/pages/PublicDashboardScenePage.tsx
index a51de46c61e..4be33dc4365 100644
--- a/public/app/features/dashboard-scene/pages/PublicDashboardScenePage.tsx
+++ b/public/app/features/dashboard-scene/pages/PublicDashboardScenePage.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { GrafanaTheme2, PageLayoutType } from '@grafana/data';
import { selectors as e2eSelectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard-scene/panel-edit/LibraryVizPanelInfo.tsx b/public/app/features/dashboard-scene/panel-edit/LibraryVizPanelInfo.tsx
index bd741ee48fd..3e850af79b6 100644
--- a/public/app/features/dashboard-scene/panel-edit/LibraryVizPanelInfo.tsx
+++ b/public/app/features/dashboard-scene/panel-edit/LibraryVizPanelInfo.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2, dateTimeFormat } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
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 c452a9cfd11..136e8f17426 100644
--- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/EmptyTransformationsMessage.tsx
+++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/EmptyTransformationsMessage.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { selectors } from '@grafana/e2e-selectors';
import { Box, Button, Stack, Text } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/NewAlertRuleButton.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/NewAlertRuleButton.tsx
index 1c52f7f262f..8116a56f648 100644
--- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/NewAlertRuleButton.tsx
+++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/NewAlertRuleButton.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useLocation } from 'react-router-dom';
import { useAsync } from 'react-use';
diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataAlertingTab.test.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataAlertingTab.test.tsx
index de4bd6e6779..e5fabb7f09d 100644
--- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataAlertingTab.test.tsx
+++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataAlertingTab.test.tsx
@@ -1,6 +1,5 @@
import { act, render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { byTestId } from 'testing-library-selector';
diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataAlertingTab.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataAlertingTab.tsx
index 5debaeb8f83..3ebc9bb51a7 100644
--- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataAlertingTab.tsx
+++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataAlertingTab.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { SceneComponentProps, SceneObjectBase } from '@grafana/scenes';
diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataPane.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataPane.tsx
index 339d006bf45..ba1188f4166 100644
--- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataPane.tsx
+++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataPane.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { Unsubscribable } from 'rxjs';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataQueriesTab.test.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataQueriesTab.test.tsx
index c2125ad114a..9264e85d079 100644
--- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataQueriesTab.test.tsx
+++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataQueriesTab.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { of, map } from 'rxjs';
import {
diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataQueriesTab.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataQueriesTab.tsx
index 2d484422eea..cc0470c1bf2 100644
--- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataQueriesTab.tsx
+++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataQueriesTab.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { CoreApp, DataSourceApi, DataSourceInstanceSettings, IconName } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataTransformationsTab.test.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataTransformationsTab.test.tsx
index 2b9766c54d1..d17d4c4ce9c 100644
--- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataTransformationsTab.test.tsx
+++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataTransformationsTab.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import {
DataTransformerConfig,
diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataTransformationsTab.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataTransformationsTab.tsx
index f10b53be30f..8548c87505f 100644
--- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataTransformationsTab.tsx
+++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataTransformationsTab.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { DragDropContext, DropResult, Droppable } from 'react-beautiful-dnd';
import { DataTransformerConfig, GrafanaTheme2, IconName, PanelData } from '@grafana/data';
diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/TransformationsDrawer.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/TransformationsDrawer.tsx
index 5e9e75dd394..cb0528e144f 100644
--- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/TransformationsDrawer.tsx
+++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/TransformationsDrawer.tsx
@@ -1,4 +1,4 @@
-import React, { FormEvent, useMemo, useState } from 'react';
+import { FormEvent, useMemo, useState } from 'react';
import { DataFrame, SelectableValue, standardTransformersRegistry } from '@grafana/data';
import { IconButton } from '@grafana/ui';
diff --git a/public/app/features/dashboard-scene/panel-edit/PanelEditControls.tsx b/public/app/features/dashboard-scene/panel-edit/PanelEditControls.tsx
index 81796cd7bdd..cf37a7888ea 100644
--- a/public/app/features/dashboard-scene/panel-edit/PanelEditControls.tsx
+++ b/public/app/features/dashboard-scene/panel-edit/PanelEditControls.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { selectors } from '@grafana/e2e-selectors';
import { config } from '@grafana/runtime';
import { InlineSwitch } from '@grafana/ui';
diff --git a/public/app/features/dashboard-scene/panel-edit/PanelEditorRenderer.tsx b/public/app/features/dashboard-scene/panel-edit/PanelEditorRenderer.tsx
index 0f7757f1b42..c7c4fbdae59 100644
--- a/public/app/features/dashboard-scene/panel-edit/PanelEditorRenderer.tsx
+++ b/public/app/features/dashboard-scene/panel-edit/PanelEditorRenderer.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard-scene/panel-edit/PanelOptions.test.tsx b/public/app/features/dashboard-scene/panel-edit/PanelOptions.test.tsx
index 197ca1dd304..83d2e0363ce 100644
--- a/public/app/features/dashboard-scene/panel-edit/PanelOptions.test.tsx
+++ b/public/app/features/dashboard-scene/panel-edit/PanelOptions.test.tsx
@@ -1,6 +1,5 @@
import { act, fireEvent, render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { standardEditorsRegistry, standardFieldConfigEditorRegistry } from '@grafana/data';
import { getPanelPlugin } from '@grafana/data/test/__mocks__/pluginMocks';
diff --git a/public/app/features/dashboard-scene/panel-edit/PanelOptions.tsx b/public/app/features/dashboard-scene/panel-edit/PanelOptions.tsx
index 11fae6fbb83..3778f882a2c 100644
--- a/public/app/features/dashboard-scene/panel-edit/PanelOptions.tsx
+++ b/public/app/features/dashboard-scene/panel-edit/PanelOptions.tsx
@@ -1,4 +1,5 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
+import * as React from 'react';
import { PanelData } from '@grafana/data';
import { OptionFilter, renderSearchHits } from 'app/features/dashboard/components/PanelEditor/OptionsPaneOptions';
diff --git a/public/app/features/dashboard-scene/panel-edit/PanelOptionsPane.tsx b/public/app/features/dashboard-scene/panel-edit/PanelOptionsPane.tsx
index 8e7673e4db7..8caf65b2cd4 100644
--- a/public/app/features/dashboard-scene/panel-edit/PanelOptionsPane.tsx
+++ b/public/app/features/dashboard-scene/panel-edit/PanelOptionsPane.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { GrafanaTheme2, PanelPluginMeta } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard-scene/panel-edit/PanelVizTypePicker.tsx b/public/app/features/dashboard-scene/panel-edit/PanelVizTypePicker.tsx
index eb376b7483a..e4a8482622c 100644
--- a/public/app/features/dashboard-scene/panel-edit/PanelVizTypePicker.tsx
+++ b/public/app/features/dashboard-scene/panel-edit/PanelVizTypePicker.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useMemo, useState } from 'react';
+import { useEffect, useMemo, useState } from 'react';
import { useLocalStorage } from 'react-use';
import { GrafanaTheme2, PanelData, SelectableValue } from '@grafana/data';
diff --git a/public/app/features/dashboard-scene/panel-edit/SaveLibraryVizPanelModal.tsx b/public/app/features/dashboard-scene/panel-edit/SaveLibraryVizPanelModal.tsx
index d1178a76aa5..c9538e7bdc7 100644
--- a/public/app/features/dashboard-scene/panel-edit/SaveLibraryVizPanelModal.tsx
+++ b/public/app/features/dashboard-scene/panel-edit/SaveLibraryVizPanelModal.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useState } from 'react';
+import { useCallback, useState } from 'react';
import { useAsync, useDebounce } from 'react-use';
import { Button, Icon, Input, Modal, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/dashboard-scene/panel-edit/VizPanelManager.tsx b/public/app/features/dashboard-scene/panel-edit/VizPanelManager.tsx
index 530bce2a9eb..1ffb2272d93 100644
--- a/public/app/features/dashboard-scene/panel-edit/VizPanelManager.tsx
+++ b/public/app/features/dashboard-scene/panel-edit/VizPanelManager.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { debounce } from 'lodash';
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import {
DataSourceApi,
diff --git a/public/app/features/dashboard-scene/panel-edit/getPanelFrameOptions.tsx b/public/app/features/dashboard-scene/panel-edit/getPanelFrameOptions.tsx
index c23d41c81fa..7762bdc2965 100644
--- a/public/app/features/dashboard-scene/panel-edit/getPanelFrameOptions.tsx
+++ b/public/app/features/dashboard-scene/panel-edit/getPanelFrameOptions.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SelectableValue } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { config } from '@grafana/runtime';
diff --git a/public/app/features/dashboard-scene/panel-edit/splitter/useSnappingSplitter.ts b/public/app/features/dashboard-scene/panel-edit/splitter/useSnappingSplitter.ts
index 95e78cac99c..31af56446cc 100644
--- a/public/app/features/dashboard-scene/panel-edit/splitter/useSnappingSplitter.ts
+++ b/public/app/features/dashboard-scene/panel-edit/splitter/useSnappingSplitter.ts
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useState, useCallback } from 'react';
import { DragHandlePosition, useSplitter } from '@grafana/ui';
@@ -25,7 +25,7 @@ interface PaneState {
export function useSnappingSplitter(options: UseSnappingSplitterOptions) {
const { paneOptions } = options;
- const [state, setState] = React.useState({ collapsed: false });
+ const [state, setState] = useState({ collapsed: false });
const onResizing = useCallback(
(flexSize: number, pixelSize: number) => {
diff --git a/public/app/features/dashboard-scene/saving/DashboardPrompt.tsx b/public/app/features/dashboard-scene/saving/DashboardPrompt.tsx
index a698782225f..f7e737d3996 100644
--- a/public/app/features/dashboard-scene/saving/DashboardPrompt.tsx
+++ b/public/app/features/dashboard-scene/saving/DashboardPrompt.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import * as H from 'history';
-import React, { useContext, useEffect, useMemo } from 'react';
+import { memo, useContext, useEffect, useMemo } from 'react';
import { Prompt } from 'react-router';
import { locationService } from '@grafana/runtime';
@@ -14,7 +14,7 @@ interface DashboardPromptProps {
dashboard: DashboardScene;
}
-export const DashboardPrompt = React.memo(({ dashboard }: DashboardPromptProps) => {
+export const DashboardPrompt = memo(({ dashboard }: DashboardPromptProps) => {
// eslint-disable-next-line react-hooks/exhaustive-deps
const originalPath = useMemo(() => locationService.getLocation().pathname, [dashboard]);
const { showModal, hideModal } = useContext(ModalsContext);
diff --git a/public/app/features/dashboard-scene/saving/SaveDashboardAsForm.tsx b/public/app/features/dashboard-scene/saving/SaveDashboardAsForm.tsx
index 0a9fb858acc..1241fffc6f0 100644
--- a/public/app/features/dashboard-scene/saving/SaveDashboardAsForm.tsx
+++ b/public/app/features/dashboard-scene/saving/SaveDashboardAsForm.tsx
@@ -1,5 +1,5 @@
import debounce from 'debounce-promise';
-import React, { ChangeEvent } from 'react';
+import { ChangeEvent } from 'react';
import { UseFormSetValue, useForm } from 'react-hook-form';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard-scene/saving/SaveDashboardDrawer.test.tsx b/public/app/features/dashboard-scene/saving/SaveDashboardDrawer.test.tsx
index f53eaf052e1..7d99dea4247 100644
--- a/public/app/features/dashboard-scene/saving/SaveDashboardDrawer.test.tsx
+++ b/public/app/features/dashboard-scene/saving/SaveDashboardDrawer.test.tsx
@@ -1,6 +1,5 @@
import { screen, render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard-scene/saving/SaveDashboardDrawer.tsx b/public/app/features/dashboard-scene/saving/SaveDashboardDrawer.tsx
index 9e25e914f07..3502d33c1e1 100644
--- a/public/app/features/dashboard-scene/saving/SaveDashboardDrawer.tsx
+++ b/public/app/features/dashboard-scene/saving/SaveDashboardDrawer.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SceneComponentProps, SceneObjectBase, SceneObjectState, SceneObjectRef } from '@grafana/scenes';
import { Drawer, Tab, TabsBar } from '@grafana/ui';
import { SaveDashboardDiff } from 'app/features/dashboard/components/SaveDashboard/SaveDashboardDiff';
diff --git a/public/app/features/dashboard-scene/saving/SaveDashboardForm.tsx b/public/app/features/dashboard-scene/saving/SaveDashboardForm.tsx
index de4b76d4cec..871eb14ce92 100644
--- a/public/app/features/dashboard-scene/saving/SaveDashboardForm.tsx
+++ b/public/app/features/dashboard-scene/saving/SaveDashboardForm.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { Button, Checkbox, TextArea, Stack, Alert, Box, Field } from '@grafana/ui';
diff --git a/public/app/features/dashboard-scene/saving/SaveProvisionedDashboardForm.tsx b/public/app/features/dashboard-scene/saving/SaveProvisionedDashboardForm.tsx
index 98aa2e407be..12ddf62f343 100644
--- a/public/app/features/dashboard-scene/saving/SaveProvisionedDashboardForm.tsx
+++ b/public/app/features/dashboard-scene/saving/SaveProvisionedDashboardForm.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { saveAs } from 'file-saver';
-import React, { useCallback, useMemo } from 'react';
+import { useCallback, useMemo } from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
import { Button, ClipboardButton, Stack, CodeEditor, Box } from '@grafana/ui';
diff --git a/public/app/features/dashboard-scene/saving/shared.tsx b/public/app/features/dashboard-scene/saving/shared.tsx
index 29b9f3a70b1..d06ffb55463 100644
--- a/public/app/features/dashboard-scene/saving/shared.tsx
+++ b/public/app/features/dashboard-scene/saving/shared.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { isFetchError } from '@grafana/runtime';
diff --git a/public/app/features/dashboard-scene/scene/AddLibraryPanelDrawer.tsx b/public/app/features/dashboard-scene/scene/AddLibraryPanelDrawer.tsx
index 60b0240694d..30bc359ca6c 100644
--- a/public/app/features/dashboard-scene/scene/AddLibraryPanelDrawer.tsx
+++ b/public/app/features/dashboard-scene/scene/AddLibraryPanelDrawer.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import {
SceneComponentProps,
SceneGridLayout,
diff --git a/public/app/features/dashboard-scene/scene/DashboardControls.test.tsx b/public/app/features/dashboard-scene/scene/DashboardControls.test.tsx
index 30b391e0aba..a5b18c1e6c4 100644
--- a/public/app/features/dashboard-scene/scene/DashboardControls.test.tsx
+++ b/public/app/features/dashboard-scene/scene/DashboardControls.test.tsx
@@ -1,5 +1,4 @@
import { render } from '@testing-library/react';
-import React from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { SceneDataLayerControls, SceneVariableSet, TextBoxVariable, VariableValueSelectors } from '@grafana/scenes';
diff --git a/public/app/features/dashboard-scene/scene/DashboardControls.tsx b/public/app/features/dashboard-scene/scene/DashboardControls.tsx
index 5614c57bfd4..a289695953b 100644
--- a/public/app/features/dashboard-scene/scene/DashboardControls.tsx
+++ b/public/app/features/dashboard-scene/scene/DashboardControls.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2, VariableHide } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard-scene/scene/DashboardDataLayerSet.tsx b/public/app/features/dashboard-scene/scene/DashboardDataLayerSet.tsx
index 453e58b81b1..49c51efedc8 100644
--- a/public/app/features/dashboard-scene/scene/DashboardDataLayerSet.tsx
+++ b/public/app/features/dashboard-scene/scene/DashboardDataLayerSet.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import {
SceneDataLayerProviderState,
SceneDataLayerProvider,
diff --git a/public/app/features/dashboard-scene/scene/DashboardGridItem.tsx b/public/app/features/dashboard-scene/scene/DashboardGridItem.tsx
index d1fb47776ed..0a48d944190 100644
--- a/public/app/features/dashboard-scene/scene/DashboardGridItem.tsx
+++ b/public/app/features/dashboard-scene/scene/DashboardGridItem.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { isEqual } from 'lodash';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { Unsubscribable } from 'rxjs';
import { config } from '@grafana/runtime';
diff --git a/public/app/features/dashboard-scene/scene/DashboardLinksControls.tsx b/public/app/features/dashboard-scene/scene/DashboardLinksControls.tsx
index a535b3517fe..0337580526a 100644
--- a/public/app/features/dashboard-scene/scene/DashboardLinksControls.tsx
+++ b/public/app/features/dashboard-scene/scene/DashboardLinksControls.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { sanitizeUrl } from '@grafana/data/src/text/sanitize';
import { selectors } from '@grafana/e2e-selectors';
import { DashboardLink } from '@grafana/schema';
diff --git a/public/app/features/dashboard-scene/scene/DashboardSceneRenderer.test.tsx b/public/app/features/dashboard-scene/scene/DashboardSceneRenderer.test.tsx
index 47d5cd076b3..c8ee835f62b 100644
--- a/public/app/features/dashboard-scene/scene/DashboardSceneRenderer.test.tsx
+++ b/public/app/features/dashboard-scene/scene/DashboardSceneRenderer.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router';
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
diff --git a/public/app/features/dashboard-scene/scene/DashboardSceneRenderer.tsx b/public/app/features/dashboard-scene/scene/DashboardSceneRenderer.tsx
index 6164551eb1c..0e220a4e448 100644
--- a/public/app/features/dashboard-scene/scene/DashboardSceneRenderer.tsx
+++ b/public/app/features/dashboard-scene/scene/DashboardSceneRenderer.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { useLocation } from 'react-router-dom';
import { GrafanaTheme2, PageLayoutType } from '@grafana/data';
diff --git a/public/app/features/dashboard-scene/scene/GoToSnapshotOriginButton.test.tsx b/public/app/features/dashboard-scene/scene/GoToSnapshotOriginButton.test.tsx
index 6e55b4d0ab0..104cccc9d86 100644
--- a/public/app/features/dashboard-scene/scene/GoToSnapshotOriginButton.test.tsx
+++ b/public/app/features/dashboard-scene/scene/GoToSnapshotOriginButton.test.tsx
@@ -1,5 +1,4 @@
import { fireEvent, render, screen } from '@testing-library/react';
-import React from 'react';
import { config, locationService } from '@grafana/runtime';
import { ConfirmModal } from '@grafana/ui';
diff --git a/public/app/features/dashboard-scene/scene/GoToSnapshotOriginButton.tsx b/public/app/features/dashboard-scene/scene/GoToSnapshotOriginButton.tsx
index 28c5c802f47..f4ff6310475 100644
--- a/public/app/features/dashboard-scene/scene/GoToSnapshotOriginButton.tsx
+++ b/public/app/features/dashboard-scene/scene/GoToSnapshotOriginButton.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { textUtil } from '@grafana/data';
import { config, locationService } from '@grafana/runtime';
diff --git a/public/app/features/dashboard-scene/scene/LibraryVizPanel.tsx b/public/app/features/dashboard-scene/scene/LibraryVizPanel.tsx
index 2756a632cfb..c5b3d172817 100644
--- a/public/app/features/dashboard-scene/scene/LibraryVizPanel.tsx
+++ b/public/app/features/dashboard-scene/scene/LibraryVizPanel.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import {
SceneComponentProps,
SceneObjectBase,
diff --git a/public/app/features/dashboard-scene/scene/NavToolbarActions.test.tsx b/public/app/features/dashboard-scene/scene/NavToolbarActions.test.tsx
index ce2bfb8fa66..9e8b862be00 100644
--- a/public/app/features/dashboard-scene/scene/NavToolbarActions.test.tsx
+++ b/public/app/features/dashboard-scene/scene/NavToolbarActions.test.tsx
@@ -1,6 +1,5 @@
import { screen, render, act } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
diff --git a/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx b/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx
index 28e2902509d..f3a147d9578 100644
--- a/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx
+++ b/public/app/features/dashboard-scene/scene/NavToolbarActions.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useEffect, useId, useState } from 'react';
+import { useEffect, useId, useState } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
@@ -321,7 +322,7 @@ export function ToolbarActions({ dashboard }: Props) {
fill="outline"
onClick={() => {
DashboardInteractions.toolbarShareClick();
- dashboard.showModal(new ShareModal({ dashboardRef: dashboard.getRef() }));
+ dashboard.showModal(new ShareModal({}));
}}
data-testid={selectors.components.NavToolbar.shareDashboard}
>
diff --git a/public/app/features/dashboard-scene/scene/PanelLinks.tsx b/public/app/features/dashboard-scene/scene/PanelLinks.tsx
index 62643f15e38..3e46299dc83 100644
--- a/public/app/features/dashboard-scene/scene/PanelLinks.tsx
+++ b/public/app/features/dashboard-scene/scene/PanelLinks.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { DataLink, LinkModel } from '@grafana/data';
import { SceneComponentProps, SceneObjectBase, SceneObjectState, VizPanel } from '@grafana/scenes';
import { Dropdown, Icon, Menu, PanelChrome, ToolbarButton } from '@grafana/ui';
diff --git a/public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx b/public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx
index d33ed831670..24a0314c676 100644
--- a/public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx
+++ b/public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx
@@ -84,7 +84,7 @@ export function panelMenuBehavior(menu: VizPanelMenu, isRepeat = false) {
iconClassName: 'share-alt',
onClick: () => {
DashboardInteractions.panelMenuItemClicked('share');
- dashboard.showModal(new ShareModal({ panelRef: panel.getRef(), dashboardRef: dashboard.getRef() }));
+ dashboard.showModal(new ShareModal({ panelRef: panel.getRef() }));
},
shortcut: 'p s',
});
@@ -139,7 +139,6 @@ export function panelMenuBehavior(menu: VizPanelMenu, isRepeat = false) {
dashboard.showModal(
new ShareModal({
panelRef: panel.getRef(),
- dashboardRef: dashboard.getRef(),
activeTab: shareDashboardType.libraryPanel,
})
);
diff --git a/public/app/features/dashboard-scene/scene/PanelNotices.tsx b/public/app/features/dashboard-scene/scene/PanelNotices.tsx
index 673ea89ce06..97c7779a083 100644
--- a/public/app/features/dashboard-scene/scene/PanelNotices.tsx
+++ b/public/app/features/dashboard-scene/scene/PanelNotices.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SceneComponentProps, SceneObjectBase, VizPanel, sceneGraph } from '@grafana/scenes';
import { PanelHeaderNotices } from 'app/features/dashboard/dashgrid/PanelHeader/PanelHeaderNotices';
diff --git a/public/app/features/dashboard-scene/scene/PanelTimeRange.tsx b/public/app/features/dashboard-scene/scene/PanelTimeRange.tsx
index cd4d0637c65..372327eb58d 100644
--- a/public/app/features/dashboard-scene/scene/PanelTimeRange.tsx
+++ b/public/app/features/dashboard-scene/scene/PanelTimeRange.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { dateMath, getDefaultTimeRange, GrafanaTheme2, rangeUtil, TimeRange } from '@grafana/data';
import {
diff --git a/public/app/features/dashboard-scene/scene/Scopes/ScopesDashboardsScene.tsx b/public/app/features/dashboard-scene/scene/Scopes/ScopesDashboardsScene.tsx
index 40eb79ade3a..3fa727e583b 100644
--- a/public/app/features/dashboard-scene/scene/Scopes/ScopesDashboardsScene.tsx
+++ b/public/app/features/dashboard-scene/scene/Scopes/ScopesDashboardsScene.tsx
@@ -1,10 +1,9 @@
import { css } from '@emotion/css';
-import React from 'react';
import { Link } from 'react-router-dom';
import { GrafanaTheme2, Scope, urlUtil } from '@grafana/data';
import { SceneComponentProps, SceneObjectBase, SceneObjectState } from '@grafana/scenes';
-import { CustomScrollbar, Icon, Input, LoadingPlaceholder, useStyles2 } from '@grafana/ui';
+import { CustomScrollbar, Icon, IconButton, Input, LoadingPlaceholder, useStyles2 } from '@grafana/ui';
import { useQueryParams } from 'app/core/hooks/useQueryParams';
import { t } from 'app/core/internationalization';
@@ -63,7 +62,7 @@ export class ScopesDashboardsScene extends SceneObjectBase) {
- const { filteredDashboards, isLoading } = model.useState();
+ const { filteredDashboards, isLoading, searchQuery } = model.useState();
const styles = useStyles2(getStyles);
const [queryParams] = useQueryParams();
@@ -76,6 +75,17 @@ export function ScopesDashboardsSceneRenderer({ model }: SceneComponentProps model.changeSearchQuery('')}
+ />
+ ) : undefined
+ }
onChange={(evt) => model.changeSearchQuery(evt.currentTarget.value)}
/>
diff --git a/public/app/features/dashboard-scene/scene/Scopes/ScopesFiltersScene.tsx b/public/app/features/dashboard-scene/scene/Scopes/ScopesFiltersScene.tsx
index fa2213265f5..b96e129a0ad 100644
--- a/public/app/features/dashboard-scene/scene/Scopes/ScopesFiltersScene.tsx
+++ b/public/app/features/dashboard-scene/scene/Scopes/ScopesFiltersScene.tsx
@@ -1,6 +1,5 @@
import { css } from '@emotion/css';
import { isEqual } from 'lodash';
-import React from 'react';
import { finalize, from, Subscription } from 'rxjs';
import { GrafanaTheme2, Scope } from '@grafana/data';
diff --git a/public/app/features/dashboard-scene/scene/Scopes/ScopesInput.tsx b/public/app/features/dashboard-scene/scene/Scopes/ScopesInput.tsx
index b44d0ee4d11..f565ac3da71 100644
--- a/public/app/features/dashboard-scene/scene/Scopes/ScopesInput.tsx
+++ b/public/app/features/dashboard-scene/scene/Scopes/ScopesInput.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { groupBy } from 'lodash';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { IconButton, Input, Tooltip } from '@grafana/ui';
@@ -35,13 +35,20 @@ export function ScopesInput({
let titles: string[];
if (path.length > 0) {
- titles = path.map((nodeName) => {
- const { title, nodes } = currentLevel[nodeName];
+ titles = path
+ .map((nodeName) => {
+ const cl = currentLevel[nodeName];
+ if (!cl) {
+ return null;
+ }
- currentLevel = nodes;
+ const { title, nodes } = cl;
- return title;
- });
+ currentLevel = nodes;
+
+ return title;
+ })
+ .filter((title) => title !== null) as string[];
if (titles[0] === '') {
titles.splice(0, 1);
diff --git a/public/app/features/dashboard-scene/scene/Scopes/ScopesScene.test.tsx b/public/app/features/dashboard-scene/scene/Scopes/ScopesScene.test.tsx
index 418414da702..a51158e3bb6 100644
--- a/public/app/features/dashboard-scene/scene/Scopes/ScopesScene.test.tsx
+++ b/public/app/features/dashboard-scene/scene/Scopes/ScopesScene.test.tsx
@@ -46,6 +46,7 @@ import {
queryDashboardsContainer,
queryDashboardsExpand,
renderDashboard,
+ getDashboardsClear,
} from './testUtils';
jest.mock('@grafana/runtime', () => ({
@@ -280,6 +281,22 @@ describe('ScopesScene', () => {
expect(queryDashboard('2')).not.toBeInTheDocument();
});
+ it('Clears the filter', async () => {
+ await userEvents.click(getDashboardsExpand());
+ await userEvents.click(getFiltersInput());
+ await userEvents.click(getApplicationsExpand());
+ await userEvents.click(getApplicationsSlothPictureFactorySelect());
+ await userEvents.click(getFiltersApply());
+ expect(getDashboard('1')).toBeInTheDocument();
+ expect(getDashboard('2')).toBeInTheDocument();
+ await userEvents.type(getDashboardsSearch(), '1');
+ expect(queryDashboard('2')).not.toBeInTheDocument();
+ await userEvents.click(getDashboardsClear());
+ expect(getDashboardsSearch().value).toBe('');
+ expect(getDashboard('1')).toBeInTheDocument();
+ expect(getDashboard('2')).toBeInTheDocument();
+ });
+
it('Deduplicates the dashboards list', async () => {
await userEvents.click(getDashboardsExpand());
await userEvents.click(getFiltersInput());
diff --git a/public/app/features/dashboard-scene/scene/Scopes/ScopesScene.tsx b/public/app/features/dashboard-scene/scene/Scopes/ScopesScene.tsx
index f0217190b57..e661f703950 100644
--- a/public/app/features/dashboard-scene/scene/Scopes/ScopesScene.tsx
+++ b/public/app/features/dashboard-scene/scene/Scopes/ScopesScene.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { SceneComponentProps, sceneGraph, SceneObjectBase, SceneObjectState } from '@grafana/scenes';
diff --git a/public/app/features/dashboard-scene/scene/Scopes/ScopesTreeLevel.tsx b/public/app/features/dashboard-scene/scene/Scopes/ScopesTreeLevel.tsx
index 787e089448c..a8c7444ee6c 100644
--- a/public/app/features/dashboard-scene/scene/Scopes/ScopesTreeLevel.tsx
+++ b/public/app/features/dashboard-scene/scene/Scopes/ScopesTreeLevel.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { debounce } from 'lodash';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import Skeleton from 'react-loading-skeleton';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/dashboard-scene/scene/Scopes/testUtils.tsx b/public/app/features/dashboard-scene/scene/Scopes/testUtils.tsx
index 8e81fc1b162..8cd17827854 100644
--- a/public/app/features/dashboard-scene/scene/Scopes/testUtils.tsx
+++ b/public/app/features/dashboard-scene/scene/Scopes/testUtils.tsx
@@ -1,5 +1,4 @@
import { screen } from '@testing-library/react';
-import React from 'react';
import { render } from 'test/test-utils';
import { Scope, ScopeDashboardBinding, ScopeNode } from '@grafana/data';
@@ -310,6 +309,7 @@ const selectors = {
expand: 'scopes-dashboards-expand',
container: 'scopes-dashboards-container',
search: 'scopes-dashboards-search',
+ clear: 'scopes-dashboards-clear',
loading: 'scopes-dashboards-loading',
dashboard: (uid: string) => `scopes-dashboards-${uid}`,
},
@@ -324,7 +324,8 @@ export const queryDashboardsExpand = () => screen.queryByTestId(selectors.dashbo
export const getDashboardsExpand = () => screen.getByTestId(selectors.dashboards.expand);
export const queryDashboardsContainer = () => screen.queryByTestId(selectors.dashboards.container);
export const getDashboardsContainer = () => screen.getByTestId(selectors.dashboards.container);
-export const getDashboardsSearch = () => screen.getByTestId(selectors.dashboards.search);
+export const getDashboardsSearch = () => screen.getByTestId(selectors.dashboards.search);
+export const getDashboardsClear = () => screen.getByTestId(selectors.dashboards.clear);
export const queryAllDashboard = (uid: string) => screen.queryAllByTestId(selectors.dashboards.dashboard(uid));
export const queryDashboard = (uid: string) => screen.queryByTestId(selectors.dashboards.dashboard(uid));
export const getDashboard = (uid: string) => screen.getByTestId(selectors.dashboards.dashboard(uid));
diff --git a/public/app/features/dashboard-scene/scene/UnlinkLibraryPanelModal.tsx b/public/app/features/dashboard-scene/scene/UnlinkLibraryPanelModal.tsx
index 8dc2696a71d..3db5c17c0c1 100644
--- a/public/app/features/dashboard-scene/scene/UnlinkLibraryPanelModal.tsx
+++ b/public/app/features/dashboard-scene/scene/UnlinkLibraryPanelModal.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SceneComponentProps, SceneObjectBase, SceneObjectRef, SceneObjectState } from '@grafana/scenes';
import { ModalSceneObjectLike } from '../sharing/types';
diff --git a/public/app/features/dashboard-scene/scene/UnlinkModal.tsx b/public/app/features/dashboard-scene/scene/UnlinkModal.tsx
index ee1bf5749a2..5a646ecb2d7 100644
--- a/public/app/features/dashboard-scene/scene/UnlinkModal.tsx
+++ b/public/app/features/dashboard-scene/scene/UnlinkModal.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { ConfirmModal } from '@grafana/ui';
interface Props {
diff --git a/public/app/features/dashboard-scene/scene/ViewPanelScene.tsx b/public/app/features/dashboard-scene/scene/ViewPanelScene.tsx
index 81dd1f6dc68..33885113f0a 100644
--- a/public/app/features/dashboard-scene/scene/ViewPanelScene.tsx
+++ b/public/app/features/dashboard-scene/scene/ViewPanelScene.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import {
SceneComponentProps,
SceneObjectBase,
diff --git a/public/app/features/dashboard-scene/scene/keyboardShortcuts.ts b/public/app/features/dashboard-scene/scene/keyboardShortcuts.ts
index dfa49e6625a..f0edd586360 100644
--- a/public/app/features/dashboard-scene/scene/keyboardShortcuts.ts
+++ b/public/app/features/dashboard-scene/scene/keyboardShortcuts.ts
@@ -60,7 +60,7 @@ export function setupKeyboardShortcuts(scene: DashboardScene) {
keybindings.addBinding({
key: 'p s',
onTrigger: withFocusedPanel(scene, async (vizPanel: VizPanel) => {
- scene.showModal(new ShareModal({ panelRef: vizPanel.getRef(), dashboardRef: scene.getRef() }));
+ scene.showModal(new ShareModal({ panelRef: vizPanel.getRef() }));
}),
});
diff --git a/public/app/features/dashboard-scene/scene/row-actions/RowActions.tsx b/public/app/features/dashboard-scene/scene/row-actions/RowActions.tsx
index bc38c83bde8..9dadfd0cbad 100644
--- a/public/app/features/dashboard-scene/scene/row-actions/RowActions.tsx
+++ b/public/app/features/dashboard-scene/scene/row-actions/RowActions.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { SceneComponentProps, SceneGridRow, SceneObjectBase, SceneObjectState, VizPanel } from '@grafana/scenes';
diff --git a/public/app/features/dashboard-scene/scene/row-actions/RowOptionsButton.tsx b/public/app/features/dashboard-scene/scene/row-actions/RowOptionsButton.tsx
index ef10894cf36..546c7de8387 100644
--- a/public/app/features/dashboard-scene/scene/row-actions/RowOptionsButton.tsx
+++ b/public/app/features/dashboard-scene/scene/row-actions/RowOptionsButton.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { SceneObject } from '@grafana/scenes';
import { Icon, ModalsController } from '@grafana/ui';
diff --git a/public/app/features/dashboard-scene/scene/row-actions/RowOptionsForm.test.tsx b/public/app/features/dashboard-scene/scene/row-actions/RowOptionsForm.test.tsx
index c6bcf17fb93..f112fb3d465 100644
--- a/public/app/features/dashboard-scene/scene/row-actions/RowOptionsForm.test.tsx
+++ b/public/app/features/dashboard-scene/scene/row-actions/RowOptionsForm.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard-scene/scene/row-actions/RowOptionsForm.tsx b/public/app/features/dashboard-scene/scene/row-actions/RowOptionsForm.tsx
index 538a35382e7..270f7a7f5ea 100644
--- a/public/app/features/dashboard-scene/scene/row-actions/RowOptionsForm.tsx
+++ b/public/app/features/dashboard-scene/scene/row-actions/RowOptionsForm.tsx
@@ -1,4 +1,5 @@
-import React, { useCallback, useState } from 'react';
+import { useCallback, useState } from 'react';
+import * as React from 'react';
import { useForm } from 'react-hook-form';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard-scene/scene/row-actions/RowOptionsModal.tsx b/public/app/features/dashboard-scene/scene/row-actions/RowOptionsModal.tsx
index 2f23db9add7..bad07845d4d 100644
--- a/public/app/features/dashboard-scene/scene/row-actions/RowOptionsModal.tsx
+++ b/public/app/features/dashboard-scene/scene/row-actions/RowOptionsModal.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { SceneObject } from '@grafana/scenes';
import { Modal, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts
index 9a23fb1866e..444676ca936 100644
--- a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts
+++ b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts
@@ -504,6 +504,47 @@ describe('transformSaveModelToScene', () => {
expect(repeater.state.maxPerRow).toBe(8);
});
+ it('When horizontal repeat is set should modify the width to 24', () => {
+ const panel = {
+ title: '',
+ type: 'text-plugin-34',
+ gridPos: { x: 0, y: 0, w: 8, h: 8 },
+ repeat: 'server',
+ repeatDirection: 'h',
+ maxPerRow: 8,
+ };
+
+ const gridItem = buildGridItemForPanel(new PanelModel(panel));
+ const repeater = gridItem as DashboardGridItem;
+
+ expect(repeater.state.maxPerRow).toBe(8);
+ expect(repeater.state.variableName).toBe('server');
+ expect(repeater.state.width).toBe(24);
+ expect(repeater.state.height).toBe(8);
+ expect(repeater.state.repeatDirection).toBe('h');
+ expect(repeater.state.maxPerRow).toBe(8);
+ });
+
+ it('When horizontal repeat is NOT fully configured should not modify the width', () => {
+ const panel = {
+ title: '',
+ type: 'text-plugin-34',
+ gridPos: { x: 0, y: 0, w: 8, h: 8 },
+ repeatDirection: 'h',
+ maxPerRow: 8,
+ };
+
+ const gridItem = buildGridItemForPanel(new PanelModel(panel));
+ const repeater = gridItem as DashboardGridItem;
+
+ expect(repeater.state.maxPerRow).toBe(8);
+ expect(repeater.state.variableName).toBe(undefined);
+ expect(repeater.state.width).toBe(8);
+ expect(repeater.state.height).toBe(8);
+ expect(repeater.state.repeatDirection).toBe(undefined);
+ expect(repeater.state.maxPerRow).toBe(8);
+ });
+
it('should apply query caching options to SceneQueryRunner', () => {
const panel = {
title: '',
diff --git a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts
index aa6bae5fc31..2d76314a1cb 100644
--- a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts
+++ b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts
@@ -443,11 +443,10 @@ export function buildGridItemForLibPanel(panel: PanelModel) {
}
export function buildGridItemForPanel(panel: PanelModel): DashboardGridItem {
- const repeatDirection: RepeatDirection = panel.repeatDirection === 'h' ? 'h' : 'v';
- const repeatOptions = panel.repeat
+ const repeatOptions: Partial<{ variableName: string; repeatDirection: RepeatDirection }> = panel.repeat
? {
variableName: panel.repeat,
- repeatDirection,
+ repeatDirection: panel.repeatDirection === 'h' ? 'h' : 'v',
}
: {};
@@ -501,7 +500,7 @@ export function buildGridItemForPanel(panel: PanelModel): DashboardGridItem {
key: `grid-item-${panel.id}`,
x: panel.gridPos.x,
y: panel.gridPos.y,
- width: repeatDirection === 'h' ? 24 : panel.gridPos.w,
+ width: repeatOptions.repeatDirection === 'h' ? 24 : panel.gridPos.w,
height: panel.gridPos.h,
itemHeight: panel.gridPos.h,
body,
diff --git a/public/app/features/dashboard-scene/settings/AnnotationsEditView.tsx b/public/app/features/dashboard-scene/settings/AnnotationsEditView.tsx
index ded0738d759..7ae1b3887bc 100644
--- a/public/app/features/dashboard-scene/settings/AnnotationsEditView.tsx
+++ b/public/app/features/dashboard-scene/settings/AnnotationsEditView.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { AnnotationQuery, NavModel, NavModelItem, PageLayoutType, getDataSourceRef } from '@grafana/data';
import { getDataSourceSrv } from '@grafana/runtime';
import { SceneComponentProps, SceneObjectBase, VizPanel, dataLayers } from '@grafana/scenes';
diff --git a/public/app/features/dashboard-scene/settings/DashboardLinksEditView.test.tsx b/public/app/features/dashboard-scene/settings/DashboardLinksEditView.test.tsx
index 810d1125de0..a16cdc73ea2 100644
--- a/public/app/features/dashboard-scene/settings/DashboardLinksEditView.test.tsx
+++ b/public/app/features/dashboard-scene/settings/DashboardLinksEditView.test.tsx
@@ -1,5 +1,5 @@
import { render as RTLRender } from '@testing-library/react';
-import React from 'react';
+import * as React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { SceneGridLayout, SceneTimeRange, behaviors } from '@grafana/scenes';
diff --git a/public/app/features/dashboard-scene/settings/DashboardLinksEditView.tsx b/public/app/features/dashboard-scene/settings/DashboardLinksEditView.tsx
index 91d8fef4c8e..1d96da8a43e 100644
--- a/public/app/features/dashboard-scene/settings/DashboardLinksEditView.tsx
+++ b/public/app/features/dashboard-scene/settings/DashboardLinksEditView.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { NavModel, NavModelItem, PageLayoutType, arrayUtils } from '@grafana/data';
import { SceneComponentProps, SceneObjectBase } from '@grafana/scenes';
import { DashboardLink } from '@grafana/schema';
diff --git a/public/app/features/dashboard-scene/settings/DeleteDashboardButton.tsx b/public/app/features/dashboard-scene/settings/DeleteDashboardButton.tsx
index f1fcc2e5a81..fffa45b91db 100644
--- a/public/app/features/dashboard-scene/settings/DeleteDashboardButton.tsx
+++ b/public/app/features/dashboard-scene/settings/DeleteDashboardButton.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useAsyncFn, useToggle } from 'react-use';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard-scene/settings/GeneralSettingsEditView.tsx b/public/app/features/dashboard-scene/settings/GeneralSettingsEditView.tsx
index ec68a8db964..fafe32472c7 100644
--- a/public/app/features/dashboard-scene/settings/GeneralSettingsEditView.tsx
+++ b/public/app/features/dashboard-scene/settings/GeneralSettingsEditView.tsx
@@ -1,4 +1,4 @@
-import React, { ChangeEvent } from 'react';
+import { ChangeEvent } from 'react';
import { PageLayoutType } from '@grafana/data';
import { config } from '@grafana/runtime';
diff --git a/public/app/features/dashboard-scene/settings/JsonModelEditView.tsx b/public/app/features/dashboard-scene/settings/JsonModelEditView.tsx
index 070dcf781c2..30db2382027 100644
--- a/public/app/features/dashboard-scene/settings/JsonModelEditView.tsx
+++ b/public/app/features/dashboard-scene/settings/JsonModelEditView.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { GrafanaTheme2, PageLayoutType } from '@grafana/data';
import { SceneComponentProps, SceneObjectBase, sceneUtils } from '@grafana/scenes';
diff --git a/public/app/features/dashboard-scene/settings/PermissionsEditView.tsx b/public/app/features/dashboard-scene/settings/PermissionsEditView.tsx
index b36e4b1ff70..5dfa1a49659 100644
--- a/public/app/features/dashboard-scene/settings/PermissionsEditView.tsx
+++ b/public/app/features/dashboard-scene/settings/PermissionsEditView.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PageLayoutType } from '@grafana/data';
import { SceneComponentProps, SceneObjectBase } from '@grafana/scenes';
import { Permissions } from 'app/core/components/AccessControl';
diff --git a/public/app/features/dashboard-scene/settings/VariablesEditView.tsx b/public/app/features/dashboard-scene/settings/VariablesEditView.tsx
index be8dea55b3c..23caefd0570 100644
--- a/public/app/features/dashboard-scene/settings/VariablesEditView.tsx
+++ b/public/app/features/dashboard-scene/settings/VariablesEditView.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { NavModel, NavModelItem, PageLayoutType } from '@grafana/data';
import { SceneComponentProps, SceneObjectBase, SceneVariable, SceneVariables, sceneGraph } from '@grafana/scenes';
import { Page } from 'app/core/components/Page/Page';
diff --git a/public/app/features/dashboard-scene/settings/VersionsEditView.tsx b/public/app/features/dashboard-scene/settings/VersionsEditView.tsx
index 93cfda6b644..c2acbb9b7af 100644
--- a/public/app/features/dashboard-scene/settings/VersionsEditView.tsx
+++ b/public/app/features/dashboard-scene/settings/VersionsEditView.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { PageLayoutType, dateTimeFormat, dateTimeFormatTimeAgo } from '@grafana/data';
import { SceneComponentProps, SceneObjectBase, sceneGraph } from '@grafana/scenes';
diff --git a/public/app/features/dashboard-scene/settings/annotations/AngularEditorLoader.tsx b/public/app/features/dashboard-scene/settings/annotations/AngularEditorLoader.tsx
index bf04402ccbb..edd42f4b7ff 100644
--- a/public/app/features/dashboard-scene/settings/annotations/AngularEditorLoader.tsx
+++ b/public/app/features/dashboard-scene/settings/annotations/AngularEditorLoader.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
import { AnnotationQuery, DataSourceApi } from '@grafana/data';
import { AngularComponent, getAngularLoader } from '@grafana/runtime';
@@ -17,7 +17,7 @@ interface ScopeProps {
};
}
-export class AngularEditorLoader extends React.PureComponent {
+export class AngularEditorLoader extends PureComponent {
ref: HTMLDivElement | null = null;
angularComponent?: AngularComponent;
scopeProps?: ScopeProps;
diff --git a/public/app/features/dashboard-scene/settings/annotations/AnnotationSettingsEdit.test.tsx b/public/app/features/dashboard-scene/settings/annotations/AnnotationSettingsEdit.test.tsx
index f2ce2c54bf3..96f849bf01a 100644
--- a/public/app/features/dashboard-scene/settings/annotations/AnnotationSettingsEdit.test.tsx
+++ b/public/app/features/dashboard-scene/settings/annotations/AnnotationSettingsEdit.test.tsx
@@ -1,6 +1,5 @@
import { act, render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { of } from 'rxjs';
import {
diff --git a/public/app/features/dashboard-scene/settings/annotations/AnnotationSettingsEdit.tsx b/public/app/features/dashboard-scene/settings/annotations/AnnotationSettingsEdit.tsx
index d90845156d6..1fe19e12cc7 100644
--- a/public/app/features/dashboard-scene/settings/annotations/AnnotationSettingsEdit.tsx
+++ b/public/app/features/dashboard-scene/settings/annotations/AnnotationSettingsEdit.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
+import * as React from 'react';
import { useAsync } from 'react-use';
import {
diff --git a/public/app/features/dashboard-scene/settings/annotations/AnnotationSettingsList.test.tsx b/public/app/features/dashboard-scene/settings/annotations/AnnotationSettingsList.test.tsx
index ab7a07b7393..9f379ef0dcd 100644
--- a/public/app/features/dashboard-scene/settings/annotations/AnnotationSettingsList.test.tsx
+++ b/public/app/features/dashboard-scene/settings/annotations/AnnotationSettingsList.test.tsx
@@ -1,6 +1,5 @@
import { act, render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { AnnotationQuery } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard-scene/settings/annotations/AnnotationSettingsList.tsx b/public/app/features/dashboard-scene/settings/annotations/AnnotationSettingsList.tsx
index 154851834e2..9e7ed1d814e 100644
--- a/public/app/features/dashboard-scene/settings/annotations/AnnotationSettingsList.tsx
+++ b/public/app/features/dashboard-scene/settings/annotations/AnnotationSettingsList.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { AnnotationQuery } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard-scene/settings/links/DashboardLinkForm.tsx b/public/app/features/dashboard-scene/settings/links/DashboardLinkForm.tsx
index eb4cd33700e..bd96ef16289 100644
--- a/public/app/features/dashboard-scene/settings/links/DashboardLinkForm.tsx
+++ b/public/app/features/dashboard-scene/settings/links/DashboardLinkForm.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { SelectableValue } from '@grafana/data';
import { DashboardLink } from '@grafana/schema';
diff --git a/public/app/features/dashboard-scene/settings/links/DashboardLinkList.tsx b/public/app/features/dashboard-scene/settings/links/DashboardLinkList.tsx
index 6d3555ab6f8..8b4fd73ca84 100644
--- a/public/app/features/dashboard-scene/settings/links/DashboardLinkList.tsx
+++ b/public/app/features/dashboard-scene/settings/links/DashboardLinkList.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { DashboardLink } from '@grafana/schema';
diff --git a/public/app/features/dashboard-scene/settings/variables/VariableEditorForm.tsx b/public/app/features/dashboard-scene/settings/variables/VariableEditorForm.tsx
index e94b5b09044..4e2e2777825 100644
--- a/public/app/features/dashboard-scene/settings/variables/VariableEditorForm.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/VariableEditorForm.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { FormEvent, useCallback, useState } from 'react';
+import { FormEvent, useCallback, useState } from 'react';
import { useAsyncFn } from 'react-use';
import { lastValueFrom } from 'rxjs';
diff --git a/public/app/features/dashboard-scene/settings/variables/VariableEditorList.tsx b/public/app/features/dashboard-scene/settings/variables/VariableEditorList.tsx
index cc2fcb41ef6..0464169940a 100644
--- a/public/app/features/dashboard-scene/settings/variables/VariableEditorList.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/VariableEditorList.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { ReactElement } from 'react';
+import { ReactElement } from 'react';
import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard-scene/settings/variables/VariableEditorListRow.tsx b/public/app/features/dashboard-scene/settings/variables/VariableEditorListRow.tsx
index 0a2305e78a0..d378a280a8f 100644
--- a/public/app/features/dashboard-scene/settings/variables/VariableEditorListRow.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/VariableEditorListRow.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { ReactElement, useState } from 'react';
+import { ReactElement, useState } from 'react';
import { Draggable } from 'react-beautiful-dnd';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/dashboard-scene/settings/variables/components/AdHocVariableForm.test.tsx b/public/app/features/dashboard-scene/settings/variables/components/AdHocVariableForm.test.tsx
index 610a2a9eea9..3aae0735cce 100644
--- a/public/app/features/dashboard-scene/settings/variables/components/AdHocVariableForm.test.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/components/AdHocVariableForm.test.tsx
@@ -1,6 +1,6 @@
import { act, render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
+import * as React from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { mockDataSource } from 'app/features/alerting/unified/mocks';
diff --git a/public/app/features/dashboard-scene/settings/variables/components/AdHocVariableForm.tsx b/public/app/features/dashboard-scene/settings/variables/components/AdHocVariableForm.tsx
index 415e9f6cc21..e683e1ea981 100644
--- a/public/app/features/dashboard-scene/settings/variables/components/AdHocVariableForm.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/components/AdHocVariableForm.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { DataSourceInstanceSettings, MetricFindValue, readCSV } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard-scene/settings/variables/components/ConstantVariableForm.tsx b/public/app/features/dashboard-scene/settings/variables/components/ConstantVariableForm.tsx
index 262429fc62b..212d5d9093b 100644
--- a/public/app/features/dashboard-scene/settings/variables/components/ConstantVariableForm.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/components/ConstantVariableForm.tsx
@@ -1,4 +1,4 @@
-import React, { FormEvent } from 'react';
+import { FormEvent } from 'react';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard-scene/settings/variables/components/CustomVariableForm.test.tsx b/public/app/features/dashboard-scene/settings/variables/components/CustomVariableForm.test.tsx
index ec55c94b26d..334383998df 100644
--- a/public/app/features/dashboard-scene/settings/variables/components/CustomVariableForm.test.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/components/CustomVariableForm.test.tsx
@@ -1,5 +1,4 @@
import { render, fireEvent } from '@testing-library/react';
-import React from 'react';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard-scene/settings/variables/components/CustomVariableForm.tsx b/public/app/features/dashboard-scene/settings/variables/components/CustomVariableForm.tsx
index 1850b1c5774..5c11178141a 100644
--- a/public/app/features/dashboard-scene/settings/variables/components/CustomVariableForm.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/components/CustomVariableForm.tsx
@@ -1,4 +1,4 @@
-import React, { FormEvent } from 'react';
+import { FormEvent } from 'react';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard-scene/settings/variables/components/DataSourceVariableForm.tsx b/public/app/features/dashboard-scene/settings/variables/components/DataSourceVariableForm.tsx
index ac77b8c747c..52300ca4c5d 100644
--- a/public/app/features/dashboard-scene/settings/variables/components/DataSourceVariableForm.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/components/DataSourceVariableForm.tsx
@@ -1,4 +1,4 @@
-import React, { FormEvent } from 'react';
+import { FormEvent } from 'react';
import { SelectableValue } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard-scene/settings/variables/components/GroupByVariableForm.test.tsx b/public/app/features/dashboard-scene/settings/variables/components/GroupByVariableForm.test.tsx
index e59b0e4f3e0..a959b73e5bd 100644
--- a/public/app/features/dashboard-scene/settings/variables/components/GroupByVariableForm.test.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/components/GroupByVariableForm.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { byTestId } from 'testing-library-selector';
import { VariableSupportType } from '@grafana/data';
diff --git a/public/app/features/dashboard-scene/settings/variables/components/GroupByVariableForm.tsx b/public/app/features/dashboard-scene/settings/variables/components/GroupByVariableForm.tsx
index f982ab92361..20fd841727b 100644
--- a/public/app/features/dashboard-scene/settings/variables/components/GroupByVariableForm.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/components/GroupByVariableForm.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { DataSourceInstanceSettings, MetricFindValue, readCSV } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard-scene/settings/variables/components/IntervalVariableForm.tsx b/public/app/features/dashboard-scene/settings/variables/components/IntervalVariableForm.tsx
index 3f525e2d8fe..a921ff96e50 100644
--- a/public/app/features/dashboard-scene/settings/variables/components/IntervalVariableForm.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/components/IntervalVariableForm.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { ChangeEvent, FormEvent } from 'react';
+import { ChangeEvent, FormEvent } from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard-scene/settings/variables/components/QueryEditor.tsx b/public/app/features/dashboard-scene/settings/variables/components/QueryEditor.tsx
index 18436c85c2b..14be6030ce0 100644
--- a/public/app/features/dashboard-scene/settings/variables/components/QueryEditor.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/components/QueryEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { DataSourceApi, LoadingState, TimeRange } from '@grafana/data';
import { getTemplateSrv } from '@grafana/runtime';
import { QueryVariable } from '@grafana/scenes';
diff --git a/public/app/features/dashboard-scene/settings/variables/components/QueryVariableForm.test.tsx b/public/app/features/dashboard-scene/settings/variables/components/QueryVariableForm.test.tsx
index 0e154ed447d..8000aebdd9a 100644
--- a/public/app/features/dashboard-scene/settings/variables/components/QueryVariableForm.test.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/components/QueryVariableForm.test.tsx
@@ -1,6 +1,7 @@
import { act, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { FormEvent } from 'react';
+import { FormEvent } from 'react';
+import * as React from 'react';
import { of } from 'rxjs';
import {
diff --git a/public/app/features/dashboard-scene/settings/variables/components/QueryVariableForm.tsx b/public/app/features/dashboard-scene/settings/variables/components/QueryVariableForm.tsx
index a1a9cfbc3f4..9a8e0c73078 100644
--- a/public/app/features/dashboard-scene/settings/variables/components/QueryVariableForm.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/components/QueryVariableForm.tsx
@@ -1,4 +1,4 @@
-import React, { FormEvent } from 'react';
+import { FormEvent } from 'react';
import { useAsync } from 'react-use';
import { DataSourceInstanceSettings, SelectableValue, TimeRange } from '@grafana/data';
diff --git a/public/app/features/dashboard-scene/settings/variables/components/SelectionOptionsForm.tsx b/public/app/features/dashboard-scene/settings/variables/components/SelectionOptionsForm.tsx
index 79a661c4ef0..de2ba28a91f 100644
--- a/public/app/features/dashboard-scene/settings/variables/components/SelectionOptionsForm.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/components/SelectionOptionsForm.tsx
@@ -1,4 +1,4 @@
-import React, { ChangeEvent, FormEvent } from 'react';
+import { ChangeEvent, FormEvent } from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { Stack } from '@grafana/ui';
diff --git a/public/app/features/dashboard-scene/settings/variables/components/TextBoxVariableForm.test.tsx b/public/app/features/dashboard-scene/settings/variables/components/TextBoxVariableForm.test.tsx
index a1551b0028f..044d91c92ca 100644
--- a/public/app/features/dashboard-scene/settings/variables/components/TextBoxVariableForm.test.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/components/TextBoxVariableForm.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TextBoxVariableForm } from './TextBoxVariableForm';
diff --git a/public/app/features/dashboard-scene/settings/variables/components/TextBoxVariableForm.tsx b/public/app/features/dashboard-scene/settings/variables/components/TextBoxVariableForm.tsx
index 9715fac4a17..df1953f14f5 100644
--- a/public/app/features/dashboard-scene/settings/variables/components/TextBoxVariableForm.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/components/TextBoxVariableForm.tsx
@@ -1,4 +1,4 @@
-import React, { FormEvent } from 'react';
+import { FormEvent } from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { VariableLegend } from 'app/features/dashboard-scene/settings/variables/components/VariableLegend';
diff --git a/public/app/features/dashboard-scene/settings/variables/components/VariableCheckboxField.tsx b/public/app/features/dashboard-scene/settings/variables/components/VariableCheckboxField.tsx
index 730cee62336..61610109ee5 100644
--- a/public/app/features/dashboard-scene/settings/variables/components/VariableCheckboxField.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/components/VariableCheckboxField.tsx
@@ -1,5 +1,6 @@
import { useId } from '@react-aria/utils';
-import React, { ChangeEvent, PropsWithChildren, ReactElement } from 'react';
+import { ChangeEvent, PropsWithChildren, ReactElement } from 'react';
+import * as React from 'react';
import { Checkbox } from '@grafana/ui';
diff --git a/public/app/features/dashboard-scene/settings/variables/components/VariableHideSelect.tsx b/public/app/features/dashboard-scene/settings/variables/components/VariableHideSelect.tsx
index 839eb132364..272d0e40ed4 100644
--- a/public/app/features/dashboard-scene/settings/variables/components/VariableHideSelect.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/components/VariableHideSelect.tsx
@@ -1,4 +1,4 @@
-import React, { PropsWithChildren, useMemo } from 'react';
+import { PropsWithChildren, useMemo } from 'react';
import { VariableType, VariableHide } from '@grafana/data';
import { Field, RadioButtonGroup } from '@grafana/ui';
diff --git a/public/app/features/dashboard-scene/settings/variables/components/VariableLegend.tsx b/public/app/features/dashboard-scene/settings/variables/components/VariableLegend.tsx
index 55dd01203ce..d0d3ce24cee 100644
--- a/public/app/features/dashboard-scene/settings/variables/components/VariableLegend.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/components/VariableLegend.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Legend, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/dashboard-scene/settings/variables/components/VariableSelectField.tsx b/public/app/features/dashboard-scene/settings/variables/components/VariableSelectField.tsx
index 9f0024a7ab1..e7140b69021 100644
--- a/public/app/features/dashboard-scene/settings/variables/components/VariableSelectField.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/components/VariableSelectField.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { PropsWithChildren, useId } from 'react';
+import { PropsWithChildren, useId } from 'react';
+import * as React from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { Field, Select, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/dashboard-scene/settings/variables/components/VariableTextAreaField.tsx b/public/app/features/dashboard-scene/settings/variables/components/VariableTextAreaField.tsx
index b7382c9239a..ae3e82ac525 100644
--- a/public/app/features/dashboard-scene/settings/variables/components/VariableTextAreaField.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/components/VariableTextAreaField.tsx
@@ -1,6 +1,7 @@
import { css } from '@emotion/css';
import { useId } from '@react-aria/utils';
-import React, { FormEvent, PropsWithChildren, ReactElement } from 'react';
+import { FormEvent, PropsWithChildren, ReactElement } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Field, TextArea, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/dashboard-scene/settings/variables/components/VariableTextField.tsx b/public/app/features/dashboard-scene/settings/variables/components/VariableTextField.tsx
index 8b6ccf05d48..6de619d8f9d 100644
--- a/public/app/features/dashboard-scene/settings/variables/components/VariableTextField.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/components/VariableTextField.tsx
@@ -1,5 +1,6 @@
import { useId } from '@react-aria/utils';
-import React, { FormEvent, PropsWithChildren } from 'react';
+import { FormEvent, PropsWithChildren } from 'react';
+import * as React from 'react';
import { Field, Input } from '@grafana/ui';
diff --git a/public/app/features/dashboard-scene/settings/variables/components/VariableTypeSelect.tsx b/public/app/features/dashboard-scene/settings/variables/components/VariableTypeSelect.tsx
index 06235597388..4d18833eb1d 100644
--- a/public/app/features/dashboard-scene/settings/variables/components/VariableTypeSelect.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/components/VariableTypeSelect.tsx
@@ -1,4 +1,4 @@
-import React, { PropsWithChildren, useMemo } from 'react';
+import { PropsWithChildren, useMemo } from 'react';
import { SelectableValue, VariableType } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard-scene/settings/variables/components/VariableValuesPreview.tsx b/public/app/features/dashboard-scene/settings/variables/components/VariableValuesPreview.tsx
index 0265144ba53..3bc5e915da6 100644
--- a/public/app/features/dashboard-scene/settings/variables/components/VariableValuesPreview.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/components/VariableValuesPreview.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { MouseEvent, useCallback, useEffect, useState } from 'react';
+import { MouseEvent, useCallback, useEffect, useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard-scene/settings/variables/editors/AdHocFiltersVariableEditor.test.tsx b/public/app/features/dashboard-scene/settings/variables/editors/AdHocFiltersVariableEditor.test.tsx
index b80caf607e9..eaeee5427fa 100644
--- a/public/app/features/dashboard-scene/settings/variables/editors/AdHocFiltersVariableEditor.test.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/editors/AdHocFiltersVariableEditor.test.tsx
@@ -1,6 +1,6 @@
import { render, act } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
+import * as React from 'react';
import { of } from 'rxjs';
import {
diff --git a/public/app/features/dashboard-scene/settings/variables/editors/AdHocFiltersVariableEditor.tsx b/public/app/features/dashboard-scene/settings/variables/editors/AdHocFiltersVariableEditor.tsx
index 8aa2a2a6daf..dc03d1b347b 100644
--- a/public/app/features/dashboard-scene/settings/variables/editors/AdHocFiltersVariableEditor.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/editors/AdHocFiltersVariableEditor.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useAsync } from 'react-use';
import { DataSourceInstanceSettings, MetricFindValue } from '@grafana/data';
diff --git a/public/app/features/dashboard-scene/settings/variables/editors/ConstantVariableEditor.test.tsx b/public/app/features/dashboard-scene/settings/variables/editors/ConstantVariableEditor.test.tsx
index dbb1b8f7ab3..94b26d3537c 100644
--- a/public/app/features/dashboard-scene/settings/variables/editors/ConstantVariableEditor.test.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/editors/ConstantVariableEditor.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { ConstantVariable } from '@grafana/scenes';
diff --git a/public/app/features/dashboard-scene/settings/variables/editors/ConstantVariableEditor.tsx b/public/app/features/dashboard-scene/settings/variables/editors/ConstantVariableEditor.tsx
index de4d3203dbd..10f42d992e1 100644
--- a/public/app/features/dashboard-scene/settings/variables/editors/ConstantVariableEditor.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/editors/ConstantVariableEditor.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { ConstantVariable } from '@grafana/scenes';
diff --git a/public/app/features/dashboard-scene/settings/variables/editors/CustomVariableEditor.test.tsx b/public/app/features/dashboard-scene/settings/variables/editors/CustomVariableEditor.test.tsx
index 3a63f900cea..90292024c02 100644
--- a/public/app/features/dashboard-scene/settings/variables/editors/CustomVariableEditor.test.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/editors/CustomVariableEditor.test.tsx
@@ -1,5 +1,4 @@
import { render, fireEvent } from '@testing-library/react';
-import React from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { CustomVariable } from '@grafana/scenes';
diff --git a/public/app/features/dashboard-scene/settings/variables/editors/CustomVariableEditor.tsx b/public/app/features/dashboard-scene/settings/variables/editors/CustomVariableEditor.tsx
index 724218276b2..9b507c34a66 100644
--- a/public/app/features/dashboard-scene/settings/variables/editors/CustomVariableEditor.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/editors/CustomVariableEditor.tsx
@@ -1,4 +1,4 @@
-import React, { FormEvent } from 'react';
+import { FormEvent } from 'react';
import { CustomVariable } from '@grafana/scenes';
diff --git a/public/app/features/dashboard-scene/settings/variables/editors/DataSourceVariableEditor.test.tsx b/public/app/features/dashboard-scene/settings/variables/editors/DataSourceVariableEditor.test.tsx
index 0b1e4c333a9..8dd102b49f3 100644
--- a/public/app/features/dashboard-scene/settings/variables/editors/DataSourceVariableEditor.test.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/editors/DataSourceVariableEditor.test.tsx
@@ -2,7 +2,6 @@
import { render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { DataSourceVariable } from '@grafana/scenes';
diff --git a/public/app/features/dashboard-scene/settings/variables/editors/DataSourceVariableEditor.tsx b/public/app/features/dashboard-scene/settings/variables/editors/DataSourceVariableEditor.tsx
index 6c36f94e3ef..82deb3965fd 100644
--- a/public/app/features/dashboard-scene/settings/variables/editors/DataSourceVariableEditor.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/editors/DataSourceVariableEditor.tsx
@@ -1,4 +1,4 @@
-import React, { FormEvent } from 'react';
+import { FormEvent } from 'react';
import { SelectableValue } from '@grafana/data';
import { DataSourceVariable } from '@grafana/scenes';
diff --git a/public/app/features/dashboard-scene/settings/variables/editors/GroupByVariableEditor.test.tsx b/public/app/features/dashboard-scene/settings/variables/editors/GroupByVariableEditor.test.tsx
index 48b01d8f08f..689db0d1abc 100644
--- a/public/app/features/dashboard-scene/settings/variables/editors/GroupByVariableEditor.test.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/editors/GroupByVariableEditor.test.tsx
@@ -1,6 +1,5 @@
import { act, render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { MetricFindValue, VariableSupportType } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard-scene/settings/variables/editors/GroupByVariableEditor.tsx b/public/app/features/dashboard-scene/settings/variables/editors/GroupByVariableEditor.tsx
index 01cffb31c84..808dee6dad2 100644
--- a/public/app/features/dashboard-scene/settings/variables/editors/GroupByVariableEditor.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/editors/GroupByVariableEditor.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useAsync } from 'react-use';
import { DataSourceInstanceSettings, DataSourceRef, MetricFindValue } from '@grafana/data';
diff --git a/public/app/features/dashboard-scene/settings/variables/editors/IntervalVariableEditor.test.tsx b/public/app/features/dashboard-scene/settings/variables/editors/IntervalVariableEditor.test.tsx
index 5e1ddd110e2..ef51fde16f6 100644
--- a/public/app/features/dashboard-scene/settings/variables/editors/IntervalVariableEditor.test.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/editors/IntervalVariableEditor.test.tsx
@@ -2,7 +2,6 @@
import { render, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { IntervalVariable } from '@grafana/scenes';
diff --git a/public/app/features/dashboard-scene/settings/variables/editors/IntervalVariableEditor.tsx b/public/app/features/dashboard-scene/settings/variables/editors/IntervalVariableEditor.tsx
index 3ffc414d7f4..7b513d34127 100644
--- a/public/app/features/dashboard-scene/settings/variables/editors/IntervalVariableEditor.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/editors/IntervalVariableEditor.tsx
@@ -1,4 +1,4 @@
-import React, { ChangeEvent, FormEvent } from 'react';
+import { ChangeEvent, FormEvent } from 'react';
import { SelectableValue } from '@grafana/data';
import { IntervalVariable } from '@grafana/scenes';
diff --git a/public/app/features/dashboard-scene/settings/variables/editors/QueryVariableEditor.test.tsx b/public/app/features/dashboard-scene/settings/variables/editors/QueryVariableEditor.test.tsx
index 10b7832ff05..d96bb9516ca 100644
--- a/public/app/features/dashboard-scene/settings/variables/editors/QueryVariableEditor.test.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/editors/QueryVariableEditor.test.tsx
@@ -1,6 +1,6 @@
import { getByRole, render, screen, act, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
+import * as React from 'react';
import { lastValueFrom, of } from 'rxjs';
import {
diff --git a/public/app/features/dashboard-scene/settings/variables/editors/QueryVariableEditor.tsx b/public/app/features/dashboard-scene/settings/variables/editors/QueryVariableEditor.tsx
index c0f64a0cb52..539290d26e9 100644
--- a/public/app/features/dashboard-scene/settings/variables/editors/QueryVariableEditor.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/editors/QueryVariableEditor.tsx
@@ -1,4 +1,5 @@
-import React, { FormEvent } from 'react';
+import { FormEvent } from 'react';
+import * as React from 'react';
import { SelectableValue, DataSourceInstanceSettings } from '@grafana/data';
import { QueryVariable, sceneGraph } from '@grafana/scenes';
diff --git a/public/app/features/dashboard-scene/settings/variables/editors/TextBoxVariableEditor.test.tsx b/public/app/features/dashboard-scene/settings/variables/editors/TextBoxVariableEditor.test.tsx
index 063a1d033f3..ea7489abd00 100644
--- a/public/app/features/dashboard-scene/settings/variables/editors/TextBoxVariableEditor.test.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/editors/TextBoxVariableEditor.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TextBoxVariable } from '@grafana/scenes';
diff --git a/public/app/features/dashboard-scene/settings/variables/editors/TextBoxVariableEditor.tsx b/public/app/features/dashboard-scene/settings/variables/editors/TextBoxVariableEditor.tsx
index 2f7bbe256ef..5f5124198f8 100644
--- a/public/app/features/dashboard-scene/settings/variables/editors/TextBoxVariableEditor.tsx
+++ b/public/app/features/dashboard-scene/settings/variables/editors/TextBoxVariableEditor.tsx
@@ -1,4 +1,4 @@
-import React, { FormEvent } from 'react';
+import { FormEvent } from 'react';
import { TextBoxVariable } from '@grafana/scenes';
diff --git a/public/app/features/dashboard-scene/settings/version-history/DiffGroup.tsx b/public/app/features/dashboard-scene/settings/version-history/DiffGroup.tsx
index cbded5fd9ce..e678f9edce0 100644
--- a/public/app/features/dashboard-scene/settings/version-history/DiffGroup.tsx
+++ b/public/app/features/dashboard-scene/settings/version-history/DiffGroup.tsx
@@ -1,6 +1,5 @@
import { css } from '@emotion/css';
import { last } from 'lodash';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/dashboard-scene/settings/version-history/DiffTitle.tsx b/public/app/features/dashboard-scene/settings/version-history/DiffTitle.tsx
index e1bfa6b3aa1..19d7b9ffd3e 100644
--- a/public/app/features/dashboard-scene/settings/version-history/DiffTitle.tsx
+++ b/public/app/features/dashboard-scene/settings/version-history/DiffTitle.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2, Icon } from '@grafana/ui';
diff --git a/public/app/features/dashboard-scene/settings/version-history/DiffValues.tsx b/public/app/features/dashboard-scene/settings/version-history/DiffValues.tsx
index c9ff1247f90..d996c5718a1 100644
--- a/public/app/features/dashboard-scene/settings/version-history/DiffValues.tsx
+++ b/public/app/features/dashboard-scene/settings/version-history/DiffValues.tsx
@@ -1,6 +1,5 @@
import { css } from '@emotion/css';
import { isArray, isObject, isUndefined } from 'lodash';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2, Icon } from '@grafana/ui';
diff --git a/public/app/features/dashboard-scene/settings/version-history/DiffViewer.tsx b/public/app/features/dashboard-scene/settings/version-history/DiffViewer.tsx
index 9422a8ec1a9..6ec14cc51ed 100644
--- a/public/app/features/dashboard-scene/settings/version-history/DiffViewer.tsx
+++ b/public/app/features/dashboard-scene/settings/version-history/DiffViewer.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import ReactDiffViewer, { ReactDiffViewerProps, DiffMethod } from 'react-diff-viewer';
import tinycolor from 'tinycolor2';
diff --git a/public/app/features/dashboard-scene/settings/version-history/RevertDashboardModal.tsx b/public/app/features/dashboard-scene/settings/version-history/RevertDashboardModal.tsx
index 6d27baf3f17..c3e44c132d1 100644
--- a/public/app/features/dashboard-scene/settings/version-history/RevertDashboardModal.tsx
+++ b/public/app/features/dashboard-scene/settings/version-history/RevertDashboardModal.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { ConfirmModal } from '@grafana/ui';
import { useAppNotification } from 'app/core/copy/appNotification';
diff --git a/public/app/features/dashboard-scene/settings/version-history/VersionHistoryButtons.tsx b/public/app/features/dashboard-scene/settings/version-history/VersionHistoryButtons.tsx
index 073b9c64d8d..1287b059982 100644
--- a/public/app/features/dashboard-scene/settings/version-history/VersionHistoryButtons.tsx
+++ b/public/app/features/dashboard-scene/settings/version-history/VersionHistoryButtons.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Tooltip, Button, Stack } from '@grafana/ui';
type VersionsButtonsType = {
diff --git a/public/app/features/dashboard-scene/settings/version-history/VersionHistoryComparison.tsx b/public/app/features/dashboard-scene/settings/version-history/VersionHistoryComparison.tsx
index 7faaaa587b5..02be0c099b7 100644
--- a/public/app/features/dashboard-scene/settings/version-history/VersionHistoryComparison.tsx
+++ b/public/app/features/dashboard-scene/settings/version-history/VersionHistoryComparison.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Button, ModalsController, CollapsableSection, useStyles2, Stack, Icon, Box } from '@grafana/ui';
diff --git a/public/app/features/dashboard-scene/settings/version-history/VersionHistoryHeader.tsx b/public/app/features/dashboard-scene/settings/version-history/VersionHistoryHeader.tsx
index 6c3738f9057..05987ee2838 100644
--- a/public/app/features/dashboard-scene/settings/version-history/VersionHistoryHeader.tsx
+++ b/public/app/features/dashboard-scene/settings/version-history/VersionHistoryHeader.tsx
@@ -1,6 +1,5 @@
import { css } from '@emotion/css';
import { noop } from 'lodash';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Icon, IconButton, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/dashboard-scene/settings/version-history/VersionHistoryTable.tsx b/public/app/features/dashboard-scene/settings/version-history/VersionHistoryTable.tsx
index a347c72eed5..5ae97bc63e7 100644
--- a/public/app/features/dashboard-scene/settings/version-history/VersionHistoryTable.tsx
+++ b/public/app/features/dashboard-scene/settings/version-history/VersionHistoryTable.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Checkbox, Button, Tag, ModalsController, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/dashboard-scene/sharing/ShareButton/ShareButton.test.tsx b/public/app/features/dashboard-scene/sharing/ShareButton/ShareButton.test.tsx
index 3fec88b051c..842b257470a 100644
--- a/public/app/features/dashboard-scene/sharing/ShareButton/ShareButton.test.tsx
+++ b/public/app/features/dashboard-scene/sharing/ShareButton/ShareButton.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { selectors as e2eSelectors } from '@grafana/e2e-selectors';
import { SceneGridLayout, SceneTimeRange, VizPanel } from '@grafana/scenes';
@@ -24,16 +23,6 @@ describe('ShareButton', () => {
expect(await screen.findByTestId(selector.shareLink)).toBeInTheDocument();
expect(await screen.findByTestId(selector.arrowMenu)).toBeInTheDocument();
});
-
- it('should call createAndCopyDashboardShortLink when share link clicked', async () => {
- setup();
-
- const shareLink = await screen.findByTestId(selector.shareLink);
-
- await userEvent.click(shareLink);
- expect(createAndCopyDashboardShortLinkMock).toHaveBeenCalled();
- });
-
it('should render menu when arrow button clicked', async () => {
setup();
diff --git a/public/app/features/dashboard-scene/sharing/ShareButton/ShareButton.tsx b/public/app/features/dashboard-scene/sharing/ShareButton/ShareButton.tsx
index 01fcf60706b..cc7518fc85f 100644
--- a/public/app/features/dashboard-scene/sharing/ShareButton/ShareButton.tsx
+++ b/public/app/features/dashboard-scene/sharing/ShareButton/ShareButton.tsx
@@ -1,9 +1,10 @@
-import React, { useCallback, useState } from 'react';
+import { useCallback, useState } from 'react';
import { useAsyncFn } from 'react-use';
import { selectors as e2eSelectors } from '@grafana/e2e-selectors';
import { VizPanel } from '@grafana/scenes';
import { Button, ButtonGroup, Dropdown } from '@grafana/ui';
+import { t, Trans } from 'app/core/internationalization';
import { DashboardScene } from '../../scene/DashboardScene';
import { DashboardInteractions } from '../../utils/interactions';
@@ -32,8 +33,13 @@ export default function ShareButton({ dashboard, panel }: { dashboard: Dashboard
return (
-
- Share
+
+ Share
diff --git a/public/app/features/dashboard-scene/sharing/ShareButton/ShareMenu.test.tsx b/public/app/features/dashboard-scene/sharing/ShareButton/ShareMenu.test.tsx
index 0cb71d0cae1..0da03f45dda 100644
--- a/public/app/features/dashboard-scene/sharing/ShareButton/ShareMenu.test.tsx
+++ b/public/app/features/dashboard-scene/sharing/ShareButton/ShareMenu.test.tsx
@@ -1,6 +1,4 @@
import { render, screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import React from 'react';
import { selectors as e2eSelectors } from '@grafana/e2e-selectors';
import { SceneGridLayout, SceneTimeRange, VizPanel } from '@grafana/scenes';
@@ -35,14 +33,6 @@ describe('ShareMenu', () => {
expect(await screen.queryByTestId(selector.shareExternally)).not.toBeInTheDocument();
});
- it('should call createAndCopyDashboardShortLink when share internally clicked', async () => {
- setup();
-
- const shareLink = await screen.findByTestId(selector.shareInternally);
-
- await userEvent.click(shareLink);
- expect(createAndCopyDashboardShortLinkMock).toHaveBeenCalled();
- });
});
function setup() {
diff --git a/public/app/features/dashboard-scene/sharing/ShareButton/ShareMenu.tsx b/public/app/features/dashboard-scene/sharing/ShareButton/ShareMenu.tsx
index 0962d87a1c0..9ccf3be0654 100644
--- a/public/app/features/dashboard-scene/sharing/ShareButton/ShareMenu.tsx
+++ b/public/app/features/dashboard-scene/sharing/ShareButton/ShareMenu.tsx
@@ -1,6 +1,3 @@
-import React from 'react';
-import { useAsyncFn } from 'react-use';
-
import { selectors as e2eSelectors } from '@grafana/e2e-selectors';
import { VizPanel } from '@grafana/scenes';
import { Menu } from '@grafana/ui';
@@ -11,15 +8,20 @@ import { DashboardScene } from '../../scene/DashboardScene';
import { ShareDrawer } from '../ShareDrawer/ShareDrawer';
import { ShareExternally } from './share-externally/ShareExternally';
+import { ShareInternally } from './share-internally/ShareInternally';
import { ShareSnapshot } from './share-snapshot/ShareSnapshot';
-import { buildShareUrl } from './utils';
const newShareButtonSelector = e2eSelectors.pages.Dashboard.DashNav.newShareButton.menu;
export default function ShareMenu({ dashboard, panel }: { dashboard: DashboardScene; panel?: VizPanel }) {
- const [_, buildUrl] = useAsyncFn(async () => {
- return await buildShareUrl(dashboard, panel);
- }, [dashboard]);
+ const onShareInternallyClick = () => {
+ const drawer = new ShareDrawer({
+ title: t('share-dashboard.menu.share-internally-title', 'Share internally'),
+ body: new ShareInternally({ panelRef: panel?.getRef() }),
+ });
+
+ dashboard.showModal(drawer);
+ };
const onShareExternallyClick = () => {
const drawer = new ShareDrawer({
@@ -46,7 +48,7 @@ export default function ShareMenu({ dashboard, panel }: { dashboard: DashboardSc
label={t('share-dashboard.menu.share-internally-title', 'Share internally')}
description={t('share-dashboard.menu.share-internally-description', 'Advanced settings')}
icon="building"
- onClick={buildUrl}
+ onClick={onShareInternallyClick}
/>
{isPublicDashboardsEnabled() && (
}) {
+ const { useAbsoluteTimeRange, useShortUrl, theme } = getShareLinkConfiguration();
+ super({
+ ...state,
+ useLockedTime: useAbsoluteTimeRange,
+ useShortUrl,
+ selectedTheme: theme,
+ });
+ }
+}
+
+function ShareInternallyRenderer({ model }: SceneComponentProps) {
+ const styles = useStyles2(getStyles);
+ const { useLockedTime, useShortUrl, selectedTheme, isBuildUrlLoading } = model.useState();
+
+ return (
+ <>
+
+
+ Updating your settings will modify the default copy link to include these changes.
+
+
+
+
+
+ Create a personalized, direct link to share your dashboard within your organization, with the following
+ customization settings:
+
+
+
+
+
+
+
+
+
+ Lock time range
+
+
+
+
+
+ Shorten link
+
+
+
+
+
+ {isBuildUrlLoading && }
+
+
+
+ Copy link
+
+ >
+ );
+}
+
+const getStyles = (theme: GrafanaTheme2) => ({
+ configDescription: css({
+ marginBottom: theme.spacing(2),
+ }),
+ copyButtonContainer: css({
+ marginTop: theme.spacing(2),
+ }),
+});
diff --git a/public/app/features/dashboard-scene/sharing/ShareButton/share-snapshot/CreateSnapshot.tsx b/public/app/features/dashboard-scene/sharing/ShareButton/share-snapshot/CreateSnapshot.tsx
index 88774c566e0..73aaf435fde 100644
--- a/public/app/features/dashboard-scene/sharing/ShareButton/share-snapshot/CreateSnapshot.tsx
+++ b/public/app/features/dashboard-scene/sharing/ShareButton/share-snapshot/CreateSnapshot.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import {
diff --git a/public/app/features/dashboard-scene/sharing/ShareButton/share-snapshot/ShareSnapshot.tsx b/public/app/features/dashboard-scene/sharing/ShareButton/share-snapshot/ShareSnapshot.tsx
index 4cc3c700a9f..d225a75b1e3 100644
--- a/public/app/features/dashboard-scene/sharing/ShareButton/share-snapshot/ShareSnapshot.tsx
+++ b/public/app/features/dashboard-scene/sharing/ShareButton/share-snapshot/ShareSnapshot.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import useAsyncFn from 'react-use/lib/useAsyncFn';
import { selectors as e2eSelectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard-scene/sharing/ShareButton/share-snapshot/SnapshotActions.tsx b/public/app/features/dashboard-scene/sharing/ShareButton/share-snapshot/SnapshotActions.tsx
index 903a58df867..79e5b827151 100644
--- a/public/app/features/dashboard-scene/sharing/ShareButton/share-snapshot/SnapshotActions.tsx
+++ b/public/app/features/dashboard-scene/sharing/ShareButton/share-snapshot/SnapshotActions.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Button, ClipboardButton, Stack } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
diff --git a/public/app/features/dashboard-scene/sharing/ShareButton/utils.ts b/public/app/features/dashboard-scene/sharing/ShareButton/utils.ts
index ca63311f91a..f6dc5b466f3 100644
--- a/public/app/features/dashboard-scene/sharing/ShareButton/utils.ts
+++ b/public/app/features/dashboard-scene/sharing/ShareButton/utils.ts
@@ -1,16 +1,48 @@
import { VizPanel } from '@grafana/scenes';
-import { createAndCopyDashboardShortLink } from 'app/core/utils/shortLinks';
+import { createAndCopyShareDashboardLink } from 'app/core/utils/shortLinks';
import { getTrackingSource } from 'app/features/dashboard/components/ShareModal/utils';
+import store from '../../../../core/store';
import { DashboardScene } from '../../scene/DashboardScene';
import { DashboardInteractions } from '../../utils/interactions';
+export type ShareLinkConfiguration = {
+ useAbsoluteTimeRange: boolean;
+ useShortUrl: boolean;
+ theme: string;
+};
+
+const DEFAULT_SHARE_LINK_CONFIGURATION: ShareLinkConfiguration = {
+ useAbsoluteTimeRange: true,
+ useShortUrl: true,
+ theme: 'current',
+};
+
export const buildShareUrl = async (dashboard: DashboardScene, panel?: VizPanel) => {
+ const { useAbsoluteTimeRange, useShortUrl, theme } = getShareLinkConfiguration();
DashboardInteractions.shareLinkCopied({
- currentTimeRange: true,
- theme: 'current',
- shortenURL: true,
+ currentTimeRange: useAbsoluteTimeRange,
+ theme,
+ shortenURL: useShortUrl,
shareResource: getTrackingSource(panel?.getRef()),
});
- return await createAndCopyDashboardShortLink(dashboard, { useAbsoluteTimeRange: true, theme: 'current' });
+ return await createAndCopyShareDashboardLink(dashboard, {
+ useAbsoluteTimeRange,
+ theme,
+ useShortUrl,
+ });
};
+
+const SHARE_LINK_CONFIGURATION = 'grafana.dashboard.link.shareConfiguration';
+// Function that returns share link configuration from local storage
+export function getShareLinkConfiguration(): ShareLinkConfiguration {
+ if (store.exists(SHARE_LINK_CONFIGURATION)) {
+ return store.getObject(SHARE_LINK_CONFIGURATION) || DEFAULT_SHARE_LINK_CONFIGURATION;
+ }
+
+ return DEFAULT_SHARE_LINK_CONFIGURATION;
+}
+
+export function updateShareLinkConfiguration(config: ShareLinkConfiguration) {
+ store.setObject(SHARE_LINK_CONFIGURATION, config);
+}
diff --git a/public/app/features/dashboard-scene/sharing/ShareDrawer/ShareDrawer.tsx b/public/app/features/dashboard-scene/sharing/ShareDrawer/ShareDrawer.tsx
index 282979a13c8..a183ca49416 100644
--- a/public/app/features/dashboard-scene/sharing/ShareDrawer/ShareDrawer.tsx
+++ b/public/app/features/dashboard-scene/sharing/ShareDrawer/ShareDrawer.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import {
SceneComponentProps,
SceneObject,
diff --git a/public/app/features/dashboard-scene/sharing/ShareDrawer/ShareDrawerConfirmAction.tsx b/public/app/features/dashboard-scene/sharing/ShareDrawer/ShareDrawerConfirmAction.tsx
index 91aeab1bc84..eba806b6011 100644
--- a/public/app/features/dashboard-scene/sharing/ShareDrawer/ShareDrawerConfirmAction.tsx
+++ b/public/app/features/dashboard-scene/sharing/ShareDrawer/ShareDrawerConfirmAction.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Spinner, Stack, Text } from '@grafana/ui';
diff --git a/public/app/features/dashboard-scene/sharing/ShareDrawer/ShareDrawerContext.tsx b/public/app/features/dashboard-scene/sharing/ShareDrawer/ShareDrawerContext.tsx
index 53006f154fa..213f2c2f964 100644
--- a/public/app/features/dashboard-scene/sharing/ShareDrawer/ShareDrawerContext.tsx
+++ b/public/app/features/dashboard-scene/sharing/ShareDrawer/ShareDrawerContext.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import { createContext, useContext } from 'react';
import { DashboardScene } from '../../scene/DashboardScene';
@@ -6,10 +6,10 @@ interface Context {
dashboard: DashboardScene;
}
-export const ShareDrawerContext = React.createContext(undefined);
+export const ShareDrawerContext = createContext(undefined);
const useShareDrawerContext = () => {
- const context = React.useContext(ShareDrawerContext);
+ const context = useContext(ShareDrawerContext);
if (context === undefined) {
throw new Error('useShareDrawerContext must be used within a DrawerContext');
diff --git a/public/app/features/dashboard-scene/sharing/ShareExportTab.tsx b/public/app/features/dashboard-scene/sharing/ShareExportTab.tsx
index 9faa5f51be1..a56428878da 100644
--- a/public/app/features/dashboard-scene/sharing/ShareExportTab.tsx
+++ b/public/app/features/dashboard-scene/sharing/ShareExportTab.tsx
@@ -1,5 +1,4 @@
import saveAs from 'file-saver';
-import React from 'react';
import { useAsync } from 'react-use';
import AutoSizer from 'react-virtualized-auto-sizer';
@@ -13,6 +12,7 @@ import { DashboardModel } from 'app/features/dashboard/state';
import { transformSceneToSaveModel } from '../serialization/transformSceneToSaveModel';
import { getVariablesCompatibility } from '../utils/getVariablesCompatibility';
import { DashboardInteractions } from '../utils/interactions';
+import { getDashboardSceneFor } from '../utils/utils';
import { SceneShareTabState } from './types';
@@ -56,8 +56,8 @@ export class ShareExportTab extends SceneObjectBase {
}
public async getExportableDashboardJson() {
- const { dashboardRef, isSharingExternally } = this.state;
- const saveModel = transformSceneToSaveModel(dashboardRef.resolve());
+ const { isSharingExternally } = this.state;
+ const saveModel = transformSceneToSaveModel(getDashboardSceneFor(this));
const exportable = isSharingExternally
? await this._exporter.makeExportable(
diff --git a/public/app/features/dashboard-scene/sharing/ShareLibraryPanelTab.tsx b/public/app/features/dashboard-scene/sharing/ShareLibraryPanelTab.tsx
index 61c16ddda28..435601736a4 100644
--- a/public/app/features/dashboard-scene/sharing/ShareLibraryPanelTab.tsx
+++ b/public/app/features/dashboard-scene/sharing/ShareLibraryPanelTab.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SceneComponentProps, SceneObjectBase, SceneObjectRef, VizPanel } from '@grafana/scenes';
import { LibraryPanel } from '@grafana/schema/dist/esm/index.gen';
import { t } from 'app/core/internationalization';
@@ -9,6 +7,7 @@ import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
import { DashboardGridItem } from '../scene/DashboardGridItem';
import { gridItemToPanel, transformSceneToSaveModel } from '../serialization/transformSceneToSaveModel';
+import { getDashboardSceneFor } from '../utils/utils';
import { SceneShareTabState } from './types';
@@ -26,7 +25,7 @@ export class ShareLibraryPanelTab extends SceneObjectBase) {
- const { panelRef, dashboardRef, modalRef } = model.useState();
+ const { panelRef, modalRef } = model.useState();
if (!panelRef) {
return null;
@@ -36,7 +35,7 @@ function ShareLibraryPanelTabRenderer({ model }: SceneComponentProps ({
createShortLink: jest.fn().mockResolvedValue(`http://localhost:3000/goto/shortend-uid`),
}));
+setPluginImportUtils({
+ importPanelPlugin: (id: string) => Promise.resolve(getPanelPlugin({})),
+ getPanelPluginFromCache: (id: string) => undefined,
+});
+
describe('ShareLinkTab', () => {
const fakeCurrentDate = dateTime('2019-02-11T19:00:00.000Z').toDate();
@@ -48,7 +54,7 @@ describe('ShareLinkTab', () => {
describe('with disabled locked range range', () => {
it('should generate share url with relative time', async () => {
const tab = buildAndRenderScenario({});
- act(() => tab.onToggleLockedTime());
+ await act(() => tab.onToggleLockedTime());
expect(await screen.findByRole('textbox', { name: 'Link URL' })).toHaveValue(
'http://dashboards.grafana.com/grafana/d/dash-1?from=now-6h&to=now&viewPanel=panel-12'
@@ -58,7 +64,7 @@ describe('ShareLinkTab', () => {
it('should add theme when specified', async () => {
const tab = buildAndRenderScenario({});
- act(() => tab.onThemeChange('light'));
+ await act(() => tab.onThemeChange('light'));
expect(await screen.findByRole('textbox', { name: 'Link URL' })).toHaveValue(
'http://dashboards.grafana.com/grafana/d/dash-1?from=2019-02-11T13:00:00.000Z&to=2019-02-11T19:00:00.000Z&viewPanel=panel-12&theme=light'
@@ -97,8 +103,8 @@ function buildAndRenderScenario(options: ScenarioOptions) {
pluginId: 'table',
key: 'panel-12',
});
-
- const dashboard = new DashboardScene({
+ const tab = new ShareLinkTab({ panelRef: panel.getRef() });
+ const scene = new DashboardScene({
title: 'hello',
uid: 'dash-1',
meta: {
@@ -117,9 +123,10 @@ function buildAndRenderScenario(options: ScenarioOptions) {
}),
],
}),
+ overlay: tab,
});
- const tab = new ShareLinkTab({ dashboardRef: dashboard.getRef(), panelRef: panel.getRef() });
+ activateFullSceneTree(scene);
render( );
diff --git a/public/app/features/dashboard-scene/sharing/ShareLinkTab.tsx b/public/app/features/dashboard-scene/sharing/ShareLinkTab.tsx
index 1a98396a20f..7a04d62a09a 100644
--- a/public/app/features/dashboard-scene/sharing/ShareLinkTab.tsx
+++ b/public/app/features/dashboard-scene/sharing/ShareLinkTab.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { dateTime } from '@grafana/data';
import { selectors as e2eSelectors } from '@grafana/e2e-selectors';
import { config } from '@grafana/runtime';
@@ -13,18 +11,24 @@ import { getTrackingSource, shareDashboardType } from 'app/features/dashboard/co
import { DashboardInteractions } from '../utils/interactions';
import { getDashboardUrl } from '../utils/urlBuilders';
+import { getDashboardSceneFor } from '../utils/utils';
+import { updateShareLinkConfiguration } from './ShareButton/utils';
import { SceneShareTabState } from './types';
export interface ShareLinkTabState extends SceneShareTabState, ShareOptions {
panelRef?: SceneObjectRef;
}
-interface ShareOptions {
+export interface ShareLinkConfiguration {
useLockedTime: boolean;
useShortUrl: boolean;
selectedTheme: string;
+}
+
+interface ShareOptions extends ShareLinkConfiguration {
shareUrl: string;
imageUrl: string;
+ isBuildUrlLoading: boolean;
}
export class ShareLinkTab extends SceneObjectBase {
@@ -32,14 +36,15 @@ export class ShareLinkTab extends SceneObjectBase {
static Component = ShareLinkTabRenderer;
- constructor(state: Omit) {
+ constructor(state: Partial) {
super({
...state,
- useLockedTime: true,
- useShortUrl: false,
- selectedTheme: 'current',
+ useLockedTime: state.useLockedTime ?? true,
+ useShortUrl: state.useShortUrl ?? false,
+ selectedTheme: state.selectedTheme ?? 'current',
shareUrl: '',
imageUrl: '',
+ isBuildUrlLoading: false,
});
this.addActivationHandler(() => {
@@ -48,12 +53,13 @@ export class ShareLinkTab extends SceneObjectBase {
}
async buildUrl() {
- const { panelRef, dashboardRef, useLockedTime: useAbsoluteTimeRange, useShortUrl, selectedTheme } = this.state;
- const dashboard = dashboardRef.resolve();
+ this.setState({ isBuildUrlLoading: true });
+ const { panelRef, useLockedTime: useAbsoluteTimeRange, useShortUrl, selectedTheme } = this.state;
+ const dashboard = getDashboardSceneFor(this);
const panel = panelRef?.resolve();
- const opts = { useAbsoluteTimeRange, theme: selectedTheme };
- let shareUrl = await createDashboardShareUrl(dashboard, opts, panel);
+ const opts = { useAbsoluteTimeRange, theme: selectedTheme, useShortUrl };
+ let shareUrl = createDashboardShareUrl(dashboard, opts, panel);
if (useShortUrl) {
shareUrl = await createShortLink(shareUrl);
@@ -81,26 +87,43 @@ export class ShareLinkTab extends SceneObjectBase {
timeZone: getRenderTimeZone(timeRange.getTimeZone()),
});
- this.setState({ shareUrl, imageUrl });
+ this.setState({ shareUrl, imageUrl, isBuildUrlLoading: false });
}
public getTabLabel() {
return t('share-modal.tab-title.link', 'Link');
}
- onToggleLockedTime = () => {
- this.setState({ useLockedTime: !this.state.useLockedTime });
- this.buildUrl();
+ onToggleLockedTime = async () => {
+ const useLockedTime = !this.state.useLockedTime;
+ updateShareLinkConfiguration({
+ useAbsoluteTimeRange: useLockedTime,
+ useShortUrl: this.state.useShortUrl,
+ theme: this.state.selectedTheme,
+ });
+ this.setState({ useLockedTime });
+ await this.buildUrl();
};
- onUrlShorten = () => {
- this.setState({ useShortUrl: !this.state.useShortUrl });
- this.buildUrl();
+ onUrlShorten = async () => {
+ const useShortUrl = !this.state.useShortUrl;
+ this.setState({ useShortUrl });
+ updateShareLinkConfiguration({
+ useShortUrl,
+ useAbsoluteTimeRange: this.state.useLockedTime,
+ theme: this.state.selectedTheme,
+ });
+ await this.buildUrl();
};
- onThemeChange = (value: string) => {
+ onThemeChange = async (value: string) => {
this.setState({ selectedTheme: value });
- this.buildUrl();
+ updateShareLinkConfiguration({
+ theme: value,
+ useShortUrl: this.state.useShortUrl,
+ useAbsoluteTimeRange: this.state.useLockedTime,
+ });
+ await this.buildUrl();
};
getShareUrl = () => {
@@ -119,9 +142,9 @@ export class ShareLinkTab extends SceneObjectBase {
function ShareLinkTabRenderer({ model }: SceneComponentProps) {
const state = model.useState();
- const { panelRef, dashboardRef } = state;
+ const { panelRef } = state;
- const dashboard = dashboardRef.resolve();
+ const dashboard = getDashboardSceneFor(model);
const panel = panelRef?.resolve();
const timeRange = sceneGraph.getTimeRange(panel ?? dashboard);
diff --git a/public/app/features/dashboard-scene/sharing/ShareModal.tsx b/public/app/features/dashboard-scene/sharing/ShareModal.tsx
index 86d6ab6976d..d015501e143 100644
--- a/public/app/features/dashboard-scene/sharing/ShareModal.tsx
+++ b/public/app/features/dashboard-scene/sharing/ShareModal.tsx
@@ -1,4 +1,4 @@
-import React, { ComponentProps } from 'react';
+import { ComponentProps } from 'react';
import { config } from '@grafana/runtime';
import { SceneComponentProps, SceneObjectBase, SceneObjectState, VizPanel, SceneObjectRef } from '@grafana/scenes';
@@ -8,7 +8,6 @@ import { t } from 'app/core/internationalization';
import { isPublicDashboardsEnabled } from 'app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboardUtils';
import { getTrackingSource } from '../../dashboard/components/ShareModal/utils';
-import { DashboardScene } from '../scene/DashboardScene';
import { LibraryVizPanel } from '../scene/LibraryVizPanel';
import { DashboardInteractions } from '../utils/interactions';
import { getDashboardSceneFor } from '../utils/utils';
@@ -22,7 +21,6 @@ import { SharePublicDashboardTab } from './public-dashboards/SharePublicDashboar
import { ModalSceneObjectLike, SceneShareTab, SceneShareTabState } from './types';
interface ShareModalState extends SceneObjectState {
- dashboardRef: SceneObjectRef;
panelRef?: SceneObjectRef;
tabs?: SceneShareTab[];
activeTab: string;
@@ -51,36 +49,36 @@ export class ShareModal extends SceneObjectBase implements Moda
}
private buildTabs() {
- const { dashboardRef, panelRef } = this.state;
+ const { panelRef } = this.state;
const modalRef = this.getRef();
- const tabs: SceneShareTab[] = [new ShareLinkTab({ dashboardRef, panelRef, modalRef })];
+ const tabs: SceneShareTab[] = [new ShareLinkTab({ panelRef, modalRef })];
const dashboard = getDashboardSceneFor(this);
if (!panelRef) {
- tabs.push(new ShareExportTab({ dashboardRef, modalRef }));
+ tabs.push(new ShareExportTab({ modalRef }));
}
if (contextSrv.isSignedIn && config.snapshotEnabled && dashboard.canEditDashboard()) {
- tabs.push(new ShareSnapshotTab({ panelRef, dashboardRef, modalRef }));
+ tabs.push(new ShareSnapshotTab({ panelRef, dashboardRef: dashboard.getRef(), modalRef }));
}
if (panelRef) {
- tabs.push(new SharePanelEmbedTab({ panelRef, dashboardRef }));
+ tabs.push(new SharePanelEmbedTab({ panelRef }));
const panel = panelRef.resolve();
const isLibraryPanel = panel.parent instanceof LibraryVizPanel;
if (panel instanceof VizPanel) {
if (!isLibraryPanel) {
- tabs.push(new ShareLibraryPanelTab({ panelRef, dashboardRef, modalRef }));
+ tabs.push(new ShareLibraryPanelTab({ panelRef, modalRef }));
}
}
}
if (!panelRef) {
- tabs.push(...customDashboardTabs.map((Tab) => new Tab({ dashboardRef, modalRef })));
+ tabs.push(...customDashboardTabs.map((Tab) => new Tab({ modalRef })));
if (isPublicDashboardsEnabled()) {
- tabs.push(new SharePublicDashboardTab({ dashboardRef, modalRef }));
+ tabs.push(new SharePublicDashboardTab({ modalRef }));
}
}
diff --git a/public/app/features/dashboard-scene/sharing/SharePanelEmbedTab.tsx b/public/app/features/dashboard-scene/sharing/SharePanelEmbedTab.tsx
index 1b5cf04dbc6..584d64868e4 100644
--- a/public/app/features/dashboard-scene/sharing/SharePanelEmbedTab.tsx
+++ b/public/app/features/dashboard-scene/sharing/SharePanelEmbedTab.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { TimeRange } from '@grafana/data';
import { SceneComponentProps, sceneGraph, SceneObjectBase, SceneObjectRef, VizPanel } from '@grafana/scenes';
import { t } from 'app/core/internationalization';
@@ -9,7 +7,7 @@ import { buildParams, shareDashboardType } from 'app/features/dashboard/componen
import { DashboardScene } from '../scene/DashboardScene';
import { PanelTimeRange } from '../scene/PanelTimeRange';
import { getDashboardUrl } from '../utils/urlBuilders';
-import { getPanelIdForVizPanel } from '../utils/utils';
+import { getDashboardSceneFor, getPanelIdForVizPanel } from '../utils/utils';
import { SceneShareTabState } from './types';
@@ -31,10 +29,10 @@ export class SharePanelEmbedTab extends SceneObjectBase
}
function SharePanelEmbedTabRenderer({ model }: SceneComponentProps) {
- const { panelRef, dashboardRef } = model.useState();
+ const { panelRef } = model.useState();
const p = panelRef.resolve();
- const dash = dashboardRef.resolve();
+ const dash = getDashboardSceneFor(model);
const { uid: dashUid } = dash.useState();
const id = getPanelIdForVizPanel(p);
const timeRangeState = sceneGraph.getTimeRange(p);
diff --git a/public/app/features/dashboard-scene/sharing/ShareSnapshotTab.tsx b/public/app/features/dashboard-scene/sharing/ShareSnapshotTab.tsx
index 8acccc7cd11..6ac56345c50 100644
--- a/public/app/features/dashboard-scene/sharing/ShareSnapshotTab.tsx
+++ b/public/app/features/dashboard-scene/sharing/ShareSnapshotTab.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import useAsyncFn from 'react-use/lib/useAsyncFn';
import { SelectableValue } from '@grafana/data';
@@ -13,6 +12,7 @@ import { getTrackingSource, shareDashboardType } from 'app/features/dashboard/co
import { getDashboardSnapshotSrv, SnapshotSharingOptions } from 'app/features/dashboard/services/SnapshotSrv';
import { dispatch } from 'app/store/store';
+import { DashboardScene } from '../scene/DashboardScene';
import { transformSceneToSaveModel, trimDashboardForSnapshot } from '../serialization/transformSceneToSaveModel';
import { DashboardInteractions } from '../utils/interactions';
@@ -48,10 +48,10 @@ const getDefaultExpireOption = () => {
};
export interface ShareSnapshotTabState extends SceneShareTabState {
+ dashboardRef: SceneObjectRef;
panelRef?: SceneObjectRef;
snapshotName: string;
selectedExpireOption: SelectableValue;
-
snapshotSharingOptions?: SnapshotSharingOptions;
}
diff --git a/public/app/features/dashboard-scene/sharing/public-dashboards/ConfigPublicDashboard.tsx b/public/app/features/dashboard-scene/sharing/public-dashboards/ConfigPublicDashboard.tsx
index c4dc496a989..c7b9110bbf1 100644
--- a/public/app/features/dashboard-scene/sharing/public-dashboards/ConfigPublicDashboard.tsx
+++ b/public/app/features/dashboard-scene/sharing/public-dashboards/ConfigPublicDashboard.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { SceneComponentProps, sceneGraph } from '@grafana/scenes';
@@ -10,6 +9,8 @@ import { ConfigPublicDashboardBase } from 'app/features/dashboard/components/Sha
import { PublicDashboard } from 'app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboardUtils';
import { AccessControlAction } from 'app/types';
+import { shareDashboardType } from '../../../dashboard/components/ShareModal/utils';
+import { getDashboardSceneFor } from '../../utils/utils';
import { ShareModal } from '../ShareModal';
import { ConfirmModal } from './ConfirmModal';
@@ -25,8 +26,8 @@ export function ConfigPublicDashboard({ model, publicDashboard, isGetLoading }:
const styles = useStyles2(getStyles);
const hasWritePermissions = contextSrv.hasPermission(AccessControlAction.DashboardsPublicWrite);
- const { dashboardRef } = model.useState();
- const dashboard = dashboardRef.resolve();
+
+ const dashboard = getDashboardSceneFor(model);
const { isDirty } = dashboard.useState();
const [deletePublicDashboard] = useDeletePublicDashboardMutation();
const hasTemplateVariables = (dashboard.state.$variables?.state.variables.length ?? 0) > 0;
@@ -52,7 +53,7 @@ export function ConfigPublicDashboard({ model, publicDashboard, isGetLoading }:
),
onDismiss: () => {
- dashboard.showModal(new ShareModal({ dashboardRef, activeTab: 'Public Dashboard' }));
+ dashboard.showModal(new ShareModal({ activeTab: shareDashboardType.publicDashboard }));
},
onConfirm: () => {
deletePublicDashboard({ dashboard, dashboardUid: dashboard.state.uid!, uid: publicDashboard!.uid });
diff --git a/public/app/features/dashboard-scene/sharing/public-dashboards/ConfirmModal.tsx b/public/app/features/dashboard-scene/sharing/public-dashboards/ConfirmModal.tsx
index 38c28676733..2021a7fff14 100644
--- a/public/app/features/dashboard-scene/sharing/public-dashboards/ConfirmModal.tsx
+++ b/public/app/features/dashboard-scene/sharing/public-dashboards/ConfirmModal.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SceneComponentProps, SceneObjectBase, SceneObjectState } from '@grafana/scenes';
import { ConfirmModal as ConfirmModalComponent, ConfirmModalProps } from '@grafana/ui';
diff --git a/public/app/features/dashboard-scene/sharing/public-dashboards/CreatePublicDashboard.tsx b/public/app/features/dashboard-scene/sharing/public-dashboards/CreatePublicDashboard.tsx
index 5b01c56aa72..ec733e57d00 100644
--- a/public/app/features/dashboard-scene/sharing/public-dashboards/CreatePublicDashboard.tsx
+++ b/public/app/features/dashboard-scene/sharing/public-dashboards/CreatePublicDashboard.tsx
@@ -1,14 +1,13 @@
-import React from 'react';
-
import { SceneComponentProps } from '@grafana/scenes';
import { CreatePublicDashboardBase } from 'app/features/dashboard/components/ShareModal/SharePublicDashboard/CreatePublicDashboard/CreatePublicDashboard';
+import { getDashboardSceneFor } from '../../utils/utils';
+
import { SharePublicDashboardTab } from './SharePublicDashboardTab';
import { useUnsupportedDatasources } from './hooks';
export function CreatePublicDashboard({ model }: SceneComponentProps) {
- const { dashboardRef } = model.useState();
- const dashboard = dashboardRef.resolve();
+ const dashboard = getDashboardSceneFor(model);
const unsupportedDataSources = useUnsupportedDatasources(dashboard);
const hasTemplateVariables = (dashboard.state.$variables?.state.variables.length ?? 0) > 0;
diff --git a/public/app/features/dashboard-scene/sharing/public-dashboards/SharePublicDashboardTab.tsx b/public/app/features/dashboard-scene/sharing/public-dashboards/SharePublicDashboardTab.tsx
index 311652d5fb8..d33daa5b1e5 100644
--- a/public/app/features/dashboard-scene/sharing/public-dashboards/SharePublicDashboardTab.tsx
+++ b/public/app/features/dashboard-scene/sharing/public-dashboards/SharePublicDashboardTab.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SceneComponentProps, SceneObjectBase } from '@grafana/scenes';
import { t } from 'app/core/internationalization';
import { useGetPublicDashboardQuery } from 'app/features/dashboard/api/publicDashboardApi';
@@ -7,6 +5,7 @@ import { Loader } from 'app/features/dashboard/components/ShareModal/SharePublic
import { publicDashboardPersisted } from 'app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboardUtils';
import { shareDashboardType } from 'app/features/dashboard/components/ShareModal/utils';
+import { getDashboardSceneFor } from '../../utils/utils';
import { SceneShareTabState } from '../types';
import { ConfigPublicDashboard } from './ConfigPublicDashboard';
@@ -23,7 +22,7 @@ export class SharePublicDashboardTab extends SceneObjectBase
function SharePublicDashboardTabRenderer({ model }: SceneComponentProps) {
const { data: publicDashboard, isLoading: isGetLoading } = useGetPublicDashboardQuery(
- model.state.dashboardRef.resolve().state.uid!
+ getDashboardSceneFor(model).state.uid!
);
return (
diff --git a/public/app/features/dashboard-scene/sharing/types.ts b/public/app/features/dashboard-scene/sharing/types.ts
index 1d4aadf0907..dc4ddb676e6 100644
--- a/public/app/features/dashboard-scene/sharing/types.ts
+++ b/public/app/features/dashboard-scene/sharing/types.ts
@@ -1,13 +1,10 @@
import { SceneObject, SceneObjectRef, SceneObjectState } from '@grafana/scenes';
-import { DashboardScene } from '../scene/DashboardScene';
-
export interface ModalSceneObjectLike {
onDismiss: () => void;
}
export interface SceneShareTabState extends SceneObjectState {
- dashboardRef: SceneObjectRef;
modalRef?: SceneObjectRef;
}
diff --git a/public/app/features/dashboard-scene/solo/SoloPanelPage.tsx b/public/app/features/dashboard-scene/solo/SoloPanelPage.tsx
index e875ee2f06a..29ec4dcdcbb 100644
--- a/public/app/features/dashboard-scene/solo/SoloPanelPage.tsx
+++ b/public/app/features/dashboard-scene/solo/SoloPanelPage.tsx
@@ -1,5 +1,5 @@
// Libraries
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import { Alert, Spinner } from '@grafana/ui';
import PageLoader from 'app/core/components/PageLoader/PageLoader';
diff --git a/public/app/features/dashboard-scene/utils/registerDynamicDashNavAction.ts b/public/app/features/dashboard-scene/utils/registerDynamicDashNavAction.ts
index 46ac63e6149..fb610ca237a 100644
--- a/public/app/features/dashboard-scene/utils/registerDynamicDashNavAction.ts
+++ b/public/app/features/dashboard-scene/utils/registerDynamicDashNavAction.ts
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { DashboardModel } from '../../dashboard/state';
diff --git a/public/app/features/dashboard-scene/variables/VariablesDependenciesButton.tsx b/public/app/features/dashboard-scene/variables/VariablesDependenciesButton.tsx
index 5f8667661df..b1b4af26cd8 100644
--- a/public/app/features/dashboard-scene/variables/VariablesDependenciesButton.tsx
+++ b/public/app/features/dashboard-scene/variables/VariablesDependenciesButton.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { reportInteraction } from '@grafana/runtime';
import { SceneVariable, SceneVariableState } from '@grafana/scenes';
diff --git a/public/app/features/dashboard/components/AddLibraryPanelWidget/AddLibraryPanelWidget.tsx b/public/app/features/dashboard/components/AddLibraryPanelWidget/AddLibraryPanelWidget.tsx
index 345ab73e352..99bda00dfd0 100644
--- a/public/app/features/dashboard/components/AddLibraryPanelWidget/AddLibraryPanelWidget.tsx
+++ b/public/app/features/dashboard/components/AddLibraryPanelWidget/AddLibraryPanelWidget.tsx
@@ -1,5 +1,5 @@
import { css, cx, keyframes } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import tinycolor from 'tinycolor2';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/dashboard/components/AddPanelButton/AddPanelButton.test.tsx b/public/app/features/dashboard/components/AddPanelButton/AddPanelButton.test.tsx
index 69bc4cf2c90..b5b08485029 100644
--- a/public/app/features/dashboard/components/AddPanelButton/AddPanelButton.test.tsx
+++ b/public/app/features/dashboard/components/AddPanelButton/AddPanelButton.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { defaultDashboard } from '@grafana/schema';
diff --git a/public/app/features/dashboard/components/AddPanelButton/AddPanelButton.tsx b/public/app/features/dashboard/components/AddPanelButton/AddPanelButton.tsx
index 197bd4e9817..e76b3769ad0 100644
--- a/public/app/features/dashboard/components/AddPanelButton/AddPanelButton.tsx
+++ b/public/app/features/dashboard/components/AddPanelButton/AddPanelButton.tsx
@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from 'react';
+import { useState, useEffect } from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { Dropdown, Button, Icon } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/AddPanelButton/AddPanelMenu.test.tsx b/public/app/features/dashboard/components/AddPanelButton/AddPanelMenu.test.tsx
index 3f82b9d7ca8..e30e856600d 100644
--- a/public/app/features/dashboard/components/AddPanelButton/AddPanelMenu.test.tsx
+++ b/public/app/features/dashboard/components/AddPanelButton/AddPanelMenu.test.tsx
@@ -1,5 +1,4 @@
import { act, fireEvent, render, screen } from '@testing-library/react';
-import React from 'react';
import { PluginType } from '@grafana/data';
import { locationService, reportInteraction } from '@grafana/runtime';
diff --git a/public/app/features/dashboard/components/AddPanelButton/AddPanelMenu.tsx b/public/app/features/dashboard/components/AddPanelButton/AddPanelMenu.tsx
index 796d713cc73..4ff03483ab4 100644
--- a/public/app/features/dashboard/components/AddPanelButton/AddPanelMenu.tsx
+++ b/public/app/features/dashboard/components/AddPanelButton/AddPanelMenu.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { config, locationService } from '@grafana/runtime';
diff --git a/public/app/features/dashboard/components/AddWidgetModal/AddWidgetModal.tsx b/public/app/features/dashboard/components/AddWidgetModal/AddWidgetModal.tsx
index 2dc2e392dbe..85572494816 100644
--- a/public/app/features/dashboard/components/AddWidgetModal/AddWidgetModal.tsx
+++ b/public/app/features/dashboard/components/AddWidgetModal/AddWidgetModal.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
import { GrafanaTheme2, PanelPluginMeta } from '@grafana/data';
import { locationService } from '@grafana/runtime';
diff --git a/public/app/features/dashboard/components/AnnotationSettings/AnnotationSettingsEdit.tsx b/public/app/features/dashboard/components/AnnotationSettings/AnnotationSettingsEdit.tsx
index acd171bb47b..645d74a6ec4 100644
--- a/public/app/features/dashboard/components/AnnotationSettings/AnnotationSettingsEdit.tsx
+++ b/public/app/features/dashboard/components/AnnotationSettings/AnnotationSettingsEdit.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
+import * as React from 'react';
import { useAsync } from 'react-use';
import {
diff --git a/public/app/features/dashboard/components/AnnotationSettings/AnnotationSettingsList.tsx b/public/app/features/dashboard/components/AnnotationSettings/AnnotationSettingsList.tsx
index 937fb188daa..5743aafdc5a 100644
--- a/public/app/features/dashboard/components/AnnotationSettings/AnnotationSettingsList.tsx
+++ b/public/app/features/dashboard/components/AnnotationSettings/AnnotationSettingsList.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { arrayUtils, AnnotationQuery } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard/components/DashNav/DashNav.tsx b/public/app/features/dashboard/components/DashNav/DashNav.tsx
index 73375c196af..2e0c1122221 100644
--- a/public/app/features/dashboard/components/DashNav/DashNav.tsx
+++ b/public/app/features/dashboard/components/DashNav/DashNav.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { ReactNode } from 'react';
+import { memo, ReactNode } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { useLocation } from 'react-router-dom';
@@ -79,7 +79,7 @@ export function addCustomRightAction(content: DynamicDashNavButtonModel) {
type Props = OwnProps & ConnectedProps;
-export const DashNav = React.memo((props) => {
+export const DashNav = memo((props) => {
// this ensures the component rerenders when the location changes
useLocation();
const forceUpdate = useForceUpdate();
diff --git a/public/app/features/dashboard/components/DashNav/DashNavButton.tsx b/public/app/features/dashboard/components/DashNav/DashNavButton.tsx
index df71687f1b7..48bc1a19d17 100644
--- a/public/app/features/dashboard/components/DashNav/DashNavButton.tsx
+++ b/public/app/features/dashboard/components/DashNav/DashNavButton.tsx
@@ -1,6 +1,7 @@
// Libraries
import { css } from '@emotion/css';
-import React, { MouseEvent } from 'react';
+import { MouseEvent } from 'react';
+import * as React from 'react';
// Components
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/dashboard/components/DashNav/DashNavTimeControls.test.tsx b/public/app/features/dashboard/components/DashNav/DashNavTimeControls.test.tsx
index 836eaef3f59..2ce08413581 100644
--- a/public/app/features/dashboard/components/DashNav/DashNavTimeControls.test.tsx
+++ b/public/app/features/dashboard/components/DashNav/DashNavTimeControls.test.tsx
@@ -1,5 +1,4 @@
import { render } from '@testing-library/react';
-import React from 'react';
import { getDashboardModel } from '../../../../../test/helpers/getDashboardModel';
import { DashboardModel } from '../../state/DashboardModel';
diff --git a/public/app/features/dashboard/components/DashNav/DashNavTimeControls.tsx b/public/app/features/dashboard/components/DashNav/DashNavTimeControls.tsx
index aef39caf3d2..df8653bf5e3 100644
--- a/public/app/features/dashboard/components/DashNav/DashNavTimeControls.tsx
+++ b/public/app/features/dashboard/components/DashNav/DashNavTimeControls.tsx
@@ -1,4 +1,4 @@
-import React, { Component } from 'react';
+import { Component } from 'react';
import { Unsubscribable } from 'rxjs';
import { dateMath, TimeRange, TimeZone } from '@grafana/data';
diff --git a/public/app/features/dashboard/components/DashNav/ShareButton.tsx b/public/app/features/dashboard/components/DashNav/ShareButton.tsx
index 2ff6ac53448..5a73143687e 100644
--- a/public/app/features/dashboard/components/DashNav/ShareButton.tsx
+++ b/public/app/features/dashboard/components/DashNav/ShareButton.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src';
import { locationService } from '@grafana/runtime';
import { Button } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/DashboardLoading/DashboardFailed.tsx b/public/app/features/dashboard/components/DashboardLoading/DashboardFailed.tsx
index 7cbc204729b..9601c1a026f 100644
--- a/public/app/features/dashboard/components/DashboardLoading/DashboardFailed.tsx
+++ b/public/app/features/dashboard/components/DashboardLoading/DashboardFailed.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { Alert } from '@grafana/ui';
import { getMessageFromError } from 'app/core/utils/errors';
diff --git a/public/app/features/dashboard/components/DashboardLoading/DashboardLoading.tsx b/public/app/features/dashboard/components/DashboardLoading/DashboardLoading.tsx
index 8bd51c865b8..46333190fca 100644
--- a/public/app/features/dashboard/components/DashboardLoading/DashboardLoading.tsx
+++ b/public/app/features/dashboard/components/DashboardLoading/DashboardLoading.tsx
@@ -1,5 +1,4 @@
import { css, keyframes } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { locationService } from '@grafana/runtime';
diff --git a/public/app/features/dashboard/components/DashboardPermissions/AccessControlDashboardPermissions.tsx b/public/app/features/dashboard/components/DashboardPermissions/AccessControlDashboardPermissions.tsx
index 212ba319048..6b31090b447 100644
--- a/public/app/features/dashboard/components/DashboardPermissions/AccessControlDashboardPermissions.tsx
+++ b/public/app/features/dashboard/components/DashboardPermissions/AccessControlDashboardPermissions.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Permissions } from 'app/core/components/AccessControl';
import { Page } from 'app/core/components/Page/Page';
import { contextSrv } from 'app/core/core';
diff --git a/public/app/features/dashboard/components/DashboardPrompt/DashboardPrompt.tsx b/public/app/features/dashboard/components/DashboardPrompt/DashboardPrompt.tsx
index 6a1c8544a71..ef984a5d9ea 100644
--- a/public/app/features/dashboard/components/DashboardPrompt/DashboardPrompt.tsx
+++ b/public/app/features/dashboard/components/DashboardPrompt/DashboardPrompt.tsx
@@ -1,6 +1,6 @@
import * as H from 'history';
import { find } from 'lodash';
-import React, { useContext, useEffect, useState } from 'react';
+import { memo, useContext, useEffect, useState } from 'react';
import { Prompt } from 'react-router-dom';
import { locationService } from '@grafana/runtime';
@@ -26,7 +26,7 @@ interface State {
originalPath?: string;
}
-export const DashboardPrompt = React.memo(({ dashboard }: Props) => {
+export const DashboardPrompt = memo(({ dashboard }: Props) => {
const [state, setState] = useState({ original: null });
const dispatch = useDispatch();
const { original, originalPath } = state;
diff --git a/public/app/features/dashboard/components/DashboardRow/DashboardRow.test.tsx b/public/app/features/dashboard/components/DashboardRow/DashboardRow.test.tsx
index 41259887f5a..a36703ab642 100644
--- a/public/app/features/dashboard/components/DashboardRow/DashboardRow.test.tsx
+++ b/public/app/features/dashboard/components/DashboardRow/DashboardRow.test.tsx
@@ -1,6 +1,5 @@
import { screen, render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { createTheme } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard/components/DashboardRow/DashboardRow.tsx b/public/app/features/dashboard/components/DashboardRow/DashboardRow.tsx
index 0c6852f7b6b..80cba9c2c77 100644
--- a/public/app/features/dashboard/components/DashboardRow/DashboardRow.tsx
+++ b/public/app/features/dashboard/components/DashboardRow/DashboardRow.tsx
@@ -1,6 +1,6 @@
import { css, cx } from '@emotion/css';
import { indexOf } from 'lodash';
-import React from 'react';
+import { Component } from 'react';
import { Unsubscribable } from 'rxjs';
import { GrafanaTheme2 } from '@grafana/data';
@@ -20,7 +20,7 @@ export interface DashboardRowProps extends Themeable2 {
dashboard: DashboardModel;
}
-export class UnthemedDashboardRow extends React.Component {
+export class UnthemedDashboardRow extends Component {
sub?: Unsubscribable;
componentDidMount() {
diff --git a/public/app/features/dashboard/components/DashboardSettings/AnnotationsSettings.test.tsx b/public/app/features/dashboard/components/DashboardSettings/AnnotationsSettings.test.tsx
index f90472ac6e8..6bd55b389aa 100644
--- a/public/app/features/dashboard/components/DashboardSettings/AnnotationsSettings.test.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/AnnotationsSettings.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { locationService, setAngularLoader, setDataSourceSrv } from '@grafana/runtime';
diff --git a/public/app/features/dashboard/components/DashboardSettings/AnnotationsSettings.tsx b/public/app/features/dashboard/components/DashboardSettings/AnnotationsSettings.tsx
index 005c067ee49..a99e41eb84f 100644
--- a/public/app/features/dashboard/components/DashboardSettings/AnnotationsSettings.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/AnnotationsSettings.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { AnnotationQuery, getDataSourceRef, NavModelItem } from '@grafana/data';
import { getDataSourceSrv, locationService } from '@grafana/runtime';
import { Page } from 'app/core/components/Page/Page';
diff --git a/public/app/features/dashboard/components/DashboardSettings/AutoRefreshIntervals.test.tsx b/public/app/features/dashboard/components/DashboardSettings/AutoRefreshIntervals.test.tsx
index 5ab5d6638a6..b23c6fabc1c 100644
--- a/public/app/features/dashboard/components/DashboardSettings/AutoRefreshIntervals.test.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/AutoRefreshIntervals.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { defaultIntervals } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/DashboardSettings/AutoRefreshIntervals.tsx b/public/app/features/dashboard/components/DashboardSettings/AutoRefreshIntervals.tsx
index 892a30a03af..a351454deb0 100644
--- a/public/app/features/dashboard/components/DashboardSettings/AutoRefreshIntervals.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/AutoRefreshIntervals.tsx
@@ -1,4 +1,5 @@
-import React, { useCallback, useEffect, useMemo, useState } from 'react';
+import { useCallback, useEffect, useMemo, useState } from 'react';
+import * as React from 'react';
import { Input, defaultIntervals, Field } from '@grafana/ui';
import { t } from 'app/core/internationalization';
diff --git a/public/app/features/dashboard/components/DashboardSettings/DashboardSettings.tsx b/public/app/features/dashboard/components/DashboardSettings/DashboardSettings.tsx
index 81367c1affc..322552dd9a3 100644
--- a/public/app/features/dashboard/components/DashboardSettings/DashboardSettings.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/DashboardSettings.tsx
@@ -1,5 +1,5 @@
import * as H from 'history';
-import React, { useEffect, useMemo, useState } from 'react';
+import { useEffect, useMemo, useState } from 'react';
import { useLocation } from 'react-router-dom';
import { locationUtil, NavModel, NavModelItem } from '@grafana/data';
diff --git a/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.test.tsx b/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.test.tsx
index b3af73b81bd..b4b63faa8fc 100644
--- a/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.test.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
import { selectOptionInTest } from 'test/helpers/selectOptionInTest';
diff --git a/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.tsx b/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.tsx
index 5f86114fc0a..8e9ca51534b 100644
--- a/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/GeneralSettings.tsx
@@ -1,4 +1,4 @@
-import React, { ChangeEvent, useState } from 'react';
+import { useCallback, ChangeEvent, useState } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { TimeZone } from '@grafana/data';
@@ -52,7 +52,7 @@ export function GeneralSettingsUnconnected({
setRenderCounter(renderCounter + 1);
};
- const onTitleChange = React.useCallback(
+ const onTitleChange = useCallback(
(title: string) => {
dashboard.title = title;
setDashboardTitle(title);
@@ -60,7 +60,7 @@ export function GeneralSettingsUnconnected({
[setDashboardTitle, dashboard]
);
- const onDescriptionChange = React.useCallback(
+ const onDescriptionChange = useCallback(
(description: string) => {
dashboard.description = description;
setDashboardDescription(description);
diff --git a/public/app/features/dashboard/components/DashboardSettings/JsonEditorSettings.tsx b/public/app/features/dashboard/components/DashboardSettings/JsonEditorSettings.tsx
index 95dd2d3d3f7..ad651c6edec 100644
--- a/public/app/features/dashboard/components/DashboardSettings/JsonEditorSettings.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/JsonEditorSettings.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Button, CodeEditor, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/DashboardSettings/LinksSettings.test.tsx b/public/app/features/dashboard/components/DashboardSettings/LinksSettings.test.tsx
index 867885d095f..98d08bc2191 100644
--- a/public/app/features/dashboard/components/DashboardSettings/LinksSettings.test.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/LinksSettings.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
diff --git a/public/app/features/dashboard/components/DashboardSettings/LinksSettings.tsx b/public/app/features/dashboard/components/DashboardSettings/LinksSettings.tsx
index edef4baf5d4..e4cb8495023 100644
--- a/public/app/features/dashboard/components/DashboardSettings/LinksSettings.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/LinksSettings.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { locationService } from '@grafana/runtime';
import { Page } from 'app/core/components/Page/Page';
diff --git a/public/app/features/dashboard/components/DashboardSettings/ListNewButton.tsx b/public/app/features/dashboard/components/DashboardSettings/ListNewButton.tsx
index 582a9fcc2f0..d6e8a0d9ce6 100644
--- a/public/app/features/dashboard/components/DashboardSettings/ListNewButton.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/ListNewButton.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { ButtonHTMLAttributes } from 'react';
+import { ButtonHTMLAttributes } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Button, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/DashboardSettings/TimePickerSettings.tsx b/public/app/features/dashboard/components/DashboardSettings/TimePickerSettings.tsx
index 0c0845b7995..d7d35e21ab2 100644
--- a/public/app/features/dashboard/components/DashboardSettings/TimePickerSettings.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/TimePickerSettings.tsx
@@ -1,5 +1,6 @@
import { isEmpty } from 'lodash';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
+import * as React from 'react';
import { rangeUtil, TimeZone } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard/components/DashboardSettings/VersionsSettings.test.tsx b/public/app/features/dashboard/components/DashboardSettings/VersionsSettings.test.tsx
index a9b34053458..77983e110fb 100644
--- a/public/app/features/dashboard/components/DashboardSettings/VersionsSettings.test.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/VersionsSettings.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
diff --git a/public/app/features/dashboard/components/DashboardSettings/VersionsSettings.tsx b/public/app/features/dashboard/components/DashboardSettings/VersionsSettings.tsx
index a741bd51a71..c22f31c9437 100644
--- a/public/app/features/dashboard/components/DashboardSettings/VersionsSettings.tsx
+++ b/public/app/features/dashboard/components/DashboardSettings/VersionsSettings.tsx
@@ -1,4 +1,5 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
+import * as React from 'react';
import { Spinner, HorizontalGroup } from '@grafana/ui';
import { Page } from 'app/core/components/Page/Page';
diff --git a/public/app/features/dashboard/components/DeleteDashboard/DeleteDashboardButton.tsx b/public/app/features/dashboard/components/DeleteDashboard/DeleteDashboardButton.tsx
index a2240c735c8..80f85899733 100644
--- a/public/app/features/dashboard/components/DeleteDashboard/DeleteDashboardButton.tsx
+++ b/public/app/features/dashboard/components/DeleteDashboard/DeleteDashboardButton.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { selectors } from '@grafana/e2e-selectors';
import { Button, ModalsController } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
diff --git a/public/app/features/dashboard/components/DeleteDashboard/DeleteDashboardModal.tsx b/public/app/features/dashboard/components/DeleteDashboard/DeleteDashboardModal.tsx
index 0cd44c3ccb2..0bb0ae5a9a0 100644
--- a/public/app/features/dashboard/components/DeleteDashboard/DeleteDashboardModal.tsx
+++ b/public/app/features/dashboard/components/DeleteDashboard/DeleteDashboardModal.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { connect, ConnectedProps } from 'react-redux';
import useAsyncFn from 'react-use/lib/useAsyncFn';
diff --git a/public/app/features/dashboard/components/GenAI/GenAIButton.test.tsx b/public/app/features/dashboard/components/GenAI/GenAIButton.test.tsx
index fc76cf269d0..164892a221f 100644
--- a/public/app/features/dashboard/components/GenAI/GenAIButton.test.tsx
+++ b/public/app/features/dashboard/components/GenAI/GenAIButton.test.tsx
@@ -1,6 +1,5 @@
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { Router } from 'react-router-dom';
import { Observable } from 'rxjs';
diff --git a/public/app/features/dashboard/components/GenAI/GenAIButton.tsx b/public/app/features/dashboard/components/GenAI/GenAIButton.tsx
index 566dd8e7ede..a8bbad79b50 100644
--- a/public/app/features/dashboard/components/GenAI/GenAIButton.tsx
+++ b/public/app/features/dashboard/components/GenAI/GenAIButton.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useCallback, useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Button, Spinner, useStyles2, Tooltip, Toggletip, Text } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/GenAI/GenAIDashDescriptionButton.tsx b/public/app/features/dashboard/components/GenAI/GenAIDashDescriptionButton.tsx
index cc565ea1c8c..feeb7a08a0b 100644
--- a/public/app/features/dashboard/components/GenAI/GenAIDashDescriptionButton.tsx
+++ b/public/app/features/dashboard/components/GenAI/GenAIDashDescriptionButton.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { getDashboardSrv } from '../../services/DashboardSrv';
import { GenAIButton } from './GenAIButton';
diff --git a/public/app/features/dashboard/components/GenAI/GenAIDashTitleButton.tsx b/public/app/features/dashboard/components/GenAI/GenAIDashTitleButton.tsx
index 78c3c4ef755..9888c514ce4 100644
--- a/public/app/features/dashboard/components/GenAI/GenAIDashTitleButton.tsx
+++ b/public/app/features/dashboard/components/GenAI/GenAIDashTitleButton.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { getDashboardSrv } from '../../services/DashboardSrv';
import { GenAIButton } from './GenAIButton';
diff --git a/public/app/features/dashboard/components/GenAI/GenAIDashboardChangesButton.tsx b/public/app/features/dashboard/components/GenAI/GenAIDashboardChangesButton.tsx
index 735774d6b72..ac636d16d77 100644
--- a/public/app/features/dashboard/components/GenAI/GenAIDashboardChangesButton.tsx
+++ b/public/app/features/dashboard/components/GenAI/GenAIDashboardChangesButton.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { DashboardModel } from '../../state';
diff --git a/public/app/features/dashboard/components/GenAI/GenAIHistory.tsx b/public/app/features/dashboard/components/GenAI/GenAIHistory.tsx
index e0c67da99bf..08e286eabb9 100644
--- a/public/app/features/dashboard/components/GenAI/GenAIHistory.tsx
+++ b/public/app/features/dashboard/components/GenAI/GenAIHistory.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Alert, Button, Icon, Input, Stack, Text, TextLink, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/GenAI/GenAIPanelDescriptionButton.tsx b/public/app/features/dashboard/components/GenAI/GenAIPanelDescriptionButton.tsx
index 9739387ba28..7f62d0c6682 100644
--- a/public/app/features/dashboard/components/GenAI/GenAIPanelDescriptionButton.tsx
+++ b/public/app/features/dashboard/components/GenAI/GenAIPanelDescriptionButton.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Panel } from '@grafana/schema';
import { getDashboardSrv } from '../../services/DashboardSrv';
diff --git a/public/app/features/dashboard/components/GenAI/GenAIPanelTitleButton.tsx b/public/app/features/dashboard/components/GenAI/GenAIPanelTitleButton.tsx
index 0995952b9e0..18f6761b076 100644
--- a/public/app/features/dashboard/components/GenAI/GenAIPanelTitleButton.tsx
+++ b/public/app/features/dashboard/components/GenAI/GenAIPanelTitleButton.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Dashboard, Panel } from '@grafana/schema';
import { GenAIButton } from './GenAIButton';
diff --git a/public/app/features/dashboard/components/GenAI/GenerationHistoryCarousel.tsx b/public/app/features/dashboard/components/GenAI/GenerationHistoryCarousel.tsx
index 58e5bdee4d0..4390ab00949 100644
--- a/public/app/features/dashboard/components/GenAI/GenerationHistoryCarousel.tsx
+++ b/public/app/features/dashboard/components/GenAI/GenerationHistoryCarousel.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Text, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/GenAI/MinimalisticPagination.tsx b/public/app/features/dashboard/components/GenAI/MinimalisticPagination.tsx
index ce59b2a69de..1d57d7dc528 100644
--- a/public/app/features/dashboard/components/GenAI/MinimalisticPagination.tsx
+++ b/public/app/features/dashboard/components/GenAI/MinimalisticPagination.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { IconButton, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/GenAI/QuickFeedback.tsx b/public/app/features/dashboard/components/GenAI/QuickFeedback.tsx
index d555368814c..5bceea90bb2 100644
--- a/public/app/features/dashboard/components/GenAI/QuickFeedback.tsx
+++ b/public/app/features/dashboard/components/GenAI/QuickFeedback.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Button, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/HelpWizard/HelpWizard.test.tsx b/public/app/features/dashboard/components/HelpWizard/HelpWizard.test.tsx
index 15a2a62e578..26f51c03999 100644
--- a/public/app/features/dashboard/components/HelpWizard/HelpWizard.test.tsx
+++ b/public/app/features/dashboard/components/HelpWizard/HelpWizard.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { FieldType, getDefaultTimeRange, LoadingState, toDataFrame } from '@grafana/data';
import { getPanelPlugin } from '@grafana/data/test/__mocks__/pluginMocks';
diff --git a/public/app/features/dashboard/components/HelpWizard/HelpWizard.tsx b/public/app/features/dashboard/components/HelpWizard/HelpWizard.tsx
index ed2176b1644..3b511c024be 100644
--- a/public/app/features/dashboard/components/HelpWizard/HelpWizard.tsx
+++ b/public/app/features/dashboard/components/HelpWizard/HelpWizard.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo, useEffect } from 'react';
+import { useMemo, useEffect } from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
import { PanelPlugin, GrafanaTheme2, FeatureState } from '@grafana/data';
diff --git a/public/app/features/dashboard/components/Inspector/InspectContent.tsx b/public/app/features/dashboard/components/Inspector/InspectContent.tsx
index 55fa0e51ec7..edfdb35bab5 100644
--- a/public/app/features/dashboard/components/Inspector/InspectContent.tsx
+++ b/public/app/features/dashboard/components/Inspector/InspectContent.tsx
@@ -1,5 +1,5 @@
import { isEmpty } from 'lodash';
-import React, { useState } from 'react';
+import { useState } from 'react';
import {
CoreApp,
diff --git a/public/app/features/dashboard/components/Inspector/PanelInspector.tsx b/public/app/features/dashboard/components/Inspector/PanelInspector.tsx
index 3c9a56d9637..863ee5cfbfc 100644
--- a/public/app/features/dashboard/components/Inspector/PanelInspector.tsx
+++ b/public/app/features/dashboard/components/Inspector/PanelInspector.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { connect, MapStateToProps } from 'react-redux';
import { useLocation } from 'react-router-dom';
diff --git a/public/app/features/dashboard/components/LinksSettings/LinkSettingsEdit.tsx b/public/app/features/dashboard/components/LinksSettings/LinkSettingsEdit.tsx
index 309d296aa30..eff987312df 100644
--- a/public/app/features/dashboard/components/LinksSettings/LinkSettingsEdit.tsx
+++ b/public/app/features/dashboard/components/LinksSettings/LinkSettingsEdit.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { DashboardLink } from '@grafana/schema';
import { DashboardLinkForm } from 'app/features/dashboard-scene/settings/links/DashboardLinkForm';
diff --git a/public/app/features/dashboard/components/LinksSettings/LinkSettingsList.tsx b/public/app/features/dashboard/components/LinksSettings/LinkSettingsList.tsx
index 09076805f5b..eba6de5db76 100644
--- a/public/app/features/dashboard/components/LinksSettings/LinkSettingsList.tsx
+++ b/public/app/features/dashboard/components/LinksSettings/LinkSettingsList.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { arrayUtils } from '@grafana/data';
import { DashboardLink } from '@grafana/schema';
diff --git a/public/app/features/dashboard/components/PanelEditor/AngularPanelOptions.tsx b/public/app/features/dashboard/components/PanelEditor/AngularPanelOptions.tsx
index df62f2fcb04..7d33350ac6c 100644
--- a/public/app/features/dashboard/components/PanelEditor/AngularPanelOptions.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/AngularPanelOptions.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { PanelPlugin, PanelPluginMeta } from '@grafana/data';
diff --git a/public/app/features/dashboard/components/PanelEditor/DynamicConfigValueEditor.tsx b/public/app/features/dashboard/components/PanelEditor/DynamicConfigValueEditor.tsx
index e6dbd47bf01..d062cfeb732 100644
--- a/public/app/features/dashboard/components/PanelEditor/DynamicConfigValueEditor.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/DynamicConfigValueEditor.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { useId } from 'react';
+import { useId } from 'react';
import Highlighter from 'react-highlight-words';
import {
diff --git a/public/app/features/dashboard/components/PanelEditor/OptionsPane.tsx b/public/app/features/dashboard/components/PanelEditor/OptionsPane.tsx
index 32a7d658271..d44d699c978 100644
--- a/public/app/features/dashboard/components/PanelEditor/OptionsPane.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/OptionsPane.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard/components/PanelEditor/OptionsPaneCategory.tsx b/public/app/features/dashboard/components/PanelEditor/OptionsPaneCategory.tsx
index 25b6ddee7fa..a849f83f076 100644
--- a/public/app/features/dashboard/components/PanelEditor/OptionsPaneCategory.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/OptionsPaneCategory.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { ReactNode, useCallback, useEffect, useState, useRef } from 'react';
+import { ReactNode, useCallback, useEffect, useState, useRef } from 'react';
+import * as React from 'react';
import { useLocalStorage } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor.tsx b/public/app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor.tsx
index bc65bee8eb1..debeed4e2a2 100644
--- a/public/app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/OptionsPaneCategoryDescriptor.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { OptionsPaneCategory } from './OptionsPaneCategory';
import { OptionsPaneItemDescriptor } from './OptionsPaneItemDescriptor';
diff --git a/public/app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor.tsx b/public/app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor.tsx
index c8b67b5e8ce..54d84347cd0 100644
--- a/public/app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/OptionsPaneItemDescriptor.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { ReactNode } from 'react';
+import { ReactNode } from 'react';
+import * as React from 'react';
import Highlighter from 'react-highlight-words';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/dashboard/components/PanelEditor/OptionsPaneItemOverrides.tsx b/public/app/features/dashboard/components/PanelEditor/OptionsPaneItemOverrides.tsx
index 83e0c93c7a8..e069cd90985 100644
--- a/public/app/features/dashboard/components/PanelEditor/OptionsPaneItemOverrides.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/OptionsPaneItemOverrides.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Tooltip, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/PanelEditor/OptionsPaneOptions.test.tsx b/public/app/features/dashboard/components/PanelEditor/OptionsPaneOptions.test.tsx
index 948318a4681..e096f073f83 100644
--- a/public/app/features/dashboard/components/PanelEditor/OptionsPaneOptions.test.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/OptionsPaneOptions.test.tsx
@@ -1,5 +1,4 @@
import { fireEvent, render, screen, within } from '@testing-library/react';
-import React from 'react';
import { Provider } from 'react-redux';
import configureMockStore from 'redux-mock-store';
diff --git a/public/app/features/dashboard/components/PanelEditor/OptionsPaneOptions.tsx b/public/app/features/dashboard/components/PanelEditor/OptionsPaneOptions.tsx
index c27378cb556..e843b9848c0 100644
--- a/public/app/features/dashboard/components/PanelEditor/OptionsPaneOptions.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/OptionsPaneOptions.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
+import * as React from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { config } from '@grafana/runtime';
diff --git a/public/app/features/dashboard/components/PanelEditor/OverrideCategoryTitle.tsx b/public/app/features/dashboard/components/PanelEditor/OverrideCategoryTitle.tsx
index 32d3847dd5c..ca12ab018fc 100644
--- a/public/app/features/dashboard/components/PanelEditor/OverrideCategoryTitle.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/OverrideCategoryTitle.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { FieldConfigOptionsRegistry, GrafanaTheme2, ConfigOverrideRule } from '@grafana/data';
import { HorizontalGroup, Icon, IconButton, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/PanelEditor/PanelEditor.tsx b/public/app/features/dashboard/components/PanelEditor/PanelEditor.tsx
index ee32162851c..a77c269d0ca 100644
--- a/public/app/features/dashboard/components/PanelEditor/PanelEditor.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/PanelEditor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import AutoSizer from 'react-virtualized-auto-sizer';
import { Subscription } from 'rxjs';
diff --git a/public/app/features/dashboard/components/PanelEditor/PanelEditorQueries.tsx b/public/app/features/dashboard/components/PanelEditor/PanelEditorQueries.tsx
index 13babf80fad..7f87d410e20 100644
--- a/public/app/features/dashboard/components/PanelEditor/PanelEditorQueries.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/PanelEditorQueries.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { DataQuery, getDataSourceRef } from '@grafana/data';
import { locationService } from '@grafana/runtime';
diff --git a/public/app/features/dashboard/components/PanelEditor/PanelEditorTableView.test.tsx b/public/app/features/dashboard/components/PanelEditor/PanelEditorTableView.test.tsx
index 989cce72a87..6a7703dec7f 100644
--- a/public/app/features/dashboard/components/PanelEditor/PanelEditorTableView.test.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/PanelEditorTableView.test.tsx
@@ -1,5 +1,4 @@
import { act, fireEvent, render, screen } from '@testing-library/react';
-import React from 'react';
import { Provider } from 'react-redux';
import configureMockStore from 'redux-mock-store';
import { ReplaySubject } from 'rxjs';
diff --git a/public/app/features/dashboard/components/PanelEditor/PanelEditorTableView.tsx b/public/app/features/dashboard/components/PanelEditor/PanelEditorTableView.tsx
index aa006ad53cb..74e66a0ed07 100644
--- a/public/app/features/dashboard/components/PanelEditor/PanelEditorTableView.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/PanelEditorTableView.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { RefreshEvent } from '@grafana/runtime';
import { PanelChrome } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/PanelEditor/PanelEditorTabs.tsx b/public/app/features/dashboard/components/PanelEditor/PanelEditorTabs.tsx
index 5c7769d7654..cad04df45f3 100644
--- a/public/app/features/dashboard/components/PanelEditor/PanelEditorTabs.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/PanelEditorTabs.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useCallback, useEffect } from 'react';
+import { memo, useCallback, useEffect } from 'react';
import { Subscription } from 'rxjs';
import { GrafanaTheme2 } from '@grafana/data';
@@ -22,7 +22,7 @@ interface PanelEditorTabsProps {
onChangeTab: (tab: PanelEditorTab) => void;
}
-export const PanelEditorTabs = React.memo(({ panel, dashboard, tabs, onChangeTab }: PanelEditorTabsProps) => {
+export const PanelEditorTabs = memo(({ panel, dashboard, tabs, onChangeTab }: PanelEditorTabsProps) => {
const forceUpdate = useForceUpdate();
const styles = useStyles2(getStyles);
diff --git a/public/app/features/dashboard/components/PanelEditor/PanelHeaderCorner.test.tsx b/public/app/features/dashboard/components/PanelEditor/PanelHeaderCorner.test.tsx
index 5e2067ce961..fd46e18b065 100644
--- a/public/app/features/dashboard/components/PanelEditor/PanelHeaderCorner.test.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/PanelHeaderCorner.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { createTheme } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard/components/PanelEditor/PanelHeaderCorner.tsx b/public/app/features/dashboard/components/PanelEditor/PanelHeaderCorner.tsx
index 1d5c7a5a8e1..c508a7050c3 100644
--- a/public/app/features/dashboard/components/PanelEditor/PanelHeaderCorner.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/PanelHeaderCorner.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { Component } from 'react';
+import { Component } from 'react';
import { renderMarkdown, LinkModelSupplier, ScopedVars, IconName } from '@grafana/data';
import { GrafanaTheme2 } from '@grafana/data/';
diff --git a/public/app/features/dashboard/components/PanelEditor/PanelNotSupported.test.tsx b/public/app/features/dashboard/components/PanelEditor/PanelNotSupported.test.tsx
index b5e6f9ed926..44e6f738506 100644
--- a/public/app/features/dashboard/components/PanelEditor/PanelNotSupported.test.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/PanelNotSupported.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { locationService } from '@grafana/runtime';
diff --git a/public/app/features/dashboard/components/PanelEditor/PanelNotSupported.tsx b/public/app/features/dashboard/components/PanelEditor/PanelNotSupported.tsx
index ea60c728c8f..ffd97689612 100644
--- a/public/app/features/dashboard/components/PanelEditor/PanelNotSupported.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/PanelNotSupported.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { locationService } from '@grafana/runtime';
import { Button, VerticalGroup } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/PanelEditor/VisualizationButton.tsx b/public/app/features/dashboard/components/PanelEditor/VisualizationButton.tsx
index 87c8453bafb..17acd43a090 100644
--- a/public/app/features/dashboard/components/PanelEditor/VisualizationButton.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/VisualizationButton.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { ToolbarButton, ButtonGroup } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/PanelEditor/VisualizationSelectPane.tsx b/public/app/features/dashboard/components/PanelEditor/VisualizationSelectPane.tsx
index 372734eb211..2d6d2dcd6e8 100644
--- a/public/app/features/dashboard/components/PanelEditor/VisualizationSelectPane.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/VisualizationSelectPane.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useCallback, useRef, useState } from 'react';
+import { useCallback, useRef, useState } from 'react';
import { useLocalStorage } from 'react-use';
import { GrafanaTheme2, PanelData, SelectableValue } from '@grafana/data';
diff --git a/public/app/features/dashboard/components/PanelEditor/getFieldOverrideElements.tsx b/public/app/features/dashboard/components/PanelEditor/getFieldOverrideElements.tsx
index 26035fb57ba..5ed6672b923 100644
--- a/public/app/features/dashboard/components/PanelEditor/getFieldOverrideElements.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/getFieldOverrideElements.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { cloneDeep } from 'lodash';
-import React from 'react';
+import * as React from 'react';
import {
FieldConfigOptionsRegistry,
diff --git a/public/app/features/dashboard/components/PanelEditor/getLibraryPanelOptions.tsx b/public/app/features/dashboard/components/PanelEditor/getLibraryPanelOptions.tsx
index 8f1036efcb4..b2fcd9faa07 100644
--- a/public/app/features/dashboard/components/PanelEditor/getLibraryPanelOptions.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/getLibraryPanelOptions.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Input } from '@grafana/ui';
import { LibraryPanelInformation } from 'app/features/library-panels/components/LibraryPanelInfo/LibraryPanelInfo';
diff --git a/public/app/features/dashboard/components/PanelEditor/getPanelFrameOptions.tsx b/public/app/features/dashboard/components/PanelEditor/getPanelFrameOptions.tsx
index 0c48dcaaf41..810ab710f6f 100644
--- a/public/app/features/dashboard/components/PanelEditor/getPanelFrameOptions.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/getPanelFrameOptions.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { selectors } from '@grafana/e2e-selectors';
import { config } from '@grafana/runtime';
import { DataLinksInlineEditor, Input, RadioButtonGroup, Select, Switch, TextArea } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/PanelEditor/getVisualizationOptions.tsx b/public/app/features/dashboard/components/PanelEditor/getVisualizationOptions.tsx
index ebcd9658a9f..eb5cdf588b9 100644
--- a/public/app/features/dashboard/components/PanelEditor/getVisualizationOptions.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/getVisualizationOptions.tsx
@@ -1,5 +1,4 @@
import { get as lodashGet } from 'lodash';
-import React from 'react';
import {
EventBus,
diff --git a/public/app/features/dashboard/components/PublicDashboard/PublicDashboardsFooter.tsx b/public/app/features/dashboard/components/PublicDashboard/PublicDashboardsFooter.tsx
index 8bfb8ba3469..884f22dedc8 100644
--- a/public/app/features/dashboard/components/PublicDashboard/PublicDashboardsFooter.tsx
+++ b/public/app/features/dashboard/components/PublicDashboard/PublicDashboardsFooter.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors as e2eSelectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard/components/PublicDashboard/usePublicDashboardConfig.tsx b/public/app/features/dashboard/components/PublicDashboard/usePublicDashboardConfig.tsx
index eff429de19a..9c1d602206a 100644
--- a/public/app/features/dashboard/components/PublicDashboard/usePublicDashboardConfig.tsx
+++ b/public/app/features/dashboard/components/PublicDashboard/usePublicDashboardConfig.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2, useTheme2 } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/PublicDashboardNotAvailable/PublicDashboardNotAvailable.tsx b/public/app/features/dashboard/components/PublicDashboardNotAvailable/PublicDashboardNotAvailable.tsx
index 6e4bf939f95..e060b16fd59 100644
--- a/public/app/features/dashboard/components/PublicDashboardNotAvailable/PublicDashboardNotAvailable.tsx
+++ b/public/app/features/dashboard/components/PublicDashboardNotAvailable/PublicDashboardNotAvailable.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data/src';
import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src';
diff --git a/public/app/features/dashboard/components/RepeatRowSelect/RepeatRowSelect.tsx b/public/app/features/dashboard/components/RepeatRowSelect/RepeatRowSelect.tsx
index de9ce1c1977..c35a286a4ea 100644
--- a/public/app/features/dashboard/components/RepeatRowSelect/RepeatRowSelect.tsx
+++ b/public/app/features/dashboard/components/RepeatRowSelect/RepeatRowSelect.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useMemo } from 'react';
+import { useCallback, useMemo } from 'react';
import { SelectableValue } from '@grafana/data';
import { SceneObject, sceneGraph } from '@grafana/scenes';
diff --git a/public/app/features/dashboard/components/RowOptions/RowOptionsButton.tsx b/public/app/features/dashboard/components/RowOptions/RowOptionsButton.tsx
index f4d820a652b..8e37db59dc9 100644
--- a/public/app/features/dashboard/components/RowOptions/RowOptionsButton.tsx
+++ b/public/app/features/dashboard/components/RowOptions/RowOptionsButton.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { Icon, ModalsController } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/RowOptions/RowOptionsForm.test.tsx b/public/app/features/dashboard/components/RowOptions/RowOptionsForm.test.tsx
index 96be5fb9f4d..9a1f5fb8c01 100644
--- a/public/app/features/dashboard/components/RowOptions/RowOptionsForm.test.tsx
+++ b/public/app/features/dashboard/components/RowOptions/RowOptionsForm.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard/components/RowOptions/RowOptionsForm.tsx b/public/app/features/dashboard/components/RowOptions/RowOptionsForm.tsx
index 13705193411..5029fbe3a7c 100644
--- a/public/app/features/dashboard/components/RowOptions/RowOptionsForm.tsx
+++ b/public/app/features/dashboard/components/RowOptions/RowOptionsForm.tsx
@@ -1,4 +1,5 @@
-import React, { useCallback, useState } from 'react';
+import { useCallback, useState } from 'react';
+import * as React from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { Button, Field, Modal, Input, Alert } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/RowOptions/RowOptionsModal.tsx b/public/app/features/dashboard/components/RowOptions/RowOptionsModal.tsx
index 68a7070551a..b16e9b6403d 100644
--- a/public/app/features/dashboard/components/RowOptions/RowOptionsModal.tsx
+++ b/public/app/features/dashboard/components/RowOptions/RowOptionsModal.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { Modal, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/SaveDashboard/DashboardValidation.tsx b/public/app/features/dashboard/components/SaveDashboard/DashboardValidation.tsx
index 6225baac685..1dd48ce9555 100644
--- a/public/app/features/dashboard/components/SaveDashboard/DashboardValidation.tsx
+++ b/public/app/features/dashboard/components/SaveDashboard/DashboardValidation.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { useAsync } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/dashboard/components/SaveDashboard/SaveDashboardButton.tsx b/public/app/features/dashboard/components/SaveDashboard/SaveDashboardButton.tsx
index 34107900acb..c4c718bda4d 100644
--- a/public/app/features/dashboard/components/SaveDashboard/SaveDashboardButton.tsx
+++ b/public/app/features/dashboard/components/SaveDashboard/SaveDashboardButton.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { selectors } from '@grafana/e2e-selectors';
import { reportInteraction } from '@grafana/runtime';
import { Button, ButtonVariant, ComponentSize, ModalsController } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/SaveDashboard/SaveDashboardDiff.tsx b/public/app/features/dashboard/components/SaveDashboard/SaveDashboardDiff.tsx
index 8859c59f6cf..b5de88d530b 100644
--- a/public/app/features/dashboard/components/SaveDashboard/SaveDashboardDiff.tsx
+++ b/public/app/features/dashboard/components/SaveDashboard/SaveDashboardDiff.tsx
@@ -1,4 +1,4 @@
-import React, { ReactElement } from 'react';
+import { ReactElement } from 'react';
import { useAsync } from 'react-use';
import { Box, Spinner, Stack } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/SaveDashboard/SaveDashboardDrawer.test.tsx b/public/app/features/dashboard/components/SaveDashboard/SaveDashboardDrawer.test.tsx
index 1303bcefd16..7d1c0af7c55 100644
--- a/public/app/features/dashboard/components/SaveDashboard/SaveDashboardDrawer.test.tsx
+++ b/public/app/features/dashboard/components/SaveDashboard/SaveDashboardDrawer.test.tsx
@@ -1,6 +1,5 @@
import { render, waitFor, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { Provider } from 'react-redux';
import { configureStore } from 'app/store/configureStore';
diff --git a/public/app/features/dashboard/components/SaveDashboard/SaveDashboardDrawer.tsx b/public/app/features/dashboard/components/SaveDashboard/SaveDashboardDrawer.tsx
index efd7839824f..1e680c5f161 100644
--- a/public/app/features/dashboard/components/SaveDashboard/SaveDashboardDrawer.tsx
+++ b/public/app/features/dashboard/components/SaveDashboard/SaveDashboardDrawer.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
import { config, isFetchError } from '@grafana/runtime';
import { Drawer, Tab, TabsBar } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/SaveDashboard/SaveDashboardErrorProxy.tsx b/public/app/features/dashboard/components/SaveDashboard/SaveDashboardErrorProxy.tsx
index 0049a8a2caf..de6e5d81606 100644
--- a/public/app/features/dashboard/components/SaveDashboard/SaveDashboardErrorProxy.tsx
+++ b/public/app/features/dashboard/components/SaveDashboard/SaveDashboardErrorProxy.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { FetchError } from '@grafana/runtime';
diff --git a/public/app/features/dashboard/components/SaveDashboard/UnsavedChangesModal.tsx b/public/app/features/dashboard/components/SaveDashboard/UnsavedChangesModal.tsx
index 5fe3bdfe1cf..4c6030d0556 100644
--- a/public/app/features/dashboard/components/SaveDashboard/UnsavedChangesModal.tsx
+++ b/public/app/features/dashboard/components/SaveDashboard/UnsavedChangesModal.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { Button, Modal } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.test.tsx b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.test.tsx
index 807cf6ac44e..aefda5932ce 100644
--- a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.test.tsx
+++ b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.test.tsx
@@ -1,6 +1,5 @@
import { screen, render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { DashboardModel } from 'app/features/dashboard/state';
import * as api from 'app/features/manage-dashboards/state/actions';
diff --git a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.tsx b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.tsx
index e5e99478969..e11482af296 100644
--- a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.tsx
+++ b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardAsForm.tsx
@@ -1,4 +1,4 @@
-import React, { ChangeEvent } from 'react';
+import { ChangeEvent } from 'react';
import { config } from '@grafana/runtime';
import { Button, Input, Switch, Form, Field, InputControl, Label, TextArea, Stack } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.test.tsx b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.test.tsx
index cf52a3984dc..ef7c6a605f1 100644
--- a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.test.tsx
+++ b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.test.tsx
@@ -1,6 +1,5 @@
import { screen, render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { Dashboard } from '@grafana/schema';
import { DashboardModel } from 'app/features/dashboard/state';
diff --git a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.tsx b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.tsx
index 492863b5c9a..cd1823f75f7 100644
--- a/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.tsx
+++ b/public/app/features/dashboard/components/SaveDashboard/forms/SaveDashboardForm.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard/components/SaveDashboard/forms/SaveProvisionedDashboardForm.tsx b/public/app/features/dashboard/components/SaveDashboard/forms/SaveProvisionedDashboardForm.tsx
index d8c3cb4b720..91231608aa0 100644
--- a/public/app/features/dashboard/components/SaveDashboard/forms/SaveProvisionedDashboardForm.tsx
+++ b/public/app/features/dashboard/components/SaveDashboard/forms/SaveProvisionedDashboardForm.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { saveAs } from 'file-saver';
-import React, { useCallback, useState } from 'react';
+import { useCallback, useState } from 'react';
import { Button, ClipboardButton, HorizontalGroup, TextArea, Stack } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/ShareModal/ShareEmbed.test.tsx b/public/app/features/dashboard/components/ShareModal/ShareEmbed.test.tsx
index bd19caed810..7707d15a419 100644
--- a/public/app/features/dashboard/components/ShareModal/ShareEmbed.test.tsx
+++ b/public/app/features/dashboard/components/ShareModal/ShareEmbed.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { BootData } from '@grafana/data';
import { setEchoSrv } from '@grafana/runtime/src';
diff --git a/public/app/features/dashboard/components/ShareModal/ShareEmbed.tsx b/public/app/features/dashboard/components/ShareModal/ShareEmbed.tsx
index 4ff8be1eaab..5dd04a46885 100644
--- a/public/app/features/dashboard/components/ShareModal/ShareEmbed.tsx
+++ b/public/app/features/dashboard/components/ShareModal/ShareEmbed.tsx
@@ -1,4 +1,4 @@
-import React, { FormEvent, useEffect, useState } from 'react';
+import { FormEvent, useEffect, useState } from 'react';
import { useEffectOnce } from 'react-use';
import { RawTimeRange, TimeRange } from '@grafana/data';
diff --git a/public/app/features/dashboard/components/ShareModal/ShareExport.tsx b/public/app/features/dashboard/components/ShareModal/ShareExport.tsx
index 6ba26550ce3..aa942ce4877 100644
--- a/public/app/features/dashboard/components/ShareModal/ShareExport.tsx
+++ b/public/app/features/dashboard/components/ShareModal/ShareExport.tsx
@@ -1,5 +1,5 @@
import { saveAs } from 'file-saver';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { Button, Field, Modal, Switch } from '@grafana/ui';
import { appEvents } from 'app/core/core';
diff --git a/public/app/features/dashboard/components/ShareModal/ShareLibraryPanel.tsx b/public/app/features/dashboard/components/ShareModal/ShareLibraryPanel.tsx
index a67d7d050cb..94aca5e30fc 100644
--- a/public/app/features/dashboard/components/ShareModal/ShareLibraryPanel.tsx
+++ b/public/app/features/dashboard/components/ShareModal/ShareLibraryPanel.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import { reportInteraction } from '@grafana/runtime/src';
import { Trans } from 'app/core/internationalization';
diff --git a/public/app/features/dashboard/components/ShareModal/ShareLink.test.tsx b/public/app/features/dashboard/components/ShareModal/ShareLink.test.tsx
index 205e09e8a65..a862b20b43e 100644
--- a/public/app/features/dashboard/components/ShareModal/ShareLink.test.tsx
+++ b/public/app/features/dashboard/components/ShareModal/ShareLink.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { BootData, getDefaultTimeRange } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard/components/ShareModal/ShareLink.tsx b/public/app/features/dashboard/components/ShareModal/ShareLink.tsx
index 595f0d5a6dd..31cdc11f142 100644
--- a/public/app/features/dashboard/components/ShareModal/ShareLink.tsx
+++ b/public/app/features/dashboard/components/ShareModal/ShareLink.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { selectors as e2eSelectors } from '@grafana/e2e-selectors';
import { Alert, ClipboardButton, Field, FieldSet, Input, Switch, TextLink } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/ShareModal/ShareModal.tsx b/public/app/features/dashboard/components/ShareModal/ShareModal.tsx
index b50c79a1735..937ae1af519 100644
--- a/public/app/features/dashboard/components/ShareModal/ShareModal.tsx
+++ b/public/app/features/dashboard/components/ShareModal/ShareModal.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { Modal, ModalTabsHeader, TabContent, Themeable2, withTheme2 } from '@grafana/ui';
import { config } from 'app/core/config';
diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/ConfigPublicDashboard.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/ConfigPublicDashboard.tsx
index 86e18772afd..e88d1bebf84 100644
--- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/ConfigPublicDashboard.tsx
+++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/ConfigPublicDashboard.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { useForm } from 'react-hook-form';
import { GrafanaTheme2, TimeRange } from '@grafana/data/src';
diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/Configuration.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/Configuration.tsx
index 8a7eeb3e511..e05e3a5e1b0 100644
--- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/Configuration.tsx
+++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/Configuration.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { UseFormRegister } from 'react-hook-form';
import { TimeRange } from '@grafana/data/src';
diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/EmailSharingConfiguration.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/EmailSharingConfiguration.tsx
index 16d97cb2748..fdda22950a0 100644
--- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/EmailSharingConfiguration.tsx
+++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/EmailSharingConfiguration.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { useForm, Controller } from 'react-hook-form';
import { useWindowSize } from 'react-use';
diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/SettingsBar.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/SettingsBar.tsx
index be34a9874cf..358a4f3402d 100644
--- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/SettingsBar.tsx
+++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/SettingsBar.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/SettingsBarHeader.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/SettingsBarHeader.tsx
index cb74d7bc546..5e60ca765e8 100644
--- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/SettingsBarHeader.tsx
+++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/SettingsBarHeader.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { IconButton, ReactUtils, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/SettingsSummary.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/SettingsSummary.tsx
index d907ba78bb4..f7d435b6803 100644
--- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/SettingsSummary.tsx
+++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ConfigPublicDashboard/SettingsSummary.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2, TimeRange } from '@grafana/data';
import { Spinner, TimeRangeLabel, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/CreatePublicDashboard/AcknowledgeCheckboxes.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/CreatePublicDashboard/AcknowledgeCheckboxes.tsx
index 27766f87131..0880b9eec80 100644
--- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/CreatePublicDashboard/AcknowledgeCheckboxes.tsx
+++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/CreatePublicDashboard/AcknowledgeCheckboxes.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { UseFormRegister } from 'react-hook-form';
import { GrafanaTheme2 } from '@grafana/data/src';
diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/CreatePublicDashboard/CreatePublicDashboard.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/CreatePublicDashboard/CreatePublicDashboard.tsx
index 14fc23a0afb..2287fef08d4 100644
--- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/CreatePublicDashboard/CreatePublicDashboard.tsx
+++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/CreatePublicDashboard/CreatePublicDashboard.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { useForm } from 'react-hook-form';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ModalAlerts/EmailSharingPricingAlert.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ModalAlerts/EmailSharingPricingAlert.tsx
index 6b212096821..8a40532eb7d 100644
--- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ModalAlerts/EmailSharingPricingAlert.tsx
+++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ModalAlerts/EmailSharingPricingAlert.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Alert, Button, Stack } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ModalAlerts/NoUpsertPermissionsAlert.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ModalAlerts/NoUpsertPermissionsAlert.tsx
index f3894367a25..7d68fe772d3 100644
--- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ModalAlerts/NoUpsertPermissionsAlert.tsx
+++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ModalAlerts/NoUpsertPermissionsAlert.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src';
import { Alert } from '@grafana/ui/src';
import { Trans, t } from 'app/core/internationalization';
diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ModalAlerts/PublicDashboardAlert.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ModalAlerts/PublicDashboardAlert.tsx
index 017e41a88dc..067ee44bb49 100644
--- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ModalAlerts/PublicDashboardAlert.tsx
+++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ModalAlerts/PublicDashboardAlert.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Alert, Button, Stack } from '@grafana/ui';
import { Trans } from '../../../../../../core/internationalization';
diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ModalAlerts/SaveDashboardChangesAlert.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ModalAlerts/SaveDashboardChangesAlert.tsx
index 4534754c8dd..e322986eca1 100644
--- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ModalAlerts/SaveDashboardChangesAlert.tsx
+++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ModalAlerts/SaveDashboardChangesAlert.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Alert } from '@grafana/ui/src';
import { t } from 'app/core/internationalization';
diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ModalAlerts/UnsupportedDataSourcesAlert.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ModalAlerts/UnsupportedDataSourcesAlert.tsx
index 0db873e5e29..06a7f1d8916 100644
--- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ModalAlerts/UnsupportedDataSourcesAlert.tsx
+++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ModalAlerts/UnsupportedDataSourcesAlert.tsx
@@ -1,6 +1,5 @@
import { css } from '@emotion/css';
import cx from 'classnames';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data/src';
import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src';
diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ModalAlerts/UnsupportedTemplateVariablesAlert.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ModalAlerts/UnsupportedTemplateVariablesAlert.tsx
index c20a2d2693d..673160baabf 100644
--- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ModalAlerts/UnsupportedTemplateVariablesAlert.tsx
+++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ModalAlerts/UnsupportedTemplateVariablesAlert.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src';
import { Alert } from '@grafana/ui/src';
import { Trans, t } from 'app/core/internationalization';
diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboard.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboard.tsx
index 36cbd0d3b96..227193cbbf4 100644
--- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboard.tsx
+++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/SharePublicDashboard.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data/src';
import { Spinner, useStyles2 } from '@grafana/ui/src';
diff --git a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/utilsTest.tsx b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/utilsTest.tsx
index 1434710a4ed..6ef2e1bec2b 100644
--- a/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/utilsTest.tsx
+++ b/public/app/features/dashboard/components/ShareModal/SharePublicDashboard/utilsTest.tsx
@@ -1,6 +1,6 @@
import { fireEvent, render, screen, waitFor, waitForElementToBeRemoved } from '@testing-library/react';
import { http, HttpResponse } from 'msw';
-import React from 'react';
+import * as React from 'react';
import { Provider } from 'react-redux';
import { configureStore } from '../../../../../store/configureStore';
diff --git a/public/app/features/dashboard/components/ShareModal/ShareSnapshot.tsx b/public/app/features/dashboard/components/ShareModal/ShareSnapshot.tsx
index 9ef4546c674..b6dd25275fb 100644
--- a/public/app/features/dashboard/components/ShareModal/ShareSnapshot.tsx
+++ b/public/app/features/dashboard/components/ShareModal/ShareSnapshot.tsx
@@ -1,4 +1,5 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
+import * as React from 'react';
import { isEmptyObject, SelectableValue, VariableRefresh } from '@grafana/data';
import { getBackendSrv } from '@grafana/runtime';
diff --git a/public/app/features/dashboard/components/ShareModal/ThemePicker.tsx b/public/app/features/dashboard/components/ShareModal/ThemePicker.tsx
index c9133d9c7a8..e38af724303 100644
--- a/public/app/features/dashboard/components/ShareModal/ThemePicker.tsx
+++ b/public/app/features/dashboard/components/ShareModal/ThemePicker.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SelectableValue } from '@grafana/data';
import { RadioButtonGroup, Field } from '@grafana/ui';
import { t } from 'app/core/internationalization';
diff --git a/public/app/features/dashboard/components/ShareModal/ViewJsonModal.tsx b/public/app/features/dashboard/components/ShareModal/ViewJsonModal.tsx
index 93a6e56edd4..b3aa51f326a 100644
--- a/public/app/features/dashboard/components/ShareModal/ViewJsonModal.tsx
+++ b/public/app/features/dashboard/components/ShareModal/ViewJsonModal.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
import { ClipboardButton, CodeEditor, Modal } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/ShareModal/types.ts b/public/app/features/dashboard/components/ShareModal/types.ts
index 14cbe0fab24..cabf30ebed2 100644
--- a/public/app/features/dashboard/components/ShareModal/types.ts
+++ b/public/app/features/dashboard/components/ShareModal/types.ts
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { NavModelItem } from '@grafana/data';
import { LibraryPanel } from '@grafana/schema/dist/esm/index.gen';
diff --git a/public/app/features/dashboard/components/SubMenu/AnnotationPicker.tsx b/public/app/features/dashboard/components/SubMenu/AnnotationPicker.tsx
index db810281b99..02a7ee2830f 100644
--- a/public/app/features/dashboard/components/SubMenu/AnnotationPicker.tsx
+++ b/public/app/features/dashboard/components/SubMenu/AnnotationPicker.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { AnnotationQuery, EventBus, GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard/components/SubMenu/Annotations.tsx b/public/app/features/dashboard/components/SubMenu/Annotations.tsx
index 02967e42066..f70255a878f 100644
--- a/public/app/features/dashboard/components/SubMenu/Annotations.tsx
+++ b/public/app/features/dashboard/components/SubMenu/Annotations.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { AnnotationQuery, DataQuery, EventBus } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard/components/SubMenu/DashboardLinks.tsx b/public/app/features/dashboard/components/SubMenu/DashboardLinks.tsx
index b45ca71a03f..b442b1ad768 100644
--- a/public/app/features/dashboard/components/SubMenu/DashboardLinks.tsx
+++ b/public/app/features/dashboard/components/SubMenu/DashboardLinks.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useEffectOnce } from 'react-use';
import { sanitizeUrl } from '@grafana/data/src/text/sanitize';
diff --git a/public/app/features/dashboard/components/SubMenu/DashboardLinksDashboard.tsx b/public/app/features/dashboard/components/SubMenu/DashboardLinksDashboard.tsx
index 5d02274ad8f..76946da2697 100644
--- a/public/app/features/dashboard/components/SubMenu/DashboardLinksDashboard.tsx
+++ b/public/app/features/dashboard/components/SubMenu/DashboardLinksDashboard.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
+import { forwardRef } from 'react';
import { useAsync } from 'react-use';
import { GrafanaTheme2, ScopedVars } from '@grafana/data';
@@ -170,7 +170,7 @@ function getStyles(theme: GrafanaTheme2) {
};
}
-export const DashboardLinkButton = React.forwardRef(({ className, ...otherProps }, ref) => {
+export const DashboardLinkButton = forwardRef(({ className, ...otherProps }, ref) => {
const styles = useStyles2(getStyles);
const Component = otherProps.href ? LinkButton : Button;
return (
diff --git a/public/app/features/dashboard/components/SubMenu/SubMenu.tsx b/public/app/features/dashboard/components/SubMenu/SubMenu.tsx
index 6b1eea31d6a..3fdc08ad079 100644
--- a/public/app/features/dashboard/components/SubMenu/SubMenu.tsx
+++ b/public/app/features/dashboard/components/SubMenu/SubMenu.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
+import * as React from 'react';
import { connect, MapStateToProps } from 'react-redux';
import { AnnotationQuery, DataQuery, TypedVariableModel, GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/dashboard/components/SubMenu/SubMenuItems.tsx b/public/app/features/dashboard/components/SubMenu/SubMenuItems.tsx
index 22e815c5aab..9c43e1722d4 100644
--- a/public/app/features/dashboard/components/SubMenu/SubMenuItems.tsx
+++ b/public/app/features/dashboard/components/SubMenu/SubMenuItems.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { GrafanaTheme2, TypedVariableModel, VariableHide } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard/components/TransformationsEditor/TransformationEditor.tsx b/public/app/features/dashboard/components/TransformationsEditor/TransformationEditor.tsx
index fa092978cda..8cbeddccbad 100644
--- a/public/app/features/dashboard/components/TransformationsEditor/TransformationEditor.tsx
+++ b/public/app/features/dashboard/components/TransformationsEditor/TransformationEditor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useMemo, useState } from 'react';
+import { createElement, useEffect, useMemo, useState } from 'react';
import { mergeMap } from 'rxjs/operators';
import {
@@ -69,7 +69,7 @@ export const TransformationEditor = ({
const editor = useMemo(
() =>
- React.createElement(uiConfig.editor, {
+ createElement(uiConfig.editor, {
options: { ...uiConfig.transformation.defaultOptions, ...config.transformation.options },
input,
onChange: (opts) => {
diff --git a/public/app/features/dashboard/components/TransformationsEditor/TransformationEditorHelpDisplay.test.tsx b/public/app/features/dashboard/components/TransformationsEditor/TransformationEditorHelpDisplay.test.tsx
index b365b8d0504..f53ea9672dd 100644
--- a/public/app/features/dashboard/components/TransformationsEditor/TransformationEditorHelpDisplay.test.tsx
+++ b/public/app/features/dashboard/components/TransformationsEditor/TransformationEditorHelpDisplay.test.tsx
@@ -1,5 +1,4 @@
import { render, screen, fireEvent } from '@testing-library/react';
-import React from 'react';
import { TransformerRegistryItem } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard/components/TransformationsEditor/TransformationEditorHelpDisplay.tsx b/public/app/features/dashboard/components/TransformationsEditor/TransformationEditorHelpDisplay.tsx
index 47fce758daa..3bca17be7c8 100644
--- a/public/app/features/dashboard/components/TransformationsEditor/TransformationEditorHelpDisplay.tsx
+++ b/public/app/features/dashboard/components/TransformationsEditor/TransformationEditorHelpDisplay.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { TransformerRegistryItem } from '@grafana/data';
import { Drawer } from '@grafana/ui';
import { OperationRowHelp } from 'app/core/components/QueryOperationRow/OperationRowHelp';
diff --git a/public/app/features/dashboard/components/TransformationsEditor/TransformationFilter.tsx b/public/app/features/dashboard/components/TransformationsEditor/TransformationFilter.tsx
index dce12d11781..f3dc7dfba93 100644
--- a/public/app/features/dashboard/components/TransformationsEditor/TransformationFilter.tsx
+++ b/public/app/features/dashboard/components/TransformationsEditor/TransformationFilter.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import {
DataTransformerConfig,
diff --git a/public/app/features/dashboard/components/TransformationsEditor/TransformationOperationRow.tsx b/public/app/features/dashboard/components/TransformationsEditor/TransformationOperationRow.tsx
index aa5f6df86f5..a1f7db3b37d 100644
--- a/public/app/features/dashboard/components/TransformationsEditor/TransformationOperationRow.tsx
+++ b/public/app/features/dashboard/components/TransformationsEditor/TransformationOperationRow.tsx
@@ -1,4 +1,5 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
+import * as React from 'react';
import { useToggle } from 'react-use';
import { DataTransformerConfig, TransformerRegistryItem, FrameMatcherID, DataTopic } from '@grafana/data';
diff --git a/public/app/features/dashboard/components/TransformationsEditor/TransformationOperationRows.tsx b/public/app/features/dashboard/components/TransformationsEditor/TransformationOperationRows.tsx
index 6a3ba81a214..142f32aaf8e 100644
--- a/public/app/features/dashboard/components/TransformationsEditor/TransformationOperationRows.tsx
+++ b/public/app/features/dashboard/components/TransformationsEditor/TransformationOperationRows.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { DataTransformerConfig, standardTransformersRegistry } from '@grafana/data';
import { TransformationOperationRow } from './TransformationOperationRow';
diff --git a/public/app/features/dashboard/components/TransformationsEditor/TransformationPicker.tsx b/public/app/features/dashboard/components/TransformationsEditor/TransformationPicker.tsx
index 48656e7289b..594f5f3ab75 100644
--- a/public/app/features/dashboard/components/TransformationsEditor/TransformationPicker.tsx
+++ b/public/app/features/dashboard/components/TransformationsEditor/TransformationPicker.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { FormEventHandler, KeyboardEventHandler, ReactNode } from 'react';
+import { FormEventHandler, KeyboardEventHandler, ReactNode } from 'react';
import { DocsId, GrafanaTheme2, TransformerRegistryItem } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard/components/TransformationsEditor/TransformationPickerNg.tsx b/public/app/features/dashboard/components/TransformationsEditor/TransformationPickerNg.tsx
index 2acc57372e9..9247eac21e6 100644
--- a/public/app/features/dashboard/components/TransformationsEditor/TransformationPickerNg.tsx
+++ b/public/app/features/dashboard/components/TransformationsEditor/TransformationPickerNg.tsx
@@ -1,5 +1,5 @@
import { cx, css } from '@emotion/css';
-import React, { FormEventHandler, KeyboardEventHandler, ReactNode, useCallback } from 'react';
+import { FormEventHandler, KeyboardEventHandler, ReactNode, useCallback } from 'react';
import {
DataFrame,
diff --git a/public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.test.tsx b/public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.test.tsx
index e272b3bf3d4..958bed2991b 100644
--- a/public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.test.tsx
+++ b/public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { DataTransformerConfig, standardTransformersRegistry } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.tsx b/public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.tsx
index b1efc16b8d3..256f51fd814 100644
--- a/public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.tsx
+++ b/public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.tsx
@@ -1,4 +1,5 @@
-import React, { ChangeEvent } from 'react';
+import { ChangeEvent } from 'react';
+import * as React from 'react';
import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd';
import { Unsubscribable } from 'rxjs';
diff --git a/public/app/features/dashboard/components/VersionHistory/RevertDashboardModal.tsx b/public/app/features/dashboard/components/VersionHistory/RevertDashboardModal.tsx
index e24c2155693..5a4451b4596 100644
--- a/public/app/features/dashboard/components/VersionHistory/RevertDashboardModal.tsx
+++ b/public/app/features/dashboard/components/VersionHistory/RevertDashboardModal.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import { ConfirmModal } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/VersionHistory/VersionHistoryComparison.tsx b/public/app/features/dashboard/components/VersionHistory/VersionHistoryComparison.tsx
index 0dab8cccf2c..2f23cd32e17 100644
--- a/public/app/features/dashboard/components/VersionHistory/VersionHistoryComparison.tsx
+++ b/public/app/features/dashboard/components/VersionHistory/VersionHistoryComparison.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Button, ModalsController, CollapsableSection, useStyles2, Stack, Icon, Box } from '@grafana/ui';
diff --git a/public/app/features/dashboard/components/VersionHistory/VersionHistoryTable.tsx b/public/app/features/dashboard/components/VersionHistory/VersionHistoryTable.tsx
index 2f698bdc67c..2cd8514992a 100644
--- a/public/app/features/dashboard/components/VersionHistory/VersionHistoryTable.tsx
+++ b/public/app/features/dashboard/components/VersionHistory/VersionHistoryTable.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Checkbox, Button, Tag, ModalsController, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/dashboard/containers/DashboardPage.test.tsx b/public/app/features/dashboard/containers/DashboardPage.test.tsx
index 5df1f991e5c..66072472742 100644
--- a/public/app/features/dashboard/containers/DashboardPage.test.tsx
+++ b/public/app/features/dashboard/containers/DashboardPage.test.tsx
@@ -1,6 +1,6 @@
import { render, screen, waitFor } from '@testing-library/react';
import { KBarProvider } from 'kbar';
-import React from 'react';
+import { Component } from 'react';
import { Provider } from 'react-redux';
import { match, Router } from 'react-router-dom';
import { useEffectOnce } from 'react-use';
@@ -39,7 +39,7 @@ jest.mock('app/features/dashboard/dashgrid/LazyLoader', () => {
});
jest.mock('app/features/dashboard/components/DashboardSettings/GeneralSettings', () => {
- class GeneralSettings extends React.Component<{}, {}> {
+ class GeneralSettings extends Component<{}, {}> {
render() {
return <>general settings>;
}
diff --git a/public/app/features/dashboard/containers/DashboardPage.tsx b/public/app/features/dashboard/containers/DashboardPage.tsx
index 5578ff93dd0..b2902fdad03 100644
--- a/public/app/features/dashboard/containers/DashboardPage.tsx
+++ b/public/app/features/dashboard/containers/DashboardPage.tsx
@@ -1,5 +1,5 @@
import { cx } from '@emotion/css';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { NavModel, NavModelItem, TimeRange, PageLayoutType, locationUtil } from '@grafana/data';
diff --git a/public/app/features/dashboard/containers/DashboardPageProxy.test.tsx b/public/app/features/dashboard/containers/DashboardPageProxy.test.tsx
index a89cd34d749..cad16a8b2b2 100644
--- a/public/app/features/dashboard/containers/DashboardPageProxy.test.tsx
+++ b/public/app/features/dashboard/containers/DashboardPageProxy.test.tsx
@@ -1,5 +1,4 @@
import { act, render, screen, waitFor } from '@testing-library/react';
-import React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
import { Props } from 'react-virtualized-auto-sizer';
diff --git a/public/app/features/dashboard/containers/DashboardPageProxy.tsx b/public/app/features/dashboard/containers/DashboardPageProxy.tsx
index 1a1bf22c777..9a00b266ba0 100644
--- a/public/app/features/dashboard/containers/DashboardPageProxy.tsx
+++ b/public/app/features/dashboard/containers/DashboardPageProxy.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useAsync } from 'react-use';
import { config } from '@grafana/runtime';
diff --git a/public/app/features/dashboard/containers/NewDashboardWithDS.tsx b/public/app/features/dashboard/containers/NewDashboardWithDS.tsx
index b1a7aa041e4..5da67c8fe32 100644
--- a/public/app/features/dashboard/containers/NewDashboardWithDS.tsx
+++ b/public/app/features/dashboard/containers/NewDashboardWithDS.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { getDataSourceSrv, locationService } from '@grafana/runtime';
import { Page } from 'app/core/components/Page/Page';
diff --git a/public/app/features/dashboard/containers/PublicDashboardPage.test.tsx b/public/app/features/dashboard/containers/PublicDashboardPage.test.tsx
index 7ae9cedb1e3..e2619b6f757 100644
--- a/public/app/features/dashboard/containers/PublicDashboardPage.test.tsx
+++ b/public/app/features/dashboard/containers/PublicDashboardPage.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { Provider } from 'react-redux';
import { match, Router } from 'react-router-dom';
import { useEffectOnce } from 'react-use';
diff --git a/public/app/features/dashboard/containers/PublicDashboardPage.tsx b/public/app/features/dashboard/containers/PublicDashboardPage.tsx
index 451b3acfc3e..7d12cf4bf08 100644
--- a/public/app/features/dashboard/containers/PublicDashboardPage.tsx
+++ b/public/app/features/dashboard/containers/PublicDashboardPage.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import { usePrevious } from 'react-use';
import { GrafanaTheme2, PageLayoutType, TimeZone } from '@grafana/data';
diff --git a/public/app/features/dashboard/containers/PublicDashboardPageProxy.test.tsx b/public/app/features/dashboard/containers/PublicDashboardPageProxy.test.tsx
index 7d56f52a2e8..6da46204b9a 100644
--- a/public/app/features/dashboard/containers/PublicDashboardPageProxy.test.tsx
+++ b/public/app/features/dashboard/containers/PublicDashboardPageProxy.test.tsx
@@ -1,5 +1,4 @@
import { render, screen, waitFor } from '@testing-library/react';
-import React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
diff --git a/public/app/features/dashboard/containers/PublicDashboardPageProxy.tsx b/public/app/features/dashboard/containers/PublicDashboardPageProxy.tsx
index f7820295318..cb5020d9dda 100644
--- a/public/app/features/dashboard/containers/PublicDashboardPageProxy.tsx
+++ b/public/app/features/dashboard/containers/PublicDashboardPageProxy.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { config } from '@grafana/runtime';
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
diff --git a/public/app/features/dashboard/containers/SoloPanelPage.test.tsx b/public/app/features/dashboard/containers/SoloPanelPage.test.tsx
index c24325c2497..97932973433 100644
--- a/public/app/features/dashboard/containers/SoloPanelPage.test.tsx
+++ b/public/app/features/dashboard/containers/SoloPanelPage.test.tsx
@@ -1,5 +1,5 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
+import { Component } from 'react';
import { match } from 'react-router-dom';
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
@@ -17,7 +17,7 @@ import { Props, SoloPanelPage } from './SoloPanelPage';
jest.mock('app/features/dashboard/components/DashboardSettings/GeneralSettings', () => ({}));
jest.mock('app/features/dashboard/dashgrid/DashboardPanel', () => {
- class DashboardPanel extends React.Component {
+ class DashboardPanel extends Component {
render() {
// In this test we only check whether a new panel has arrived in the props
return <>{this.props.panel?.title}>;
diff --git a/public/app/features/dashboard/containers/SoloPanelPage.tsx b/public/app/features/dashboard/containers/SoloPanelPage.tsx
index 4628ed79685..0295dc62d8b 100644
--- a/public/app/features/dashboard/containers/SoloPanelPage.tsx
+++ b/public/app/features/dashboard/containers/SoloPanelPage.tsx
@@ -1,4 +1,4 @@
-import React, { Component } from 'react';
+import { Component } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import AutoSizer from 'react-virtualized-auto-sizer';
diff --git a/public/app/features/dashboard/dashgrid/DashboardEmpty.test.tsx b/public/app/features/dashboard/dashgrid/DashboardEmpty.test.tsx
index 8f47962a4d0..4490d3ae84f 100644
--- a/public/app/features/dashboard/dashgrid/DashboardEmpty.test.tsx
+++ b/public/app/features/dashboard/dashgrid/DashboardEmpty.test.tsx
@@ -1,5 +1,4 @@
import { act, fireEvent, render, screen } from '@testing-library/react';
-import React from 'react';
import { locationService, reportInteraction } from '@grafana/runtime';
import { defaultDashboard } from '@grafana/schema';
diff --git a/public/app/features/dashboard/dashgrid/DashboardEmpty.tsx b/public/app/features/dashboard/dashgrid/DashboardEmpty.tsx
index 653555ead9b..e8065787e83 100644
--- a/public/app/features/dashboard/dashgrid/DashboardEmpty.tsx
+++ b/public/app/features/dashboard/dashgrid/DashboardEmpty.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard/dashgrid/DashboardGrid.test.tsx b/public/app/features/dashboard/dashgrid/DashboardGrid.test.tsx
index 818f0fd05d0..be9499a53de 100644
--- a/public/app/features/dashboard/dashgrid/DashboardGrid.test.tsx
+++ b/public/app/features/dashboard/dashgrid/DashboardGrid.test.tsx
@@ -1,5 +1,4 @@
import { act, render, screen } from '@testing-library/react';
-import React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
import { useEffectOnce } from 'react-use';
diff --git a/public/app/features/dashboard/dashgrid/DashboardGrid.tsx b/public/app/features/dashboard/dashgrid/DashboardGrid.tsx
index f265fe4f52a..cb09e66048a 100644
--- a/public/app/features/dashboard/dashgrid/DashboardGrid.tsx
+++ b/public/app/features/dashboard/dashgrid/DashboardGrid.tsx
@@ -1,5 +1,6 @@
import classNames from 'classnames';
-import React, { PureComponent, CSSProperties } from 'react';
+import { PureComponent, CSSProperties } from 'react';
+import * as React from 'react';
import ReactGridLayout, { ItemCallback } from 'react-grid-layout';
import { Subscription } from 'rxjs';
diff --git a/public/app/features/dashboard/dashgrid/DashboardPanel.tsx b/public/app/features/dashboard/dashgrid/DashboardPanel.tsx
index ffc36abee2b..b0873eabb07 100644
--- a/public/app/features/dashboard/dashgrid/DashboardPanel.tsx
+++ b/public/app/features/dashboard/dashgrid/DashboardPanel.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { StoreState } from 'app/types';
diff --git a/public/app/features/dashboard/dashgrid/LazyLoader.tsx b/public/app/features/dashboard/dashgrid/LazyLoader.tsx
index e42d4c8f9c9..2bf951ce466 100644
--- a/public/app/features/dashboard/dashgrid/LazyLoader.tsx
+++ b/public/app/features/dashboard/dashgrid/LazyLoader.tsx
@@ -1,4 +1,5 @@
-import React, { useId, useRef, useState } from 'react';
+import { useId, useRef, useState } from 'react';
+import * as React from 'react';
import { useEffectOnce } from 'react-use';
export interface Props {
diff --git a/public/app/features/dashboard/dashgrid/PanelChromeAngular.tsx b/public/app/features/dashboard/dashgrid/PanelChromeAngular.tsx
index ee81841799e..c17f5a27bad 100644
--- a/public/app/features/dashboard/dashgrid/PanelChromeAngular.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelChromeAngular.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { connect, MapDispatchToProps, MapStateToProps } from 'react-redux';
import { Subscription } from 'rxjs';
diff --git a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenu.tsx b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenu.tsx
index 78a6ce46343..90555fa7535 100644
--- a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenu.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenu.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { PanelMenuItem } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenuWrapper.tsx b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenuWrapper.tsx
index d769112ba99..338573bb23a 100644
--- a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenuWrapper.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderMenuWrapper.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { LoadingState } from '@grafana/data';
diff --git a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderNotice.tsx b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderNotice.tsx
index 9a9ff4be290..0d828d7184f 100644
--- a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderNotice.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderNotice.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2, QueryResultMetaNotice } from '@grafana/data';
import { Icon, ToolbarButton, Tooltip, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderNotices.tsx b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderNotices.tsx
index 29f1222dc85..82936d03c61 100644
--- a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderNotices.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderNotices.tsx
@@ -1,4 +1,5 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
+import * as React from 'react';
import { DataFrame, QueryResultMetaNotice } from '@grafana/data';
import { locationService } from '@grafana/runtime';
diff --git a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderTitleItems.test.tsx b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderTitleItems.test.tsx
index 517bb9ead42..044e5e54f4c 100644
--- a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderTitleItems.test.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderTitleItems.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { LoadingState, TimeRange } from '@grafana/data';
diff --git a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderTitleItems.tsx b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderTitleItems.tsx
index 5f113e1a433..304f5178ff0 100644
--- a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderTitleItems.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderTitleItems.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { PanelData, GrafanaTheme2, PanelModel, LinkModel, AlertState, DataLink } from '@grafana/data';
import { Icon, PanelChrome, Tooltip, useStyles2, TimePickerTooltip } from '@grafana/ui';
diff --git a/public/app/features/dashboard/dashgrid/PanelLinks.tsx b/public/app/features/dashboard/dashgrid/PanelLinks.tsx
index 2d7c8d9e491..4844ee567b4 100644
--- a/public/app/features/dashboard/dashgrid/PanelLinks.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelLinks.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { DataLink, GrafanaTheme2, LinkModel } from '@grafana/data';
import { Dropdown, Icon, Menu, ToolbarButton, useStyles2, PanelChrome } from '@grafana/ui';
diff --git a/public/app/features/dashboard/dashgrid/PanelLoadTimeMonitor.test.tsx b/public/app/features/dashboard/dashgrid/PanelLoadTimeMonitor.test.tsx
index cc960b006f1..48358aa563c 100644
--- a/public/app/features/dashboard/dashgrid/PanelLoadTimeMonitor.test.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelLoadTimeMonitor.test.tsx
@@ -1,5 +1,4 @@
import { render } from '@testing-library/react';
-import React from 'react';
const mockPushMeasurement = jest.fn();
diff --git a/public/app/features/dashboard/dashgrid/PanelStateWrapper.test.tsx b/public/app/features/dashboard/dashgrid/PanelStateWrapper.test.tsx
index c46d74b3728..d37ebdc1af7 100644
--- a/public/app/features/dashboard/dashgrid/PanelStateWrapper.test.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelStateWrapper.test.tsx
@@ -1,5 +1,4 @@
import { act, fireEvent, render, screen } from '@testing-library/react';
-import React from 'react';
import { Provider } from 'react-redux';
import configureMockStore from 'redux-mock-store';
import { ReplaySubject } from 'rxjs';
diff --git a/public/app/features/dashboard/dashgrid/PanelStateWrapper.tsx b/public/app/features/dashboard/dashgrid/PanelStateWrapper.tsx
index 405cf80dd18..c1eb01e3b11 100644
--- a/public/app/features/dashboard/dashgrid/PanelStateWrapper.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelStateWrapper.tsx
@@ -1,5 +1,5 @@
import { debounce } from 'lodash';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { Subscription } from 'rxjs';
import {
diff --git a/public/app/features/dashboard/utils/getPanelChromeProps.tsx b/public/app/features/dashboard/utils/getPanelChromeProps.tsx
index 926a307203c..f430d744943 100644
--- a/public/app/features/dashboard/utils/getPanelChromeProps.tsx
+++ b/public/app/features/dashboard/utils/getPanelChromeProps.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { LinkModel, PanelData, PanelPlugin, renderMarkdown } from '@grafana/data';
import { config, getTemplateSrv, locationService } from '@grafana/runtime';
diff --git a/public/app/features/datasources/components/BasicSettings.test.tsx b/public/app/features/datasources/components/BasicSettings.test.tsx
index 283adbf75ce..893352990b4 100644
--- a/public/app/features/datasources/components/BasicSettings.test.tsx
+++ b/public/app/features/datasources/components/BasicSettings.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/datasources/components/BasicSettings.tsx b/public/app/features/datasources/components/BasicSettings.tsx
index 243b9a946eb..02f6ba4035a 100644
--- a/public/app/features/datasources/components/BasicSettings.tsx
+++ b/public/app/features/datasources/components/BasicSettings.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/datasources/components/ButtonRow.test.tsx b/public/app/features/datasources/components/ButtonRow.test.tsx
index 0fd13592b15..b2bfe7ed35d 100644
--- a/public/app/features/datasources/components/ButtonRow.test.tsx
+++ b/public/app/features/datasources/components/ButtonRow.test.tsx
@@ -1,5 +1,4 @@
import { screen, render } from '@testing-library/react';
-import React from 'react';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/datasources/components/ButtonRow.tsx b/public/app/features/datasources/components/ButtonRow.tsx
index 8239b2f7b56..117b69aa436 100644
--- a/public/app/features/datasources/components/ButtonRow.tsx
+++ b/public/app/features/datasources/components/ButtonRow.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { Button } from '@grafana/ui';
diff --git a/public/app/features/datasources/components/CloudInfoBox.tsx b/public/app/features/datasources/components/CloudInfoBox.tsx
index 5873fd2def2..c34c44ce810 100644
--- a/public/app/features/datasources/components/CloudInfoBox.tsx
+++ b/public/app/features/datasources/components/CloudInfoBox.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { DataSourceSettings } from '@grafana/data';
import { GrafanaEdition } from '@grafana/data/src/types/config';
import { Alert } from '@grafana/ui';
diff --git a/public/app/features/datasources/components/DashboardsTable.test.tsx b/public/app/features/datasources/components/DashboardsTable.test.tsx
index 8ce9bcad388..3aac4b5a6a9 100644
--- a/public/app/features/datasources/components/DashboardsTable.test.tsx
+++ b/public/app/features/datasources/components/DashboardsTable.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { PluginDashboard } from 'app/types';
diff --git a/public/app/features/datasources/components/DashboardsTable.tsx b/public/app/features/datasources/components/DashboardsTable.tsx
index 49eebab0a3a..5ac4705ec88 100644
--- a/public/app/features/datasources/components/DashboardsTable.tsx
+++ b/public/app/features/datasources/components/DashboardsTable.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Button, Icon } from '@grafana/ui';
import { PluginDashboard } from 'app/types';
diff --git a/public/app/features/datasources/components/DataSourceAddButton.tsx b/public/app/features/datasources/components/DataSourceAddButton.tsx
index c236d1fc447..8d7de1d5cc0 100644
--- a/public/app/features/datasources/components/DataSourceAddButton.tsx
+++ b/public/app/features/datasources/components/DataSourceAddButton.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { config } from '@grafana/runtime';
import { LinkButton } from '@grafana/ui';
import { contextSrv } from 'app/core/core';
diff --git a/public/app/features/datasources/components/DataSourceCategories.tsx b/public/app/features/datasources/components/DataSourceCategories.tsx
index 76c73cad02f..89ef44ff3c7 100644
--- a/public/app/features/datasources/components/DataSourceCategories.tsx
+++ b/public/app/features/datasources/components/DataSourceCategories.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { DataSourcePluginMeta, GrafanaTheme2 } from '@grafana/data';
import { LinkButton, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/datasources/components/DataSourceDashboards.test.tsx b/public/app/features/datasources/components/DataSourceDashboards.test.tsx
index 38c94d0dba2..38e9a751267 100644
--- a/public/app/features/datasources/components/DataSourceDashboards.test.tsx
+++ b/public/app/features/datasources/components/DataSourceDashboards.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { Provider } from 'react-redux';
import { configureStore } from 'app/store/configureStore';
diff --git a/public/app/features/datasources/components/DataSourceDashboards.tsx b/public/app/features/datasources/components/DataSourceDashboards.tsx
index 37c8eeaa741..7b954ae9d03 100644
--- a/public/app/features/datasources/components/DataSourceDashboards.tsx
+++ b/public/app/features/datasources/components/DataSourceDashboards.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import PageLoader from 'app/core/components/PageLoader/PageLoader';
import { importDashboard, removeDashboard } from 'app/features/dashboard/state/actions';
diff --git a/public/app/features/datasources/components/DataSourceLoadError.tsx b/public/app/features/datasources/components/DataSourceLoadError.tsx
index de27a9a5436..82b577cae05 100644
--- a/public/app/features/datasources/components/DataSourceLoadError.tsx
+++ b/public/app/features/datasources/components/DataSourceLoadError.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Button } from '@grafana/ui';
import { DataSourceRights } from '../types';
diff --git a/public/app/features/datasources/components/DataSourceMissingRightsMessage.tsx b/public/app/features/datasources/components/DataSourceMissingRightsMessage.tsx
index 420ddf6bd4e..1086367d45b 100644
--- a/public/app/features/datasources/components/DataSourceMissingRightsMessage.tsx
+++ b/public/app/features/datasources/components/DataSourceMissingRightsMessage.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Alert } from '@grafana/ui';
export const missingRightsMessage =
diff --git a/public/app/features/datasources/components/DataSourcePluginConfigPage.tsx b/public/app/features/datasources/components/DataSourcePluginConfigPage.tsx
index d55c9f0a623..17682b5ff1f 100644
--- a/public/app/features/datasources/components/DataSourcePluginConfigPage.tsx
+++ b/public/app/features/datasources/components/DataSourcePluginConfigPage.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { GenericDataSourcePlugin } from '../types';
export type Props = {
diff --git a/public/app/features/datasources/components/DataSourcePluginSettings.tsx b/public/app/features/datasources/components/DataSourcePluginSettings.tsx
index 5e5fa1c57a4..a56911d01b3 100644
--- a/public/app/features/datasources/components/DataSourcePluginSettings.tsx
+++ b/public/app/features/datasources/components/DataSourcePluginSettings.tsx
@@ -1,5 +1,5 @@
import { cloneDeep } from 'lodash';
-import React, { PureComponent } from 'react';
+import { createElement, PureComponent } from 'react';
import { DataSourcePluginMeta, DataSourceSettings } from '@grafana/data';
import { AngularComponent, getAngularLoader } from '@grafana/runtime';
@@ -77,7 +77,7 @@ export class DataSourcePluginSettings extends PureComponent {
return (
(this.element = element)}>
{plugin.components.ConfigEditor &&
- React.createElement(plugin.components.ConfigEditor, {
+ createElement(plugin.components.ConfigEditor, {
options: dataSource,
onOptionsChange: this.onModelChanged,
})}
diff --git a/public/app/features/datasources/components/DataSourcePluginState.tsx b/public/app/features/datasources/components/DataSourcePluginState.tsx
index ac1315607e4..88b53def03c 100644
--- a/public/app/features/datasources/components/DataSourcePluginState.tsx
+++ b/public/app/features/datasources/components/DataSourcePluginState.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PluginState } from '@grafana/data';
import { PluginStateInfo } from 'app/features/plugins/components/PluginStateInfo';
diff --git a/public/app/features/datasources/components/DataSourceReadOnlyMessage.tsx b/public/app/features/datasources/components/DataSourceReadOnlyMessage.tsx
index fc47032432d..de0a437834d 100644
--- a/public/app/features/datasources/components/DataSourceReadOnlyMessage.tsx
+++ b/public/app/features/datasources/components/DataSourceReadOnlyMessage.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { selectors as e2eSelectors } from '@grafana/e2e-selectors';
import { Alert } from '@grafana/ui';
diff --git a/public/app/features/datasources/components/DataSourceTabPage.tsx b/public/app/features/datasources/components/DataSourceTabPage.tsx
index b322de27bf9..2857cebe084 100644
--- a/public/app/features/datasources/components/DataSourceTabPage.tsx
+++ b/public/app/features/datasources/components/DataSourceTabPage.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Page } from 'app/core/components/Page/Page';
import { useDataSourceSettingsNav } from 'app/features/connections/hooks/useDataSourceSettingsNav';
diff --git a/public/app/features/datasources/components/DataSourceTestingStatus.test.tsx b/public/app/features/datasources/components/DataSourceTestingStatus.test.tsx
index e02c98a910a..809e480b927 100644
--- a/public/app/features/datasources/components/DataSourceTestingStatus.test.tsx
+++ b/public/app/features/datasources/components/DataSourceTestingStatus.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { getMockDataSource } from '../__mocks__';
diff --git a/public/app/features/datasources/components/DataSourceTestingStatus.tsx b/public/app/features/datasources/components/DataSourceTestingStatus.tsx
index 99e93655236..a234396e290 100644
--- a/public/app/features/datasources/components/DataSourceTestingStatus.tsx
+++ b/public/app/features/datasources/components/DataSourceTestingStatus.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { HTMLAttributes } from 'react';
+import { HTMLAttributes } from 'react';
import { DataSourceSettings as DataSourceSettingsType, GrafanaTheme2 } from '@grafana/data';
import { selectors as e2eSelectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/datasources/components/DataSourceTitle.tsx b/public/app/features/datasources/components/DataSourceTitle.tsx
index 62321b35a74..846fd3b6cbb 100644
--- a/public/app/features/datasources/components/DataSourceTitle.tsx
+++ b/public/app/features/datasources/components/DataSourceTitle.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/datasources/components/DataSourceTypeCard.tsx b/public/app/features/datasources/components/DataSourceTypeCard.tsx
index 3ad177773de..c939e00cd52 100644
--- a/public/app/features/datasources/components/DataSourceTypeCard.tsx
+++ b/public/app/features/datasources/components/DataSourceTypeCard.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { DataSourcePluginMeta, GrafanaTheme2 } from '@grafana/data';
import { selectors as e2eSelectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/datasources/components/DataSourceTypeCardList.tsx b/public/app/features/datasources/components/DataSourceTypeCardList.tsx
index 1749688f5eb..ffcfa10cdbf 100644
--- a/public/app/features/datasources/components/DataSourceTypeCardList.tsx
+++ b/public/app/features/datasources/components/DataSourceTypeCardList.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { DataSourcePluginMeta } from '@grafana/data';
import { List } from '@grafana/ui';
diff --git a/public/app/features/datasources/components/DataSourcesList.test.tsx b/public/app/features/datasources/components/DataSourcesList.test.tsx
index 06659449116..a3c320f3ed7 100644
--- a/public/app/features/datasources/components/DataSourcesList.test.tsx
+++ b/public/app/features/datasources/components/DataSourcesList.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
diff --git a/public/app/features/datasources/components/DataSourcesList.tsx b/public/app/features/datasources/components/DataSourcesList.tsx
index cb4454dab38..e0ad9e5c19f 100644
--- a/public/app/features/datasources/components/DataSourcesList.tsx
+++ b/public/app/features/datasources/components/DataSourcesList.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
import { DataSourceSettings, GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/datasources/components/DataSourcesListCard.tsx b/public/app/features/datasources/components/DataSourcesListCard.tsx
index 25bbed81d59..f93c3d91def 100644
--- a/public/app/features/datasources/components/DataSourcesListCard.tsx
+++ b/public/app/features/datasources/components/DataSourcesListCard.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import Skeleton from 'react-loading-skeleton';
import { DataSourceSettings, GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/datasources/components/DataSourcesListHeader.tsx b/public/app/features/datasources/components/DataSourcesListHeader.tsx
index 4961a22e172..413d9284045 100644
--- a/public/app/features/datasources/components/DataSourcesListHeader.tsx
+++ b/public/app/features/datasources/components/DataSourcesListHeader.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { SelectableValue } from '@grafana/data';
import PageActionBar from 'app/core/components/PageActionBar/PageActionBar';
diff --git a/public/app/features/datasources/components/EditDataSource.test.tsx b/public/app/features/datasources/components/EditDataSource.test.tsx
index 5962d39b6c0..f858ec485d4 100644
--- a/public/app/features/datasources/components/EditDataSource.test.tsx
+++ b/public/app/features/datasources/components/EditDataSource.test.tsx
@@ -1,5 +1,4 @@
import { screen, render } from '@testing-library/react';
-import React from 'react';
import { Provider } from 'react-redux';
import { PluginExtensionTypes, PluginState } from '@grafana/data';
diff --git a/public/app/features/datasources/components/EditDataSource.tsx b/public/app/features/datasources/components/EditDataSource.tsx
index b23508a020c..afd594ef0ed 100644
--- a/public/app/features/datasources/components/EditDataSource.tsx
+++ b/public/app/features/datasources/components/EditDataSource.tsx
@@ -1,6 +1,7 @@
import { AnyAction } from '@reduxjs/toolkit';
import { omit } from 'lodash';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
+import * as React from 'react';
import {
DataSourcePluginContextProvider,
diff --git a/public/app/features/datasources/components/EditDataSourceActions.tsx b/public/app/features/datasources/components/EditDataSourceActions.tsx
index ffc1eee3c3b..566ba35355e 100644
--- a/public/app/features/datasources/components/EditDataSourceActions.tsx
+++ b/public/app/features/datasources/components/EditDataSourceActions.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { config } from '@grafana/runtime';
import { LinkButton } from '@grafana/ui';
import { contextSrv } from 'app/core/core';
diff --git a/public/app/features/datasources/components/NewDataSource.tsx b/public/app/features/datasources/components/NewDataSource.tsx
index 4414ed7971e..86501a76477 100644
--- a/public/app/features/datasources/components/NewDataSource.tsx
+++ b/public/app/features/datasources/components/NewDataSource.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { AnyAction } from 'redux';
import { DataSourcePluginMeta, PluginType } from '@grafana/data';
diff --git a/public/app/features/datasources/components/picker/AddNewDataSourceButton.tsx b/public/app/features/datasources/components/picker/AddNewDataSourceButton.tsx
index bc7bf9508c5..7e703eeea80 100644
--- a/public/app/features/datasources/components/picker/AddNewDataSourceButton.tsx
+++ b/public/app/features/datasources/components/picker/AddNewDataSourceButton.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { LinkButton, ButtonVariant } from '@grafana/ui';
import { contextSrv } from 'app/core/core';
import { Trans } from 'app/core/internationalization';
diff --git a/public/app/features/datasources/components/picker/BuiltInDataSourceList.tsx b/public/app/features/datasources/components/picker/BuiltInDataSourceList.tsx
index 513c33e0027..d282962315a 100644
--- a/public/app/features/datasources/components/picker/BuiltInDataSourceList.tsx
+++ b/public/app/features/datasources/components/picker/BuiltInDataSourceList.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { DataSourceInstanceSettings } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { DataSourceRef } from '@grafana/schema';
diff --git a/public/app/features/datasources/components/picker/DataSourceCard.tsx b/public/app/features/datasources/components/picker/DataSourceCard.tsx
index 162fbaea0d6..ba0c71aa144 100644
--- a/public/app/features/datasources/components/picker/DataSourceCard.tsx
+++ b/public/app/features/datasources/components/picker/DataSourceCard.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { DataSourceInstanceSettings, GrafanaTheme2 } from '@grafana/data';
import { Card, TagList, useTheme2 } from '@grafana/ui';
diff --git a/public/app/features/datasources/components/picker/DataSourceList.tsx b/public/app/features/datasources/components/picker/DataSourceList.tsx
index 0d2238a8820..fa2600418a6 100644
--- a/public/app/features/datasources/components/picker/DataSourceList.tsx
+++ b/public/app/features/datasources/components/picker/DataSourceList.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { useRef } from 'react';
+import { useRef } from 'react';
+import * as React from 'react';
import { Observable } from 'rxjs';
import { DataSourceInstanceSettings, DataSourceRef, GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/datasources/components/picker/DataSourceLogo.tsx b/public/app/features/datasources/components/picker/DataSourceLogo.tsx
index 022ed55573f..35b2ae5ed7d 100644
--- a/public/app/features/datasources/components/picker/DataSourceLogo.tsx
+++ b/public/app/features/datasources/components/picker/DataSourceLogo.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { DataSourceInstanceSettings, DataSourceJsonData, GrafanaTheme2 } from '@grafana/data';
import { useStyles2, useTheme2 } from '@grafana/ui';
diff --git a/public/app/features/datasources/components/picker/DataSourceModal.test.tsx b/public/app/features/datasources/components/picker/DataSourceModal.test.tsx
index 1f6a622d660..c4e1251f984 100644
--- a/public/app/features/datasources/components/picker/DataSourceModal.test.tsx
+++ b/public/app/features/datasources/components/picker/DataSourceModal.test.tsx
@@ -1,6 +1,5 @@
import { queryByTestId, render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { DataSourceInstanceSettings, DataSourcePluginMeta, PluginMetaInfo, PluginType } from '@grafana/data';
import { config } from '@grafana/runtime';
diff --git a/public/app/features/datasources/components/picker/DataSourceModal.tsx b/public/app/features/datasources/components/picker/DataSourceModal.tsx
index 6c416042cce..908f13670a2 100644
--- a/public/app/features/datasources/components/picker/DataSourceModal.tsx
+++ b/public/app/features/datasources/components/picker/DataSourceModal.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { once } from 'lodash';
-import React, { useState } from 'react';
+import { useMemo, useState } from 'react';
import { DataSourceInstanceSettings, DataSourceRef, GrafanaTheme2 } from '@grafana/data';
import { config, reportInteraction } from '@grafana/runtime';
@@ -93,7 +93,7 @@ export function DataSourceModal({
});
};
// Memoizing to keep once() cached so it avoids reporting multiple times
- const reportSearchUsageOnce = React.useMemo(
+ const reportSearchUsageOnce = useMemo(
() =>
once(() => {
reportInteraction(INTERACTION_EVENT_NAME, { item: 'search', src: analyticsInteractionSrc });
diff --git a/public/app/features/datasources/components/picker/DataSourcePicker.test.tsx b/public/app/features/datasources/components/picker/DataSourcePicker.test.tsx
index c13140a43c3..2395065224b 100644
--- a/public/app/features/datasources/components/picker/DataSourcePicker.test.tsx
+++ b/public/app/features/datasources/components/picker/DataSourcePicker.test.tsx
@@ -1,7 +1,6 @@
import { findByText, render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { UserEvent } from '@testing-library/user-event/dist/types/setup/setup';
-import React from 'react';
import { DataSourceInstanceSettings, DataSourcePluginMeta, PluginMetaInfo, PluginType } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/datasources/components/picker/DataSourcePicker.tsx b/public/app/features/datasources/components/picker/DataSourcePicker.tsx
index 994fcc67bcc..14dd2676050 100644
--- a/public/app/features/datasources/components/picker/DataSourcePicker.tsx
+++ b/public/app/features/datasources/components/picker/DataSourcePicker.tsx
@@ -3,7 +3,8 @@ import { autoUpdate, flip, offset, shift, size, useFloating } from '@floating-ui
import { useDialog } from '@react-aria/dialog';
import { FocusScope } from '@react-aria/focus';
import { useOverlay } from '@react-aria/overlays';
-import React, { useCallback, useEffect, useRef, useState } from 'react';
+import { useCallback, useEffect, useRef, useState } from 'react';
+import * as React from 'react';
import { Observable } from 'rxjs';
import { DataSourceInstanceSettings, GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/datasources/components/useDataSourceInfo.tsx b/public/app/features/datasources/components/useDataSourceInfo.tsx
index 7285c2a0a8c..c3cc951214d 100644
--- a/public/app/features/datasources/components/useDataSourceInfo.tsx
+++ b/public/app/features/datasources/components/useDataSourceInfo.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Badge } from '@grafana/ui';
import { PageInfoItem } from 'app/core/components/Page/types';
diff --git a/public/app/features/datasources/hooks.ts b/public/app/features/datasources/hooks.ts
index 54b6eeceb23..3a08d716cb2 100644
--- a/public/app/features/datasources/hooks.ts
+++ b/public/app/features/datasources/hooks.ts
@@ -1,4 +1,5 @@
-import React, { useCallback, useEffect, useRef } from 'react';
+import { useCallback, useEffect, useRef } from 'react';
+import * as React from 'react';
import { useLocalStorage } from 'react-use';
import { Observable } from 'rxjs';
diff --git a/public/app/features/dimensions/editors/BackgroundSizeEditor.tsx b/public/app/features/dimensions/editors/BackgroundSizeEditor.tsx
index 8d51bb2bdf5..0e2df696124 100644
--- a/public/app/features/dimensions/editors/BackgroundSizeEditor.tsx
+++ b/public/app/features/dimensions/editors/BackgroundSizeEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { SelectableValue, StandardEditorProps } from '@grafana/data';
import { InlineField, InlineFieldRow, RadioButtonGroup } from '@grafana/ui/src';
diff --git a/public/app/features/dimensions/editors/ColorDimensionEditor.tsx b/public/app/features/dimensions/editors/ColorDimensionEditor.tsx
index 2cbbab2b3e7..d0b8b7a9c3c 100644
--- a/public/app/features/dimensions/editors/ColorDimensionEditor.tsx
+++ b/public/app/features/dimensions/editors/ColorDimensionEditor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { GrafanaTheme2, SelectableValue, StandardEditorProps, FieldNamePickerBaseNameMode } from '@grafana/data';
import { ColorDimensionConfig } from '@grafana/schema';
diff --git a/public/app/features/dimensions/editors/FileUploader.tsx b/public/app/features/dimensions/editors/FileUploader.tsx
index 7e58eaf4617..fe7373ccabc 100644
--- a/public/app/features/dimensions/editors/FileUploader.tsx
+++ b/public/app/features/dimensions/editors/FileUploader.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { Dispatch, SetStateAction, useState } from 'react';
+import { Dispatch, SetStateAction, useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { FileDropzone, useStyles2, Button, DropzoneFile, Field } from '@grafana/ui';
diff --git a/public/app/features/dimensions/editors/FolderPickerTab.tsx b/public/app/features/dimensions/editors/FolderPickerTab.tsx
index ec7c2255022..cdd7e2eb61f 100644
--- a/public/app/features/dimensions/editors/FolderPickerTab.tsx
+++ b/public/app/features/dimensions/editors/FolderPickerTab.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { Dispatch, SetStateAction, useEffect, useState } from 'react';
+import { Dispatch, SetStateAction, useEffect, useState } from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { Field, FilterInput, Select, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/dimensions/editors/IconSelector.tsx b/public/app/features/dimensions/editors/IconSelector.tsx
index 6f383e6ad06..3e5bfcbb951 100644
--- a/public/app/features/dimensions/editors/IconSelector.tsx
+++ b/public/app/features/dimensions/editors/IconSelector.tsx
@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from 'react';
+import { useState, useEffect } from 'react';
import { SelectableValue } from '@grafana/data';
import { getBackendSrv } from '@grafana/runtime';
diff --git a/public/app/features/dimensions/editors/ResourceCards.tsx b/public/app/features/dimensions/editors/ResourceCards.tsx
index 77006929f4a..33e6fa87081 100644
--- a/public/app/features/dimensions/editors/ResourceCards.tsx
+++ b/public/app/features/dimensions/editors/ResourceCards.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { memo, CSSProperties } from 'react';
+import { memo, CSSProperties } from 'react';
+import * as React from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
import { areEqual, FixedSizeGrid as Grid } from 'react-window';
diff --git a/public/app/features/dimensions/editors/ResourceDimensionEditor.tsx b/public/app/features/dimensions/editors/ResourceDimensionEditor.tsx
index 925ac4fdbb7..457152533eb 100644
--- a/public/app/features/dimensions/editors/ResourceDimensionEditor.tsx
+++ b/public/app/features/dimensions/editors/ResourceDimensionEditor.tsx
@@ -1,4 +1,5 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
+import * as React from 'react';
import { FieldNamePickerConfigSettings, StandardEditorProps, StandardEditorsRegistryItem } from '@grafana/data';
import { ResourceDimensionConfig, ResourceDimensionMode } from '@grafana/schema';
diff --git a/public/app/features/dimensions/editors/ResourcePicker.tsx b/public/app/features/dimensions/editors/ResourcePicker.tsx
index 19af481161d..737b0cac4b0 100644
--- a/public/app/features/dimensions/editors/ResourcePicker.tsx
+++ b/public/app/features/dimensions/editors/ResourcePicker.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { createRef } from 'react';
+import { createRef } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import {
diff --git a/public/app/features/dimensions/editors/ResourcePickerPopover.tsx b/public/app/features/dimensions/editors/ResourcePickerPopover.tsx
index 2a72c20a9e2..3becc33cfba 100644
--- a/public/app/features/dimensions/editors/ResourcePickerPopover.tsx
+++ b/public/app/features/dimensions/editors/ResourcePickerPopover.tsx
@@ -2,7 +2,7 @@ import { css } from '@emotion/css';
import { useDialog } from '@react-aria/dialog';
import { FocusScope } from '@react-aria/focus';
import { useOverlay } from '@react-aria/overlays';
-import React, { createRef, useState } from 'react';
+import { createRef, useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { getBackendSrv } from '@grafana/runtime';
diff --git a/public/app/features/dimensions/editors/ScalarDimensionEditor.tsx b/public/app/features/dimensions/editors/ScalarDimensionEditor.tsx
index f9eb5432ce1..aaacb13b841 100644
--- a/public/app/features/dimensions/editors/ScalarDimensionEditor.tsx
+++ b/public/app/features/dimensions/editors/ScalarDimensionEditor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { FieldType, GrafanaTheme2, SelectableValue, StandardEditorProps } from '@grafana/data';
import { ScalarDimensionMode, ScalarDimensionConfig } from '@grafana/schema';
diff --git a/public/app/features/dimensions/editors/ScaleDimensionEditor.tsx b/public/app/features/dimensions/editors/ScaleDimensionEditor.tsx
index d15ee101cb7..df20b6a5761 100644
--- a/public/app/features/dimensions/editors/ScaleDimensionEditor.tsx
+++ b/public/app/features/dimensions/editors/ScaleDimensionEditor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useCallback, useMemo } from 'react';
+import { useCallback, useMemo } from 'react';
import { GrafanaTheme2, SelectableValue, StandardEditorProps } from '@grafana/data';
import { ScaleDimensionConfig } from '@grafana/schema';
diff --git a/public/app/features/dimensions/editors/TextDimensionEditor.tsx b/public/app/features/dimensions/editors/TextDimensionEditor.tsx
index 65b12180e54..9f345e43a7e 100644
--- a/public/app/features/dimensions/editors/TextDimensionEditor.tsx
+++ b/public/app/features/dimensions/editors/TextDimensionEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import {
FieldNamePickerConfigSettings,
diff --git a/public/app/features/dimensions/editors/ThresholdsEditor/ThresholdsEditor.test.tsx b/public/app/features/dimensions/editors/ThresholdsEditor/ThresholdsEditor.test.tsx
index 77781f098ad..b014aef0408 100644
--- a/public/app/features/dimensions/editors/ThresholdsEditor/ThresholdsEditor.test.tsx
+++ b/public/app/features/dimensions/editors/ThresholdsEditor/ThresholdsEditor.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { createTheme, Threshold, ThresholdsMode } from '@grafana/data';
import { mockThemeContext } from '@grafana/ui';
diff --git a/public/app/features/dimensions/editors/ThresholdsEditor/ThresholdsEditor.tsx b/public/app/features/dimensions/editors/ThresholdsEditor/ThresholdsEditor.tsx
index b980f611d4f..0988e4170c6 100644
--- a/public/app/features/dimensions/editors/ThresholdsEditor/ThresholdsEditor.tsx
+++ b/public/app/features/dimensions/editors/ThresholdsEditor/ThresholdsEditor.tsx
@@ -1,6 +1,7 @@
import { css } from '@emotion/css';
import { isNumber } from 'lodash';
-import React, { ChangeEvent, PureComponent } from 'react';
+import { ChangeEvent, PureComponent } from 'react';
+import * as React from 'react';
import {
GrafanaTheme2,
diff --git a/public/app/features/dimensions/editors/ThresholdsEditor/thresholds.tsx b/public/app/features/dimensions/editors/ThresholdsEditor/thresholds.tsx
index e89003ba9f9..335300534f4 100644
--- a/public/app/features/dimensions/editors/ThresholdsEditor/thresholds.tsx
+++ b/public/app/features/dimensions/editors/ThresholdsEditor/thresholds.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
import { StandardEditorProps, ThresholdsConfig, ThresholdsMode, ThresholdsFieldConfigSettings } from '@grafana/data';
@@ -6,7 +6,7 @@ import { ThresholdsEditor } from './ThresholdsEditor';
type Props = StandardEditorProps
;
-export class ThresholdsValueEditor extends React.PureComponent {
+export class ThresholdsValueEditor extends PureComponent {
constructor(props: Props) {
super(props);
}
diff --git a/public/app/features/dimensions/editors/URLPickerTab.tsx b/public/app/features/dimensions/editors/URLPickerTab.tsx
index 51504e36dd2..9bc7c861e78 100644
--- a/public/app/features/dimensions/editors/URLPickerTab.tsx
+++ b/public/app/features/dimensions/editors/URLPickerTab.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { Dispatch, SetStateAction } from 'react';
+import { Dispatch, SetStateAction } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Field, Input, Label, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingEditRow.tsx b/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingEditRow.tsx
index 27120d7b56e..3e316222664 100644
--- a/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingEditRow.tsx
+++ b/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingEditRow.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useCallback, useEffect, useRef } from 'react';
+import { useCallback, useEffect, useRef } from 'react';
+import * as React from 'react';
import { Draggable } from 'react-beautiful-dnd';
import { GrafanaTheme2, MappingType, SpecialValueMatch, SelectableValue, ValueMappingResult } from '@grafana/data';
diff --git a/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditor.test.tsx b/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditor.test.tsx
index c62fc73bf78..33ba102f63d 100644
--- a/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditor.test.tsx
+++ b/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditor.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { MappingType, StandardEditorsRegistryItem } from '@grafana/data';
diff --git a/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditor.tsx b/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditor.tsx
index 120bcb43d04..9bdb3ec96c8 100644
--- a/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditor.tsx
+++ b/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useCallback, useMemo, useState } from 'react';
+import { memo, useCallback, useMemo, useState } from 'react';
import { GrafanaTheme2, MappingType, StandardEditorProps, ValueMapping } from '@grafana/data';
import { useStyles2, VerticalGroup, Icon, ColorPicker, Button, Modal } from '@grafana/ui';
@@ -13,7 +13,7 @@ export interface Props extends StandardEditorProps {
showIcon?: boolean;
}
-export const ValueMappingsEditor = React.memo((props: Props) => {
+export const ValueMappingsEditor = memo((props: Props) => {
const { value, onChange, item } = props;
const styles = useStyles2(getStyles);
diff --git a/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditorModal.test.tsx b/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditorModal.test.tsx
index 14f7d348d46..1090c942122 100644
--- a/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditorModal.test.tsx
+++ b/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditorModal.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { selectOptionInTest } from 'test/helpers/selectOptionInTest';
import { MappingType } from '@grafana/data';
diff --git a/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditorModal.tsx b/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditorModal.tsx
index cce6d85614c..ae9aaf3c9c0 100644
--- a/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditorModal.tsx
+++ b/public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditorModal.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { uniqueId } from 'lodash';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd';
import { GrafanaTheme2, MappingType, SelectableValue, SpecialValueMatch, ValueMapping } from '@grafana/data';
diff --git a/public/app/features/explore/ContentOutline/ContentOutline.test.tsx b/public/app/features/explore/ContentOutline/ContentOutline.test.tsx
index b79c823859c..537755195bf 100644
--- a/public/app/features/explore/ContentOutline/ContentOutline.test.tsx
+++ b/public/app/features/explore/ContentOutline/ContentOutline.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { ContentOutline } from './ContentOutline';
diff --git a/public/app/features/explore/ContentOutline/ContentOutline.tsx b/public/app/features/explore/ContentOutline/ContentOutline.tsx
index 05d5adda510..a40362363de 100644
--- a/public/app/features/explore/ContentOutline/ContentOutline.tsx
+++ b/public/app/features/explore/ContentOutline/ContentOutline.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { useEffect, useRef, useState } from 'react';
+import { Fragment, useEffect, useRef, useState } from 'react';
import { useToggle, useScroll } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
@@ -158,7 +158,7 @@ export function ContentOutline({ scroller, panelId }: { scroller: HTMLElement |
{outlineItems.map((item) => {
return (
-
+
))}
-
+
);
})}
diff --git a/public/app/features/explore/ContentOutline/ContentOutlineContext.tsx b/public/app/features/explore/ContentOutline/ContentOutlineContext.tsx
index 3e91de93e83..d2189f88e1a 100644
--- a/public/app/features/explore/ContentOutline/ContentOutlineContext.tsx
+++ b/public/app/features/explore/ContentOutline/ContentOutlineContext.tsx
@@ -1,5 +1,5 @@
import { uniqueId } from 'lodash';
-import React, { useState, useContext, createContext, ReactNode, useCallback, useRef, useEffect } from 'react';
+import { useState, useContext, createContext, ReactNode, useCallback, useRef, useEffect } from 'react';
import { ContentOutlineItemBaseProps, ITEM_TYPES } from './ContentOutlineItem';
diff --git a/public/app/features/explore/ContentOutline/ContentOutlineItem.tsx b/public/app/features/explore/ContentOutline/ContentOutlineItem.tsx
index 6db6252ed2a..0d8c6fedbf0 100644
--- a/public/app/features/explore/ContentOutline/ContentOutlineItem.tsx
+++ b/public/app/features/explore/ContentOutline/ContentOutlineItem.tsx
@@ -1,4 +1,5 @@
-import React, { useEffect, useRef, ReactNode } from 'react';
+import { useEffect, useRef, ReactNode } from 'react';
+import * as React from 'react';
import { useContentOutlineContext } from './ContentOutlineContext';
diff --git a/public/app/features/explore/ContentOutline/ContentOutlineItemButton.tsx b/public/app/features/explore/ContentOutline/ContentOutlineItemButton.tsx
index 4b45e2efa79..a12de2635f5 100644
--- a/public/app/features/explore/ContentOutline/ContentOutlineItemButton.tsx
+++ b/public/app/features/explore/ContentOutline/ContentOutlineItemButton.tsx
@@ -1,5 +1,6 @@
import { cx, css } from '@emotion/css';
-import React, { ButtonHTMLAttributes, useEffect, useRef, useState } from 'react';
+import { ButtonHTMLAttributes, useEffect, useRef, useState } from 'react';
+import * as React from 'react';
import { IconName, isIconName, GrafanaTheme2 } from '@grafana/data';
import { Button, Icon, Tooltip, useTheme2 } from '@grafana/ui';
diff --git a/public/app/features/explore/CorrelationEditorModeBar.tsx b/public/app/features/explore/CorrelationEditorModeBar.tsx
index cca5fa35bc4..401c56421ea 100644
--- a/public/app/features/explore/CorrelationEditorModeBar.tsx
+++ b/public/app/features/explore/CorrelationEditorModeBar.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { Prompt } from 'react-router-dom';
import { useBeforeUnload, useUnmount } from 'react-use';
diff --git a/public/app/features/explore/CorrelationHelper.tsx b/public/app/features/explore/CorrelationHelper.tsx
index c352410ddb5..14bcd722857 100644
--- a/public/app/features/explore/CorrelationHelper.tsx
+++ b/public/app/features/explore/CorrelationHelper.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState, useEffect, useId } from 'react';
+import { useState, useEffect, useId } from 'react';
import { useForm } from 'react-hook-form';
import { useAsync } from 'react-use';
diff --git a/public/app/features/explore/CorrelationTransformationAddModal.tsx b/public/app/features/explore/CorrelationTransformationAddModal.tsx
index f99414d5890..6c97ab11c09 100644
--- a/public/app/features/explore/CorrelationTransformationAddModal.tsx
+++ b/public/app/features/explore/CorrelationTransformationAddModal.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useId, useState, useMemo, useEffect } from 'react';
+import { useId, useState, useMemo, useEffect } from 'react';
import Highlighter from 'react-highlight-words';
import { useForm, Controller } from 'react-hook-form';
diff --git a/public/app/features/explore/CorrelationUnsavedChangesModal.tsx b/public/app/features/explore/CorrelationUnsavedChangesModal.tsx
index 45883d7a87b..5aaf6f2fc9e 100644
--- a/public/app/features/explore/CorrelationUnsavedChangesModal.tsx
+++ b/public/app/features/explore/CorrelationUnsavedChangesModal.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { Button, Modal } from '@grafana/ui';
diff --git a/public/app/features/explore/CustomContainer.tsx b/public/app/features/explore/CustomContainer.tsx
index dbbba6c798b..1a9c1286693 100644
--- a/public/app/features/explore/CustomContainer.tsx
+++ b/public/app/features/explore/CustomContainer.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { AbsoluteTimeRange, DataFrame, dateTime, EventBus, LoadingState, SplitOpen } from '@grafana/data';
import { PanelRenderer } from '@grafana/runtime';
diff --git a/public/app/features/explore/ElapsedTime.tsx b/public/app/features/explore/ElapsedTime.tsx
index 9996100f93a..3519a22ee19 100644
--- a/public/app/features/explore/ElapsedTime.tsx
+++ b/public/app/features/explore/ElapsedTime.tsx
@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from 'react';
+import { useState, useEffect } from 'react';
import { useInterval } from 'react-use';
import { Time, TimeProps } from './Time';
diff --git a/public/app/features/explore/ErrorContainer.test.tsx b/public/app/features/explore/ErrorContainer.test.tsx
index a3699acc9d4..381569a4247 100644
--- a/public/app/features/explore/ErrorContainer.test.tsx
+++ b/public/app/features/explore/ErrorContainer.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { ErrorContainer, ErrorContainerProps } from './ErrorContainer';
diff --git a/public/app/features/explore/ErrorContainer.tsx b/public/app/features/explore/ErrorContainer.tsx
index c93b044b797..38b94ec7093 100644
--- a/public/app/features/explore/ErrorContainer.tsx
+++ b/public/app/features/explore/ErrorContainer.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { DataQueryError } from '@grafana/data';
import { Alert } from '@grafana/ui';
import { FadeIn } from 'app/core/components/Animations/FadeIn';
diff --git a/public/app/features/explore/Explore.test.tsx b/public/app/features/explore/Explore.test.tsx
index 70de7d816ad..4ea74b48fc4 100644
--- a/public/app/features/explore/Explore.test.tsx
+++ b/public/app/features/explore/Explore.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { Props as AutoSizerProps } from 'react-virtualized-auto-sizer';
import { TestProvider } from 'test/helpers/TestProvider';
diff --git a/public/app/features/explore/Explore.tsx b/public/app/features/explore/Explore.tsx
index 7fc9e95c58b..22ce2d7688b 100644
--- a/public/app/features/explore/Explore.tsx
+++ b/public/app/features/explore/Explore.tsx
@@ -1,6 +1,6 @@
import { css, cx } from '@emotion/css';
import { get, groupBy } from 'lodash';
-import React from 'react';
+import { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import AutoSizer, { HorizontalSize } from 'react-virtualized-auto-sizer';
@@ -139,7 +139,7 @@ export type Props = ExploreProps & ConnectedProps;
* `format`, to indicate eventual transformations by the datasources' result transformers.
*/
-export class Explore extends React.PureComponent {
+export class Explore extends PureComponent {
scrollElement: HTMLDivElement | undefined;
graphEventBus: EventBus;
logsEventBus: EventBus;
diff --git a/public/app/features/explore/ExploreDrawer.tsx b/public/app/features/explore/ExploreDrawer.tsx
index 2b5c82f0b9b..e3199701c0a 100644
--- a/public/app/features/explore/ExploreDrawer.tsx
+++ b/public/app/features/explore/ExploreDrawer.tsx
@@ -1,7 +1,7 @@
// Libraries
import { css, cx, keyframes } from '@emotion/css';
import { Resizable, ResizeCallback } from 're-resizable';
-import React from 'react';
+import * as React from 'react';
// Services & Utils
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/explore/ExplorePage.tsx b/public/app/features/explore/ExplorePage.tsx
index b50317e1a8e..050c0eaf16f 100644
--- a/public/app/features/explore/ExplorePage.tsx
+++ b/public/app/features/explore/ExplorePage.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { config } from '@grafana/runtime';
diff --git a/public/app/features/explore/ExplorePaneContainer.tsx b/public/app/features/explore/ExplorePaneContainer.tsx
index a8b8feace21..9a43fed4656 100644
--- a/public/app/features/explore/ExplorePaneContainer.tsx
+++ b/public/app/features/explore/ExplorePaneContainer.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useMemo, useRef, useState } from 'react';
+import { useEffect, useMemo, useRef, useState } from 'react';
import { connect } from 'react-redux';
import { EventBusSrv, getTimeZone } from '@grafana/data';
diff --git a/public/app/features/explore/ExploreQueryInspector.test.tsx b/public/app/features/explore/ExploreQueryInspector.test.tsx
index 734e206848c..5b085980883 100644
--- a/public/app/features/explore/ExploreQueryInspector.test.tsx
+++ b/public/app/features/explore/ExploreQueryInspector.test.tsx
@@ -1,5 +1,5 @@
import { render, screen, fireEvent } from '@testing-library/react';
-import React, { ComponentProps } from 'react';
+import { ComponentProps } from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
import { Observable } from 'rxjs';
diff --git a/public/app/features/explore/ExploreQueryInspector.tsx b/public/app/features/explore/ExploreQueryInspector.tsx
index f04cc153c89..a414197294a 100644
--- a/public/app/features/explore/ExploreQueryInspector.tsx
+++ b/public/app/features/explore/ExploreQueryInspector.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { CoreApp, GrafanaTheme2, LoadingState } from '@grafana/data';
diff --git a/public/app/features/explore/ExploreRunQueryButton.test.tsx b/public/app/features/explore/ExploreRunQueryButton.test.tsx
index 5860c852657..e2b518654e9 100644
--- a/public/app/features/explore/ExploreRunQueryButton.test.tsx
+++ b/public/app/features/explore/ExploreRunQueryButton.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { Provider } from 'react-redux';
import { DatasourceSrvMock, MockDataSourceApi } from 'test/mocks/datasource_srv';
diff --git a/public/app/features/explore/ExploreRunQueryButton.tsx b/public/app/features/explore/ExploreRunQueryButton.tsx
index d1e9132482c..26d1f03b894 100644
--- a/public/app/features/explore/ExploreRunQueryButton.tsx
+++ b/public/app/features/explore/ExploreRunQueryButton.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { ConnectedProps, connect } from 'react-redux';
import { config, reportInteraction } from '@grafana/runtime';
diff --git a/public/app/features/explore/ExploreTimeControls.tsx b/public/app/features/explore/ExploreTimeControls.tsx
index 5401395b842..07c92e8fba5 100644
--- a/public/app/features/explore/ExploreTimeControls.tsx
+++ b/public/app/features/explore/ExploreTimeControls.tsx
@@ -1,4 +1,4 @@
-import React, { Component } from 'react';
+import { Component } from 'react';
import { TimeRange, RawTimeRange, dateTimeForTimeZone, dateMath } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime';
diff --git a/public/app/features/explore/ExploreToolbar.tsx b/public/app/features/explore/ExploreToolbar.tsx
index 2cbf320e0ca..a97aa3a46d9 100644
--- a/public/app/features/explore/ExploreToolbar.tsx
+++ b/public/app/features/explore/ExploreToolbar.tsx
@@ -1,6 +1,6 @@
import { css, cx } from '@emotion/css';
import { pick } from 'lodash';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { shallowEqual } from 'react-redux';
import { DataSourceInstanceSettings, RawTimeRange, GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/explore/FeatureTogglePage.tsx b/public/app/features/explore/FeatureTogglePage.tsx
index f7ca69bd6d2..30ea2ad3c48 100644
--- a/public/app/features/explore/FeatureTogglePage.tsx
+++ b/public/app/features/explore/FeatureTogglePage.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/explore/FlameGraph/FlameGraphExploreContainer.tsx b/public/app/features/explore/FlameGraph/FlameGraphExploreContainer.tsx
index 43d7ceb7e54..7e2b5198c9a 100644
--- a/public/app/features/explore/FlameGraph/FlameGraphExploreContainer.tsx
+++ b/public/app/features/explore/FlameGraph/FlameGraphExploreContainer.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { DataFrame, GrafanaTheme2, CoreApp } from '@grafana/data';
import { FlameGraph } from '@grafana/flamegraph';
diff --git a/public/app/features/explore/Graph/ExploreGraph.tsx b/public/app/features/explore/Graph/ExploreGraph.tsx
index cb09a5481fb..221ee9c1f37 100644
--- a/public/app/features/explore/Graph/ExploreGraph.tsx
+++ b/public/app/features/explore/Graph/ExploreGraph.tsx
@@ -1,5 +1,6 @@
import { identity } from 'lodash';
-import React, { useEffect, useMemo, useRef, useState } from 'react';
+import { useEffect, useMemo, useRef, useState } from 'react';
+import * as React from 'react';
import { usePrevious } from 'react-use';
import {
diff --git a/public/app/features/explore/Graph/ExploreGraphLabel.tsx b/public/app/features/explore/Graph/ExploreGraphLabel.tsx
index 72d1c609d2c..a8be709f53b 100644
--- a/public/app/features/explore/Graph/ExploreGraphLabel.tsx
+++ b/public/app/features/explore/Graph/ExploreGraphLabel.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SelectableValue } from '@grafana/data';
import { RadioButtonGroup } from '@grafana/ui';
import { EXPLORE_GRAPH_STYLES, ExploreGraphStyle } from 'app/types';
diff --git a/public/app/features/explore/Graph/GraphContainer.tsx b/public/app/features/explore/Graph/GraphContainer.tsx
index 19edc6aff48..e844073f7ab 100644
--- a/public/app/features/explore/Graph/GraphContainer.tsx
+++ b/public/app/features/explore/Graph/GraphContainer.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useCallback, useMemo, useState } from 'react';
+import { useCallback, useMemo, useState } from 'react';
import { useToggle } from 'react-use';
import {
diff --git a/public/app/features/explore/LiveTailButton.tsx b/public/app/features/explore/LiveTailButton.tsx
index 81d71a18b6e..bcfcb121a0b 100644
--- a/public/app/features/explore/LiveTailButton.tsx
+++ b/public/app/features/explore/LiveTailButton.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useRef } from 'react';
+import { useRef } from 'react';
import { CSSTransition } from 'react-transition-group';
import { Tooltip, ButtonGroup, ToolbarButton } from '@grafana/ui';
diff --git a/public/app/features/explore/Logs/LiveLogs.test.tsx b/public/app/features/explore/Logs/LiveLogs.test.tsx
index 9606d6c0858..83fb5e13fb8 100644
--- a/public/app/features/explore/Logs/LiveLogs.test.tsx
+++ b/public/app/features/explore/Logs/LiveLogs.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { LogRowModel } from '@grafana/data';
diff --git a/public/app/features/explore/Logs/LiveLogs.tsx b/public/app/features/explore/Logs/LiveLogs.tsx
index 0a269840e2f..31b7d2f87cf 100644
--- a/public/app/features/explore/Logs/LiveLogs.tsx
+++ b/public/app/features/explore/Logs/LiveLogs.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
+import * as React from 'react';
import tinycolor from 'tinycolor2';
import { LogRowModel, dateTimeFormat, GrafanaTheme2, LogsSortOrder } from '@grafana/data';
diff --git a/public/app/features/explore/Logs/Logs.test.tsx b/public/app/features/explore/Logs/Logs.test.tsx
index e5f46da4923..ec8ddda9938 100644
--- a/public/app/features/explore/Logs/Logs.test.tsx
+++ b/public/app/features/explore/Logs/Logs.test.tsx
@@ -1,6 +1,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { ComponentProps } from 'react';
+import { ComponentProps } from 'react';
import { Provider } from 'react-redux';
import {
diff --git a/public/app/features/explore/Logs/Logs.tsx b/public/app/features/explore/Logs/Logs.tsx
index fb671e75b54..0544b3720fd 100644
--- a/public/app/features/explore/Logs/Logs.tsx
+++ b/public/app/features/explore/Logs/Logs.tsx
@@ -1,7 +1,8 @@
import { css, cx } from '@emotion/css';
import { capitalize, groupBy } from 'lodash';
import memoizeOne from 'memoize-one';
-import React, { useCallback, useEffect, useState, useRef } from 'react';
+import { useCallback, useEffect, useState, useRef } from 'react';
+import * as React from 'react';
import { usePrevious, useUnmount } from 'react-use';
import {
diff --git a/public/app/features/explore/Logs/LogsColumnSearch.tsx b/public/app/features/explore/Logs/LogsColumnSearch.tsx
index 33faae16435..1569d02bb76 100644
--- a/public/app/features/explore/Logs/LogsColumnSearch.tsx
+++ b/public/app/features/explore/Logs/LogsColumnSearch.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data/src';
import { Field, Input, useTheme2 } from '@grafana/ui/src';
diff --git a/public/app/features/explore/Logs/LogsContainer.tsx b/public/app/features/explore/Logs/LogsContainer.tsx
index aef5c4792e8..0b56ffdf521 100644
--- a/public/app/features/explore/Logs/LogsContainer.tsx
+++ b/public/app/features/explore/Logs/LogsContainer.tsx
@@ -1,4 +1,5 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
+import * as React from 'react';
import { connect, ConnectedProps } from 'react-redux';
import {
diff --git a/public/app/features/explore/Logs/LogsFeedback.tsx b/public/app/features/explore/Logs/LogsFeedback.tsx
index 91b3e1aa0a1..df042d16449 100644
--- a/public/app/features/explore/Logs/LogsFeedback.tsx
+++ b/public/app/features/explore/Logs/LogsFeedback.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Icon, Stack, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/explore/Logs/LogsMetaRow.test.tsx b/public/app/features/explore/Logs/LogsMetaRow.test.tsx
index 83755343cdb..4774402dbc0 100644
--- a/public/app/features/explore/Logs/LogsMetaRow.test.tsx
+++ b/public/app/features/explore/Logs/LogsMetaRow.test.tsx
@@ -1,7 +1,7 @@
import { fireEvent, render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import saveAs from 'file-saver';
-import React, { ComponentProps } from 'react';
+import { ComponentProps } from 'react';
import { FieldType, LogLevel, LogsDedupStrategy, standardTransformersRegistry, toDataFrame } from '@grafana/data';
import { organizeFieldsTransformer } from '@grafana/data/src/transformations/transformers/organize';
diff --git a/public/app/features/explore/Logs/LogsMetaRow.tsx b/public/app/features/explore/Logs/LogsMetaRow.tsx
index b6608f69b20..c6c3e17ceed 100644
--- a/public/app/features/explore/Logs/LogsMetaRow.tsx
+++ b/public/app/features/explore/Logs/LogsMetaRow.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import saveAs from 'file-saver';
-import React from 'react';
+import { memo } from 'react';
import { lastValueFrom } from 'rxjs';
import {
@@ -53,7 +53,7 @@ enum DownloadFormat {
CSV = 'csv',
}
-export const LogsMetaRow = React.memo(
+export const LogsMetaRow = memo(
({
meta,
dedupStrategy,
diff --git a/public/app/features/explore/Logs/LogsNavigation.test.tsx b/public/app/features/explore/Logs/LogsNavigation.test.tsx
index 6c2a5153bd4..42b1b3cd332 100644
--- a/public/app/features/explore/Logs/LogsNavigation.test.tsx
+++ b/public/app/features/explore/Logs/LogsNavigation.test.tsx
@@ -1,6 +1,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { ComponentProps } from 'react';
+import { ComponentProps } from 'react';
import { LogsSortOrder } from '@grafana/data';
import { DataQuery } from '@grafana/schema';
diff --git a/public/app/features/explore/Logs/LogsNavigation.tsx b/public/app/features/explore/Logs/LogsNavigation.tsx
index b605f284a99..24b51f6a407 100644
--- a/public/app/features/explore/Logs/LogsNavigation.tsx
+++ b/public/app/features/explore/Logs/LogsNavigation.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { isEqual } from 'lodash';
-import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
+import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { AbsoluteTimeRange, GrafanaTheme2, LogsSortOrder } from '@grafana/data';
import { config, reportInteraction } from '@grafana/runtime';
diff --git a/public/app/features/explore/Logs/LogsNavigationPages.test.tsx b/public/app/features/explore/Logs/LogsNavigationPages.test.tsx
index bd0a4e76301..4dcfb1a50b0 100644
--- a/public/app/features/explore/Logs/LogsNavigationPages.test.tsx
+++ b/public/app/features/explore/Logs/LogsNavigationPages.test.tsx
@@ -1,6 +1,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { ComponentProps } from 'react';
+import { ComponentProps } from 'react';
import { LogsNavigationPages } from './LogsNavigationPages';
diff --git a/public/app/features/explore/Logs/LogsNavigationPages.tsx b/public/app/features/explore/Logs/LogsNavigationPages.tsx
index a6b1fd20108..6d2bea0d2ec 100644
--- a/public/app/features/explore/Logs/LogsNavigationPages.tsx
+++ b/public/app/features/explore/Logs/LogsNavigationPages.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { dateTimeFormat, systemDateFormats, GrafanaTheme2 } from '@grafana/data';
import { TimeZone } from '@grafana/schema';
diff --git a/public/app/features/explore/Logs/LogsSamplePanel.test.tsx b/public/app/features/explore/Logs/LogsSamplePanel.test.tsx
index ad48e63839d..6ab0e78d187 100644
--- a/public/app/features/explore/Logs/LogsSamplePanel.test.tsx
+++ b/public/app/features/explore/Logs/LogsSamplePanel.test.tsx
@@ -1,6 +1,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { ComponentProps } from 'react';
+import { ComponentProps } from 'react';
import { FieldType, LoadingState, SupplementaryQueryType, DataSourceApi, createDataFrame } from '@grafana/data';
import { DataQuery } from '@grafana/schema';
diff --git a/public/app/features/explore/Logs/LogsSamplePanel.tsx b/public/app/features/explore/Logs/LogsSamplePanel.tsx
index 5e628b38c4b..0f4e2539ddd 100644
--- a/public/app/features/explore/Logs/LogsSamplePanel.tsx
+++ b/public/app/features/explore/Logs/LogsSamplePanel.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import {
DataQueryResponse,
diff --git a/public/app/features/explore/Logs/LogsTable.test.tsx b/public/app/features/explore/Logs/LogsTable.test.tsx
index b22a2277395..6dff92ec2c5 100644
--- a/public/app/features/explore/Logs/LogsTable.test.tsx
+++ b/public/app/features/explore/Logs/LogsTable.test.tsx
@@ -1,5 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
-import React, { ComponentProps } from 'react';
+import { ComponentProps } from 'react';
import { DataFrame, FieldType, LogsSortOrder, standardTransformersRegistry, toUtc } from '@grafana/data';
import { organizeFieldsTransformer } from '@grafana/data/src/transformations/transformers/organize';
diff --git a/public/app/features/explore/Logs/LogsTable.tsx b/public/app/features/explore/Logs/LogsTable.tsx
index 107045ffe79..ddb3dcb1e5c 100644
--- a/public/app/features/explore/Logs/LogsTable.tsx
+++ b/public/app/features/explore/Logs/LogsTable.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
import { lastValueFrom } from 'rxjs';
import {
diff --git a/public/app/features/explore/Logs/LogsTableActiveFields.tsx b/public/app/features/explore/Logs/LogsTableActiveFields.tsx
index 802c59e6f99..8ca6656ab8c 100644
--- a/public/app/features/explore/Logs/LogsTableActiveFields.tsx
+++ b/public/app/features/explore/Logs/LogsTableActiveFields.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { DragDropContext, Draggable, DraggableProvided, Droppable, DropResult } from 'react-beautiful-dnd';
import { GrafanaTheme2 } from '@grafana/data/src';
diff --git a/public/app/features/explore/Logs/LogsTableAvailableFields.tsx b/public/app/features/explore/Logs/LogsTableAvailableFields.tsx
index 8ab7d480508..a0804ac82af 100644
--- a/public/app/features/explore/Logs/LogsTableAvailableFields.tsx
+++ b/public/app/features/explore/Logs/LogsTableAvailableFields.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { useTheme2 } from '@grafana/ui/src';
import { getLogsFieldsStyles } from './LogsTableActiveFields';
diff --git a/public/app/features/explore/Logs/LogsTableEmptyFields.tsx b/public/app/features/explore/Logs/LogsTableEmptyFields.tsx
index a4a2c05426b..1704050a461 100644
--- a/public/app/features/explore/Logs/LogsTableEmptyFields.tsx
+++ b/public/app/features/explore/Logs/LogsTableEmptyFields.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useTheme2 } from '@grafana/ui';
diff --git a/public/app/features/explore/Logs/LogsTableMultiSelect.tsx b/public/app/features/explore/Logs/LogsTableMultiSelect.tsx
index 31b2d7c0b40..7bdca2b8fa7 100644
--- a/public/app/features/explore/Logs/LogsTableMultiSelect.tsx
+++ b/public/app/features/explore/Logs/LogsTableMultiSelect.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data/src';
import { useTheme2 } from '@grafana/ui/src';
diff --git a/public/app/features/explore/Logs/LogsTableNavField.tsx b/public/app/features/explore/Logs/LogsTableNavField.tsx
index d883ae8ed30..c53796e26be 100644
--- a/public/app/features/explore/Logs/LogsTableNavField.tsx
+++ b/public/app/features/explore/Logs/LogsTableNavField.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Checkbox, Icon, useTheme2 } from '@grafana/ui';
diff --git a/public/app/features/explore/Logs/LogsTableWrap.test.tsx b/public/app/features/explore/Logs/LogsTableWrap.test.tsx
index 9e5b59c93f9..91e863e3af9 100644
--- a/public/app/features/explore/Logs/LogsTableWrap.test.tsx
+++ b/public/app/features/explore/Logs/LogsTableWrap.test.tsx
@@ -1,5 +1,5 @@
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
-import React, { ComponentProps } from 'react';
+import { ComponentProps } from 'react';
import { act } from 'react-test-renderer';
import {
diff --git a/public/app/features/explore/Logs/LogsTableWrap.tsx b/public/app/features/explore/Logs/LogsTableWrap.tsx
index d80f620475a..d3755b6dc56 100644
--- a/public/app/features/explore/Logs/LogsTableWrap.tsx
+++ b/public/app/features/explore/Logs/LogsTableWrap.tsx
@@ -1,6 +1,7 @@
import { css } from '@emotion/css';
import { Resizable, ResizeCallback } from 're-resizable';
-import React, { useCallback, useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
+import * as React from 'react';
import {
DataFrame,
diff --git a/public/app/features/explore/Logs/LogsVolumePanel.test.tsx b/public/app/features/explore/Logs/LogsVolumePanel.test.tsx
index 46bb7db737f..bc7629f2401 100644
--- a/public/app/features/explore/Logs/LogsVolumePanel.test.tsx
+++ b/public/app/features/explore/Logs/LogsVolumePanel.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { DataQueryResponse, LoadingState, EventBusSrv } from '@grafana/data';
diff --git a/public/app/features/explore/Logs/LogsVolumePanel.tsx b/public/app/features/explore/Logs/LogsVolumePanel.tsx
index fc5c446ffbf..320d7acfaea 100644
--- a/public/app/features/explore/Logs/LogsVolumePanel.tsx
+++ b/public/app/features/explore/Logs/LogsVolumePanel.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { identity } from 'lodash';
-import React from 'react';
+import * as React from 'react';
import {
AbsoluteTimeRange,
diff --git a/public/app/features/explore/Logs/LogsVolumePanelList.test.tsx b/public/app/features/explore/Logs/LogsVolumePanelList.test.tsx
index 81767d27c0e..b411fcc83cd 100644
--- a/public/app/features/explore/Logs/LogsVolumePanelList.test.tsx
+++ b/public/app/features/explore/Logs/LogsVolumePanelList.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { DataQueryResponse, LoadingState, EventBusSrv } from '@grafana/data';
diff --git a/public/app/features/explore/Logs/LogsVolumePanelList.tsx b/public/app/features/explore/Logs/LogsVolumePanelList.tsx
index 5da391991c3..7cdecfe9f08 100644
--- a/public/app/features/explore/Logs/LogsVolumePanelList.tsx
+++ b/public/app/features/explore/Logs/LogsVolumePanelList.tsx
@@ -1,6 +1,7 @@
import { css } from '@emotion/css';
import { flatten, groupBy, mapValues, sortBy } from 'lodash';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
+import * as React from 'react';
import {
AbsoluteTimeRange,
diff --git a/public/app/features/explore/Logs/PopoverMenu.test.tsx b/public/app/features/explore/Logs/PopoverMenu.test.tsx
index 81b9371526a..8c4f2ac4482 100644
--- a/public/app/features/explore/Logs/PopoverMenu.test.tsx
+++ b/public/app/features/explore/Logs/PopoverMenu.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { createLogRow } from '../../logs/components/__mocks__/logRow';
diff --git a/public/app/features/explore/Logs/PopoverMenu.tsx b/public/app/features/explore/Logs/PopoverMenu.tsx
index 6bc0265145c..641bae885b6 100644
--- a/public/app/features/explore/Logs/PopoverMenu.tsx
+++ b/public/app/features/explore/Logs/PopoverMenu.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useRef } from 'react';
+import { useEffect, useRef } from 'react';
import { GrafanaTheme2, LogRowModel } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime';
diff --git a/public/app/features/explore/Logs/utils/LogsCrossFadeTransition.tsx b/public/app/features/explore/Logs/utils/LogsCrossFadeTransition.tsx
index 209fa67ccc7..ca62b7c310d 100644
--- a/public/app/features/explore/Logs/utils/LogsCrossFadeTransition.tsx
+++ b/public/app/features/explore/Logs/utils/LogsCrossFadeTransition.tsx
@@ -1,6 +1,7 @@
import { css } from '@emotion/css';
import memoizeOne from 'memoize-one';
-import React, { useRef } from 'react';
+import { useRef } from 'react';
+import * as React from 'react';
import { CSSTransition } from 'react-transition-group';
const transitionDuration = 500;
diff --git a/public/app/features/explore/MetaInfoText.test.tsx b/public/app/features/explore/MetaInfoText.test.tsx
index 53edd865cd1..14bc5363f4f 100644
--- a/public/app/features/explore/MetaInfoText.test.tsx
+++ b/public/app/features/explore/MetaInfoText.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { MetaInfoText, MetaItemProps } from './MetaInfoText';
describe('MetaInfoText', () => {
diff --git a/public/app/features/explore/MetaInfoText.tsx b/public/app/features/explore/MetaInfoText.tsx
index 29c8528d355..906ff0c2c9c 100644
--- a/public/app/features/explore/MetaInfoText.tsx
+++ b/public/app/features/explore/MetaInfoText.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { memo } from 'react';
+import { memo } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/explore/NoData.tsx b/public/app/features/explore/NoData.tsx
index ed819de9ffe..130f38750ef 100644
--- a/public/app/features/explore/NoData.tsx
+++ b/public/app/features/explore/NoData.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data/src';
import { useStyles2, PanelContainer } from '@grafana/ui';
diff --git a/public/app/features/explore/NoDataSourceCallToAction.tsx b/public/app/features/explore/NoDataSourceCallToAction.tsx
index a3e773f3a57..7fe19a35a09 100644
--- a/public/app/features/explore/NoDataSourceCallToAction.tsx
+++ b/public/app/features/explore/NoDataSourceCallToAction.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { LinkButton, CallToActionCard, Icon, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/explore/NodeGraph/NodeGraphContainer.test.tsx b/public/app/features/explore/NodeGraph/NodeGraphContainer.test.tsx
index bc1f3f2ae1f..0b21c899eb2 100644
--- a/public/app/features/explore/NodeGraph/NodeGraphContainer.test.tsx
+++ b/public/app/features/explore/NodeGraph/NodeGraphContainer.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { getDefaultTimeRange, MutableDataFrame } from '@grafana/data';
diff --git a/public/app/features/explore/NodeGraph/NodeGraphContainer.tsx b/public/app/features/explore/NodeGraph/NodeGraphContainer.tsx
index d47dbd7aa21..9894c43d086 100644
--- a/public/app/features/explore/NodeGraph/NodeGraphContainer.tsx
+++ b/public/app/features/explore/NodeGraph/NodeGraphContainer.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useRef, useState } from 'react';
+import { useEffect, useRef, useState } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { useToggle, useWindowSize } from 'react-use';
diff --git a/public/app/features/explore/PrometheusListView/ItemLabels.tsx b/public/app/features/explore/PrometheusListView/ItemLabels.tsx
index 453edc18e4c..e3c2a27ddcc 100644
--- a/public/app/features/explore/PrometheusListView/ItemLabels.tsx
+++ b/public/app/features/explore/PrometheusListView/ItemLabels.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { Field, GrafanaTheme2 } from '@grafana/data/';
import { InstantQueryRefIdIndex } from '@grafana/prometheus';
diff --git a/public/app/features/explore/PrometheusListView/ItemValues.test.tsx b/public/app/features/explore/PrometheusListView/ItemValues.test.tsx
index f753896dbca..aeb0e2e1c69 100644
--- a/public/app/features/explore/PrometheusListView/ItemValues.test.tsx
+++ b/public/app/features/explore/PrometheusListView/ItemValues.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { ItemValues } from './ItemValues';
import { RawListValue } from './RawListItem';
diff --git a/public/app/features/explore/PrometheusListView/ItemValues.tsx b/public/app/features/explore/PrometheusListView/ItemValues.tsx
index d874f806a01..8b6919922c5 100644
--- a/public/app/features/explore/PrometheusListView/ItemValues.tsx
+++ b/public/app/features/explore/PrometheusListView/ItemValues.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data/';
import { useStyles2 } from '@grafana/ui/';
diff --git a/public/app/features/explore/PrometheusListView/RawListContainer.test.tsx b/public/app/features/explore/PrometheusListView/RawListContainer.test.tsx
index 8e7d9583f00..8f3d27dbac8 100644
--- a/public/app/features/explore/PrometheusListView/RawListContainer.test.tsx
+++ b/public/app/features/explore/PrometheusListView/RawListContainer.test.tsx
@@ -1,5 +1,4 @@
import { render, screen, within } from '@testing-library/react';
-import React from 'react';
import { FieldType, FormattedValue, toDataFrame } from '@grafana/data/src';
diff --git a/public/app/features/explore/PrometheusListView/RawListContainer.tsx b/public/app/features/explore/PrometheusListView/RawListContainer.tsx
index 92fb50b9040..dfc6381c1e8 100644
--- a/public/app/features/explore/PrometheusListView/RawListContainer.tsx
+++ b/public/app/features/explore/PrometheusListView/RawListContainer.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { cloneDeep } from 'lodash';
-import React, { useEffect, useId, useRef, useState } from 'react';
+import { useEffect, useId, useRef, useState } from 'react';
import { useWindowSize } from 'react-use';
import { VariableSizeList as List } from 'react-window';
diff --git a/public/app/features/explore/PrometheusListView/RawListItem.test.tsx b/public/app/features/explore/PrometheusListView/RawListItem.test.tsx
index ab92ad6ddca..d39e81c2a1d 100644
--- a/public/app/features/explore/PrometheusListView/RawListItem.test.tsx
+++ b/public/app/features/explore/PrometheusListView/RawListItem.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import RawListItem, { RawListProps } from './RawListItem';
diff --git a/public/app/features/explore/PrometheusListView/RawListItem.tsx b/public/app/features/explore/PrometheusListView/RawListItem.tsx
index e7eb1c25e05..8f1f03d490f 100644
--- a/public/app/features/explore/PrometheusListView/RawListItem.tsx
+++ b/public/app/features/explore/PrometheusListView/RawListItem.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { useCopyToClipboard } from 'react-use';
import { Field, GrafanaTheme2 } from '@grafana/data/';
diff --git a/public/app/features/explore/PrometheusListView/RawListItemAttributes.test.tsx b/public/app/features/explore/PrometheusListView/RawListItemAttributes.test.tsx
index 27c3ab604d8..8be09545558 100644
--- a/public/app/features/explore/PrometheusListView/RawListItemAttributes.test.tsx
+++ b/public/app/features/explore/PrometheusListView/RawListItemAttributes.test.tsx
@@ -1,5 +1,4 @@
import { render } from '@testing-library/react';
-import React from 'react';
import { RawListValue } from './RawListItem';
import RawListItemAttributes from './RawListItemAttributes';
diff --git a/public/app/features/explore/PrometheusListView/RawListItemAttributes.tsx b/public/app/features/explore/PrometheusListView/RawListItemAttributes.tsx
index fb3996a8636..296ddb81a0b 100644
--- a/public/app/features/explore/PrometheusListView/RawListItemAttributes.tsx
+++ b/public/app/features/explore/PrometheusListView/RawListItemAttributes.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data/';
import { useStyles2 } from '@grafana/ui/';
diff --git a/public/app/features/explore/QueriesDrawer/QueriesDrawerContext.tsx b/public/app/features/explore/QueriesDrawer/QueriesDrawerContext.tsx
index abd4e76476a..7aedc47296f 100644
--- a/public/app/features/explore/QueriesDrawer/QueriesDrawerContext.tsx
+++ b/public/app/features/explore/QueriesDrawer/QueriesDrawerContext.tsx
@@ -1,4 +1,4 @@
-import React, { PropsWithChildren, useState, createContext, useContext, useEffect } from 'react';
+import { PropsWithChildren, useState, createContext, useContext, useEffect } from 'react';
import { config } from '@grafana/runtime';
import { useSelector } from 'app/types';
diff --git a/public/app/features/explore/QueriesDrawer/QueriesDrawerDropdown.tsx b/public/app/features/explore/QueriesDrawer/QueriesDrawerDropdown.tsx
index 3cd4c211236..c68b7340e96 100644
--- a/public/app/features/explore/QueriesDrawer/QueriesDrawerDropdown.tsx
+++ b/public/app/features/explore/QueriesDrawer/QueriesDrawerDropdown.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { Button, ButtonGroup, Dropdown, Menu, ToolbarButton } from '@grafana/ui';
import { useStyles2 } from '@grafana/ui/';
diff --git a/public/app/features/explore/QueriesDrawer/mocks.tsx b/public/app/features/explore/QueriesDrawer/mocks.tsx
index ed9d5ceb590..37bf17fada4 100644
--- a/public/app/features/explore/QueriesDrawer/mocks.tsx
+++ b/public/app/features/explore/QueriesDrawer/mocks.tsx
@@ -1,4 +1,4 @@
-import React, { PropsWithChildren, useState } from 'react';
+import { PropsWithChildren, useState } from 'react';
import { QueriesDrawerContext, Tabs } from './QueriesDrawerContext';
diff --git a/public/app/features/explore/QueryLibrary/QueryLibrary.tsx b/public/app/features/explore/QueryLibrary/QueryLibrary.tsx
index 11173ca0384..d0e9a107664 100644
--- a/public/app/features/explore/QueryLibrary/QueryLibrary.tsx
+++ b/public/app/features/explore/QueryLibrary/QueryLibrary.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { QueryTemplatesList } from './QueryTemplatesList';
export function QueryLibrary() {
diff --git a/public/app/features/explore/QueryLibrary/QueryTemplatesList.tsx b/public/app/features/explore/QueryLibrary/QueryTemplatesList.tsx
index a5d495ee346..eed3e100131 100644
--- a/public/app/features/explore/QueryLibrary/QueryTemplatesList.tsx
+++ b/public/app/features/explore/QueryLibrary/QueryTemplatesList.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { EmptyState, Spinner } from '@grafana/ui';
import { useAllQueryTemplatesQuery } from 'app/features/query-library';
import { QueryTemplate } from 'app/features/query-library/types';
diff --git a/public/app/features/explore/QueryLibrary/QueryTemplatesTable/ActionsCell.tsx b/public/app/features/explore/QueryLibrary/QueryTemplatesTable/ActionsCell.tsx
index 4ffd14edad6..69ac1e65bdf 100644
--- a/public/app/features/explore/QueryLibrary/QueryTemplatesTable/ActionsCell.tsx
+++ b/public/app/features/explore/QueryLibrary/QueryTemplatesTable/ActionsCell.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { reportInteraction, getAppEvents } from '@grafana/runtime';
import { DataQuery } from '@grafana/schema';
import { IconButton } from '@grafana/ui';
diff --git a/public/app/features/explore/QueryLibrary/QueryTemplatesTable/AddedByCell.tsx b/public/app/features/explore/QueryLibrary/QueryTemplatesTable/AddedByCell.tsx
index f93889c959d..b9903195d47 100644
--- a/public/app/features/explore/QueryLibrary/QueryTemplatesTable/AddedByCell.tsx
+++ b/public/app/features/explore/QueryLibrary/QueryTemplatesTable/AddedByCell.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { useQueryLibraryListStyles } from './styles';
type AddedByCellProps = {
diff --git a/public/app/features/explore/QueryLibrary/QueryTemplatesTable/DatasourceTypeCell.tsx b/public/app/features/explore/QueryLibrary/QueryTemplatesTable/DatasourceTypeCell.tsx
index 2c9db92cd04..bdc361b7532 100644
--- a/public/app/features/explore/QueryLibrary/QueryTemplatesTable/DatasourceTypeCell.tsx
+++ b/public/app/features/explore/QueryLibrary/QueryTemplatesTable/DatasourceTypeCell.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { CellProps } from 'react-table';
import { useDatasource } from '../utils/useDatasource';
diff --git a/public/app/features/explore/QueryLibrary/QueryTemplatesTable/DateAddedCell.tsx b/public/app/features/explore/QueryLibrary/QueryTemplatesTable/DateAddedCell.tsx
index 3a8b59f08df..29bf6a96b07 100644
--- a/public/app/features/explore/QueryLibrary/QueryTemplatesTable/DateAddedCell.tsx
+++ b/public/app/features/explore/QueryLibrary/QueryTemplatesTable/DateAddedCell.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { CellProps } from 'react-table';
import { dateTime } from '@grafana/data';
diff --git a/public/app/features/explore/QueryLibrary/QueryTemplatesTable/QueryDescriptionCell.tsx b/public/app/features/explore/QueryLibrary/QueryTemplatesTable/QueryDescriptionCell.tsx
index 95b8a7d9221..bb87eabc1da 100644
--- a/public/app/features/explore/QueryLibrary/QueryTemplatesTable/QueryDescriptionCell.tsx
+++ b/public/app/features/explore/QueryLibrary/QueryTemplatesTable/QueryDescriptionCell.tsx
@@ -1,5 +1,4 @@
import { cx } from '@emotion/css';
-import React from 'react';
import { CellProps } from 'react-table';
import { Spinner } from '@grafana/ui';
diff --git a/public/app/features/explore/QueryLibrary/QueryTemplatesTable/index.tsx b/public/app/features/explore/QueryLibrary/QueryTemplatesTable/index.tsx
index 5654cb98577..376e7457dd8 100644
--- a/public/app/features/explore/QueryLibrary/QueryTemplatesTable/index.tsx
+++ b/public/app/features/explore/QueryLibrary/QueryTemplatesTable/index.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { SortByFn } from 'react-table';
import { Column, InteractiveTable } from '@grafana/ui';
diff --git a/public/app/features/explore/QueryRows.test.tsx b/public/app/features/explore/QueryRows.test.tsx
index a65ebe6c18a..4e7c330bc9a 100644
--- a/public/app/features/explore/QueryRows.test.tsx
+++ b/public/app/features/explore/QueryRows.test.tsx
@@ -1,5 +1,4 @@
import { fireEvent, render, screen } from '@testing-library/react';
-import React from 'react';
import { Provider } from 'react-redux';
import { DataSourceApi } from '@grafana/data';
diff --git a/public/app/features/explore/QueryRows.tsx b/public/app/features/explore/QueryRows.tsx
index 59ad9d32208..05ee928f126 100644
--- a/public/app/features/explore/QueryRows.tsx
+++ b/public/app/features/explore/QueryRows.tsx
@@ -1,5 +1,5 @@
import { createSelector } from '@reduxjs/toolkit';
-import React, { useCallback, useMemo } from 'react';
+import { useCallback, useMemo } from 'react';
import { CoreApp, getNextRefId } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime';
diff --git a/public/app/features/explore/RawPrometheus/RawPrometheusContainer.test.tsx b/public/app/features/explore/RawPrometheus/RawPrometheusContainer.test.tsx
index bdc901630ba..7efd5f866e9 100644
--- a/public/app/features/explore/RawPrometheus/RawPrometheusContainer.test.tsx
+++ b/public/app/features/explore/RawPrometheus/RawPrometheusContainer.test.tsx
@@ -1,5 +1,4 @@
import { fireEvent, render, screen, within } from '@testing-library/react';
-import React from 'react';
import { FieldType, getDefaultTimeRange, InternalTimeZones, toDataFrame, LoadingState } from '@grafana/data';
import { getTemplateSrv } from 'app/features/templating/template_srv';
diff --git a/public/app/features/explore/RawPrometheus/RawPrometheusContainer.tsx b/public/app/features/explore/RawPrometheus/RawPrometheusContainer.tsx
index 71910d544ba..4269c1d7724 100644
--- a/public/app/features/explore/RawPrometheus/RawPrometheusContainer.tsx
+++ b/public/app/features/explore/RawPrometheus/RawPrometheusContainer.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { applyFieldOverrides, DataFrame, SelectableValue, SplitOpen } from '@grafana/data';
diff --git a/public/app/features/explore/ResponseErrorContainer.test.tsx b/public/app/features/explore/ResponseErrorContainer.test.tsx
index 80bf3e9fd46..8039b2e99b7 100644
--- a/public/app/features/explore/ResponseErrorContainer.test.tsx
+++ b/public/app/features/explore/ResponseErrorContainer.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { DataQueryError, LoadingState } from '@grafana/data';
diff --git a/public/app/features/explore/ResponseErrorContainer.tsx b/public/app/features/explore/ResponseErrorContainer.tsx
index 8c84c75a5ee..e0724c1a666 100644
--- a/public/app/features/explore/ResponseErrorContainer.tsx
+++ b/public/app/features/explore/ResponseErrorContainer.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { LoadingState } from '@grafana/data';
import { useSelector } from 'app/types';
diff --git a/public/app/features/explore/RichHistory/RichHistory.test.tsx b/public/app/features/explore/RichHistory/RichHistory.test.tsx
index b938b63fc2e..dce1e5381d7 100644
--- a/public/app/features/explore/RichHistory/RichHistory.test.tsx
+++ b/public/app/features/explore/RichHistory/RichHistory.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { SortOrder } from 'app/core/utils/richHistory';
diff --git a/public/app/features/explore/RichHistory/RichHistory.tsx b/public/app/features/explore/RichHistory/RichHistory.tsx
index 297a6a578f4..063029baaea 100644
--- a/public/app/features/explore/RichHistory/RichHistory.tsx
+++ b/public/app/features/explore/RichHistory/RichHistory.tsx
@@ -1,5 +1,5 @@
import { debounce } from 'lodash';
-import React, { useState, useEffect } from 'react';
+import { useState, useEffect } from 'react';
import { SelectableValue } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/explore/RichHistory/RichHistoryAddToLibrary.tsx b/public/app/features/explore/RichHistory/RichHistoryAddToLibrary.tsx
index 47de3d424b8..a9cc225455a 100644
--- a/public/app/features/explore/RichHistory/RichHistoryAddToLibrary.tsx
+++ b/public/app/features/explore/RichHistory/RichHistoryAddToLibrary.tsx
@@ -1,5 +1,5 @@
import { t } from 'i18next';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { AppEvents, dateTime } from '@grafana/data';
import { getAppEvents } from '@grafana/runtime';
diff --git a/public/app/features/explore/RichHistory/RichHistoryAddToLibraryForm.tsx b/public/app/features/explore/RichHistory/RichHistoryAddToLibraryForm.tsx
index b7bed1dce81..b787773fb42 100644
--- a/public/app/features/explore/RichHistory/RichHistoryAddToLibraryForm.tsx
+++ b/public/app/features/explore/RichHistory/RichHistoryAddToLibraryForm.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { useForm } from 'react-hook-form';
import { DataSourcePicker } from '@grafana/runtime';
diff --git a/public/app/features/explore/RichHistory/RichHistoryCard.test.tsx b/public/app/features/explore/RichHistory/RichHistoryCard.test.tsx
index ce8e8e2956b..c547dd1572f 100644
--- a/public/app/features/explore/RichHistory/RichHistoryCard.test.tsx
+++ b/public/app/features/explore/RichHistory/RichHistoryCard.test.tsx
@@ -1,6 +1,5 @@
import { fireEvent, render, screen, getByText } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { DataSourceApi, DataSourceInstanceSettings, DataSourcePluginMeta } from '@grafana/data';
diff --git a/public/app/features/explore/RichHistory/RichHistoryCard.tsx b/public/app/features/explore/RichHistory/RichHistoryCard.tsx
index a6496a6e908..a7aa69293d9 100644
--- a/public/app/features/explore/RichHistory/RichHistoryCard.tsx
+++ b/public/app/features/explore/RichHistory/RichHistoryCard.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { useCallback, useState } from 'react';
+import { useCallback, useState } from 'react';
+import * as React from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { GrafanaTheme2, DataSourceApi } from '@grafana/data';
diff --git a/public/app/features/explore/RichHistory/RichHistoryContainer.test.tsx b/public/app/features/explore/RichHistory/RichHistoryContainer.test.tsx
index 5c970520028..e721abb7a88 100644
--- a/public/app/features/explore/RichHistory/RichHistoryContainer.test.tsx
+++ b/public/app/features/explore/RichHistory/RichHistoryContainer.test.tsx
@@ -1,5 +1,4 @@
import { render } from '@testing-library/react';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { SortOrder } from 'app/core/utils/richHistory';
diff --git a/public/app/features/explore/RichHistory/RichHistoryContainer.tsx b/public/app/features/explore/RichHistory/RichHistoryContainer.tsx
index ed14ac0b352..7618301dad3 100644
--- a/public/app/features/explore/RichHistory/RichHistoryContainer.tsx
+++ b/public/app/features/explore/RichHistory/RichHistoryContainer.tsx
@@ -1,5 +1,5 @@
// Libraries
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { config, reportInteraction } from '@grafana/runtime';
diff --git a/public/app/features/explore/RichHistory/RichHistoryQueriesTab.test.tsx b/public/app/features/explore/RichHistory/RichHistoryQueriesTab.test.tsx
index 06b51138a08..a996a5b5b89 100644
--- a/public/app/features/explore/RichHistory/RichHistoryQueriesTab.test.tsx
+++ b/public/app/features/explore/RichHistory/RichHistoryQueriesTab.test.tsx
@@ -1,5 +1,4 @@
import { fireEvent, render, screen } from '@testing-library/react';
-import React from 'react';
import * as reactUse from 'react-use';
import { TestProvider } from 'test/helpers/TestProvider';
import { MockDataSourceApi } from 'test/mocks/datasource_srv';
diff --git a/public/app/features/explore/RichHistory/RichHistoryQueriesTab.tsx b/public/app/features/explore/RichHistory/RichHistoryQueriesTab.tsx
index 469371caa4a..dfbfed05bcf 100644
--- a/public/app/features/explore/RichHistory/RichHistoryQueriesTab.tsx
+++ b/public/app/features/explore/RichHistory/RichHistoryQueriesTab.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import { useAsync } from 'react-use';
import { DataSourceApi, GrafanaTheme2, SelectableValue } from '@grafana/data';
diff --git a/public/app/features/explore/RichHistory/RichHistorySettingsTab.test.tsx b/public/app/features/explore/RichHistory/RichHistorySettingsTab.test.tsx
index 3b31f66799e..3bced44a05a 100644
--- a/public/app/features/explore/RichHistory/RichHistorySettingsTab.test.tsx
+++ b/public/app/features/explore/RichHistory/RichHistorySettingsTab.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { RichHistorySettingsTab, RichHistorySettingsProps } from './RichHistorySettingsTab';
diff --git a/public/app/features/explore/RichHistory/RichHistorySettingsTab.tsx b/public/app/features/explore/RichHistory/RichHistorySettingsTab.tsx
index d8e4a2eac7a..43b10370c4f 100644
--- a/public/app/features/explore/RichHistory/RichHistorySettingsTab.tsx
+++ b/public/app/features/explore/RichHistory/RichHistorySettingsTab.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { getAppEvents } from '@grafana/runtime';
diff --git a/public/app/features/explore/RichHistory/RichHistoryStarredTab.test.tsx b/public/app/features/explore/RichHistory/RichHistoryStarredTab.test.tsx
index e7e64dd0f1f..3da7bfec73f 100644
--- a/public/app/features/explore/RichHistory/RichHistoryStarredTab.test.tsx
+++ b/public/app/features/explore/RichHistory/RichHistoryStarredTab.test.tsx
@@ -1,5 +1,4 @@
import { fireEvent, render, screen } from '@testing-library/react';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { SortOrder } from 'app/core/utils/richHistory';
diff --git a/public/app/features/explore/RichHistory/RichHistoryStarredTab.tsx b/public/app/features/explore/RichHistory/RichHistoryStarredTab.tsx
index f534d084709..793d4bd5de0 100644
--- a/public/app/features/explore/RichHistory/RichHistoryStarredTab.tsx
+++ b/public/app/features/explore/RichHistory/RichHistoryStarredTab.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import { useAsync } from 'react-use';
import { DataSourceApi, GrafanaTheme2, SelectableValue } from '@grafana/data';
diff --git a/public/app/features/explore/SecondaryActions.test.tsx b/public/app/features/explore/SecondaryActions.test.tsx
index 7641541290c..e0c13db476e 100644
--- a/public/app/features/explore/SecondaryActions.test.tsx
+++ b/public/app/features/explore/SecondaryActions.test.tsx
@@ -1,7 +1,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { noop } from 'lodash';
-import React from 'react';
import { QueriesDrawerContextProviderMock } from './QueriesDrawer/mocks';
import { SecondaryActions } from './SecondaryActions';
diff --git a/public/app/features/explore/SecondaryActions.tsx b/public/app/features/explore/SecondaryActions.tsx
index cdba3e51854..47f9988f3d0 100644
--- a/public/app/features/explore/SecondaryActions.tsx
+++ b/public/app/features/explore/SecondaryActions.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Components } from '@grafana/e2e-selectors';
diff --git a/public/app/features/explore/ShortLinkButtonMenu.tsx b/public/app/features/explore/ShortLinkButtonMenu.tsx
index 36451f39ead..ef1d7c6cdd2 100644
--- a/public/app/features/explore/ShortLinkButtonMenu.tsx
+++ b/public/app/features/explore/ShortLinkButtonMenu.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { IconName } from '@grafana/data';
import { reportInteraction, config } from '@grafana/runtime';
diff --git a/public/app/features/explore/SupplementaryResultError.test.tsx b/public/app/features/explore/SupplementaryResultError.test.tsx
index 2b5aa9a1df4..5bc62688279 100644
--- a/public/app/features/explore/SupplementaryResultError.test.tsx
+++ b/public/app/features/explore/SupplementaryResultError.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { SupplementaryResultError } from './SupplementaryResultError';
diff --git a/public/app/features/explore/SupplementaryResultError.tsx b/public/app/features/explore/SupplementaryResultError.tsx
index 0ad91832057..e2064cedc0a 100644
--- a/public/app/features/explore/SupplementaryResultError.tsx
+++ b/public/app/features/explore/SupplementaryResultError.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { DataQueryError, GrafanaTheme2 } from '@grafana/data';
import { Alert, AlertVariant, Button, useTheme2 } from '@grafana/ui';
diff --git a/public/app/features/explore/Table/TableContainer.test.tsx b/public/app/features/explore/Table/TableContainer.test.tsx
index d373617ace4..af987261ead 100644
--- a/public/app/features/explore/Table/TableContainer.test.tsx
+++ b/public/app/features/explore/Table/TableContainer.test.tsx
@@ -1,5 +1,4 @@
import { render, screen, within } from '@testing-library/react';
-import React from 'react';
import { DataFrame, FieldType, getDefaultTimeRange, InternalTimeZones, toDataFrame } from '@grafana/data';
diff --git a/public/app/features/explore/Table/TableContainer.tsx b/public/app/features/explore/Table/TableContainer.tsx
index 6626977824b..c94149dbefb 100644
--- a/public/app/features/explore/Table/TableContainer.tsx
+++ b/public/app/features/explore/Table/TableContainer.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { applyFieldOverrides, SplitOpen, DataFrame, LoadingState, FieldType } from '@grafana/data';
diff --git a/public/app/features/explore/Time.tsx b/public/app/features/explore/Time.tsx
index b4d75eb79d9..cc1a5bfc481 100644
--- a/public/app/features/explore/Time.tsx
+++ b/public/app/features/explore/Time.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { toDuration } from '@grafana/data';
export interface TimeProps {
diff --git a/public/app/features/explore/TimeSyncButton.test.tsx b/public/app/features/explore/TimeSyncButton.test.tsx
index d87d72e6581..b45406132be 100644
--- a/public/app/features/explore/TimeSyncButton.test.tsx
+++ b/public/app/features/explore/TimeSyncButton.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { TimeSyncButton } from './TimeSyncButton';
diff --git a/public/app/features/explore/TimeSyncButton.tsx b/public/app/features/explore/TimeSyncButton.tsx
index d0f74356757..d3a625bb0da 100644
--- a/public/app/features/explore/TimeSyncButton.tsx
+++ b/public/app/features/explore/TimeSyncButton.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Tooltip, ToolbarButton } from '@grafana/ui';
interface TimeSyncButtonProps {
diff --git a/public/app/features/explore/TraceView/TraceView.test.tsx b/public/app/features/explore/TraceView/TraceView.test.tsx
index 6a767bafbdf..0f5cac923a1 100644
--- a/public/app/features/explore/TraceView/TraceView.test.tsx
+++ b/public/app/features/explore/TraceView/TraceView.test.tsx
@@ -1,6 +1,6 @@
import { render, prettyDOM, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { createRef } from 'react';
+import { createRef } from 'react';
import { Provider } from 'react-redux';
import { DataFrame, MutableDataFrame } from '@grafana/data';
diff --git a/public/app/features/explore/TraceView/TraceView.tsx b/public/app/features/explore/TraceView/TraceView.tsx
index f44534301dd..2e409d9d083 100644
--- a/public/app/features/explore/TraceView/TraceView.tsx
+++ b/public/app/features/explore/TraceView/TraceView.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { RefObject, useMemo, useState } from 'react';
+import { RefObject, useMemo, useState } from 'react';
import { useToggle } from 'react-use';
import {
diff --git a/public/app/features/explore/TraceView/TraceViewContainer.test.tsx b/public/app/features/explore/TraceView/TraceViewContainer.test.tsx
index dcb0347ee23..7773460e920 100644
--- a/public/app/features/explore/TraceView/TraceViewContainer.test.tsx
+++ b/public/app/features/explore/TraceView/TraceViewContainer.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { Provider } from 'react-redux';
import { configureStore } from '../../../store/configureStore';
diff --git a/public/app/features/explore/TraceView/TraceViewContainer.tsx b/public/app/features/explore/TraceView/TraceViewContainer.tsx
index d36aa60f68e..68bb08dcad5 100644
--- a/public/app/features/explore/TraceView/TraceViewContainer.tsx
+++ b/public/app/features/explore/TraceView/TraceViewContainer.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { DataFrame, SplitOpen } from '@grafana/data';
import { PanelChrome } from '@grafana/ui';
diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/Actions/ActionButton.tsx b/public/app/features/explore/TraceView/components/TracePageHeader/Actions/ActionButton.tsx
index 9149c81c07c..545436eb14d 100644
--- a/public/app/features/explore/TraceView/components/TracePageHeader/Actions/ActionButton.tsx
+++ b/public/app/features/explore/TraceView/components/TracePageHeader/Actions/ActionButton.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2, IconName } from '@grafana/data';
import { Button, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/Actions/TracePageActions.tsx b/public/app/features/explore/TraceView/components/TracePageHeader/Actions/TracePageActions.tsx
index 5595caf1e9a..69fd9176a8e 100644
--- a/public/app/features/explore/TraceView/components/TracePageHeader/Actions/TracePageActions.tsx
+++ b/public/app/features/explore/TraceView/components/TracePageHeader/Actions/TracePageActions.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { GrafanaTheme2, CoreApp, DataFrame } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime';
diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/SearchBar/NextPrevResult.test.tsx b/public/app/features/explore/TraceView/components/TracePageHeader/SearchBar/NextPrevResult.test.tsx
index 31883a9a7ca..8c815ac8d11 100644
--- a/public/app/features/explore/TraceView/components/TracePageHeader/SearchBar/NextPrevResult.test.tsx
+++ b/public/app/features/explore/TraceView/components/TracePageHeader/SearchBar/NextPrevResult.test.tsx
@@ -14,7 +14,7 @@
import { act, render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { createTheme } from '@grafana/data';
diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/SearchBar/NextPrevResult.tsx b/public/app/features/explore/TraceView/components/TracePageHeader/SearchBar/NextPrevResult.tsx
index 424aa66308f..ebd2d107888 100644
--- a/public/app/features/explore/TraceView/components/TracePageHeader/SearchBar/NextPrevResult.tsx
+++ b/public/app/features/explore/TraceView/components/TracePageHeader/SearchBar/NextPrevResult.tsx
@@ -14,7 +14,8 @@
import { css, cx } from '@emotion/css';
import { get, maxBy, values } from 'lodash';
-import React, { memo, Dispatch, SetStateAction, useEffect, useCallback } from 'react';
+import { memo, Dispatch, SetStateAction, useEffect, useCallback } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { config, reportInteraction } from '@grafana/runtime';
diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/SearchBar/TracePageSearchBar.test.tsx b/public/app/features/explore/TraceView/components/TracePageHeader/SearchBar/TracePageSearchBar.test.tsx
index 691a85826e0..de1eb8a4147 100644
--- a/public/app/features/explore/TraceView/components/TracePageHeader/SearchBar/TracePageSearchBar.test.tsx
+++ b/public/app/features/explore/TraceView/components/TracePageHeader/SearchBar/TracePageSearchBar.test.tsx
@@ -13,7 +13,6 @@
// limitations under the License.
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { defaultFilters } from '../../../useSearch';
import { trace } from '../TracePageHeader.test';
diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/SearchBar/TracePageSearchBar.tsx b/public/app/features/explore/TraceView/components/TracePageHeader/SearchBar/TracePageSearchBar.tsx
index 0a49a52546e..d7fdb854d28 100644
--- a/public/app/features/explore/TraceView/components/TracePageHeader/SearchBar/TracePageSearchBar.tsx
+++ b/public/app/features/explore/TraceView/components/TracePageHeader/SearchBar/TracePageSearchBar.tsx
@@ -13,7 +13,7 @@
// limitations under the License.
import { css } from '@emotion/css';
-import React, { memo, Dispatch, SetStateAction, useMemo } from 'react';
+import { memo, Dispatch, SetStateAction, useMemo } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Button, Switch, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.test.tsx b/public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.test.tsx
index 0f4f697978d..9a465d8a389 100644
--- a/public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.test.tsx
+++ b/public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.test.tsx
@@ -1,6 +1,6 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { defaultFilters } from '../../../useSearch';
import { Trace } from '../../types/trace';
diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.tsx b/public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.tsx
index 6de82f34043..6345ebee034 100644
--- a/public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.tsx
+++ b/public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.tsx
@@ -15,7 +15,8 @@
import { css } from '@emotion/css';
import { SpanStatusCode } from '@opentelemetry/api';
import { uniq } from 'lodash';
-import React, { useState, useEffect, memo, useCallback } from 'react';
+import { useState, useEffect, memo, useCallback } from 'react';
+import * as React from 'react';
import { GrafanaTheme2, SelectableValue, toOption } from '@grafana/data';
import { AccessoryButton } from '@grafana/experimental';
diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/CanvasSpanGraph.test.tsx b/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/CanvasSpanGraph.test.tsx
index e49fbfe48b0..d22a1b12fd4 100644
--- a/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/CanvasSpanGraph.test.tsx
+++ b/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/CanvasSpanGraph.test.tsx
@@ -13,7 +13,6 @@
// limitations under the License.
import { render } from '@testing-library/react';
-import React from 'react';
import { createTheme } from '@grafana/data';
diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/GraphTicks.test.tsx b/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/GraphTicks.test.tsx
index ade36dcc5dc..d963a473079 100644
--- a/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/GraphTicks.test.tsx
+++ b/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/GraphTicks.test.tsx
@@ -13,7 +13,6 @@
// limitations under the License.
import { render, screen } from '@testing-library/react';
-import React from 'react';
import GraphTicks, { GraphTicksProps } from './GraphTicks';
diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/GraphTicks.tsx b/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/GraphTicks.tsx
index 5827fd07110..c16b340f748 100644
--- a/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/GraphTicks.tsx
+++ b/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/GraphTicks.tsx
@@ -13,7 +13,6 @@
// limitations under the License.
import { css } from '@emotion/css';
-import React from 'react';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/Scrubber.test.tsx b/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/Scrubber.test.tsx
index 384e047bcc9..b57f4274519 100644
--- a/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/Scrubber.test.tsx
+++ b/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/Scrubber.test.tsx
@@ -13,7 +13,6 @@
// limitations under the License.
import { render, screen, fireEvent, within } from '@testing-library/react';
-import React from 'react';
import Scrubber, { ScrubberProps } from './Scrubber';
diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/Scrubber.tsx b/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/Scrubber.tsx
index 5cf5d5f178b..e1058694f62 100644
--- a/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/Scrubber.tsx
+++ b/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/Scrubber.tsx
@@ -14,7 +14,7 @@
import { css } from '@emotion/css';
import cx from 'classnames';
-import React from 'react';
+import * as React from 'react';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/TickLabels.test.tsx b/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/TickLabels.test.tsx
index 1369288e204..e68013a93c2 100644
--- a/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/TickLabels.test.tsx
+++ b/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/TickLabels.test.tsx
@@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { render, screen } from '@testing-library/react';
-import React from 'react';
import TickLabels from './TickLabels';
diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/TickLabels.tsx b/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/TickLabels.tsx
index e63dd89018b..bc5c5525c42 100644
--- a/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/TickLabels.tsx
+++ b/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/TickLabels.tsx
@@ -13,7 +13,6 @@
// limitations under the License.
import { css } from '@emotion/css';
-import React from 'react';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/ViewingLayer.test.tsx b/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/ViewingLayer.test.tsx
index bbe8f896ffb..d6b98ef33a4 100644
--- a/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/ViewingLayer.test.tsx
+++ b/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/ViewingLayer.test.tsx
@@ -14,7 +14,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { polyfill as polyfillAnimationFrame } from '../../utils/test/requestAnimationFrame';
diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/index.test.tsx b/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/index.test.tsx
index 3bff839ee1c..b265de14494 100644
--- a/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/index.test.tsx
+++ b/public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/index.test.tsx
@@ -13,7 +13,6 @@
// limitations under the License.
import { getAllByTestId, render, screen } from '@testing-library/react';
-import React from 'react';
import traceGenerator from '../../demo/trace-generators';
import transformTraceData from '../../model/transform-trace-data';
diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/TracePageHeader.test.tsx b/public/app/features/explore/TraceView/components/TracePageHeader/TracePageHeader.test.tsx
index 42804129129..0896564ef5a 100644
--- a/public/app/features/explore/TraceView/components/TracePageHeader/TracePageHeader.test.tsx
+++ b/public/app/features/explore/TraceView/components/TracePageHeader/TracePageHeader.test.tsx
@@ -13,7 +13,6 @@
// limitations under the License.
import { getByText, render } from '@testing-library/react';
-import React from 'react';
import { MutableDataFrame } from '@grafana/data';
diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/TracePageHeader.tsx b/public/app/features/explore/TraceView/components/TracePageHeader/TracePageHeader.tsx
index 98fc73fa848..033f891b9a7 100644
--- a/public/app/features/explore/TraceView/components/TracePageHeader/TracePageHeader.tsx
+++ b/public/app/features/explore/TraceView/components/TracePageHeader/TracePageHeader.tsx
@@ -14,7 +14,8 @@
import { css } from '@emotion/css';
import cx from 'classnames';
-import React, { memo, useEffect, useMemo } from 'react';
+import { memo, useEffect, useMemo } from 'react';
+import * as React from 'react';
import { CoreApp, DataFrame, dateTimeFormat, GrafanaTheme2 } from '@grafana/data';
import { TimeZone } from '@grafana/schema';
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/ListView/index.test.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/ListView/index.test.tsx
index aea197eb6a1..68165d13fb4 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/ListView/index.test.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/ListView/index.test.tsx
@@ -13,7 +13,7 @@
// limitations under the License.
import { render, screen } from '@testing-library/react';
-import React from 'react';
+import * as React from 'react';
import ListView, { TListViewProps } from './index';
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanBar.test.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanBar.test.tsx
index bad7f487815..f4c278bceb4 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanBar.test.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanBar.test.tsx
@@ -14,7 +14,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanBar.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanBar.tsx
index 4f7e4707a42..fdfb3f7faf0 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanBar.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanBar.tsx
@@ -15,7 +15,8 @@
import { css } from '@emotion/css';
import cx from 'classnames';
import { groupBy as _groupBy } from 'lodash';
-import React, { useState } from 'react';
+import { useState } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanBarRow.test.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanBarRow.test.tsx
index d4a76ca054b..ea39758763f 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanBarRow.test.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanBarRow.test.tsx
@@ -14,7 +14,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { DURATION, NONE, TAG } from '@grafana/o11y-ds-frontend';
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/AccordianKeyValues.test.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/AccordianKeyValues.test.tsx
index 06c6c8f1d2d..09ceafa6391 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/AccordianKeyValues.test.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/AccordianKeyValues.test.tsx
@@ -13,7 +13,6 @@
// limitations under the License.
import { render, screen } from '@testing-library/react';
-import React from 'react';
import AccordianKeyValues, { KeyValuesSummary, AccordianKeyValuesProps } from './AccordianKeyValues';
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/AccordianLogs.test.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/AccordianLogs.test.tsx
index 190a2a736e9..8e5db8dcebd 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/AccordianLogs.test.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/AccordianLogs.test.tsx
@@ -13,7 +13,6 @@
// limitations under the License.
import { render, screen } from '@testing-library/react';
-import React from 'react';
import AccordianLogs, { AccordianLogsProps } from './AccordianLogs';
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/AccordianReferences.test.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/AccordianReferences.test.tsx
index f0bde178776..d7296055bfc 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/AccordianReferences.test.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/AccordianReferences.test.tsx
@@ -13,7 +13,6 @@
// limitations under the License.
import { render, screen } from '@testing-library/react';
-import React from 'react';
import AccordianReferences, { AccordianReferencesProps } from './AccordianReferences';
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/AccordianText.test.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/AccordianText.test.tsx
index 53ce8d23702..ec5e8110bb7 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/AccordianText.test.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/AccordianText.test.tsx
@@ -13,7 +13,6 @@
// limitations under the License.
import { render, screen, within } from '@testing-library/react';
-import React from 'react';
import AccordianText from './AccordianText';
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/KeyValuesTable.test.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/KeyValuesTable.test.tsx
index 9818ace12cb..ac89bdf22b7 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/KeyValuesTable.test.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/KeyValuesTable.test.tsx
@@ -13,7 +13,6 @@
// limitations under the License.
import { render, screen } from '@testing-library/react';
-import React from 'react';
import KeyValuesTable, { LinkValue, KeyValuesTableProps } from './KeyValuesTable';
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/KeyValuesTable.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/KeyValuesTable.tsx
index 4cab6366f46..005d3af52ea 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/KeyValuesTable.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/KeyValuesTable.tsx
@@ -14,7 +14,8 @@
import { css } from '@emotion/css';
import cx from 'classnames';
-import React, { PropsWithChildren } from 'react';
+import { PropsWithChildren } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Icon, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/SpanFlameGraph.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/SpanFlameGraph.tsx
index d3042939834..ccf70c02b05 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/SpanFlameGraph.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/SpanFlameGraph.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useCallback, useEffect } from 'react';
+import { useCallback, useEffect } from 'react';
import { useMeasure } from 'react-use';
import { lastValueFrom } from 'rxjs';
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/TextList.test.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/TextList.test.tsx
index 9870fa5e6dd..e7b34cfa4f6 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/TextList.test.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/TextList.test.tsx
@@ -13,7 +13,6 @@
// limitations under the License.
import { render, screen } from '@testing-library/react';
-import React from 'react';
import TextList from './TextList';
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/TextList.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/TextList.tsx
index 20af23d63e8..bd132e62f8a 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/TextList.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/TextList.tsx
@@ -14,7 +14,6 @@
import { css } from '@emotion/css';
import cx from 'classnames';
-import * as React from 'react';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/index.test.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/index.test.tsx
index 2594bdec00b..d9b3c14f52c 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/index.test.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/index.test.tsx
@@ -16,7 +16,6 @@ jest.mock('../utils');
import { act, render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { createDataFrame, DataSourceInstanceSettings } from '@grafana/data';
import { data } from '@grafana/flamegraph';
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/index.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/index.tsx
index 87ba15592c8..2b12605abd0 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/index.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/index.tsx
@@ -15,7 +15,7 @@
import { css } from '@emotion/css';
import { SpanStatusCode } from '@opentelemetry/api';
import cx from 'classnames';
-import React from 'react';
+import * as React from 'react';
import { DataFrame, dateTimeFormat, GrafanaTheme2, IconName, LinkModel } from '@grafana/data';
import { TraceToProfilesOptions } from '@grafana/o11y-ds-frontend';
@@ -114,6 +114,11 @@ const getStyles = (theme: GrafanaTheme2) => {
LinkIcon: css`
font-size: 1.5em;
`,
+ linkList: css({
+ display: 'flex',
+ flexWrap: 'wrap',
+ gap: '10px',
+ }),
};
};
@@ -303,6 +308,7 @@ export default function SpanDetail(props: SpanDetailProps) {
let logLinkButton: JSX.Element | null = null;
let profileLinkButton: JSX.Element | null = null;
+ let sessionLinkButton: JSX.Element | null = null;
if (createSpanLink) {
const links = createSpanLink(span);
const logsLink = links?.filter((link) => link.type === SpanLinkType.Logs);
@@ -315,6 +321,15 @@ export default function SpanDetail(props: SpanDetailProps) {
if (links && profilesLink && profilesLink.length > 0) {
profileLinkButton = createLinkButton(profilesLink[0], SpanLinkType.Profiles, 'Profiles for this span', 'link');
}
+ const sessionLink = links?.filter((link) => link.type === SpanLinkType.Session);
+ if (links && sessionLink && sessionLink.length > 0) {
+ sessionLinkButton = createLinkButton(
+ sessionLink[0],
+ SpanLinkType.Session,
+ 'Session for this span',
+ 'frontend-observability'
+ );
+ }
}
const focusSpanLink = createFocusSpanLink(traceID, spanID);
@@ -326,8 +341,11 @@ export default function SpanDetail(props: SpanDetailProps) {
- {logLinkButton}
- {profileLinkButton}
+
+ {logLinkButton}
+ {profileLinkButton}
+ {sessionLinkButton}
+
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetailRow.test.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetailRow.test.tsx
index 07d93ade138..90223e8ed2b 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetailRow.test.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetailRow.test.tsx
@@ -14,7 +14,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { createTheme } from '@grafana/data';
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetailRow.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetailRow.tsx
index 6ecfb228891..4daee5b4db8 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetailRow.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetailRow.tsx
@@ -14,7 +14,7 @@
import { css } from '@emotion/css';
import classNames from 'classnames';
-import React from 'react';
+import { PureComponent } from 'react';
import { GrafanaTheme2, LinkModel } from '@grafana/data';
import { TraceToProfilesOptions } from '@grafana/o11y-ds-frontend';
@@ -106,7 +106,7 @@ export type SpanDetailRowProps = {
setRedrawListView: (redraw: {}) => void;
};
-export class UnthemedSpanDetailRow extends React.PureComponent
{
+export class UnthemedSpanDetailRow extends PureComponent {
_detailToggle = () => {
this.props.onDetailToggled(this.props.span.spanID);
};
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanLinks.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanLinks.tsx
index a6a01960204..67fb2eab3e1 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanLinks.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanLinks.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { config, reportInteraction } from '@grafana/runtime';
import { useStyles2, MenuItem, Icon, ContextMenu } from '@grafana/ui';
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanTreeOffset.test.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanTreeOffset.test.tsx
index 76ca9291da6..9994b36dd37 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanTreeOffset.test.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanTreeOffset.test.tsx
@@ -14,7 +14,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { createTheme } from '@grafana/data';
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanTreeOffset.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanTreeOffset.tsx
index 1e4119c2850..12b0c6b31e5 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanTreeOffset.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanTreeOffset.tsx
@@ -15,7 +15,7 @@
import { css } from '@emotion/css';
import cx from 'classnames';
import { get as _get } from 'lodash';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Icon, stylesFactory, withTheme2 } from '@grafana/ui';
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/Ticks.test.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/Ticks.test.tsx
index 871f6c2afbc..5f6209a0fd9 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/Ticks.test.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/Ticks.test.tsx
@@ -13,7 +13,6 @@
// limitations under the License.
import { render } from '@testing-library/react';
-import React from 'react';
import Ticks from './Ticks';
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/TimelineHeaderRow/TimelineCollapser.test.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/TimelineHeaderRow/TimelineCollapser.test.tsx
index 0fd4a5e00ee..19cde0e0e96 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/TimelineHeaderRow/TimelineCollapser.test.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/TimelineHeaderRow/TimelineCollapser.test.tsx
@@ -13,7 +13,6 @@
// limitations under the License.
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { TimelineCollapser } from './TimelineCollapser';
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/TimelineHeaderRow/TimelineCollapser.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/TimelineHeaderRow/TimelineCollapser.tsx
index cfa75305191..092faa3c9fd 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/TimelineHeaderRow/TimelineCollapser.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/TimelineHeaderRow/TimelineCollapser.tsx
@@ -13,7 +13,6 @@
// limitations under the License.
import { css } from '@emotion/css';
-import React from 'react';
import { IconButton, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/TimelineHeaderRow/TimelineColumnResizer.test.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/TimelineHeaderRow/TimelineColumnResizer.test.tsx
index e1074cc7dc0..c8e84e096fb 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/TimelineHeaderRow/TimelineColumnResizer.test.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/TimelineHeaderRow/TimelineColumnResizer.test.tsx
@@ -14,7 +14,6 @@
import { fireEvent, render, screen } from '@testing-library/react';
import cx from 'classnames';
-import React from 'react';
import TimelineColumnResizer, { getStyles, TimelineColumnResizerProps } from './TimelineColumnResizer';
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/TimelineHeaderRow/TimelineHeaderRow.test.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/TimelineHeaderRow/TimelineHeaderRow.test.tsx
index a031fcff0c1..28cf7a26fc3 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/TimelineHeaderRow/TimelineHeaderRow.test.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/TimelineHeaderRow/TimelineHeaderRow.test.tsx
@@ -13,7 +13,6 @@
// limitations under the License.
import { render, screen } from '@testing-library/react';
-import React from 'react';
import TimelineHeaderRow, { TimelineHeaderRowProps } from './TimelineHeaderRow';
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/TimelineHeaderRow/TimelineHeaderRow.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/TimelineHeaderRow/TimelineHeaderRow.tsx
index 67534003dc6..dbfc67f8ce6 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/TimelineHeaderRow/TimelineHeaderRow.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/TimelineHeaderRow/TimelineHeaderRow.tsx
@@ -13,7 +13,6 @@
// limitations under the License.
import { css } from '@emotion/css';
-import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/TimelineHeaderRow/TimelineViewingLayer.test.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/TimelineHeaderRow/TimelineViewingLayer.test.tsx
index 654ac191b18..bd4ebb9c03b 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/TimelineHeaderRow/TimelineViewingLayer.test.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/TimelineHeaderRow/TimelineViewingLayer.test.tsx
@@ -13,7 +13,6 @@
// limitations under the License.
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { ViewRangeTime } from '../types';
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/VirtualizedTraceView.test.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/VirtualizedTraceView.test.tsx
index dd33913e41b..fd93ab261f2 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/VirtualizedTraceView.test.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/VirtualizedTraceView.test.tsx
@@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { render, screen } from '@testing-library/react';
-import React from 'react';
import traceGenerator from '../demo/trace-generators';
import transformTraceData from '../model/transform-trace-data';
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/index.test.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/index.test.tsx
index f808228710b..7ac1261dc05 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/index.test.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/index.test.tsx
@@ -14,7 +14,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { createTheme } from '@grafana/data';
diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/index.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/index.tsx
index 495fec6f4c4..dba6d3d3ae0 100644
--- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/index.tsx
+++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/index.tsx
@@ -13,7 +13,7 @@
// limitations under the License.
import { css } from '@emotion/css';
-import React, { RefObject } from 'react';
+import { PureComponent, RefObject } from 'react';
import { GrafanaTheme2, LinkModel } from '@grafana/data';
import { SpanBarOptions, TraceToProfilesOptions } from '@grafana/o11y-ds-frontend';
@@ -129,7 +129,7 @@ const NUM_TICKS = 5;
* re-render the ListView every time the cursor is moved on the trace minimap
* or `TimelineHeaderRow`.
*/
-export class UnthemedTraceTimelineViewer extends React.PureComponent {
+export class UnthemedTraceTimelineViewer extends PureComponent {
constructor(props: TProps) {
super(props);
this.state = { height: 0 };
diff --git a/public/app/features/explore/TraceView/components/common/CopyIcon.test.tsx b/public/app/features/explore/TraceView/components/common/CopyIcon.test.tsx
index d4107a4a138..5f9726c0a85 100644
--- a/public/app/features/explore/TraceView/components/common/CopyIcon.test.tsx
+++ b/public/app/features/explore/TraceView/components/common/CopyIcon.test.tsx
@@ -14,7 +14,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import CopyIcon from './CopyIcon';
diff --git a/public/app/features/explore/TraceView/components/common/CopyIcon.tsx b/public/app/features/explore/TraceView/components/common/CopyIcon.tsx
index 43164f85e1f..0f811f8226f 100644
--- a/public/app/features/explore/TraceView/components/common/CopyIcon.tsx
+++ b/public/app/features/explore/TraceView/components/common/CopyIcon.tsx
@@ -14,7 +14,7 @@
import { css } from '@emotion/css';
import cx from 'classnames';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { Button, IconName, Tooltip, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/explore/TraceView/components/common/NewWindowIcon.tsx b/public/app/features/explore/TraceView/components/common/NewWindowIcon.tsx
index 401268d6dcc..ff5f1eb9dd6 100644
--- a/public/app/features/explore/TraceView/components/common/NewWindowIcon.tsx
+++ b/public/app/features/explore/TraceView/components/common/NewWindowIcon.tsx
@@ -14,7 +14,6 @@
import { css } from '@emotion/css';
import cx from 'classnames';
-import React from 'react';
import { Icon, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/explore/TraceView/components/common/Popover.tsx b/public/app/features/explore/TraceView/components/common/Popover.tsx
index cfd1ee9e15e..adb3c052f10 100644
--- a/public/app/features/explore/TraceView/components/common/Popover.tsx
+++ b/public/app/features/explore/TraceView/components/common/Popover.tsx
@@ -1,4 +1,4 @@
-import React, { ReactElement, useRef } from 'react';
+import { cloneElement, ReactElement, useRef } from 'react';
import { Popover as GrafanaPopover, PopoverController } from '@grafana/ui';
@@ -26,7 +26,7 @@ export function Popover({ children, content, overlayClassName }: PopoverProps) {
/>
)}
- {React.cloneElement(children, {
+ {cloneElement(children, {
ref: popoverRef,
onMouseEnter: showPopper,
onMouseLeave: hidePopper,
diff --git a/public/app/features/explore/TraceView/components/common/SearchBarInput.test.tsx b/public/app/features/explore/TraceView/components/common/SearchBarInput.test.tsx
index e8cb4206e67..e613c07fcfc 100644
--- a/public/app/features/explore/TraceView/components/common/SearchBarInput.test.tsx
+++ b/public/app/features/explore/TraceView/components/common/SearchBarInput.test.tsx
@@ -13,7 +13,6 @@
// limitations under the License.
import { render, screen } from '@testing-library/react';
-import React from 'react';
import SearchBarInput from './SearchBarInput';
diff --git a/public/app/features/explore/TraceView/components/common/TraceName.tsx b/public/app/features/explore/TraceView/components/common/TraceName.tsx
index 1b8af164ce4..600b67bcef1 100644
--- a/public/app/features/explore/TraceView/components/common/TraceName.tsx
+++ b/public/app/features/explore/TraceView/components/common/TraceName.tsx
@@ -14,7 +14,6 @@
import { css } from '@emotion/css';
import cx from 'classnames';
-import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/explore/TraceView/components/settings/SpanBarSettings.tsx b/public/app/features/explore/TraceView/components/settings/SpanBarSettings.tsx
index 4c8ac4a99d0..d54e2817fdb 100644
--- a/public/app/features/explore/TraceView/components/settings/SpanBarSettings.tsx
+++ b/public/app/features/explore/TraceView/components/settings/SpanBarSettings.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import {
DataSourceJsonData,
diff --git a/public/app/features/explore/TraceView/components/types/links.ts b/public/app/features/explore/TraceView/components/types/links.ts
index 0ffe2ec5ec1..e01a081c43f 100644
--- a/public/app/features/explore/TraceView/components/types/links.ts
+++ b/public/app/features/explore/TraceView/components/types/links.ts
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { Field } from '@grafana/data';
@@ -9,6 +9,7 @@ export enum SpanLinkType {
Traces = 'trace',
Metrics = 'metric',
Profiles = 'profile',
+ Session = 'session',
Unknown = 'unknown',
}
diff --git a/public/app/features/explore/TraceView/components/url/ReferenceLink.test.tsx b/public/app/features/explore/TraceView/components/url/ReferenceLink.test.tsx
index cfc9fbc78ff..c46ba8fc81d 100644
--- a/public/app/features/explore/TraceView/components/url/ReferenceLink.test.tsx
+++ b/public/app/features/explore/TraceView/components/url/ReferenceLink.test.tsx
@@ -13,7 +13,6 @@
// limitations under the License.
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { LinkModel } from '@grafana/data';
diff --git a/public/app/features/explore/TraceView/components/url/ReferenceLink.tsx b/public/app/features/explore/TraceView/components/url/ReferenceLink.tsx
index a96c2b75cb9..d21c11d0cb8 100644
--- a/public/app/features/explore/TraceView/components/url/ReferenceLink.tsx
+++ b/public/app/features/explore/TraceView/components/url/ReferenceLink.tsx
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import React from 'react';
+import * as React from 'react';
import { Field, LinkModel } from '@grafana/data';
diff --git a/public/app/features/explore/TraceView/components/utils/DraggableManager/DraggableManager.test.ts b/public/app/features/explore/TraceView/components/utils/DraggableManager/DraggableManager.test.ts
index 15ae245d3be..f20d3652af4 100644
--- a/public/app/features/explore/TraceView/components/utils/DraggableManager/DraggableManager.test.ts
+++ b/public/app/features/explore/TraceView/components/utils/DraggableManager/DraggableManager.test.ts
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import React from 'react';
+import * as React from 'react';
import DraggableManager, { DraggableManagerOptions } from './DraggableManager';
import EUpdateTypes from './EUpdateTypes';
diff --git a/public/app/features/explore/TraceView/components/utils/DraggableManager/demo/DividerDemo.tsx b/public/app/features/explore/TraceView/components/utils/DraggableManager/demo/DividerDemo.tsx
index 26ac8b73b56..835573a5fa5 100644
--- a/public/app/features/explore/TraceView/components/utils/DraggableManager/demo/DividerDemo.tsx
+++ b/public/app/features/explore/TraceView/components/utils/DraggableManager/demo/DividerDemo.tsx
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import React from 'react';
+import { PureComponent } from 'react';
import TNil from '../../../types/TNil';
import DraggableManager from '../DraggableManager';
@@ -25,7 +25,7 @@ type DividerDemoProps = {
updateState: (update: { dividerPosition: number }) => void;
};
-export default class DividerDemo extends React.PureComponent {
+export default class DividerDemo extends PureComponent {
_dragManager: DraggableManager;
_realmElm: HTMLElement | TNil;
diff --git a/public/app/features/explore/TraceView/components/utils/DraggableManager/demo/DraggableManagerDemo.tsx b/public/app/features/explore/TraceView/components/utils/DraggableManager/demo/DraggableManagerDemo.tsx
index 439a7b5c7e2..5de0f95309a 100644
--- a/public/app/features/explore/TraceView/components/utils/DraggableManager/demo/DraggableManagerDemo.tsx
+++ b/public/app/features/explore/TraceView/components/utils/DraggableManager/demo/DraggableManagerDemo.tsx
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import React from 'react';
+import { PureComponent } from 'react';
import { TNil } from '../../../types';
@@ -27,7 +27,7 @@ export type DraggableManagerDemoState = {
regionDragging: [number, number] | TNil;
};
-export default class DraggableManagerDemo extends React.PureComponent<{}, DraggableManagerDemoState> {
+export default class DraggableManagerDemo extends PureComponent<{}, DraggableManagerDemoState> {
state: DraggableManagerDemoState;
constructor(props: {}) {
diff --git a/public/app/features/explore/TraceView/components/utils/DraggableManager/demo/RegionDemo.tsx b/public/app/features/explore/TraceView/components/utils/DraggableManager/demo/RegionDemo.tsx
index f25f9f05320..793428fcce5 100644
--- a/public/app/features/explore/TraceView/components/utils/DraggableManager/demo/RegionDemo.tsx
+++ b/public/app/features/explore/TraceView/components/utils/DraggableManager/demo/RegionDemo.tsx
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import React from 'react';
+import { PureComponent } from 'react';
import { TNil } from '../../../types';
import DraggableManager, { DraggableBounds, DraggingUpdate } from '../index';
@@ -30,7 +30,7 @@ type RegionDemoProps = {
updateState: (update: TUpdate) => void;
};
-export default class RegionDemo extends React.PureComponent {
+export default class RegionDemo extends PureComponent {
_dragManager: DraggableManager;
_realmElm: HTMLElement | TNil;
diff --git a/public/app/features/explore/TraceView/createSpanLink.test.ts b/public/app/features/explore/TraceView/createSpanLink.test.ts
index 9c0c81fa9fe..f73ed1d5f68 100644
--- a/public/app/features/explore/TraceView/createSpanLink.test.ts
+++ b/public/app/features/explore/TraceView/createSpanLink.test.ts
@@ -1266,6 +1266,57 @@ describe('createSpanLinkFactory', () => {
});
});
+ describe('should return session link', () => {
+ beforeAll(() => {
+ setLinkSrv(new LinkSrv());
+ setTemplateSrv(new TemplateSrv());
+ });
+
+ it('does not add link when no ids are present', () => {
+ const createLink = setupSpanLinkFactory();
+ expect(createLink).toBeDefined();
+ const links = createLink!(createTraceSpan());
+ const sessionLink = links?.find((link) => link.type === SpanLinkType.Session);
+ expect(sessionLink).toBe(undefined);
+ });
+
+ it('adds link when fe o11y ids are present', () => {
+ const createLink = setupSpanLinkFactory();
+ expect(createLink).toBeDefined();
+ const links = createLink!(
+ createTraceSpan({
+ process: {
+ serviceName: 'feo11y-service',
+ tags: [{ key: 'gf.feo11y.app.id', value: 'appId' }],
+ },
+ tags: [{ key: 'session_id', value: 'the-session-id' }],
+ })
+ );
+ expect(links).toHaveLength(1);
+ const sessionLink = links?.find((link) => link.type === SpanLinkType.Session);
+ expect(sessionLink).toBeDefined();
+ expect(sessionLink!.href).toBe('/a/grafana-kowalski-app/apps/appId/sessions/the-session-id');
+ });
+
+ it('adds link when session id is defined following otel semantic convention', () => {
+ const createLink = setupSpanLinkFactory();
+ expect(createLink).toBeDefined();
+ const links = createLink!(
+ createTraceSpan({
+ process: {
+ serviceName: 'feo11y-service',
+ tags: [{ key: 'gf.feo11y.app.id', value: 'appId' }],
+ },
+ tags: [{ key: 'session.id', value: 'the-otel-session-id' }],
+ })
+ );
+ expect(links).toHaveLength(1);
+ const sessionLink = links?.find((link) => link.type === SpanLinkType.Session);
+ expect(sessionLink).toBeDefined();
+ expect(sessionLink!.href).toBe('/a/grafana-kowalski-app/apps/appId/sessions/the-otel-session-id');
+ });
+ });
+
describe('should return pyroscope link', () => {
beforeAll(() => {
setDataSourceSrv({
diff --git a/public/app/features/explore/TraceView/createSpanLink.tsx b/public/app/features/explore/TraceView/createSpanLink.tsx
index c7b840d683a..3b4a5b19fb2 100644
--- a/public/app/features/explore/TraceView/createSpanLink.tsx
+++ b/public/app/features/explore/TraceView/createSpanLink.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import {
DataFrame,
DataLink,
@@ -139,6 +137,7 @@ const formatDefaultKeys = (keys: string[]) => {
const defaultKeys = formatDefaultKeys(['cluster', 'hostname', 'namespace', 'pod', 'service.name', 'service.namespace']);
export const defaultProfilingKeys = formatDefaultKeys(['service.name', 'service.namespace']);
export const pyroscopeProfileIdTagKey = 'pyroscope.profile.id';
+export const feO11yTagKey = 'gf.feo11y.app.id';
function legacyCreateSpanLinkFactory(
splitOpenFn: SplitOpen,
@@ -350,6 +349,18 @@ function legacyCreateSpanLinkFactory(
}
}
+ // Get session links
+ const feO11yLink = getLinkForFeO11y(span);
+ if (feO11yLink) {
+ links.push({
+ title: 'Session for this span',
+ href: feO11yLink,
+ content: ,
+ field,
+ type: SpanLinkType.Session,
+ });
+ }
+
return links;
};
}
@@ -384,6 +395,15 @@ function getQueryForLoki(
};
}
+function getLinkForFeO11y(span: TraceSpan): string | undefined {
+ const feO11yAppId = span.process.tags.find((tag) => tag.key === feO11yTagKey)?.value;
+ const feO11ySessionId = span.tags.find((tag) => tag.key === 'session_id' || tag.key === 'session.id')?.value;
+
+ return feO11yAppId && feO11ySessionId
+ ? `/a/grafana-kowalski-app/apps/${feO11yAppId}/sessions/${feO11ySessionId}`
+ : undefined;
+}
+
// we do not have access to the dataquery type for opensearch,
// so here is a minimal interface that handles both elasticsearch and opensearch.
interface ElasticsearchOrOpensearchQuery extends DataQuery {
diff --git a/public/app/features/explore/extensions/AddToDashboard/AddToDashboardForm.tsx b/public/app/features/explore/extensions/AddToDashboard/AddToDashboardForm.tsx
index b3bf2013a47..847a981a7bc 100644
--- a/public/app/features/explore/extensions/AddToDashboard/AddToDashboardForm.tsx
+++ b/public/app/features/explore/extensions/AddToDashboard/AddToDashboardForm.tsx
@@ -1,5 +1,5 @@
import { partial } from 'lodash';
-import React, { type ReactElement, useEffect, useState } from 'react';
+import { type ReactElement, useEffect, useState } from 'react';
import { DeepMap, FieldError, FieldErrors, useForm, Controller } from 'react-hook-form';
import { locationUtil, SelectableValue } from '@grafana/data';
diff --git a/public/app/features/explore/extensions/AddToDashboard/index.test.tsx b/public/app/features/explore/extensions/AddToDashboard/index.test.tsx
index 2d142d7f811..6c38ba8b471 100644
--- a/public/app/features/explore/extensions/AddToDashboard/index.test.tsx
+++ b/public/app/features/explore/extensions/AddToDashboard/index.test.tsx
@@ -1,6 +1,6 @@
import { act, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { ReactNode } from 'react';
+import { ReactNode } from 'react';
import { Provider } from 'react-redux';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/explore/extensions/AddToDashboard/index.tsx b/public/app/features/explore/extensions/AddToDashboard/index.tsx
index 59a2fc35450..4b6b4d7f9ad 100644
--- a/public/app/features/explore/extensions/AddToDashboard/index.tsx
+++ b/public/app/features/explore/extensions/AddToDashboard/index.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useState } from 'react';
+import { useCallback, useState } from 'react';
import { Modal, ToolbarButton } from '@grafana/ui';
import { t } from 'app/core/internationalization';
diff --git a/public/app/features/explore/extensions/ConfirmNavigationModal.tsx b/public/app/features/explore/extensions/ConfirmNavigationModal.tsx
index e9c41612adf..1d5c35302ca 100644
--- a/public/app/features/explore/extensions/ConfirmNavigationModal.tsx
+++ b/public/app/features/explore/extensions/ConfirmNavigationModal.tsx
@@ -1,4 +1,4 @@
-import React, { ReactElement } from 'react';
+import { ReactElement } from 'react';
import { locationUtil } from '@grafana/data';
import { locationService } from '@grafana/runtime';
diff --git a/public/app/features/explore/extensions/ToolbarExtensionPoint.test.tsx b/public/app/features/explore/extensions/ToolbarExtensionPoint.test.tsx
index 8dca4a16b8e..fde629deab4 100644
--- a/public/app/features/explore/extensions/ToolbarExtensionPoint.test.tsx
+++ b/public/app/features/explore/extensions/ToolbarExtensionPoint.test.tsx
@@ -1,6 +1,6 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { ReactNode } from 'react';
+import { ReactNode } from 'react';
import { Provider } from 'react-redux';
import { PluginExtensionPoints, PluginExtensionTypes } from '@grafana/data';
diff --git a/public/app/features/explore/extensions/ToolbarExtensionPoint.tsx b/public/app/features/explore/extensions/ToolbarExtensionPoint.tsx
index 477f413fa98..f12f608c2bb 100644
--- a/public/app/features/explore/extensions/ToolbarExtensionPoint.tsx
+++ b/public/app/features/explore/extensions/ToolbarExtensionPoint.tsx
@@ -1,4 +1,4 @@
-import React, { lazy, ReactElement, Suspense, useMemo, useState } from 'react';
+import { lazy, ReactElement, Suspense, useMemo, useState } from 'react';
import { type PluginExtensionLink, PluginExtensionPoints, RawTimeRange, getTimeZone } from '@grafana/data';
import { config, usePluginLinkExtensions } from '@grafana/runtime';
diff --git a/public/app/features/explore/extensions/ToolbarExtensionPointMenu.tsx b/public/app/features/explore/extensions/ToolbarExtensionPointMenu.tsx
index 651cc5103e8..1500d9a2b91 100644
--- a/public/app/features/explore/extensions/ToolbarExtensionPointMenu.tsx
+++ b/public/app/features/explore/extensions/ToolbarExtensionPointMenu.tsx
@@ -1,4 +1,4 @@
-import React, { ReactElement, useMemo } from 'react';
+import { ReactElement, useMemo } from 'react';
import { PluginExtensionLink } from '@grafana/data';
import { Menu } from '@grafana/ui';
diff --git a/public/app/features/explore/extensions/getExploreExtensionConfigs.tsx b/public/app/features/explore/extensions/getExploreExtensionConfigs.tsx
index 636d2fe1ae6..a23cf1fc3a8 100644
--- a/public/app/features/explore/extensions/getExploreExtensionConfigs.tsx
+++ b/public/app/features/explore/extensions/getExploreExtensionConfigs.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PluginExtensionPoints, type PluginExtensionLinkConfig } from '@grafana/data';
import { contextSrv } from 'app/core/core';
import { dispatch } from 'app/store/store';
diff --git a/public/app/features/explore/hooks/useExplorePageTitle.test.tsx b/public/app/features/explore/hooks/useExplorePageTitle.test.tsx
index 72aad269bb1..1df421fc88b 100644
--- a/public/app/features/explore/hooks/useExplorePageTitle.test.tsx
+++ b/public/app/features/explore/hooks/useExplorePageTitle.test.tsx
@@ -1,5 +1,4 @@
import { renderHook, waitFor } from '@testing-library/react';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
diff --git a/public/app/features/explore/hooks/useKeyboardShortcuts.test.tsx b/public/app/features/explore/hooks/useKeyboardShortcuts.test.tsx
index c58336af1c8..c270c2bce73 100644
--- a/public/app/features/explore/hooks/useKeyboardShortcuts.test.tsx
+++ b/public/app/features/explore/hooks/useKeyboardShortcuts.test.tsx
@@ -1,5 +1,4 @@
import { render, waitFor } from '@testing-library/react';
-import React from 'react';
import { dateTime, EventBusSrv } from '@grafana/data';
import { getAppEvents } from '@grafana/runtime';
diff --git a/public/app/features/explore/hooks/useSplitSizeUpdater.test.tsx b/public/app/features/explore/hooks/useSplitSizeUpdater.test.tsx
index 82f83e08fca..c9da8b56276 100644
--- a/public/app/features/explore/hooks/useSplitSizeUpdater.test.tsx
+++ b/public/app/features/explore/hooks/useSplitSizeUpdater.test.tsx
@@ -1,5 +1,5 @@
import { renderHook, act } from '@testing-library/react-hooks';
-import React, { ReactNode } from 'react';
+import { ReactNode } from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { initialExploreState } from 'app/features/explore/state/main';
diff --git a/public/app/features/explore/hooks/useStateSync/index.test.tsx b/public/app/features/explore/hooks/useStateSync/index.test.tsx
index b4b28e3a359..0d778aa92ec 100644
--- a/public/app/features/explore/hooks/useStateSync/index.test.tsx
+++ b/public/app/features/explore/hooks/useStateSync/index.test.tsx
@@ -2,7 +2,7 @@ import { act, waitFor } from '@testing-library/react';
import { renderHook } from '@testing-library/react-hooks';
import { createMemoryHistory } from 'history';
import { stringify } from 'querystring';
-import React, { ReactNode } from 'react';
+import { ReactNode } from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
diff --git a/public/app/features/explore/hooks/useTimeSrvFix.test.tsx b/public/app/features/explore/hooks/useTimeSrvFix.test.tsx
index 1b3ddbf9d89..d8d2776ddbe 100644
--- a/public/app/features/explore/hooks/useTimeSrvFix.test.tsx
+++ b/public/app/features/explore/hooks/useTimeSrvFix.test.tsx
@@ -1,7 +1,6 @@
import { renderHook, waitFor } from '@testing-library/react';
import { createMemoryHistory } from 'history';
import { stringify } from 'querystring';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
diff --git a/public/app/features/explore/spec/helper/setup.tsx b/public/app/features/explore/spec/helper/setup.tsx
index c2aa3187aff..c908d9754df 100644
--- a/public/app/features/explore/spec/helper/setup.tsx
+++ b/public/app/features/explore/spec/helper/setup.tsx
@@ -3,7 +3,6 @@ import { render, screen } from '@testing-library/react';
import { createMemoryHistory } from 'history';
import { fromPairs } from 'lodash';
import { stringify } from 'querystring';
-import React from 'react';
import { Provider } from 'react-redux';
import { Route, Router } from 'react-router-dom';
import { of } from 'rxjs';
diff --git a/public/app/features/explore/spec/interpolation.test.tsx b/public/app/features/explore/spec/interpolation.test.tsx
index be1b21416e8..d708a231a3a 100644
--- a/public/app/features/explore/spec/interpolation.test.tsx
+++ b/public/app/features/explore/spec/interpolation.test.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { Props } from 'react-virtualized-auto-sizer';
import { DataQueryRequest, EventBusSrv, serializeStateToUrlParam } from '@grafana/data';
diff --git a/public/app/features/explore/spec/queryHistory.test.tsx b/public/app/features/explore/spec/queryHistory.test.tsx
index 22e6472a694..9f7f9bb311c 100644
--- a/public/app/features/explore/spec/queryHistory.test.tsx
+++ b/public/app/features/explore/spec/queryHistory.test.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { Props } from 'react-virtualized-auto-sizer';
import { EventBusSrv, serializeStateToUrlParam } from '@grafana/data';
diff --git a/public/app/features/explore/spec/queryLibrary.test.tsx b/public/app/features/explore/spec/queryLibrary.test.tsx
index 8b9b53aa38f..7b00a22ee21 100644
--- a/public/app/features/explore/spec/queryLibrary.test.tsx
+++ b/public/app/features/explore/spec/queryLibrary.test.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { Props } from 'react-virtualized-auto-sizer';
import { EventBusSrv } from '@grafana/data';
diff --git a/public/app/features/explore/spec/split.test.tsx b/public/app/features/explore/spec/split.test.tsx
index cf2b0f61a84..0bd25b92b1c 100644
--- a/public/app/features/explore/spec/split.test.tsx
+++ b/public/app/features/explore/spec/split.test.tsx
@@ -1,6 +1,6 @@
import { act, fireEvent, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { ComponentProps } from 'react';
+import { ComponentProps } from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
import { EventBusSrv, serializeStateToUrlParam } from '@grafana/data';
diff --git a/public/app/features/explore/useLiveTailControls.ts b/public/app/features/explore/useLiveTailControls.ts
index adf7b555651..42837521e05 100644
--- a/public/app/features/explore/useLiveTailControls.ts
+++ b/public/app/features/explore/useLiveTailControls.ts
@@ -1,4 +1,5 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
+import * as React from 'react';
import { RefreshPicker } from '@grafana/ui';
import { useDispatch } from 'app/types';
diff --git a/public/app/features/expressions/ExpressionQueryEditor.tsx b/public/app/features/expressions/ExpressionQueryEditor.tsx
index 419fbe067fd..0aa63afdd06 100644
--- a/public/app/features/expressions/ExpressionQueryEditor.tsx
+++ b/public/app/features/expressions/ExpressionQueryEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useEffect, useRef } from 'react';
+import { useCallback, useEffect, useRef } from 'react';
import { DataSourceApi, QueryEditorProps, SelectableValue } from '@grafana/data';
import { InlineField, Select } from '@grafana/ui';
diff --git a/public/app/features/expressions/components/ClassicConditions.tsx b/public/app/features/expressions/components/ClassicConditions.tsx
index cc4d95e5d04..6697eb7addf 100644
--- a/public/app/features/expressions/components/ClassicConditions.tsx
+++ b/public/app/features/expressions/components/ClassicConditions.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SelectableValue } from '@grafana/data';
import { Button, Icon, InlineField, InlineFieldRow } from '@grafana/ui';
diff --git a/public/app/features/expressions/components/Condition.tsx b/public/app/features/expressions/components/Condition.tsx
index 72fc74027fe..d5118e1b768 100644
--- a/public/app/features/expressions/components/Condition.tsx
+++ b/public/app/features/expressions/components/Condition.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { FormEvent } from 'react';
+import { FormEvent } from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { Button, ButtonSelect, Icon, InlineFieldRow, Input, Select, useStyles2, Stack } from '@grafana/ui';
diff --git a/public/app/features/expressions/components/Math.tsx b/public/app/features/expressions/components/Math.tsx
index ecebcf2f675..82ac024baed 100644
--- a/public/app/features/expressions/components/Math.tsx
+++ b/public/app/features/expressions/components/Math.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { ChangeEvent } from 'react';
+import { ChangeEvent } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Icon, InlineField, InlineLabel, TextArea, Toggletip, useStyles2, Stack } from '@grafana/ui';
diff --git a/public/app/features/expressions/components/Reduce.tsx b/public/app/features/expressions/components/Reduce.tsx
index 290d6afde10..dfedab25f86 100644
--- a/public/app/features/expressions/components/Reduce.tsx
+++ b/public/app/features/expressions/components/Reduce.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { SelectableValue } from '@grafana/data';
import { InlineField, InlineFieldRow, Input, Select } from '@grafana/ui';
diff --git a/public/app/features/expressions/components/Resample.tsx b/public/app/features/expressions/components/Resample.tsx
index ecf4a0fd8ae..0984a776540 100644
--- a/public/app/features/expressions/components/Resample.tsx
+++ b/public/app/features/expressions/components/Resample.tsx
@@ -1,4 +1,4 @@
-import React, { ChangeEvent } from 'react';
+import { ChangeEvent } from 'react';
import { SelectableValue } from '@grafana/data';
import { InlineField, InlineFieldRow, Input, Select } from '@grafana/ui';
diff --git a/public/app/features/expressions/components/SqlExpr.tsx b/public/app/features/expressions/components/SqlExpr.tsx
index f5857f88929..f05ed42c224 100644
--- a/public/app/features/expressions/components/SqlExpr.tsx
+++ b/public/app/features/expressions/components/SqlExpr.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { SelectableValue } from '@grafana/data';
import { SQLEditor } from '@grafana/experimental';
diff --git a/public/app/features/expressions/components/Threshold.tsx b/public/app/features/expressions/components/Threshold.tsx
index 77d0bce5123..34583841a9a 100644
--- a/public/app/features/expressions/components/Threshold.tsx
+++ b/public/app/features/expressions/components/Threshold.tsx
@@ -1,6 +1,7 @@
import { css } from '@emotion/css';
import { AnyAction } from '@reduxjs/toolkit';
-import React, { FormEvent, useEffect, useReducer } from 'react';
+import { FormEvent, useEffect, useReducer } from 'react';
+import * as React from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { Stack } from '@grafana/experimental';
diff --git a/public/app/features/geo/editor/GazetteerPathEditor.tsx b/public/app/features/geo/editor/GazetteerPathEditor.tsx
index 1d728801649..944f23a4ac0 100644
--- a/public/app/features/geo/editor/GazetteerPathEditor.tsx
+++ b/public/app/features/geo/editor/GazetteerPathEditor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo, useState, useEffect } from 'react';
+import { useMemo, useState, useEffect } from 'react';
import { StandardEditorProps, SelectableValue } from '@grafana/data';
import { Alert, Select, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/geo/editor/locationModeEditor.tsx b/public/app/features/geo/editor/locationModeEditor.tsx
index 204db9200c9..2bce3e10980 100644
--- a/public/app/features/geo/editor/locationModeEditor.tsx
+++ b/public/app/features/geo/editor/locationModeEditor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { StandardEditorProps, DataFrame, GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/gops/configuration-tracker/components/ConfigCard.tsx b/public/app/features/gops/configuration-tracker/components/ConfigCard.tsx
index 180d5ab6538..f4f4986e2ea 100644
--- a/public/app/features/gops/configuration-tracker/components/ConfigCard.tsx
+++ b/public/app/features/gops/configuration-tracker/components/ConfigCard.tsx
@@ -1,6 +1,5 @@
// ConfigCard.tsx
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Button, Icon, LoadingPlaceholder, Stack, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/gops/configuration-tracker/components/ConfigureIRM.tsx b/public/app/features/gops/configuration-tracker/components/ConfigureIRM.tsx
index bb596a1e7ad..750100c3162 100644
--- a/public/app/features/gops/configuration-tracker/components/ConfigureIRM.tsx
+++ b/public/app/features/gops/configuration-tracker/components/ConfigureIRM.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { useHistory } from 'react-router-dom';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/gops/configuration-tracker/components/Essentials.test.tsx b/public/app/features/gops/configuration-tracker/components/Essentials.test.tsx
index 84291824a97..347c0fe4a66 100644
--- a/public/app/features/gops/configuration-tracker/components/Essentials.test.tsx
+++ b/public/app/features/gops/configuration-tracker/components/Essentials.test.tsx
@@ -1,5 +1,4 @@
import { render, screen, within } from '@testing-library/react';
-import React from 'react';
import { byRole } from 'testing-library-selector';
import { SectionsDto } from '../irmHooks';
diff --git a/public/app/features/gops/configuration-tracker/components/Essentials.tsx b/public/app/features/gops/configuration-tracker/components/Essentials.tsx
index 00cdeeb68a8..15fc2f9cefd 100644
--- a/public/app/features/gops/configuration-tracker/components/Essentials.tsx
+++ b/public/app/features/gops/configuration-tracker/components/Essentials.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Button, Drawer, Dropdown, Icon, LinkButton, Menu, Stack, Text, Tooltip, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/gops/configuration-tracker/components/ProgressBar.tsx b/public/app/features/gops/configuration-tracker/components/ProgressBar.tsx
index e1a766fd14b..fc9f4d8636b 100644
--- a/public/app/features/gops/configuration-tracker/components/ProgressBar.tsx
+++ b/public/app/features/gops/configuration-tracker/components/ProgressBar.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Text, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/gops/configuration-tracker/irmHooks.ts b/public/app/features/gops/configuration-tracker/irmHooks.ts
index b845de6033b..f182633940f 100644
--- a/public/app/features/gops/configuration-tracker/irmHooks.ts
+++ b/public/app/features/gops/configuration-tracker/irmHooks.ts
@@ -13,6 +13,7 @@ import { isContactPointReady } from './alerting/utils';
import { ConfigurationStepsEnum, DataSourceConfigurationData, IrmCardConfiguration } from './components/ConfigureIRM';
import { useGetIncidentPluginConfig } from './incidents/hooks';
import { useOnCallChatOpsConnections, useOnCallOptions } from './onCall/hooks';
+import { useSloChecks } from './slo/hooks';
interface UrlLink {
url: string;
@@ -68,13 +69,17 @@ function useGetConfigurationForApps() {
is_integration_chatops_connected,
isLoading: isOnCallConfigLoading,
} = useOnCallChatOpsConnections();
+ // configuration checks for slo
+ const { hasSlo, hasSloWithAlert, isLoading: isSloLoading } = useSloChecks();
+
// check if any of the configurations are loading
const isLoading =
isLoadingContactPoints ||
isLoadingDefaultContactPoint ||
isLoadingAlertCreatedDone ||
isIncidentsConfigLoading ||
- isOnCallConfigLoading;
+ isOnCallConfigLoading ||
+ isSloLoading;
return {
alerting: {
@@ -91,6 +96,10 @@ function useGetConfigurationForApps() {
is_chatops_connected,
is_integration_chatops_connected,
},
+ slo: {
+ hasSlo,
+ hasSloWithAlert,
+ },
isLoading,
};
}
@@ -100,6 +109,7 @@ export function useGetEssentialsConfiguration(): EssentialsConfigurationData {
alerting: { contactPoints, defaultContactpoint, isCreateAlertRuleDone },
incidents: { isChatOpsInstalled, isIncidentsInstalled },
onCall: { onCallOptions, is_chatops_connected, is_integration_chatops_connected },
+ slo: { hasSlo, hasSloWithAlert },
isLoading,
} = useGetConfigurationForApps();
@@ -165,6 +175,40 @@ export function useGetEssentialsConfiguration(): EssentialsConfigurationData {
},
done: isCreateAlertRuleDone,
},
+ {
+ title: 'Create your first SLO',
+ description: 'Create SLOs to monitor your service.',
+ button: {
+ type: 'openLink',
+ urlLink: {
+ url: '/a/grafana-slo-app/wizard/new',
+ },
+ label: 'Create',
+ urlLinkOnDone: {
+ url: '/a/grafana-slo-app/manage-slos',
+ },
+ labelOnDone: 'View',
+ },
+ done: hasSlo,
+ },
+ {
+ title: 'Enable SLO alerting',
+ description: 'Configure SLO alerting to receive notifications when your SLOs are breached.',
+ button: {
+ type: 'openLink',
+ urlLink: {
+ queryParams: { alertsEnabled: 'disabled' },
+ url: '/a/grafana-slo-app/manage-slos',
+ },
+ label: 'Enable',
+ urlLinkOnDone: {
+ queryParams: { alertsEnabled: 'enabled' },
+ url: '/a/grafana-slo-app/manage-slos',
+ },
+ labelOnDone: 'View',
+ },
+ done: hasSloWithAlert,
+ },
],
},
{
diff --git a/public/app/features/gops/configuration-tracker/slo/hooks.ts b/public/app/features/gops/configuration-tracker/slo/hooks.ts
new file mode 100644
index 00000000000..e260fc68067
--- /dev/null
+++ b/public/app/features/gops/configuration-tracker/slo/hooks.ts
@@ -0,0 +1,20 @@
+import { sloApi } from 'app/features/alerting/unified/api/sloApi';
+import { usePluginBridge } from 'app/features/alerting/unified/hooks/usePluginBridge';
+import { SupportedPlugin } from 'app/features/alerting/unified/types/pluginBridges';
+
+export function useSloChecks() {
+ const { installed: sloPluginInstalled } = usePluginBridge(SupportedPlugin.Slo);
+
+ const { data, isLoading } = sloApi.endpoints.getSlos.useQuery(undefined, {
+ skip: !sloPluginInstalled,
+ refetchOnFocus: true,
+ refetchOnReconnect: true,
+ refetchOnMountOrArgChange: true,
+ });
+
+ return {
+ isLoading,
+ hasSlo: Boolean(data?.slos.length),
+ hasSloWithAlert: Boolean(data?.slos?.some((slo) => slo.alerting)),
+ };
+}
diff --git a/public/app/features/inspector/DetailText.tsx b/public/app/features/inspector/DetailText.tsx
index 9e8f6e307d2..2ea340cc092 100644
--- a/public/app/features/inspector/DetailText.tsx
+++ b/public/app/features/inspector/DetailText.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/inspector/InspectDataOptions.tsx b/public/app/features/inspector/InspectDataOptions.tsx
index 910569f2c0f..ec8c246d95c 100644
--- a/public/app/features/inspector/InspectDataOptions.tsx
+++ b/public/app/features/inspector/InspectDataOptions.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { DataFrame, DataTransformerID, getFrameDisplayName, SelectableValue } from '@grafana/data';
import { Field, HorizontalGroup, Select, Switch, VerticalGroup, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/inspector/InspectDataTab.test.tsx b/public/app/features/inspector/InspectDataTab.test.tsx
index 37284933ce0..a19b4667437 100644
--- a/public/app/features/inspector/InspectDataTab.test.tsx
+++ b/public/app/features/inspector/InspectDataTab.test.tsx
@@ -1,6 +1,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { ComponentProps } from 'react';
+import { ComponentProps } from 'react';
import { Props } from 'react-virtualized-auto-sizer';
import { DataFrame, FieldType } from '@grafana/data';
diff --git a/public/app/features/inspector/InspectDataTab.tsx b/public/app/features/inspector/InspectDataTab.tsx
index 2fa49dacaf0..dcecf5386dc 100644
--- a/public/app/features/inspector/InspectDataTab.tsx
+++ b/public/app/features/inspector/InspectDataTab.tsx
@@ -1,5 +1,5 @@
import { cloneDeep } from 'lodash';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
import {
diff --git a/public/app/features/inspector/InspectErrorTab.test.tsx b/public/app/features/inspector/InspectErrorTab.test.tsx
index 222cbb09304..b05cf2a8089 100644
--- a/public/app/features/inspector/InspectErrorTab.test.tsx
+++ b/public/app/features/inspector/InspectErrorTab.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { InspectErrorTab } from './InspectErrorTab';
diff --git a/public/app/features/inspector/InspectErrorTab.tsx b/public/app/features/inspector/InspectErrorTab.tsx
index d79768563d4..12cb42af2c1 100644
--- a/public/app/features/inspector/InspectErrorTab.tsx
+++ b/public/app/features/inspector/InspectErrorTab.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { DataQueryError } from '@grafana/data';
import { Alert, JSONFormatter } from '@grafana/ui';
diff --git a/public/app/features/inspector/InspectJSONTab.tsx b/public/app/features/inspector/InspectJSONTab.tsx
index 7b3801d6403..1874a3e0b48 100644
--- a/public/app/features/inspector/InspectJSONTab.tsx
+++ b/public/app/features/inspector/InspectJSONTab.tsx
@@ -1,5 +1,5 @@
import { isEqual } from 'lodash';
-import React, { useState, useCallback, useMemo } from 'react';
+import { useState, useCallback, useMemo } from 'react';
import { useAsync } from 'react-use';
import AutoSizer from 'react-virtualized-auto-sizer';
import { firstValueFrom } from 'rxjs';
diff --git a/public/app/features/inspector/InspectMetadataTab.tsx b/public/app/features/inspector/InspectMetadataTab.tsx
index 53dcea54f5a..c530bb151cb 100644
--- a/public/app/features/inspector/InspectMetadataTab.tsx
+++ b/public/app/features/inspector/InspectMetadataTab.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { DataSourceApi, PanelData } from '@grafana/data';
import { Trans } from 'app/core/internationalization';
diff --git a/public/app/features/inspector/InspectStatsTab.tsx b/public/app/features/inspector/InspectStatsTab.tsx
index 0e282d75335..0c1b76e7755 100644
--- a/public/app/features/inspector/InspectStatsTab.tsx
+++ b/public/app/features/inspector/InspectStatsTab.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { PanelData, QueryResultMetaStat, TimeZone } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/inspector/InspectStatsTable.tsx b/public/app/features/inspector/InspectStatsTable.tsx
index a014e31e588..00ce94f6ec5 100644
--- a/public/app/features/inspector/InspectStatsTable.tsx
+++ b/public/app/features/inspector/InspectStatsTable.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import {
FieldType,
diff --git a/public/app/features/inspector/InspectStatsTraceIdsTable.tsx b/public/app/features/inspector/InspectStatsTraceIdsTable.tsx
index b94491db68e..7b60c55afe2 100644
--- a/public/app/features/inspector/InspectStatsTraceIdsTable.tsx
+++ b/public/app/features/inspector/InspectStatsTraceIdsTable.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/inspector/QueryInspector.tsx b/public/app/features/inspector/QueryInspector.tsx
index 3650114ea7e..73e45aa113e 100644
--- a/public/app/features/inspector/QueryInspector.tsx
+++ b/public/app/features/inspector/QueryInspector.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { Subscription } from 'rxjs';
import { LoadingState, PanelData } from '@grafana/data';
diff --git a/public/app/features/invites/InviteeRow.tsx b/public/app/features/invites/InviteeRow.tsx
index a6ad523b712..ef6592d603e 100644
--- a/public/app/features/invites/InviteeRow.tsx
+++ b/public/app/features/invites/InviteeRow.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { Button, ClipboardButton } from '@grafana/ui';
diff --git a/public/app/features/invites/InviteesTable.test.tsx b/public/app/features/invites/InviteesTable.test.tsx
index cfc96246fc2..497d5bc620a 100644
--- a/public/app/features/invites/InviteesTable.test.tsx
+++ b/public/app/features/invites/InviteesTable.test.tsx
@@ -1,5 +1,4 @@
import { render, screen, within } from '@testing-library/react';
-import React from 'react';
import { Provider } from 'react-redux';
import { configureStore } from 'app/store/configureStore';
diff --git a/public/app/features/invites/InviteesTable.tsx b/public/app/features/invites/InviteesTable.tsx
index 8b8cb727d69..397ef63acea 100644
--- a/public/app/features/invites/InviteesTable.tsx
+++ b/public/app/features/invites/InviteesTable.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { Invitee } from 'app/types';
diff --git a/public/app/features/invites/SignupInvited.test.tsx b/public/app/features/invites/SignupInvited.test.tsx
index 25c5944c578..f352df4e701 100644
--- a/public/app/features/invites/SignupInvited.test.tsx
+++ b/public/app/features/invites/SignupInvited.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { match } from 'react-router-dom';
import { TestProvider } from 'test/helpers/TestProvider';
diff --git a/public/app/features/invites/SignupInvited.tsx b/public/app/features/invites/SignupInvited.tsx
index 96c7cddeafb..37b754f59bc 100644
--- a/public/app/features/invites/SignupInvited.tsx
+++ b/public/app/features/invites/SignupInvited.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { useAsync } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/library-panels/LibraryPanelsPage.tsx b/public/app/features/library-panels/LibraryPanelsPage.tsx
index 0fc5d2ad6ae..f3cd4ee2f7d 100644
--- a/public/app/features/library-panels/LibraryPanelsPage.tsx
+++ b/public/app/features/library-panels/LibraryPanelsPage.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { Page } from 'app/core/components/Page/Page';
diff --git a/public/app/features/library-panels/components/AddLibraryPanelModal/AddLibraryPanelModal.tsx b/public/app/features/library-panels/components/AddLibraryPanelModal/AddLibraryPanelModal.tsx
index 1b393b3b8f0..15c0a7d4622 100644
--- a/public/app/features/library-panels/components/AddLibraryPanelModal/AddLibraryPanelModal.tsx
+++ b/public/app/features/library-panels/components/AddLibraryPanelModal/AddLibraryPanelModal.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
import { useAsync, useDebounce } from 'react-use';
import { FetchError, isFetchError } from '@grafana/runtime';
diff --git a/public/app/features/library-panels/components/ChangeLibraryPanelModal/ChangeLibraryPanelModal.tsx b/public/app/features/library-panels/components/ChangeLibraryPanelModal/ChangeLibraryPanelModal.tsx
index f42ab49b6bb..76623045536 100644
--- a/public/app/features/library-panels/components/ChangeLibraryPanelModal/ChangeLibraryPanelModal.tsx
+++ b/public/app/features/library-panels/components/ChangeLibraryPanelModal/ChangeLibraryPanelModal.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { ConfirmModal } from '@grafana/ui';
import { PanelModel } from '../../../dashboard/state';
diff --git a/public/app/features/library-panels/components/DeleteLibraryPanelModal/DeleteLibraryPanelModal.tsx b/public/app/features/library-panels/components/DeleteLibraryPanelModal/DeleteLibraryPanelModal.tsx
index c46cae3fdf2..a721b2039f6 100644
--- a/public/app/features/library-panels/components/DeleteLibraryPanelModal/DeleteLibraryPanelModal.tsx
+++ b/public/app/features/library-panels/components/DeleteLibraryPanelModal/DeleteLibraryPanelModal.tsx
@@ -1,4 +1,4 @@
-import React, { FC, useEffect, useMemo, useReducer } from 'react';
+import { FC, useEffect, useMemo, useReducer } from 'react';
import { LoadingState } from '@grafana/data';
import { Button, Modal, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/library-panels/components/LibraryPanelCard/LibraryPanelCard.tsx b/public/app/features/library-panels/components/LibraryPanelCard/LibraryPanelCard.tsx
index f3f68dde0f0..8c7c08141ba 100644
--- a/public/app/features/library-panels/components/LibraryPanelCard/LibraryPanelCard.tsx
+++ b/public/app/features/library-panels/components/LibraryPanelCard/LibraryPanelCard.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { ReactElement, useState } from 'react';
+import { ReactElement, useState } from 'react';
import Skeleton from 'react-loading-skeleton';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/library-panels/components/LibraryPanelInfo/LibraryPanelInfo.tsx b/public/app/features/library-panels/components/LibraryPanelInfo/LibraryPanelInfo.tsx
index ba53f14fcbb..95a517074cb 100644
--- a/public/app/features/library-panels/components/LibraryPanelInfo/LibraryPanelInfo.tsx
+++ b/public/app/features/library-panels/components/LibraryPanelInfo/LibraryPanelInfo.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { DateTimeInput, GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/library-panels/components/LibraryPanelsSearch/LibraryPanelsSearch.test.tsx b/public/app/features/library-panels/components/LibraryPanelsSearch/LibraryPanelsSearch.test.tsx
index 44ddccac466..a4723b01937 100644
--- a/public/app/features/library-panels/components/LibraryPanelsSearch/LibraryPanelsSearch.test.tsx
+++ b/public/app/features/library-panels/components/LibraryPanelsSearch/LibraryPanelsSearch.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { PanelPluginMeta, PluginMetaInfo, PluginType } from '@grafana/data';
import { config } from '@grafana/runtime';
diff --git a/public/app/features/library-panels/components/LibraryPanelsSearch/LibraryPanelsSearch.tsx b/public/app/features/library-panels/components/LibraryPanelsSearch/LibraryPanelsSearch.tsx
index 7c015f60b6a..c6813527b78 100644
--- a/public/app/features/library-panels/components/LibraryPanelsSearch/LibraryPanelsSearch.tsx
+++ b/public/app/features/library-panels/components/LibraryPanelsSearch/LibraryPanelsSearch.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { useCallback, useState } from 'react';
+import { memo, useCallback, useState } from 'react';
import { useDebounce } from 'react-use';
import { GrafanaTheme2, PanelPluginMeta, SelectableValue } from '@grafana/data';
@@ -141,7 +141,7 @@ interface SearchControlsProps {
variant?: LibraryPanelsSearchVariant;
}
-const SearchControls = React.memo(
+const SearchControls = memo(
({
variant = LibraryPanelsSearchVariant.Spacious,
showSort,
diff --git a/public/app/features/library-panels/components/LibraryPanelsView/LibraryPanelsView.tsx b/public/app/features/library-panels/components/LibraryPanelsView/LibraryPanelsView.tsx
index 22b7ae79026..b8a64c6fd29 100644
--- a/public/app/features/library-panels/components/LibraryPanelsView/LibraryPanelsView.tsx
+++ b/public/app/features/library-panels/components/LibraryPanelsView/LibraryPanelsView.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo, useReducer } from 'react';
+import { useMemo, useReducer } from 'react';
import { useDebounce } from 'react-use';
import { GrafanaTheme2, LoadingState } from '@grafana/data';
diff --git a/public/app/features/library-panels/components/OpenLibraryPanelModal/OpenLibraryPanelModal.tsx b/public/app/features/library-panels/components/OpenLibraryPanelModal/OpenLibraryPanelModal.tsx
index 581b579b8b7..83a063f7bcd 100644
--- a/public/app/features/library-panels/components/OpenLibraryPanelModal/OpenLibraryPanelModal.tsx
+++ b/public/app/features/library-panels/components/OpenLibraryPanelModal/OpenLibraryPanelModal.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import debounce from 'debounce-promise';
-import React, { MouseEvent, useCallback, useEffect, useMemo, useState } from 'react';
+import { MouseEvent, useCallback, useEffect, useMemo, useState } from 'react';
import { GrafanaTheme2, SelectableValue, urlUtil } from '@grafana/data';
import { locationService } from '@grafana/runtime';
diff --git a/public/app/features/library-panels/components/PanelLibraryOptionsGroup/PanelLibraryOptionsGroup.tsx b/public/app/features/library-panels/components/PanelLibraryOptionsGroup/PanelLibraryOptionsGroup.tsx
index 11d96ae8824..5864e4e25d3 100644
--- a/public/app/features/library-panels/components/PanelLibraryOptionsGroup/PanelLibraryOptionsGroup.tsx
+++ b/public/app/features/library-panels/components/PanelLibraryOptionsGroup/PanelLibraryOptionsGroup.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useCallback, useState } from 'react';
+import { useCallback, useState } from 'react';
import { PanelPluginMeta } from '@grafana/data';
import { Button, VerticalGroup } from '@grafana/ui';
diff --git a/public/app/features/library-panels/components/SaveLibraryPanelModal/SaveLibraryPanelModal.tsx b/public/app/features/library-panels/components/SaveLibraryPanelModal/SaveLibraryPanelModal.tsx
index 6956b60a2d9..19c4e11d28d 100644
--- a/public/app/features/library-panels/components/SaveLibraryPanelModal/SaveLibraryPanelModal.tsx
+++ b/public/app/features/library-panels/components/SaveLibraryPanelModal/SaveLibraryPanelModal.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useState } from 'react';
+import { useCallback, useState } from 'react';
import { useAsync, useDebounce } from 'react-use';
import { Button, Icon, Input, Modal, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/live/LiveConnectionWarning.tsx b/public/app/features/live/LiveConnectionWarning.tsx
index ab095d1e7e9..67e2e3a3b0e 100644
--- a/public/app/features/live/LiveConnectionWarning.tsx
+++ b/public/app/features/live/LiveConnectionWarning.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { Unsubscribable } from 'rxjs';
import { GrafanaTheme2, OrgRole } from '@grafana/data';
diff --git a/public/app/features/live/dashboard/DashboardChangedModal.tsx b/public/app/features/live/dashboard/DashboardChangedModal.tsx
index 5309bf381fc..ff8f3ba2cd9 100644
--- a/public/app/features/live/dashboard/DashboardChangedModal.tsx
+++ b/public/app/features/live/dashboard/DashboardChangedModal.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { locationService } from '@grafana/runtime';
diff --git a/public/app/features/logs/components/InfiniteScroll.test.tsx b/public/app/features/logs/components/InfiniteScroll.test.tsx
index 47429764b3b..e90e93eb45b 100644
--- a/public/app/features/logs/components/InfiniteScroll.test.tsx
+++ b/public/app/features/logs/components/InfiniteScroll.test.tsx
@@ -1,5 +1,5 @@
import { act, render, screen } from '@testing-library/react';
-import React, { useEffect, useRef, useState } from 'react';
+import { useEffect, useRef, useState } from 'react';
import { LogRowModel, dateTimeForTimeZone } from '@grafana/data';
import { convertRawToRange } from '@grafana/data/src/datetime/rangeutil';
diff --git a/public/app/features/logs/components/InfiniteScroll.tsx b/public/app/features/logs/components/InfiniteScroll.tsx
index 744584735db..65037b4a8b5 100644
--- a/public/app/features/logs/components/InfiniteScroll.tsx
+++ b/public/app/features/logs/components/InfiniteScroll.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { ReactNode, useEffect, useRef, useState } from 'react';
+import { ReactNode, useEffect, useRef, useState } from 'react';
import { AbsoluteTimeRange, LogRowModel, TimeRange } from '@grafana/data';
import { convertRawToRange, isRelativeTime, isRelativeTimeRange } from '@grafana/data/src/datetime/rangeutil';
diff --git a/public/app/features/logs/components/LoadingIndicator.tsx b/public/app/features/logs/components/LoadingIndicator.tsx
index c483b18c92f..8c33d85bb41 100644
--- a/public/app/features/logs/components/LoadingIndicator.tsx
+++ b/public/app/features/logs/components/LoadingIndicator.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { Spinner } from '@grafana/ui';
diff --git a/public/app/features/logs/components/LogDetails.test.tsx b/public/app/features/logs/components/LogDetails.test.tsx
index 1aefc0e0c95..a98dbd1a9f9 100644
--- a/public/app/features/logs/components/LogDetails.test.tsx
+++ b/public/app/features/logs/components/LogDetails.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import {
Field,
diff --git a/public/app/features/logs/components/LogDetails.tsx b/public/app/features/logs/components/LogDetails.tsx
index 6d489d91b51..9f2ebf15858 100644
--- a/public/app/features/logs/components/LogDetails.tsx
+++ b/public/app/features/logs/components/LogDetails.tsx
@@ -1,5 +1,5 @@
import { cx } from '@emotion/css';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { CoreApp, DataFrame, DataFrameType, Field, LinkModel, LogRowModel } from '@grafana/data';
import { Themeable2, withTheme2 } from '@grafana/ui';
diff --git a/public/app/features/logs/components/LogDetailsRow.test.tsx b/public/app/features/logs/components/LogDetailsRow.test.tsx
index b168cf1f521..1629efecc0e 100644
--- a/public/app/features/logs/components/LogDetailsRow.test.tsx
+++ b/public/app/features/logs/components/LogDetailsRow.test.tsx
@@ -1,5 +1,5 @@
import { fireEvent, render, screen } from '@testing-library/react';
-import React, { ComponentProps } from 'react';
+import { ComponentProps } from 'react';
import { CoreApp } from '@grafana/data';
diff --git a/public/app/features/logs/components/LogDetailsRow.tsx b/public/app/features/logs/components/LogDetailsRow.tsx
index 9f9f8ffcf78..44db6bb81ad 100644
--- a/public/app/features/logs/components/LogDetailsRow.tsx
+++ b/public/app/features/logs/components/LogDetailsRow.tsx
@@ -1,7 +1,8 @@
import { css, cx } from '@emotion/css';
import { isEqual } from 'lodash';
import memoizeOne from 'memoize-one';
-import React, { PureComponent, useEffect, useState } from 'react';
+import { PureComponent, useEffect, useState } from 'react';
+import * as React from 'react';
import {
CoreApp,
diff --git a/public/app/features/logs/components/LogLabelStats.tsx b/public/app/features/logs/components/LogLabelStats.tsx
index f2c5d1ba160..f6ac4558966 100644
--- a/public/app/features/logs/components/LogLabelStats.tsx
+++ b/public/app/features/logs/components/LogLabelStats.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { LogLabelStatsModel, GrafanaTheme2 } from '@grafana/data';
import { stylesFactory, withTheme2, Themeable2 } from '@grafana/ui';
diff --git a/public/app/features/logs/components/LogLabelStatsRow.tsx b/public/app/features/logs/components/LogLabelStatsRow.tsx
index ffeca801d52..18eeeb37953 100644
--- a/public/app/features/logs/components/LogLabelStatsRow.tsx
+++ b/public/app/features/logs/components/LogLabelStatsRow.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/logs/components/LogLabels.test.tsx b/public/app/features/logs/components/LogLabels.test.tsx
index 9bfd070d9a7..cb3c0e90dfb 100644
--- a/public/app/features/logs/components/LogLabels.test.tsx
+++ b/public/app/features/logs/components/LogLabels.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { LogLabels, LogLabelsList } from './LogLabels';
diff --git a/public/app/features/logs/components/LogLabels.tsx b/public/app/features/logs/components/LogLabels.tsx
index 2305ad7e866..6ad502f7830 100644
--- a/public/app/features/logs/components/LogLabels.tsx
+++ b/public/app/features/logs/components/LogLabels.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { memo, forwardRef, useMemo } from 'react';
import { GrafanaTheme2, Labels } from '@grafana/data';
import { Tooltip, useStyles2 } from '@grafana/ui';
@@ -12,7 +12,7 @@ interface Props {
emptyMessage?: string;
}
-export const LogLabels = React.memo(({ labels, emptyMessage }: Props) => {
+export const LogLabels = memo(({ labels, emptyMessage }: Props) => {
const styles = useStyles2(getStyles);
const displayLabels = useMemo(
() =>
@@ -53,7 +53,7 @@ interface LogLabelsArrayProps {
labels: string[];
}
-export const LogLabelsList = React.memo(({ labels }: LogLabelsArrayProps) => {
+export const LogLabelsList = memo(({ labels }: LogLabelsArrayProps) => {
const styles = useStyles2(getStyles);
return (
@@ -73,17 +73,15 @@ interface LogLabelProps {
children: JSX.Element | string;
}
-const LogLabel = React.forwardRef(
- ({ styles, tooltip, children }: LogLabelProps, ref) => {
- return (
-
-
- {children}
-
+const LogLabel = forwardRef(({ styles, tooltip, children }: LogLabelProps, ref) => {
+ return (
+
+
+ {children}
- );
- }
-);
+
+ );
+});
LogLabel.displayName = 'LogLabel';
const getStyles = (theme: GrafanaTheme2) => {
diff --git a/public/app/features/logs/components/LogMessageAnsi.test.tsx b/public/app/features/logs/components/LogMessageAnsi.test.tsx
index d6fa4e18b77..716d1364f96 100644
--- a/public/app/features/logs/components/LogMessageAnsi.test.tsx
+++ b/public/app/features/logs/components/LogMessageAnsi.test.tsx
@@ -1,5 +1,4 @@
import { render, screen, within } from '@testing-library/react';
-import React from 'react';
import { createTheme } from '@grafana/data';
diff --git a/public/app/features/logs/components/LogMessageAnsi.tsx b/public/app/features/logs/components/LogMessageAnsi.tsx
index 12ac6faa0c6..6e16ecf5e1e 100644
--- a/public/app/features/logs/components/LogMessageAnsi.tsx
+++ b/public/app/features/logs/components/LogMessageAnsi.tsx
@@ -1,5 +1,5 @@
import ansicolor from 'ansicolor';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import Highlighter from 'react-highlight-words';
import { findHighlightChunksInText, GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/logs/components/LogRow.test.tsx b/public/app/features/logs/components/LogRow.test.tsx
index 13e0290d086..bf8a34cd98f 100644
--- a/public/app/features/logs/components/LogRow.test.tsx
+++ b/public/app/features/logs/components/LogRow.test.tsx
@@ -1,6 +1,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { ComponentProps } from 'react';
+import { ComponentProps } from 'react';
import tinycolor from 'tinycolor2';
import { CoreApp, createTheme, LogLevel, LogRowModel } from '@grafana/data';
diff --git a/public/app/features/logs/components/LogRow.tsx b/public/app/features/logs/components/LogRow.tsx
index a06edb4bdf1..79af86f3144 100644
--- a/public/app/features/logs/components/LogRow.tsx
+++ b/public/app/features/logs/components/LogRow.tsx
@@ -1,7 +1,8 @@
import { cx } from '@emotion/css';
import { debounce } from 'lodash';
import memoizeOne from 'memoize-one';
-import React, { PureComponent, MouseEvent } from 'react';
+import { PureComponent, MouseEvent } from 'react';
+import * as React from 'react';
import {
Field,
diff --git a/public/app/features/logs/components/LogRowMenuCell.tsx b/public/app/features/logs/components/LogRowMenuCell.tsx
index 756e19813f7..5d3ac4be79a 100644
--- a/public/app/features/logs/components/LogRowMenuCell.tsx
+++ b/public/app/features/logs/components/LogRowMenuCell.tsx
@@ -1,4 +1,4 @@
-import React, { FocusEvent, SyntheticEvent, useCallback } from 'react';
+import { memo, FocusEvent, SyntheticEvent, useCallback } from 'react';
import { LogRowContextOptions, LogRowModel, getDefaultTimeRange, locationUtil, urlUtil } from '@grafana/data';
import { DataQuery } from '@grafana/schema';
@@ -28,7 +28,7 @@ interface Props {
onPinToContentOutlineClick?: (row: LogRowModel, onOpenContext: (row: LogRowModel) => void) => void;
}
-export const LogRowMenuCell = React.memo(
+export const LogRowMenuCell = memo(
({
logText,
onOpenContext,
diff --git a/public/app/features/logs/components/LogRowMessage.test.tsx b/public/app/features/logs/components/LogRowMessage.test.tsx
index 51ba688c9de..a09d888a157 100644
--- a/public/app/features/logs/components/LogRowMessage.test.tsx
+++ b/public/app/features/logs/components/LogRowMessage.test.tsx
@@ -1,6 +1,6 @@
import { render, screen, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { ComponentProps } from 'react';
+import { ComponentProps } from 'react';
import { CoreApp, createTheme, LogLevel, LogRowModel } from '@grafana/data';
diff --git a/public/app/features/logs/components/LogRowMessage.tsx b/public/app/features/logs/components/LogRowMessage.tsx
index 5d99484c1b2..278854465f5 100644
--- a/public/app/features/logs/components/LogRowMessage.tsx
+++ b/public/app/features/logs/components/LogRowMessage.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { memo, useMemo } from 'react';
import Highlighter from 'react-highlight-words';
import { CoreApp, findHighlightChunksInText, LogRowContextOptions, LogRowModel } from '@grafana/data';
@@ -79,7 +79,7 @@ const restructureLog = (
return line;
};
-export const LogRowMessage = React.memo((props: Props) => {
+export const LogRowMessage = memo((props: Props) => {
const {
row,
wrapLogMessage,
diff --git a/public/app/features/logs/components/LogRowMessageDisplayedFields.test.tsx b/public/app/features/logs/components/LogRowMessageDisplayedFields.test.tsx
index c4a57ef4e2a..cbc74247d51 100644
--- a/public/app/features/logs/components/LogRowMessageDisplayedFields.test.tsx
+++ b/public/app/features/logs/components/LogRowMessageDisplayedFields.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { createTheme, LogLevel } from '@grafana/data';
diff --git a/public/app/features/logs/components/LogRowMessageDisplayedFields.tsx b/public/app/features/logs/components/LogRowMessageDisplayedFields.tsx
index 18837d92929..4bc81f76cee 100644
--- a/public/app/features/logs/components/LogRowMessageDisplayedFields.tsx
+++ b/public/app/features/logs/components/LogRowMessageDisplayedFields.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { memo, useMemo } from 'react';
import { LogRowModel, Field, LinkModel, DataFrame } from '@grafana/data';
@@ -23,7 +23,7 @@ export interface Props {
onBlur: () => void;
}
-export const LogRowMessageDisplayedFields = React.memo((props: Props) => {
+export const LogRowMessageDisplayedFields = memo((props: Props) => {
const { row, detectedFields, getFieldLinks, wrapLogMessage, styles, mouseIsOver, pinned, ...rest } = props;
const wrapClassName = wrapLogMessage ? '' : displayedFieldsStyles.noWrap;
const fields = useMemo(() => getAllFields(row, getFieldLinks), [getFieldLinks, row]);
diff --git a/public/app/features/logs/components/LogRows.test.tsx b/public/app/features/logs/components/LogRows.test.tsx
index 0d6dce447d9..439bf7087fc 100644
--- a/public/app/features/logs/components/LogRows.test.tsx
+++ b/public/app/features/logs/components/LogRows.test.tsx
@@ -1,7 +1,6 @@
import { act, render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { range } from 'lodash';
-import React from 'react';
import { LogRowModel, LogsDedupStrategy, LogsSortOrder } from '@grafana/data';
diff --git a/public/app/features/logs/components/LogRows.tsx b/public/app/features/logs/components/LogRows.tsx
index 20556b9f232..a267ee9ef32 100644
--- a/public/app/features/logs/components/LogRows.tsx
+++ b/public/app/features/logs/components/LogRows.tsx
@@ -1,6 +1,6 @@
import { cx } from '@emotion/css';
import memoizeOne from 'memoize-one';
-import React, { PureComponent, MouseEvent, createRef } from 'react';
+import { PureComponent, MouseEvent, createRef } from 'react';
import {
TimeZone,
diff --git a/public/app/features/logs/components/log-context/LogContextButtons.test.tsx b/public/app/features/logs/components/log-context/LogContextButtons.test.tsx
index 41e8cc4ef6d..05b3bd19f03 100644
--- a/public/app/features/logs/components/log-context/LogContextButtons.test.tsx
+++ b/public/app/features/logs/components/log-context/LogContextButtons.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { LogContextButtons } from './LogContextButtons';
diff --git a/public/app/features/logs/components/log-context/LogContextButtons.tsx b/public/app/features/logs/components/log-context/LogContextButtons.tsx
index 01e24518c02..82358cf2a5c 100644
--- a/public/app/features/logs/components/log-context/LogContextButtons.tsx
+++ b/public/app/features/logs/components/log-context/LogContextButtons.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime';
diff --git a/public/app/features/logs/components/log-context/LogRowContextModal.test.tsx b/public/app/features/logs/components/log-context/LogRowContextModal.test.tsx
index 37bb407c7f4..d5f89e6d977 100644
--- a/public/app/features/logs/components/log-context/LogRowContextModal.test.tsx
+++ b/public/app/features/logs/components/log-context/LogRowContextModal.test.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { render, screen, waitFor, fireEvent, userEvent } from 'test/test-utils';
import {
diff --git a/public/app/features/logs/components/log-context/LogRowContextModal.tsx b/public/app/features/logs/components/log-context/LogRowContextModal.tsx
index 684b83700ee..e5a5d83f531 100644
--- a/public/app/features/logs/components/log-context/LogRowContextModal.tsx
+++ b/public/app/features/logs/components/log-context/LogRowContextModal.tsx
@@ -1,6 +1,7 @@
import { css, cx } from '@emotion/css';
import { partition } from 'lodash';
-import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
+import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
+import * as React from 'react';
import { useAsync } from 'react-use';
import {
diff --git a/public/app/features/manage-dashboards/DashboardImportPage.tsx b/public/app/features/manage-dashboards/DashboardImportPage.tsx
index 2a60019e4ad..69a0f35f866 100644
--- a/public/app/features/manage-dashboards/DashboardImportPage.tsx
+++ b/public/app/features/manage-dashboards/DashboardImportPage.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { AppEvents, GrafanaTheme2, LoadingState, NavModelItem } from '@grafana/data';
diff --git a/public/app/features/manage-dashboards/PublicDashboardListPage.tsx b/public/app/features/manage-dashboards/PublicDashboardListPage.tsx
index d65c7cb7ab8..4bf587ee73c 100644
--- a/public/app/features/manage-dashboards/PublicDashboardListPage.tsx
+++ b/public/app/features/manage-dashboards/PublicDashboardListPage.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PublicDashboardListTable } from './components/PublicDashboardListTable/PublicDashboardListTable';
export const ListPublicDashboardPage = ({}) => {
diff --git a/public/app/features/manage-dashboards/SnapshotListPage.tsx b/public/app/features/manage-dashboards/SnapshotListPage.tsx
index 3bc6f993ec2..6ea772c7200 100644
--- a/public/app/features/manage-dashboards/SnapshotListPage.tsx
+++ b/public/app/features/manage-dashboards/SnapshotListPage.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Page } from 'app/core/components/Page/Page';
import { SnapshotListTable } from './components/SnapshotListTable';
diff --git a/public/app/features/manage-dashboards/components/ImportDashboardForm.tsx b/public/app/features/manage-dashboards/components/ImportDashboardForm.tsx
index 8cb50e12a57..35a241dad27 100644
--- a/public/app/features/manage-dashboards/components/ImportDashboardForm.tsx
+++ b/public/app/features/manage-dashboards/components/ImportDashboardForm.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { Controller, FieldErrors, UseFormReturn } from 'react-hook-form';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/manage-dashboards/components/ImportDashboardLibraryPanelsList.tsx b/public/app/features/manage-dashboards/components/ImportDashboardLibraryPanelsList.tsx
index f48b12eca14..65cb03005c6 100644
--- a/public/app/features/manage-dashboards/components/ImportDashboardLibraryPanelsList.tsx
+++ b/public/app/features/manage-dashboards/components/ImportDashboardLibraryPanelsList.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { ReactElement } from 'react';
+import { ReactElement } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { LibraryPanel } from '@grafana/schema';
diff --git a/public/app/features/manage-dashboards/components/ImportDashboardOverview.tsx b/public/app/features/manage-dashboards/components/ImportDashboardOverview.tsx
index 7ead5823447..96caec35f96 100644
--- a/public/app/features/manage-dashboards/components/ImportDashboardOverview.tsx
+++ b/public/app/features/manage-dashboards/components/ImportDashboardOverview.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { dateTimeFormat } from '@grafana/data';
diff --git a/public/app/features/manage-dashboards/components/PublicDashboardListTable/DeletePublicDashboardButton.tsx b/public/app/features/manage-dashboards/components/PublicDashboardListTable/DeletePublicDashboardButton.tsx
index 14ece574fdb..b91f8e212aa 100644
--- a/public/app/features/manage-dashboards/components/PublicDashboardListTable/DeletePublicDashboardButton.tsx
+++ b/public/app/features/manage-dashboards/components/PublicDashboardListTable/DeletePublicDashboardButton.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { Button, ModalsController, ButtonProps } from '@grafana/ui/src';
import { t } from 'app/core/internationalization';
diff --git a/public/app/features/manage-dashboards/components/PublicDashboardListTable/DeletePublicDashboardModal.tsx b/public/app/features/manage-dashboards/components/PublicDashboardListTable/DeletePublicDashboardModal.tsx
index cdcd2639fa7..ae93cd5b059 100644
--- a/public/app/features/manage-dashboards/components/PublicDashboardListTable/DeletePublicDashboardModal.tsx
+++ b/public/app/features/manage-dashboards/components/PublicDashboardListTable/DeletePublicDashboardModal.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data/src';
import { ConfirmModal, useStyles2 } from '@grafana/ui/src';
diff --git a/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.test.tsx b/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.test.tsx
index 0e395959ad3..1b8e490368b 100644
--- a/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.test.tsx
+++ b/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.test.tsx
@@ -1,7 +1,6 @@
import { render, screen, waitForElementToBeRemoved, within } from '@testing-library/react';
import { http, HttpResponse } from 'msw';
import { setupServer } from 'msw/node';
-import React from 'react';
import { BrowserRouter } from 'react-router-dom';
import { TestProvider } from 'test/helpers/TestProvider';
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
diff --git a/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.tsx b/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.tsx
index c0a6d4e4d1f..7acd3bf8c96 100644
--- a/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.tsx
+++ b/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
import { useMedia } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/manage-dashboards/components/SnapshotListTable.tsx b/public/app/features/manage-dashboards/components/SnapshotListTable.tsx
index aeac45764c1..c8c36dd5e86 100644
--- a/public/app/features/manage-dashboards/components/SnapshotListTable.tsx
+++ b/public/app/features/manage-dashboards/components/SnapshotListTable.tsx
@@ -1,4 +1,4 @@
-import React, { useState, useCallback } from 'react';
+import { useState, useCallback } from 'react';
import useAsync from 'react-use/lib/useAsync';
import { config } from '@grafana/runtime';
diff --git a/public/app/features/manage-dashboards/components/SnapshotListTableRow.test.tsx b/public/app/features/manage-dashboards/components/SnapshotListTableRow.test.tsx
index df6b5bc95f8..4ddc9fd16ca 100644
--- a/public/app/features/manage-dashboards/components/SnapshotListTableRow.test.tsx
+++ b/public/app/features/manage-dashboards/components/SnapshotListTableRow.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { Snapshot } from 'app/features/dashboard/services/SnapshotSrv';
diff --git a/public/app/features/manage-dashboards/components/SnapshotListTableRow.tsx b/public/app/features/manage-dashboards/components/SnapshotListTableRow.tsx
index 9a9209ffc62..b362de0259a 100644
--- a/public/app/features/manage-dashboards/components/SnapshotListTableRow.tsx
+++ b/public/app/features/manage-dashboards/components/SnapshotListTableRow.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import Skeleton from 'react-loading-skeleton';
import { Button, LinkButton, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/migrate-to-cloud/MigrateToCloud.tsx b/public/app/features/migrate-to-cloud/MigrateToCloud.tsx
index 1b0b16628c6..bbcc8a7e62b 100644
--- a/public/app/features/migrate-to-cloud/MigrateToCloud.tsx
+++ b/public/app/features/migrate-to-cloud/MigrateToCloud.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { config } from '@grafana/runtime';
import { Page } from 'app/core/components/Page/Page';
diff --git a/public/app/features/migrate-to-cloud/cloud/InfoPane.tsx b/public/app/features/migrate-to-cloud/cloud/InfoPane.tsx
index a15b5212864..7f203730bbc 100644
--- a/public/app/features/migrate-to-cloud/cloud/InfoPane.tsx
+++ b/public/app/features/migrate-to-cloud/cloud/InfoPane.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Box, Stack, TextLink, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/migrate-to-cloud/cloud/MigrationTokenPane/DeleteMigrationTokenModal.tsx b/public/app/features/migrate-to-cloud/cloud/MigrationTokenPane/DeleteMigrationTokenModal.tsx
index 3d98e6374ef..c0a758c670b 100644
--- a/public/app/features/migrate-to-cloud/cloud/MigrationTokenPane/DeleteMigrationTokenModal.tsx
+++ b/public/app/features/migrate-to-cloud/cloud/MigrationTokenPane/DeleteMigrationTokenModal.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { Modal, Button, Text } from '@grafana/ui';
import { Trans, t } from 'app/core/internationalization';
diff --git a/public/app/features/migrate-to-cloud/cloud/MigrationTokenPane/MigrationTokenModal.tsx b/public/app/features/migrate-to-cloud/cloud/MigrationTokenPane/MigrationTokenModal.tsx
index c52cd7dcfcf..76dc43fc341 100644
--- a/public/app/features/migrate-to-cloud/cloud/MigrationTokenPane/MigrationTokenModal.tsx
+++ b/public/app/features/migrate-to-cloud/cloud/MigrationTokenPane/MigrationTokenModal.tsx
@@ -1,4 +1,4 @@
-import React, { useId } from 'react';
+import { useId } from 'react';
import { Modal, Button, Input, Stack, ClipboardButton, Field } from '@grafana/ui';
import { Trans, t } from 'app/core/internationalization';
diff --git a/public/app/features/migrate-to-cloud/cloud/MigrationTokenPane/MigrationTokenPane.tsx b/public/app/features/migrate-to-cloud/cloud/MigrationTokenPane/MigrationTokenPane.tsx
index 59b8123dced..825c86a52e1 100644
--- a/public/app/features/migrate-to-cloud/cloud/MigrationTokenPane/MigrationTokenPane.tsx
+++ b/public/app/features/migrate-to-cloud/cloud/MigrationTokenPane/MigrationTokenPane.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useState } from 'react';
+import { useCallback, useState } from 'react';
import { Box, Button, Text } from '@grafana/ui';
import { t, Trans } from 'app/core/internationalization';
diff --git a/public/app/features/migrate-to-cloud/cloud/MigrationTokenPane/TokenStatus.tsx b/public/app/features/migrate-to-cloud/cloud/MigrationTokenPane/TokenStatus.tsx
index a907d06dfe2..c9f84675e08 100644
--- a/public/app/features/migrate-to-cloud/cloud/MigrationTokenPane/TokenStatus.tsx
+++ b/public/app/features/migrate-to-cloud/cloud/MigrationTokenPane/TokenStatus.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import Skeleton from 'react-loading-skeleton';
import { Text } from '@grafana/ui';
diff --git a/public/app/features/migrate-to-cloud/cloud/Page.tsx b/public/app/features/migrate-to-cloud/cloud/Page.tsx
index 4ae3676ae67..a7c427354ce 100644
--- a/public/app/features/migrate-to-cloud/cloud/Page.tsx
+++ b/public/app/features/migrate-to-cloud/cloud/Page.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Grid, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/migrate-to-cloud/cloud/TokenErrorAlert.tsx b/public/app/features/migrate-to-cloud/cloud/TokenErrorAlert.tsx
index 998ee7fbd25..9a8459fb1a4 100644
--- a/public/app/features/migrate-to-cloud/cloud/TokenErrorAlert.tsx
+++ b/public/app/features/migrate-to-cloud/cloud/TokenErrorAlert.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Alert } from '@grafana/ui';
import { Trans, t } from 'app/core/internationalization';
diff --git a/public/app/features/migrate-to-cloud/onprem/DisconnectModal.tsx b/public/app/features/migrate-to-cloud/onprem/DisconnectModal.tsx
index f09c3759f34..f99b5ea9fa1 100644
--- a/public/app/features/migrate-to-cloud/onprem/DisconnectModal.tsx
+++ b/public/app/features/migrate-to-cloud/onprem/DisconnectModal.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Alert, ConfirmModal, Stack } from '@grafana/ui';
import { Trans, t } from 'app/core/internationalization';
diff --git a/public/app/features/migrate-to-cloud/onprem/EmptyState/CallToAction/CallToAction.test.tsx b/public/app/features/migrate-to-cloud/onprem/EmptyState/CallToAction/CallToAction.test.tsx
index aa67d067e8b..2b8005cca57 100644
--- a/public/app/features/migrate-to-cloud/onprem/EmptyState/CallToAction/CallToAction.test.tsx
+++ b/public/app/features/migrate-to-cloud/onprem/EmptyState/CallToAction/CallToAction.test.tsx
@@ -1,6 +1,5 @@
import { render as rtlRender, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { setBackendSrv } from '@grafana/runtime';
diff --git a/public/app/features/migrate-to-cloud/onprem/EmptyState/CallToAction/CallToAction.tsx b/public/app/features/migrate-to-cloud/onprem/EmptyState/CallToAction/CallToAction.tsx
index 9ab5ee9f23e..56bd133fbb8 100644
--- a/public/app/features/migrate-to-cloud/onprem/EmptyState/CallToAction/CallToAction.tsx
+++ b/public/app/features/migrate-to-cloud/onprem/EmptyState/CallToAction/CallToAction.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { Box, Button, Text } from '@grafana/ui';
import { Trans } from 'app/core/internationalization';
diff --git a/public/app/features/migrate-to-cloud/onprem/EmptyState/CallToAction/ConnectModal.tsx b/public/app/features/migrate-to-cloud/onprem/EmptyState/CallToAction/ConnectModal.tsx
index 42ed70dace8..a3f52b27b24 100644
--- a/public/app/features/migrate-to-cloud/onprem/EmptyState/CallToAction/ConnectModal.tsx
+++ b/public/app/features/migrate-to-cloud/onprem/EmptyState/CallToAction/ConnectModal.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useId } from 'react';
+import { useId } from 'react';
import { SubmitHandler, useForm } from 'react-hook-form';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/migrate-to-cloud/onprem/EmptyState/EmptyState.tsx b/public/app/features/migrate-to-cloud/onprem/EmptyState/EmptyState.tsx
index 953e5923f3c..37f56297a91 100644
--- a/public/app/features/migrate-to-cloud/onprem/EmptyState/EmptyState.tsx
+++ b/public/app/features/migrate-to-cloud/onprem/EmptyState/EmptyState.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Grid, Stack, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/migrate-to-cloud/onprem/EmptyState/InfoPaneLeft.tsx b/public/app/features/migrate-to-cloud/onprem/EmptyState/InfoPaneLeft.tsx
index eb2873f1e3d..693332bd4f6 100644
--- a/public/app/features/migrate-to-cloud/onprem/EmptyState/InfoPaneLeft.tsx
+++ b/public/app/features/migrate-to-cloud/onprem/EmptyState/InfoPaneLeft.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Box } from '@grafana/ui';
import { t, Trans } from 'app/core/internationalization';
diff --git a/public/app/features/migrate-to-cloud/onprem/EmptyState/InfoPaneRight.tsx b/public/app/features/migrate-to-cloud/onprem/EmptyState/InfoPaneRight.tsx
index 051640b60c7..f0967a6604d 100644
--- a/public/app/features/migrate-to-cloud/onprem/EmptyState/InfoPaneRight.tsx
+++ b/public/app/features/migrate-to-cloud/onprem/EmptyState/InfoPaneRight.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Box } from '@grafana/ui';
import { t, Trans } from 'app/core/internationalization';
diff --git a/public/app/features/migrate-to-cloud/onprem/MigrationInfo.tsx b/public/app/features/migrate-to-cloud/onprem/MigrationInfo.tsx
index 3e693303739..59062c4d39f 100644
--- a/public/app/features/migrate-to-cloud/onprem/MigrationInfo.tsx
+++ b/public/app/features/migrate-to-cloud/onprem/MigrationInfo.tsx
@@ -1,4 +1,4 @@
-import React, { ReactNode } from 'react';
+import { ReactNode } from 'react';
import { Stack, Text } from '@grafana/ui';
diff --git a/public/app/features/migrate-to-cloud/onprem/NameCell.tsx b/public/app/features/migrate-to-cloud/onprem/NameCell.tsx
index 30e0d30ff4c..991ea8bb389 100644
--- a/public/app/features/migrate-to-cloud/onprem/NameCell.tsx
+++ b/public/app/features/migrate-to-cloud/onprem/NameCell.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import Skeleton from 'react-loading-skeleton';
import { DataSourceInstanceSettings } from '@grafana/data';
diff --git a/public/app/features/migrate-to-cloud/onprem/Page.tsx b/public/app/features/migrate-to-cloud/onprem/Page.tsx
index 3f3799c3722..c92a1de23c0 100644
--- a/public/app/features/migrate-to-cloud/onprem/Page.tsx
+++ b/public/app/features/migrate-to-cloud/onprem/Page.tsx
@@ -1,5 +1,5 @@
import { skipToken } from '@reduxjs/toolkit/query/react';
-import React, { useCallback, useState } from 'react';
+import { useCallback, useState } from 'react';
import { Alert, Box, Button, Stack } from '@grafana/ui';
import { Trans, t } from 'app/core/internationalization';
diff --git a/public/app/features/migrate-to-cloud/onprem/ResourcesTable.test.tsx b/public/app/features/migrate-to-cloud/onprem/ResourcesTable.test.tsx
index 20996ca15d0..0bd74ef63c5 100644
--- a/public/app/features/migrate-to-cloud/onprem/ResourcesTable.test.tsx
+++ b/public/app/features/migrate-to-cloud/onprem/ResourcesTable.test.tsx
@@ -1,5 +1,4 @@
import { render as rtlRender, screen } from '@testing-library/react';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { setBackendSrv, config } from '@grafana/runtime';
diff --git a/public/app/features/migrate-to-cloud/onprem/ResourcesTable.tsx b/public/app/features/migrate-to-cloud/onprem/ResourcesTable.tsx
index 1657e721503..727a05f5511 100644
--- a/public/app/features/migrate-to-cloud/onprem/ResourcesTable.tsx
+++ b/public/app/features/migrate-to-cloud/onprem/ResourcesTable.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { InteractiveTable } from '@grafana/ui';
import { MigrateDataResponseItemDto } from '../api';
diff --git a/public/app/features/migrate-to-cloud/onprem/StatusCell.tsx b/public/app/features/migrate-to-cloud/onprem/StatusCell.tsx
index 644ea9729f2..e5ccef6049c 100644
--- a/public/app/features/migrate-to-cloud/onprem/StatusCell.tsx
+++ b/public/app/features/migrate-to-cloud/onprem/StatusCell.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { CellProps, Text, Stack, Button } from '@grafana/ui';
import { t } from 'app/core/internationalization';
diff --git a/public/app/features/migrate-to-cloud/shared/InfoItem.tsx b/public/app/features/migrate-to-cloud/shared/InfoItem.tsx
index 3d664954529..56d0cd26dcb 100644
--- a/public/app/features/migrate-to-cloud/shared/InfoItem.tsx
+++ b/public/app/features/migrate-to-cloud/shared/InfoItem.tsx
@@ -1,4 +1,4 @@
-import React, { ReactNode } from 'react';
+import { ReactNode } from 'react';
import { Stack, Text, TextLink } from '@grafana/ui';
diff --git a/public/app/features/notifications/NotificationsPage.tsx b/public/app/features/notifications/NotificationsPage.tsx
index ee3ace6faed..8c097542126 100644
--- a/public/app/features/notifications/NotificationsPage.tsx
+++ b/public/app/features/notifications/NotificationsPage.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Page } from 'app/core/components/Page/Page';
import { StoredNotifications } from './StoredNotifications';
diff --git a/public/app/features/notifications/StoredNotifications.tsx b/public/app/features/notifications/StoredNotifications.tsx
index d9a49110c07..be0e504a3bf 100644
--- a/public/app/features/notifications/StoredNotifications.tsx
+++ b/public/app/features/notifications/StoredNotifications.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { useRef, useState } from 'react';
+import { useRef, useState } from 'react';
+import * as React from 'react';
import { useEffectOnce } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/org/NewOrgPage.tsx b/public/app/features/org/NewOrgPage.tsx
index db5b6725157..df77d157580 100644
--- a/public/app/features/org/NewOrgPage.tsx
+++ b/public/app/features/org/NewOrgPage.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { NavModelItem } from '@grafana/data';
diff --git a/public/app/features/org/OrgDetailsPage.test.tsx b/public/app/features/org/OrgDetailsPage.test.tsx
index a092fc63731..0fc7ab9e728 100644
--- a/public/app/features/org/OrgDetailsPage.test.tsx
+++ b/public/app/features/org/OrgDetailsPage.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { mockToolkitActionCreator } from 'test/core/redux/mocks';
import { TestProvider } from 'test/helpers/TestProvider';
diff --git a/public/app/features/org/OrgDetailsPage.tsx b/public/app/features/org/OrgDetailsPage.tsx
index bcef33f95f9..f21d96fc1a8 100644
--- a/public/app/features/org/OrgDetailsPage.tsx
+++ b/public/app/features/org/OrgDetailsPage.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { ConnectedProps, connect } from 'react-redux';
import { Stack } from '@grafana/ui';
diff --git a/public/app/features/org/OrgProfile.test.tsx b/public/app/features/org/OrgProfile.test.tsx
index 29e604cac7a..5dd2fa78f2c 100644
--- a/public/app/features/org/OrgProfile.test.tsx
+++ b/public/app/features/org/OrgProfile.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import OrgProfile, { Props } from './OrgProfile';
diff --git a/public/app/features/org/OrgProfile.tsx b/public/app/features/org/OrgProfile.tsx
index cf65e9c3532..f70f831955c 100644
--- a/public/app/features/org/OrgProfile.tsx
+++ b/public/app/features/org/OrgProfile.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Input, Field, FieldSet, Button } from '@grafana/ui';
import { Form } from 'app/core/components/Form/Form';
import { contextSrv } from 'app/core/core';
diff --git a/public/app/features/org/SelectOrgPage.tsx b/public/app/features/org/SelectOrgPage.tsx
index d1fcf28162f..d9506fd9c52 100644
--- a/public/app/features/org/SelectOrgPage.tsx
+++ b/public/app/features/org/SelectOrgPage.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { useEffectOnce } from 'react-use';
diff --git a/public/app/features/org/UserInviteForm.tsx b/public/app/features/org/UserInviteForm.tsx
index 30762cb8816..29906104194 100644
--- a/public/app/features/org/UserInviteForm.tsx
+++ b/public/app/features/org/UserInviteForm.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { Controller } from 'react-hook-form';
import { locationUtil, SelectableValue } from '@grafana/data';
diff --git a/public/app/features/org/UserInvitePage.tsx b/public/app/features/org/UserInvitePage.tsx
index 3e51c35b383..33695fd23a9 100644
--- a/public/app/features/org/UserInvitePage.tsx
+++ b/public/app/features/org/UserInvitePage.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Page } from 'app/core/components/Page/Page';
import { contextSrv } from 'app/core/core';
diff --git a/public/app/features/panel/components/PanelDataErrorView.test.tsx b/public/app/features/panel/components/PanelDataErrorView.test.tsx
index 3f33487d211..7040b80418f 100644
--- a/public/app/features/panel/components/PanelDataErrorView.test.tsx
+++ b/public/app/features/panel/components/PanelDataErrorView.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import { defaultsDeep } from 'lodash';
-import React from 'react';
import { Provider } from 'react-redux';
import { FieldType, getDefaultTimeRange, LoadingState } from '@grafana/data';
diff --git a/public/app/features/panel/components/PanelDataErrorView.tsx b/public/app/features/panel/components/PanelDataErrorView.tsx
index b9cc3ef21b9..c8aed627344 100644
--- a/public/app/features/panel/components/PanelDataErrorView.tsx
+++ b/public/app/features/panel/components/PanelDataErrorView.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import {
CoreApp,
diff --git a/public/app/features/panel/components/PanelPluginError.tsx b/public/app/features/panel/components/PanelPluginError.tsx
index 168f5e1bd5e..d29be9dc3b0 100644
--- a/public/app/features/panel/components/PanelPluginError.tsx
+++ b/public/app/features/panel/components/PanelPluginError.tsx
@@ -1,5 +1,5 @@
// Libraries
-import React, { PureComponent, ReactNode } from 'react';
+import { PureComponent, ReactNode } from 'react';
// Types
import { PanelProps, PanelPlugin, PluginType, PanelPluginMeta } from '@grafana/data';
diff --git a/public/app/features/panel/components/PanelRenderer.tsx b/public/app/features/panel/components/PanelRenderer.tsx
index 872e73fb8e4..bfffdd6ecfb 100644
--- a/public/app/features/panel/components/PanelRenderer.tsx
+++ b/public/app/features/panel/components/PanelRenderer.tsx
@@ -1,4 +1,4 @@
-import React, { useState, useMemo, useEffect } from 'react';
+import { useState, useMemo, useEffect } from 'react';
import {
FieldConfigSource,
diff --git a/public/app/features/panel/components/VizTypePicker/PanelTypeCard.tsx b/public/app/features/panel/components/VizTypePicker/PanelTypeCard.tsx
index 8b651759f6e..94b40699f2a 100644
--- a/public/app/features/panel/components/VizTypePicker/PanelTypeCard.tsx
+++ b/public/app/features/panel/components/VizTypePicker/PanelTypeCard.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { MouseEventHandler } from 'react';
+import { MouseEventHandler } from 'react';
+import * as React from 'react';
import Skeleton from 'react-loading-skeleton';
import { GrafanaTheme2, isUnsignedPluginSignature, PanelPluginMeta, PluginState } from '@grafana/data';
diff --git a/public/app/features/panel/components/VizTypePicker/VisualizationSuggestionCard.tsx b/public/app/features/panel/components/VizTypePicker/VisualizationSuggestionCard.tsx
index b5d5880fcb1..46559272fe5 100644
--- a/public/app/features/panel/components/VizTypePicker/VisualizationSuggestionCard.tsx
+++ b/public/app/features/panel/components/VizTypePicker/VisualizationSuggestionCard.tsx
@@ -1,6 +1,6 @@
import { css, cx } from '@emotion/css';
import { cloneDeep } from 'lodash';
-import React, { CSSProperties } from 'react';
+import { CSSProperties } from 'react';
import { GrafanaTheme2, PanelData, VisualizationSuggestion } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/panel/components/VizTypePicker/VisualizationSuggestions.tsx b/public/app/features/panel/components/VizTypePicker/VisualizationSuggestions.tsx
index 94e8a9aaa9f..43ed82cbb30 100644
--- a/public/app/features/panel/components/VizTypePicker/VisualizationSuggestions.tsx
+++ b/public/app/features/panel/components/VizTypePicker/VisualizationSuggestions.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { useAsync } from 'react-use';
import AutoSizer from 'react-virtualized-auto-sizer';
diff --git a/public/app/features/panel/components/VizTypePicker/VizTypePicker.tsx b/public/app/features/panel/components/VizTypePicker/VizTypePicker.tsx
index cf7226261ae..1249ec14308 100644
--- a/public/app/features/panel/components/VizTypePicker/VizTypePicker.tsx
+++ b/public/app/features/panel/components/VizTypePicker/VizTypePicker.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { config } from '@grafana/runtime';
diff --git a/public/app/features/panel/components/VizTypePicker/VizTypePickerPlugin.tsx b/public/app/features/panel/components/VizTypePicker/VizTypePickerPlugin.tsx
index 206e814b416..1ece804df3b 100644
--- a/public/app/features/panel/components/VizTypePicker/VizTypePickerPlugin.tsx
+++ b/public/app/features/panel/components/VizTypePicker/VizTypePickerPlugin.tsx
@@ -1,4 +1,4 @@
-import React, { MouseEventHandler } from 'react';
+import { MouseEventHandler } from 'react';
import { PanelPluginMeta } from '@grafana/data';
diff --git a/public/app/features/playlist/PlaylistCard.tsx b/public/app/features/playlist/PlaylistCard.tsx
index 1706bcb93b7..dcbb174ff9f 100644
--- a/public/app/features/playlist/PlaylistCard.tsx
+++ b/public/app/features/playlist/PlaylistCard.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import Skeleton from 'react-loading-skeleton';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/playlist/PlaylistEditPage.test.tsx b/public/app/features/playlist/PlaylistEditPage.test.tsx
index 9897e5c719c..beda508e4f9 100644
--- a/public/app/features/playlist/PlaylistEditPage.test.tsx
+++ b/public/app/features/playlist/PlaylistEditPage.test.tsx
@@ -1,7 +1,6 @@
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { History, Location } from 'history';
-import React from 'react';
import { type match } from 'react-router-dom';
import { TestProvider } from 'test/helpers/TestProvider';
diff --git a/public/app/features/playlist/PlaylistEditPage.tsx b/public/app/features/playlist/PlaylistEditPage.tsx
index 7ae0f8328ed..ac8327a883d 100644
--- a/public/app/features/playlist/PlaylistEditPage.tsx
+++ b/public/app/features/playlist/PlaylistEditPage.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useAsync } from 'react-use';
import { NavModelItem } from '@grafana/data';
diff --git a/public/app/features/playlist/PlaylistForm.test.tsx b/public/app/features/playlist/PlaylistForm.test.tsx
index 366c730ed60..5d3de5da269 100644
--- a/public/app/features/playlist/PlaylistForm.test.tsx
+++ b/public/app/features/playlist/PlaylistForm.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { PlaylistForm } from './PlaylistForm';
import { Playlist } from './types';
diff --git a/public/app/features/playlist/PlaylistForm.tsx b/public/app/features/playlist/PlaylistForm.tsx
index cb6d6d75519..441a6b37500 100644
--- a/public/app/features/playlist/PlaylistForm.tsx
+++ b/public/app/features/playlist/PlaylistForm.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { config } from '@grafana/runtime';
diff --git a/public/app/features/playlist/PlaylistNewPage.test.tsx b/public/app/features/playlist/PlaylistNewPage.test.tsx
index 85f766596e9..46c549a02d6 100644
--- a/public/app/features/playlist/PlaylistNewPage.test.tsx
+++ b/public/app/features/playlist/PlaylistNewPage.test.tsx
@@ -1,6 +1,5 @@
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/playlist/PlaylistNewPage.tsx b/public/app/features/playlist/PlaylistNewPage.tsx
index eb219d23e02..1cf58fcb408 100644
--- a/public/app/features/playlist/PlaylistNewPage.tsx
+++ b/public/app/features/playlist/PlaylistNewPage.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { NavModelItem } from '@grafana/data';
import { locationService } from '@grafana/runtime';
diff --git a/public/app/features/playlist/PlaylistPage.test.tsx b/public/app/features/playlist/PlaylistPage.test.tsx
index 21312227f6c..f538148d47c 100644
--- a/public/app/features/playlist/PlaylistPage.test.tsx
+++ b/public/app/features/playlist/PlaylistPage.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { contextSrv } from 'app/core/services/context_srv';
diff --git a/public/app/features/playlist/PlaylistPage.tsx b/public/app/features/playlist/PlaylistPage.tsx
index f8cb99c6c77..0a723a415b9 100644
--- a/public/app/features/playlist/PlaylistPage.tsx
+++ b/public/app/features/playlist/PlaylistPage.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
import { useAsync } from 'react-use';
import { ConfirmModal, EmptyState, LinkButton, TextLink } from '@grafana/ui';
diff --git a/public/app/features/playlist/PlaylistPageList.tsx b/public/app/features/playlist/PlaylistPageList.tsx
index 0f3fecfe55e..d55bd14deda 100644
--- a/public/app/features/playlist/PlaylistPageList.tsx
+++ b/public/app/features/playlist/PlaylistPageList.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/playlist/PlaylistTable.tsx b/public/app/features/playlist/PlaylistTable.tsx
index 93a7167b1ce..baf10c626d2 100644
--- a/public/app/features/playlist/PlaylistTable.tsx
+++ b/public/app/features/playlist/PlaylistTable.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd';
import { FieldSet } from '@grafana/ui';
diff --git a/public/app/features/playlist/PlaylistTableRows.tsx b/public/app/features/playlist/PlaylistTableRows.tsx
index 131e6e11328..07976460463 100644
--- a/public/app/features/playlist/PlaylistTableRows.tsx
+++ b/public/app/features/playlist/PlaylistTableRows.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import pluralize from 'pluralize';
-import React, { ReactNode } from 'react';
+import { ReactNode } from 'react';
import { Draggable } from 'react-beautiful-dnd';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/playlist/ShareModal.tsx b/public/app/features/playlist/ShareModal.tsx
index 9f2103e536e..2403bc62fdf 100644
--- a/public/app/features/playlist/ShareModal.tsx
+++ b/public/app/features/playlist/ShareModal.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { SelectableValue, UrlQueryMap, urlUtil } from '@grafana/data';
import { Checkbox, ClipboardButton, Field, FieldSet, Input, Modal, RadioButtonGroup } from '@grafana/ui';
diff --git a/public/app/features/playlist/StartModal.tsx b/public/app/features/playlist/StartModal.tsx
index ba88d771026..dc8ae759761 100644
--- a/public/app/features/playlist/StartModal.tsx
+++ b/public/app/features/playlist/StartModal.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { SelectableValue, UrlQueryMap, urlUtil } from '@grafana/data';
import { config, locationService } from '@grafana/runtime';
diff --git a/public/app/features/plugins/admin/components/AppConfigWrapper.tsx b/public/app/features/plugins/admin/components/AppConfigWrapper.tsx
index 4d97a8faa01..0bc8bcc5562 100644
--- a/public/app/features/plugins/admin/components/AppConfigWrapper.tsx
+++ b/public/app/features/plugins/admin/components/AppConfigWrapper.tsx
@@ -1,7 +1,7 @@
// Libraries
import { css } from '@emotion/css';
import { cloneDeep, extend } from 'lodash';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { PluginMeta, AppPlugin, deprecationWarning } from '@grafana/data';
import { AngularComponent, getAngularLoader, getBackendSrv } from '@grafana/runtime';
diff --git a/public/app/features/plugins/admin/components/Badges/PluginAngularBadge.tsx b/public/app/features/plugins/admin/components/Badges/PluginAngularBadge.tsx
index 9202826a9d3..47244f2e64b 100644
--- a/public/app/features/plugins/admin/components/Badges/PluginAngularBadge.tsx
+++ b/public/app/features/plugins/admin/components/Badges/PluginAngularBadge.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { Badge } from '@grafana/ui';
diff --git a/public/app/features/plugins/admin/components/Badges/PluginDeprecatedBadge.tsx b/public/app/features/plugins/admin/components/Badges/PluginDeprecatedBadge.tsx
index bd24780b5d4..ff1d9af50fe 100644
--- a/public/app/features/plugins/admin/components/Badges/PluginDeprecatedBadge.tsx
+++ b/public/app/features/plugins/admin/components/Badges/PluginDeprecatedBadge.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { Badge } from '@grafana/ui';
diff --git a/public/app/features/plugins/admin/components/Badges/PluginDisabledBadge.tsx b/public/app/features/plugins/admin/components/Badges/PluginDisabledBadge.tsx
index 5c31a77fe86..70c30c148e3 100644
--- a/public/app/features/plugins/admin/components/Badges/PluginDisabledBadge.tsx
+++ b/public/app/features/plugins/admin/components/Badges/PluginDisabledBadge.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { PluginErrorCode } from '@grafana/data';
import { Badge } from '@grafana/ui';
diff --git a/public/app/features/plugins/admin/components/Badges/PluginEnterpriseBadge.tsx b/public/app/features/plugins/admin/components/Badges/PluginEnterpriseBadge.tsx
index 85d7d34638a..29f78ca9688 100644
--- a/public/app/features/plugins/admin/components/Badges/PluginEnterpriseBadge.tsx
+++ b/public/app/features/plugins/admin/components/Badges/PluginEnterpriseBadge.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { featureEnabled } from '@grafana/runtime';
import { Badge, PluginSignatureBadge, Stack, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/plugins/admin/components/Badges/PluginInstallBadge.tsx b/public/app/features/plugins/admin/components/Badges/PluginInstallBadge.tsx
index bc5c182af68..2b59203fda6 100644
--- a/public/app/features/plugins/admin/components/Badges/PluginInstallBadge.tsx
+++ b/public/app/features/plugins/admin/components/Badges/PluginInstallBadge.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { Badge, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/plugins/admin/components/Badges/PluginUpdateAvailableBadge.tsx b/public/app/features/plugins/admin/components/Badges/PluginUpdateAvailableBadge.tsx
index 17fd2c452cf..e9d93c11655 100644
--- a/public/app/features/plugins/admin/components/Badges/PluginUpdateAvailableBadge.tsx
+++ b/public/app/features/plugins/admin/components/Badges/PluginUpdateAvailableBadge.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithApp.tsx b/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithApp.tsx
index 92a8356b697..8518161a9a9 100644
--- a/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithApp.tsx
+++ b/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithApp.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { PluginMeta } from '@grafana/data';
import { Button } from '@grafana/ui';
diff --git a/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithDataSource.test.tsx b/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithDataSource.test.tsx
index 512ff968ea0..40d747aefea 100644
--- a/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithDataSource.test.tsx
+++ b/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithDataSource.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { PluginSignatureStatus } from '@grafana/data';
diff --git a/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithDataSource.tsx b/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithDataSource.tsx
index aad3e99d218..2c45596367f 100644
--- a/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithDataSource.tsx
+++ b/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithDataSource.tsx
@@ -1,4 +1,5 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
+import * as React from 'react';
import { DataSourcePluginMeta } from '@grafana/data';
import { config } from '@grafana/runtime';
diff --git a/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithPlugin.tsx b/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithPlugin.tsx
index 260633c79b1..b63970f2f8c 100644
--- a/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithPlugin.tsx
+++ b/public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithPlugin.tsx
@@ -1,4 +1,4 @@
-import React, { ReactElement } from 'react';
+import { ReactElement } from 'react';
import { PluginType } from '@grafana/data';
diff --git a/public/app/features/plugins/admin/components/HorizontalGroup.tsx b/public/app/features/plugins/admin/components/HorizontalGroup.tsx
index 0d948f963c9..6bdc6b2e790 100644
--- a/public/app/features/plugins/admin/components/HorizontalGroup.tsx
+++ b/public/app/features/plugins/admin/components/HorizontalGroup.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useTheme2 } from '@grafana/ui';
diff --git a/public/app/features/plugins/admin/components/InstallControls/ExternallyManagedButton.test.tsx b/public/app/features/plugins/admin/components/InstallControls/ExternallyManagedButton.test.tsx
index 6fd067a9712..2e8fe116d4d 100644
--- a/public/app/features/plugins/admin/components/InstallControls/ExternallyManagedButton.test.tsx
+++ b/public/app/features/plugins/admin/components/InstallControls/ExternallyManagedButton.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { config } from '@grafana/runtime';
diff --git a/public/app/features/plugins/admin/components/InstallControls/ExternallyManagedButton.tsx b/public/app/features/plugins/admin/components/InstallControls/ExternallyManagedButton.tsx
index 1bead53d3c7..8d347564125 100644
--- a/public/app/features/plugins/admin/components/InstallControls/ExternallyManagedButton.tsx
+++ b/public/app/features/plugins/admin/components/InstallControls/ExternallyManagedButton.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { config } from '@grafana/runtime';
import { HorizontalGroup, LinkButton } from '@grafana/ui';
diff --git a/public/app/features/plugins/admin/components/InstallControls/InstallControlsButton.test.tsx b/public/app/features/plugins/admin/components/InstallControls/InstallControlsButton.test.tsx
index 1da1da10d29..3894a2c05b8 100644
--- a/public/app/features/plugins/admin/components/InstallControls/InstallControlsButton.test.tsx
+++ b/public/app/features/plugins/admin/components/InstallControls/InstallControlsButton.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { PluginSignatureStatus } from '@grafana/data';
diff --git a/public/app/features/plugins/admin/components/InstallControls/InstallControlsButton.tsx b/public/app/features/plugins/admin/components/InstallControls/InstallControlsButton.tsx
index 5ea2afbc7db..2ea60c03e57 100644
--- a/public/app/features/plugins/admin/components/InstallControls/InstallControlsButton.tsx
+++ b/public/app/features/plugins/admin/components/InstallControls/InstallControlsButton.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { useLocation } from 'react-router-dom';
import { AppEvents } from '@grafana/data';
diff --git a/public/app/features/plugins/admin/components/InstallControls/InstallControlsWarning.tsx b/public/app/features/plugins/admin/components/InstallControls/InstallControlsWarning.tsx
index 278950fedac..89e1e717507 100644
--- a/public/app/features/plugins/admin/components/InstallControls/InstallControlsWarning.tsx
+++ b/public/app/features/plugins/admin/components/InstallControls/InstallControlsWarning.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2, PluginType } from '@grafana/data';
import { config, featureEnabled } from '@grafana/runtime';
diff --git a/public/app/features/plugins/admin/components/Loader.tsx b/public/app/features/plugins/admin/components/Loader.tsx
index 60d9df9555d..2af4b7e8f53 100644
--- a/public/app/features/plugins/admin/components/Loader.tsx
+++ b/public/app/features/plugins/admin/components/Loader.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Box, LoadingPlaceholder } from '@grafana/ui';
export interface Props {
diff --git a/public/app/features/plugins/admin/components/PluginActions.tsx b/public/app/features/plugins/admin/components/PluginActions.tsx
index e5df960c1f6..b9a64819ac9 100644
--- a/public/app/features/plugins/admin/components/PluginActions.tsx
+++ b/public/app/features/plugins/admin/components/PluginActions.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { config } from '@grafana/runtime';
diff --git a/public/app/features/plugins/admin/components/PluginDashboards.tsx b/public/app/features/plugins/admin/components/PluginDashboards.tsx
index 1cd035cebd1..8b222d11f0f 100644
--- a/public/app/features/plugins/admin/components/PluginDashboards.tsx
+++ b/public/app/features/plugins/admin/components/PluginDashboards.tsx
@@ -1,5 +1,5 @@
import { extend } from 'lodash';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { AppEvents, PluginMeta, DataSourceApi } from '@grafana/data';
import { getBackendSrv } from '@grafana/runtime';
diff --git a/public/app/features/plugins/admin/components/PluginDetailsBody.tsx b/public/app/features/plugins/admin/components/PluginDetailsBody.tsx
index 54420db174e..932b3dc875a 100644
--- a/public/app/features/plugins/admin/components/PluginDetailsBody.tsx
+++ b/public/app/features/plugins/admin/components/PluginDetailsBody.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { AppPlugin, GrafanaTheme2, PluginContextProvider, UrlQueryMap } from '@grafana/data';
import { config } from '@grafana/runtime';
diff --git a/public/app/features/plugins/admin/components/PluginDetailsDeprecatedWarning.tsx b/public/app/features/plugins/admin/components/PluginDetailsDeprecatedWarning.tsx
index c4977b81afc..3a268e31abb 100644
--- a/public/app/features/plugins/admin/components/PluginDetailsDeprecatedWarning.tsx
+++ b/public/app/features/plugins/admin/components/PluginDetailsDeprecatedWarning.tsx
@@ -1,4 +1,5 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
+import * as React from 'react';
import { renderMarkdown } from '@grafana/data';
import { Alert } from '@grafana/ui';
diff --git a/public/app/features/plugins/admin/components/PluginDetailsDisabledError.tsx b/public/app/features/plugins/admin/components/PluginDetailsDisabledError.tsx
index d7ca8094e17..333241a6634 100644
--- a/public/app/features/plugins/admin/components/PluginDetailsDisabledError.tsx
+++ b/public/app/features/plugins/admin/components/PluginDetailsDisabledError.tsx
@@ -1,4 +1,4 @@
-import React, { ReactElement } from 'react';
+import { ReactElement } from 'react';
import { PluginErrorCode } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/plugins/admin/components/PluginDetailsHeaderDependencies.tsx b/public/app/features/plugins/admin/components/PluginDetailsHeaderDependencies.tsx
index 034b2374a88..9d4756a8fb0 100644
--- a/public/app/features/plugins/admin/components/PluginDetailsHeaderDependencies.tsx
+++ b/public/app/features/plugins/admin/components/PluginDetailsHeaderDependencies.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2, Icon, Stack } from '@grafana/ui';
diff --git a/public/app/features/plugins/admin/components/PluginDetailsHeaderSignature.tsx b/public/app/features/plugins/admin/components/PluginDetailsHeaderSignature.tsx
index 689cea2b513..375bb27171a 100644
--- a/public/app/features/plugins/admin/components/PluginDetailsHeaderSignature.tsx
+++ b/public/app/features/plugins/admin/components/PluginDetailsHeaderSignature.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2, PluginSignatureStatus } from '@grafana/data';
import { PluginSignatureBadge, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/plugins/admin/components/PluginDetailsPage.tsx b/public/app/features/plugins/admin/components/PluginDetailsPage.tsx
index 8eaeb076516..1e33c01ebec 100644
--- a/public/app/features/plugins/admin/components/PluginDetailsPage.tsx
+++ b/public/app/features/plugins/admin/components/PluginDetailsPage.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { useLocation } from 'react-router-dom';
import { GrafanaTheme2, NavModelItem } from '@grafana/data';
diff --git a/public/app/features/plugins/admin/components/PluginDetailsSignature.tsx b/public/app/features/plugins/admin/components/PluginDetailsSignature.tsx
index f88e544cdac..92add56cc6d 100644
--- a/public/app/features/plugins/admin/components/PluginDetailsSignature.tsx
+++ b/public/app/features/plugins/admin/components/PluginDetailsSignature.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { PluginErrorCode, PluginSignatureStatus } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/plugins/admin/components/PluginList.test.tsx b/public/app/features/plugins/admin/components/PluginList.test.tsx
index 72218c02660..3d8c67c9765 100644
--- a/public/app/features/plugins/admin/components/PluginList.test.tsx
+++ b/public/app/features/plugins/admin/components/PluginList.test.tsx
@@ -1,5 +1,4 @@
import { render } from '@testing-library/react';
-import React from 'react';
import { useLocation } from 'react-router-dom';
import { PluginSignatureStatus } from '@grafana/data';
diff --git a/public/app/features/plugins/admin/components/PluginList.tsx b/public/app/features/plugins/admin/components/PluginList.tsx
index 76ad72cc2b4..a026047fe84 100644
--- a/public/app/features/plugins/admin/components/PluginList.tsx
+++ b/public/app/features/plugins/admin/components/PluginList.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useLocation } from 'react-router-dom';
import { config } from '@grafana/runtime';
diff --git a/public/app/features/plugins/admin/components/PluginListItem.test.tsx b/public/app/features/plugins/admin/components/PluginListItem.test.tsx
index 5fafd474491..8aa31776608 100644
--- a/public/app/features/plugins/admin/components/PluginListItem.test.tsx
+++ b/public/app/features/plugins/admin/components/PluginListItem.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { PluginErrorCode, PluginSignatureStatus, PluginType } from '@grafana/data';
diff --git a/public/app/features/plugins/admin/components/PluginListItem.tsx b/public/app/features/plugins/admin/components/PluginListItem.tsx
index b05c8532e4b..d54ea5aea3b 100644
--- a/public/app/features/plugins/admin/components/PluginListItem.tsx
+++ b/public/app/features/plugins/admin/components/PluginListItem.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import Skeleton from 'react-loading-skeleton';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/plugins/admin/components/PluginListItemBadges.test.tsx b/public/app/features/plugins/admin/components/PluginListItemBadges.test.tsx
index 5df75bc63d0..2864fe38af1 100644
--- a/public/app/features/plugins/admin/components/PluginListItemBadges.test.tsx
+++ b/public/app/features/plugins/admin/components/PluginListItemBadges.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { PluginErrorCode, PluginSignatureStatus } from '@grafana/data';
import { config } from '@grafana/runtime';
diff --git a/public/app/features/plugins/admin/components/PluginListItemBadges.tsx b/public/app/features/plugins/admin/components/PluginListItemBadges.tsx
index 1dcbbf99e07..bfd126460bb 100644
--- a/public/app/features/plugins/admin/components/PluginListItemBadges.tsx
+++ b/public/app/features/plugins/admin/components/PluginListItemBadges.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PluginType } from '@grafana/data';
import { HorizontalGroup, PluginSignatureBadge } from '@grafana/ui';
diff --git a/public/app/features/plugins/admin/components/PluginLogo.tsx b/public/app/features/plugins/admin/components/PluginLogo.tsx
index 2c063bd97d1..3f972592d51 100644
--- a/public/app/features/plugins/admin/components/PluginLogo.tsx
+++ b/public/app/features/plugins/admin/components/PluginLogo.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
type PluginLogoProps = {
alt: string;
diff --git a/public/app/features/plugins/admin/components/PluginSignatureDetailsBadge.tsx b/public/app/features/plugins/admin/components/PluginSignatureDetailsBadge.tsx
index 4dce5af0536..56ed277517f 100644
--- a/public/app/features/plugins/admin/components/PluginSignatureDetailsBadge.tsx
+++ b/public/app/features/plugins/admin/components/PluginSignatureDetailsBadge.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { capitalize } from 'lodash';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2, PluginSignatureType } from '@grafana/data';
import { useStyles2, Icon, Badge, IconName } from '@grafana/ui';
diff --git a/public/app/features/plugins/admin/components/PluginSubtitle.tsx b/public/app/features/plugins/admin/components/PluginSubtitle.tsx
index 53393d86d5f..ee1f42c18e8 100644
--- a/public/app/features/plugins/admin/components/PluginSubtitle.tsx
+++ b/public/app/features/plugins/admin/components/PluginSubtitle.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import { Fragment } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Alert, useStyles2 } from '@grafana/ui';
@@ -38,12 +38,12 @@ export const PluginSubtitle = ({ plugin }: Props) => {
{plugin?.details?.links && plugin.details.links.length > 0 && (
{plugin.details.links.map((link, index) => (
-
+
{index > 0 && ' | '}
{link.name}
-
+
))}
)}
diff --git a/public/app/features/plugins/admin/components/PluginUsage.tsx b/public/app/features/plugins/admin/components/PluginUsage.tsx
index 692d1fe3b23..734f35d14d7 100644
--- a/public/app/features/plugins/admin/components/PluginUsage.tsx
+++ b/public/app/features/plugins/admin/components/PluginUsage.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { useAsync } from 'react-use';
import AutoSizer from 'react-virtualized-auto-sizer';
import { of } from 'rxjs';
diff --git a/public/app/features/plugins/admin/components/SearchField.tsx b/public/app/features/plugins/admin/components/SearchField.tsx
index 6c43e063e1d..f8e42fe3c84 100644
--- a/public/app/features/plugins/admin/components/SearchField.tsx
+++ b/public/app/features/plugins/admin/components/SearchField.tsx
@@ -1,4 +1,5 @@
-import React, { useState, useRef } from 'react';
+import { useState, useRef } from 'react';
+import * as React from 'react';
import { useDebounce } from 'react-use';
import { FilterInput } from '@grafana/ui';
diff --git a/public/app/features/plugins/admin/components/VersionList.tsx b/public/app/features/plugins/admin/components/VersionList.tsx
index 42298eb31a4..6b97c51c247 100644
--- a/public/app/features/plugins/admin/components/VersionList.tsx
+++ b/public/app/features/plugins/admin/components/VersionList.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { dateTimeFormatTimeAgo, GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/plugins/admin/hooks/usePluginInfo.tsx b/public/app/features/plugins/admin/hooks/usePluginInfo.tsx
index ecd946d414e..eb9c70b3051 100644
--- a/public/app/features/plugins/admin/hooks/usePluginInfo.tsx
+++ b/public/app/features/plugins/admin/hooks/usePluginInfo.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2, PluginSignatureType } from '@grafana/data';
diff --git a/public/app/features/plugins/admin/hooks/usePluginPageExtensions.tsx b/public/app/features/plugins/admin/hooks/usePluginPageExtensions.tsx
index e02d50805ff..d9af5a9d6e1 100644
--- a/public/app/features/plugins/admin/hooks/usePluginPageExtensions.tsx
+++ b/public/app/features/plugins/admin/hooks/usePluginPageExtensions.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { PageInfoItem } from '../../../../core/components/Page/types';
import { PluginActions } from '../components/PluginActions';
diff --git a/public/app/features/plugins/admin/pages/Browse.test.tsx b/public/app/features/plugins/admin/pages/Browse.test.tsx
index 197c7dc0116..befdf53783d 100644
--- a/public/app/features/plugins/admin/pages/Browse.test.tsx
+++ b/public/app/features/plugins/admin/pages/Browse.test.tsx
@@ -1,6 +1,5 @@
import { render, RenderResult, waitFor, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { PluginType, escapeStringForRegex } from '@grafana/data';
diff --git a/public/app/features/plugins/admin/pages/Browse.tsx b/public/app/features/plugins/admin/pages/Browse.tsx
index 9f822c861c1..72343daff4d 100644
--- a/public/app/features/plugins/admin/pages/Browse.tsx
+++ b/public/app/features/plugins/admin/pages/Browse.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { ReactElement } from 'react';
+import { ReactElement } from 'react';
import { useLocation } from 'react-router-dom';
import { SelectableValue, GrafanaTheme2, PluginType } from '@grafana/data';
diff --git a/public/app/features/plugins/admin/pages/PluginDetails.test.tsx b/public/app/features/plugins/admin/pages/PluginDetails.test.tsx
index bcec74edd0e..599c8ec44af 100644
--- a/public/app/features/plugins/admin/pages/PluginDetails.test.tsx
+++ b/public/app/features/plugins/admin/pages/PluginDetails.test.tsx
@@ -1,6 +1,5 @@
import { getDefaultNormalizer, render, RenderResult, SelectorMatcherOptions, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { Route } from 'react-router-dom';
import { TestProvider } from 'test/helpers/TestProvider';
diff --git a/public/app/features/plugins/admin/pages/PluginDetails.tsx b/public/app/features/plugins/admin/pages/PluginDetails.tsx
index 575aac998f4..7040c1cad5b 100644
--- a/public/app/features/plugins/admin/pages/PluginDetails.tsx
+++ b/public/app/features/plugins/admin/pages/PluginDetails.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useParams } from 'react-router-dom';
import { PluginDetailsPage } from '../components/PluginDetailsPage';
diff --git a/public/app/features/plugins/angularDeprecation/AngularDeprecationNotice.test.tsx b/public/app/features/plugins/angularDeprecation/AngularDeprecationNotice.test.tsx
index 40e56681457..9d3417a2056 100644
--- a/public/app/features/plugins/angularDeprecation/AngularDeprecationNotice.test.tsx
+++ b/public/app/features/plugins/angularDeprecation/AngularDeprecationNotice.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { reportInteraction } from '@grafana/runtime';
diff --git a/public/app/features/plugins/angularDeprecation/AngularDeprecationNotice.tsx b/public/app/features/plugins/angularDeprecation/AngularDeprecationNotice.tsx
index affd3056bb1..bbd32647ad7 100644
--- a/public/app/features/plugins/angularDeprecation/AngularDeprecationNotice.tsx
+++ b/public/app/features/plugins/angularDeprecation/AngularDeprecationNotice.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { reportInteraction } from '@grafana/runtime';
import { Alert, Button } from '@grafana/ui';
import { LocalStorageValueProvider } from 'app/core/components/LocalStorageValueProvider';
diff --git a/public/app/features/plugins/angularDeprecation/AngularDeprecationPluginNotice.test.tsx b/public/app/features/plugins/angularDeprecation/AngularDeprecationPluginNotice.test.tsx
index 92401cdd9be..b849a3a164f 100644
--- a/public/app/features/plugins/angularDeprecation/AngularDeprecationPluginNotice.test.tsx
+++ b/public/app/features/plugins/angularDeprecation/AngularDeprecationPluginNotice.test.tsx
@@ -1,6 +1,5 @@
import { screen, render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { PluginType } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime';
diff --git a/public/app/features/plugins/angularDeprecation/AngularDeprecationPluginNotice.tsx b/public/app/features/plugins/angularDeprecation/AngularDeprecationPluginNotice.tsx
index 9f8d5b59253..8e42e1dcef1 100644
--- a/public/app/features/plugins/angularDeprecation/AngularDeprecationPluginNotice.tsx
+++ b/public/app/features/plugins/angularDeprecation/AngularDeprecationPluginNotice.tsx
@@ -1,4 +1,5 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
+import * as React from 'react';
import { PluginType } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime';
diff --git a/public/app/features/plugins/angularDeprecation/AngularMigrationNotice.test.tsx b/public/app/features/plugins/angularDeprecation/AngularMigrationNotice.test.tsx
index 07d59e6b832..0f9ee9f213e 100644
--- a/public/app/features/plugins/angularDeprecation/AngularMigrationNotice.test.tsx
+++ b/public/app/features/plugins/angularDeprecation/AngularMigrationNotice.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { AngularMigrationNotice } from './AngularMigrationNotice';
diff --git a/public/app/features/plugins/angularDeprecation/AngularMigrationNotice.tsx b/public/app/features/plugins/angularDeprecation/AngularMigrationNotice.tsx
index b131e295541..db0c5eeab8e 100644
--- a/public/app/features/plugins/angularDeprecation/AngularMigrationNotice.tsx
+++ b/public/app/features/plugins/angularDeprecation/AngularMigrationNotice.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Alert, Button, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/plugins/components/AppRootPage.test.tsx b/public/app/features/plugins/components/AppRootPage.test.tsx
index e9009ff59d0..8afc60c079b 100644
--- a/public/app/features/plugins/components/AppRootPage.test.tsx
+++ b/public/app/features/plugins/components/AppRootPage.test.tsx
@@ -1,5 +1,5 @@
import { act, render, screen } from '@testing-library/react';
-import React, { Component } from 'react';
+import { Component } from 'react';
import { Provider } from 'react-redux';
import { Route, Router } from 'react-router-dom';
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
diff --git a/public/app/features/plugins/components/AppRootPage.tsx b/public/app/features/plugins/components/AppRootPage.tsx
index 33b6f905f55..aa1d46b7491 100644
--- a/public/app/features/plugins/components/AppRootPage.tsx
+++ b/public/app/features/plugins/components/AppRootPage.tsx
@@ -1,6 +1,7 @@
// Libraries
import { AnyAction, createSlice, PayloadAction } from '@reduxjs/toolkit';
-import React, { useCallback, useEffect, useMemo, useReducer } from 'react';
+import { useCallback, useEffect, useMemo, useReducer } from 'react';
+import * as React from 'react';
import { useLocation, useRouteMatch } from 'react-router-dom';
import {
diff --git a/public/app/features/plugins/components/PluginPageContext.tsx b/public/app/features/plugins/components/PluginPageContext.tsx
index 8f10677ab44..0c85b4d46de 100644
--- a/public/app/features/plugins/components/PluginPageContext.tsx
+++ b/public/app/features/plugins/components/PluginPageContext.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import { createContext } from 'react';
import { NavModel } from '@grafana/data';
@@ -6,7 +6,7 @@ export interface PluginPageContextType {
sectionNav: NavModel;
}
-export const PluginPageContext = React.createContext(getInitialPluginPageContext());
+export const PluginPageContext = createContext(getInitialPluginPageContext());
PluginPageContext.displayName = 'PluginPageContext';
diff --git a/public/app/features/plugins/components/PluginStateInfo.tsx b/public/app/features/plugins/components/PluginStateInfo.tsx
index e27e1f0243f..bfeee14702d 100644
--- a/public/app/features/plugins/components/PluginStateInfo.tsx
+++ b/public/app/features/plugins/components/PluginStateInfo.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PluginState } from '@grafana/data';
import { Badge, BadgeProps } from '@grafana/ui';
diff --git a/public/app/features/plugins/components/PluginsErrorsInfo.tsx b/public/app/features/plugins/components/PluginsErrorsInfo.tsx
index d87a4f12db8..4f54292b984 100644
--- a/public/app/features/plugins/components/PluginsErrorsInfo.tsx
+++ b/public/app/features/plugins/components/PluginsErrorsInfo.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2, PluginErrorCode, PluginSignatureStatus, PluginType } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/plugins/extensions/getPluginExtensions.test.tsx b/public/app/features/plugins/extensions/getPluginExtensions.test.tsx
index c98b1e32772..51d3317496b 100644
--- a/public/app/features/plugins/extensions/getPluginExtensions.test.tsx
+++ b/public/app/features/plugins/extensions/getPluginExtensions.test.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { PluginExtensionComponentConfig, PluginExtensionLinkConfig, PluginExtensionTypes } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime';
diff --git a/public/app/features/plugins/extensions/usePluginComponent.test.tsx b/public/app/features/plugins/extensions/usePluginComponent.test.tsx
index c0941358dd7..cc1772ef3c3 100644
--- a/public/app/features/plugins/extensions/usePluginComponent.test.tsx
+++ b/public/app/features/plugins/extensions/usePluginComponent.test.tsx
@@ -1,6 +1,5 @@
import { act, render, screen } from '@testing-library/react';
import { renderHook } from '@testing-library/react-hooks';
-import React from 'react';
import { PluginExtensionTypes } from '@grafana/data';
diff --git a/public/app/features/plugins/extensions/utils.test.tsx b/public/app/features/plugins/extensions/utils.test.tsx
index 93958e05c90..c0189806dd2 100644
--- a/public/app/features/plugins/extensions/utils.test.tsx
+++ b/public/app/features/plugins/extensions/utils.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { type Unsubscribable } from 'rxjs';
import { type PluginExtensionLinkConfig, PluginExtensionTypes, dateTime, usePluginContext } from '@grafana/data';
diff --git a/public/app/features/plugins/extensions/utils.tsx b/public/app/features/plugins/extensions/utils.tsx
index 0c3dd0a6192..54092186677 100644
--- a/public/app/features/plugins/extensions/utils.tsx
+++ b/public/app/features/plugins/extensions/utils.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { isArray, isObject } from 'lodash';
-import React from 'react';
+import * as React from 'react';
import { useAsync } from 'react-use';
import {
diff --git a/public/app/features/plugins/extensions/validators.test.tsx b/public/app/features/plugins/extensions/validators.test.tsx
index c0474896d43..761acaa6e31 100644
--- a/public/app/features/plugins/extensions/validators.test.tsx
+++ b/public/app/features/plugins/extensions/validators.test.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import { memo } from 'react';
import { PluginExtension, PluginExtensionLinkConfig, PluginExtensionTypes } from '@grafana/data';
@@ -274,7 +274,7 @@ describe('Plugin Extension Validators', () => {
it('should return TRUE if we pass in a component wrapped with React.memo()', () => {
const Component = () => Some text
;
- const wrapped = React.memo(() => (
+ const wrapped = memo(() => (
diff --git a/public/app/features/plugins/routes.tsx b/public/app/features/plugins/routes.tsx
index 1b043628d65..a5b232521a2 100644
--- a/public/app/features/plugins/routes.tsx
+++ b/public/app/features/plugins/routes.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { NavModelItem } from '@grafana/data';
import { RouteDescriptor } from 'app/core/navigation/types';
import { getRootSectionForNode } from 'app/core/selectors/navModel';
diff --git a/public/app/features/plugins/sandbox/sandbox_components.tsx b/public/app/features/plugins/sandbox/sandbox_components.tsx
index 6e26d86a37b..e1eeb590d35 100644
--- a/public/app/features/plugins/sandbox/sandbox_components.tsx
+++ b/public/app/features/plugins/sandbox/sandbox_components.tsx
@@ -1,5 +1,6 @@
import { isFunction } from 'lodash';
-import React, { ComponentType, FC } from 'react';
+import { ComponentType, FC } from 'react';
+import * as React from 'react';
import { GrafanaPlugin, PluginExtensionConfig, PluginType } from '@grafana/data';
diff --git a/public/app/features/plugins/sandbox/utils.ts b/public/app/features/plugins/sandbox/utils.ts
index af97b19c9ec..7c5be8bc393 100644
--- a/public/app/features/plugins/sandbox/utils.ts
+++ b/public/app/features/plugins/sandbox/utils.ts
@@ -1,6 +1,6 @@
import { isNearMembraneProxy } from '@locker/near-membrane-shared';
import { cloneDeep } from 'lodash';
-import React from 'react';
+import * as React from 'react';
import { PluginSignatureType, PluginType } from '@grafana/data';
import { LogContext } from '@grafana/faro-web-sdk';
diff --git a/public/app/features/profile/ChangePasswordForm.tsx b/public/app/features/profile/ChangePasswordForm.tsx
index 9c4aa22d7dd..3b823fd7da8 100644
--- a/public/app/features/profile/ChangePasswordForm.tsx
+++ b/public/app/features/profile/ChangePasswordForm.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { Button, Field, LinkButton, Stack } from '@grafana/ui';
import { Form } from 'app/core/components/Form/Form';
diff --git a/public/app/features/profile/ChangePasswordPage.test.tsx b/public/app/features/profile/ChangePasswordPage.test.tsx
index 55c2dcb2cc3..a807b8c4a12 100644
--- a/public/app/features/profile/ChangePasswordPage.test.tsx
+++ b/public/app/features/profile/ChangePasswordPage.test.tsx
@@ -1,6 +1,5 @@
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import config from 'app/core/config';
diff --git a/public/app/features/profile/ChangePasswordPage.tsx b/public/app/features/profile/ChangePasswordPage.tsx
index a065ec2adc6..3b7452cbfc5 100644
--- a/public/app/features/profile/ChangePasswordPage.tsx
+++ b/public/app/features/profile/ChangePasswordPage.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { useMount } from 'react-use';
diff --git a/public/app/features/profile/FeatureTogglePage.tsx b/public/app/features/profile/FeatureTogglePage.tsx
index 3dd56e287c6..8f49c8f9f7f 100644
--- a/public/app/features/profile/FeatureTogglePage.tsx
+++ b/public/app/features/profile/FeatureTogglePage.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Page } from 'app/core/components/Page/Page';
import { useNavModel } from 'app/core/hooks/useNavModel';
diff --git a/public/app/features/profile/UserOrganizations.tsx b/public/app/features/profile/UserOrganizations.tsx
index 6d39fc567e8..8e0455e618e 100644
--- a/public/app/features/profile/UserOrganizations.tsx
+++ b/public/app/features/profile/UserOrganizations.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { Button, LoadingPlaceholder } from '@grafana/ui';
diff --git a/public/app/features/profile/UserProfileEditForm.tsx b/public/app/features/profile/UserProfileEditForm.tsx
index dcde61b1199..f942b6876fc 100644
--- a/public/app/features/profile/UserProfileEditForm.tsx
+++ b/public/app/features/profile/UserProfileEditForm.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { selectors } from '@grafana/e2e-selectors';
import { Button, Field, FieldSet, Icon, Input, Tooltip } from '@grafana/ui';
import { Form } from 'app/core/components/Form/Form';
diff --git a/public/app/features/profile/UserProfileEditPage.test.tsx b/public/app/features/profile/UserProfileEditPage.test.tsx
index 5a1c4d5b348..a8e27dcd80d 100644
--- a/public/app/features/profile/UserProfileEditPage.test.tsx
+++ b/public/app/features/profile/UserProfileEditPage.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor, within } from '@testing-library/react';
import userEvent, { PointerEventsCheckLevel } from '@testing-library/user-event';
-import React from 'react';
import { OrgRole, PluginExtensionComponent, PluginExtensionTypes } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/profile/UserProfileEditPage.tsx b/public/app/features/profile/UserProfileEditPage.tsx
index 613bf924891..4de0ebee3d4 100644
--- a/public/app/features/profile/UserProfileEditPage.tsx
+++ b/public/app/features/profile/UserProfileEditPage.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { Fragment, useState } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { useMount } from 'react-use';
@@ -140,11 +140,11 @@ export function UserProfileEditPage({
if (activeTab === tabId) {
return (
-
+
{pluginExtensionComponents.map(({ component: Component }, index) => (
))}
-
+
);
}
return null;
diff --git a/public/app/features/profile/UserSessions.tsx b/public/app/features/profile/UserSessions.tsx
index 9d93c5a9e08..07e081df46e 100644
--- a/public/app/features/profile/UserSessions.tsx
+++ b/public/app/features/profile/UserSessions.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { t } from 'i18next';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { Button, Icon, LoadingPlaceholder } from '@grafana/ui';
diff --git a/public/app/features/profile/UserTeams.tsx b/public/app/features/profile/UserTeams.tsx
index 75239994c1c..f95bf1c24e5 100644
--- a/public/app/features/profile/UserTeams.tsx
+++ b/public/app/features/profile/UserTeams.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { LoadingPlaceholder } from '@grafana/ui';
import { Team } from 'app/types';
diff --git a/public/app/features/query/components/QueryEditorRow.test.tsx b/public/app/features/query/components/QueryEditorRow.test.tsx
index 42e98252b9a..f348ceb793d 100644
--- a/public/app/features/query/components/QueryEditorRow.test.tsx
+++ b/public/app/features/query/components/QueryEditorRow.test.tsx
@@ -1,5 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
-import React, { PropsWithChildren } from 'react';
+import { PropsWithChildren } from 'react';
import { DataQueryRequest, dateTime, LoadingState, PanelData, toDataFrame } from '@grafana/data';
import { DataQuery } from '@grafana/schema';
diff --git a/public/app/features/query/components/QueryEditorRow.tsx b/public/app/features/query/components/QueryEditorRow.tsx
index 2317fe726da..d58d80f4dcd 100644
--- a/public/app/features/query/components/QueryEditorRow.tsx
+++ b/public/app/features/query/components/QueryEditorRow.tsx
@@ -2,7 +2,8 @@
import classNames from 'classnames';
import { cloneDeep, filter, has, uniqBy, uniqueId } from 'lodash';
import pluralize from 'pluralize';
-import React, { PureComponent, ReactNode } from 'react';
+import { PureComponent, ReactNode } from 'react';
+import * as React from 'react';
// Utils & Services
import {
diff --git a/public/app/features/query/components/QueryEditorRowHeader.test.tsx b/public/app/features/query/components/QueryEditorRowHeader.test.tsx
index aa4026ec6f4..b41298548c6 100644
--- a/public/app/features/query/components/QueryEditorRowHeader.test.tsx
+++ b/public/app/features/query/components/QueryEditorRowHeader.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { DataSourceInstanceSettings } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/query/components/QueryEditorRowHeader.tsx b/public/app/features/query/components/QueryEditorRowHeader.tsx
index b30cfebfd2a..e2bc2f63801 100644
--- a/public/app/features/query/components/QueryEditorRowHeader.tsx
+++ b/public/app/features/query/components/QueryEditorRowHeader.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { ReactNode, useState } from 'react';
+import { ReactNode, useState } from 'react';
+import * as React from 'react';
import { DataQuery, DataSourceInstanceSettings, GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/query/components/QueryEditorRows.test.tsx b/public/app/features/query/components/QueryEditorRows.test.tsx
index 706e2423630..1724928aeee 100644
--- a/public/app/features/query/components/QueryEditorRows.test.tsx
+++ b/public/app/features/query/components/QueryEditorRows.test.tsx
@@ -1,5 +1,4 @@
import { fireEvent, queryByLabelText, render, screen } from '@testing-library/react';
-import React from 'react';
import { type DataQuery } from '@grafana/schema';
import { mockDataSource } from 'app/features/alerting/unified/mocks';
diff --git a/public/app/features/query/components/QueryEditorRows.tsx b/public/app/features/query/components/QueryEditorRows.tsx
index 9399178d42a..024c1da6d80 100644
--- a/public/app/features/query/components/QueryEditorRows.tsx
+++ b/public/app/features/query/components/QueryEditorRows.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent, ReactNode } from 'react';
+import { PureComponent, ReactNode } from 'react';
import { DragDropContext, DragStart, Droppable, DropResult } from 'react-beautiful-dnd';
import {
diff --git a/public/app/features/query/components/QueryErrorAlert.tsx b/public/app/features/query/components/QueryErrorAlert.tsx
index 2f08a794314..649c6c06bff 100644
--- a/public/app/features/query/components/QueryErrorAlert.tsx
+++ b/public/app/features/query/components/QueryErrorAlert.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { DataQueryError, GrafanaTheme2 } from '@grafana/data';
import { Icon, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/query/components/QueryGroup.test.tsx b/public/app/features/query/components/QueryGroup.test.tsx
index 9a1a885ad11..6d9423247b8 100644
--- a/public/app/features/query/components/QueryGroup.test.tsx
+++ b/public/app/features/query/components/QueryGroup.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import config from 'app/core/config';
import { mockDataSource } from 'app/features/alerting/unified/mocks';
diff --git a/public/app/features/query/components/QueryGroup.tsx b/public/app/features/query/components/QueryGroup.tsx
index a522cb56a4e..79361af6ad3 100644
--- a/public/app/features/query/components/QueryGroup.tsx
+++ b/public/app/features/query/components/QueryGroup.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { PureComponent, useEffect, useState } from 'react';
+import { PureComponent, useEffect, useState } from 'react';
+import * as React from 'react';
import { Unsubscribable } from 'rxjs';
import {
diff --git a/public/app/features/query/components/QueryGroupOptions.tsx b/public/app/features/query/components/QueryGroupOptions.tsx
index c10da8f313d..7d73aa3fac1 100644
--- a/public/app/features/query/components/QueryGroupOptions.tsx
+++ b/public/app/features/query/components/QueryGroupOptions.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { PureComponent, ChangeEvent, FocusEvent } from 'react';
+import { PureComponent, ChangeEvent, FocusEvent } from 'react';
+import * as React from 'react';
import { rangeUtil, PanelData, DataSourceApi } from '@grafana/data';
import { Switch, Input, InlineFormLabel, stylesFactory } from '@grafana/ui';
diff --git a/public/app/features/sandbox/BenchmarksPage.tsx b/public/app/features/sandbox/BenchmarksPage.tsx
index 7be35b46b25..1738afe7088 100644
--- a/public/app/features/sandbox/BenchmarksPage.tsx
+++ b/public/app/features/sandbox/BenchmarksPage.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { EmotionPerfTest } from '@grafana/ui/src/components/ThemeDemos/EmotionPerfTest';
export const BenchmarksPage = () => {
diff --git a/public/app/features/sandbox/TestStuffPage.tsx b/public/app/features/sandbox/TestStuffPage.tsx
index e5507117cb5..7faa71465b7 100644
--- a/public/app/features/sandbox/TestStuffPage.tsx
+++ b/public/app/features/sandbox/TestStuffPage.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { NavModelItem } from '@grafana/data';
import { getPluginExtensions, isPluginExtensionLink } from '@grafana/runtime';
import { Button, LinkButton, Stack } from '@grafana/ui';
diff --git a/public/app/features/search/page/components/ActionRow.tsx b/public/app/features/search/page/components/ActionRow.tsx
index f76ac3009ce..0035f508f9d 100644
--- a/public/app/features/search/page/components/ActionRow.tsx
+++ b/public/app/features/search/page/components/ActionRow.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { FormEvent } from 'react';
+import { FormEvent } from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { config } from '@grafana/runtime';
diff --git a/public/app/features/search/page/components/ExplainScorePopup.tsx b/public/app/features/search/page/components/ExplainScorePopup.tsx
index 3f1b754dbdb..3d4d304a43a 100644
--- a/public/app/features/search/page/components/ExplainScorePopup.tsx
+++ b/public/app/features/search/page/components/ExplainScorePopup.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { DataFrame } from '@grafana/data';
import { CodeEditor, Modal, ModalTabsHeader, TabContent } from '@grafana/ui';
diff --git a/public/app/features/search/page/components/SearchResultsTable.test.tsx b/public/app/features/search/page/components/SearchResultsTable.test.tsx
index 1231ee39a5b..3229803696e 100644
--- a/public/app/features/search/page/components/SearchResultsTable.test.tsx
+++ b/public/app/features/search/page/components/SearchResultsTable.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { Subject } from 'rxjs';
import { applyFieldOverrides, createTheme, DataFrame, DataFrameView, FieldType, toDataFrame } from '@grafana/data';
diff --git a/public/app/features/search/page/components/SearchResultsTable.tsx b/public/app/features/search/page/components/SearchResultsTable.tsx
index bc32f4fe2d5..3540ed6e959 100644
--- a/public/app/features/search/page/components/SearchResultsTable.tsx
+++ b/public/app/features/search/page/components/SearchResultsTable.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useEffect, useMemo, useRef, useCallback, useState, CSSProperties } from 'react';
+import { useEffect, useMemo, useRef, useCallback, useState, CSSProperties } from 'react';
+import * as React from 'react';
import { useTable, Column, TableOptions, Cell } from 'react-table';
import { FixedSizeList } from 'react-window';
import InfiniteLoader from 'react-window-infinite-loader';
diff --git a/public/app/features/search/page/components/columns.tsx b/public/app/features/search/page/components/columns.tsx
index 22aea99cc16..ecbf046d6be 100644
--- a/public/app/features/search/page/components/columns.tsx
+++ b/public/app/features/search/page/components/columns.tsx
@@ -1,6 +1,5 @@
import { cx } from '@emotion/css';
import { intervalToDuration } from 'date-fns';
-import React from 'react';
import Skeleton from 'react-loading-skeleton';
import {
diff --git a/public/app/features/serviceaccounts/ServiceAccountCreatePage.test.tsx b/public/app/features/serviceaccounts/ServiceAccountCreatePage.test.tsx
index 780b4529514..346d79d6e48 100644
--- a/public/app/features/serviceaccounts/ServiceAccountCreatePage.test.tsx
+++ b/public/app/features/serviceaccounts/ServiceAccountCreatePage.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { ServiceAccountCreatePage, Props } from './ServiceAccountCreatePage';
diff --git a/public/app/features/serviceaccounts/ServiceAccountCreatePage.tsx b/public/app/features/serviceaccounts/ServiceAccountCreatePage.tsx
index 3d3f0ef3a74..036b56666ae 100644
--- a/public/app/features/serviceaccounts/ServiceAccountCreatePage.tsx
+++ b/public/app/features/serviceaccounts/ServiceAccountCreatePage.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
import { getBackendSrv, locationService } from '@grafana/runtime';
import { Button, Input, Field, FieldSet } from '@grafana/ui';
diff --git a/public/app/features/serviceaccounts/ServiceAccountPage.test.tsx b/public/app/features/serviceaccounts/ServiceAccountPage.test.tsx
index 3be5cf73cfb..e39d5c33daf 100644
--- a/public/app/features/serviceaccounts/ServiceAccountPage.test.tsx
+++ b/public/app/features/serviceaccounts/ServiceAccountPage.test.tsx
@@ -1,7 +1,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { History, Location } from 'history';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { RouteDescriptor } from 'app/core/navigation/types';
diff --git a/public/app/features/serviceaccounts/ServiceAccountPage.tsx b/public/app/features/serviceaccounts/ServiceAccountPage.tsx
index f99bc03cb4a..3ec2b9f5185 100644
--- a/public/app/features/serviceaccounts/ServiceAccountPage.tsx
+++ b/public/app/features/serviceaccounts/ServiceAccountPage.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { getTimeZone, NavModelItem } from '@grafana/data';
diff --git a/public/app/features/serviceaccounts/ServiceAccountPermissions.tsx b/public/app/features/serviceaccounts/ServiceAccountPermissions.tsx
index 7bb6e3721fb..95be8c782eb 100644
--- a/public/app/features/serviceaccounts/ServiceAccountPermissions.tsx
+++ b/public/app/features/serviceaccounts/ServiceAccountPermissions.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Permissions } from 'app/core/components/AccessControl';
import { contextSrv } from 'app/core/services/context_srv';
diff --git a/public/app/features/serviceaccounts/ServiceAccountTable.tsx b/public/app/features/serviceaccounts/ServiceAccountTable.tsx
index 1c9b45a32dc..ede46556e73 100644
--- a/public/app/features/serviceaccounts/ServiceAccountTable.tsx
+++ b/public/app/features/serviceaccounts/ServiceAccountTable.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import Skeleton from 'react-loading-skeleton';
import {
diff --git a/public/app/features/serviceaccounts/ServiceAccountsListPage.test.tsx b/public/app/features/serviceaccounts/ServiceAccountsListPage.test.tsx
index abe41f5650c..5276cd2026d 100644
--- a/public/app/features/serviceaccounts/ServiceAccountsListPage.test.tsx
+++ b/public/app/features/serviceaccounts/ServiceAccountsListPage.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { OrgRole, ServiceAccountDTO, ServiceAccountStateFilter } from 'app/types';
diff --git a/public/app/features/serviceaccounts/ServiceAccountsListPage.tsx b/public/app/features/serviceaccounts/ServiceAccountsListPage.tsx
index d5a62805bdb..ffd3f39ba59 100644
--- a/public/app/features/serviceaccounts/ServiceAccountsListPage.tsx
+++ b/public/app/features/serviceaccounts/ServiceAccountsListPage.tsx
@@ -1,5 +1,5 @@
import pluralize from 'pluralize';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { OrgRole } from '@grafana/data';
diff --git a/public/app/features/serviceaccounts/components/CreateTokenModal.tsx b/public/app/features/serviceaccounts/components/CreateTokenModal.tsx
index 92484a0cdbd..0b7dfbc2b10 100644
--- a/public/app/features/serviceaccounts/components/CreateTokenModal.tsx
+++ b/public/app/features/serviceaccounts/components/CreateTokenModal.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { v4 as uuidv4 } from 'uuid';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/serviceaccounts/components/ServiceAccountProfile.tsx b/public/app/features/serviceaccounts/components/ServiceAccountProfile.tsx
index e21f0728f15..5aa5ff9bdc0 100644
--- a/public/app/features/serviceaccounts/components/ServiceAccountProfile.tsx
+++ b/public/app/features/serviceaccounts/components/ServiceAccountProfile.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import { useState, useEffect } from 'react';
import { dateTimeFormat, GrafanaTheme2, OrgRole, TimeZone } from '@grafana/data';
import { Label, TextLink, useStyles2 } from '@grafana/ui';
@@ -19,7 +19,7 @@ interface Props {
export function ServiceAccountProfile({ serviceAccount, timeZone, onChange }: Props): JSX.Element {
const styles = useStyles2(getStyles);
const ableToWrite = contextSrv.hasPermission(AccessControlAction.ServiceAccountsWrite);
- const [roles, setRoleOptions] = React.useState([]);
+ const [roles, setRoleOptions] = useState([]);
const onRoleChange = (role: OrgRole) => {
onChange({ ...serviceAccount, role: role });
@@ -29,7 +29,7 @@ export function ServiceAccountProfile({ serviceAccount, timeZone, onChange }: Pr
onChange({ ...serviceAccount, name: newValue });
};
- React.useEffect(() => {
+ useEffect(() => {
async function fetchOptions() {
try {
if (contextSrv.hasPermission(AccessControlAction.ActionRolesList)) {
diff --git a/public/app/features/serviceaccounts/components/ServiceAccountProfileRow.tsx b/public/app/features/serviceaccounts/components/ServiceAccountProfileRow.tsx
index f32ce3ee720..8fad7855b82 100644
--- a/public/app/features/serviceaccounts/components/ServiceAccountProfileRow.tsx
+++ b/public/app/features/serviceaccounts/components/ServiceAccountProfileRow.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { useEffect, useRef, useState } from 'react';
+import { useEffect, useRef, useState } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { ConfirmButton, Input, Label, LegacyInputStatus, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/serviceaccounts/components/ServiceAccountRoleRow.tsx b/public/app/features/serviceaccounts/components/ServiceAccountRoleRow.tsx
index aab6b4bf0ae..bdbb0864e7a 100644
--- a/public/app/features/serviceaccounts/components/ServiceAccountRoleRow.tsx
+++ b/public/app/features/serviceaccounts/components/ServiceAccountRoleRow.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Label } from '@grafana/ui';
import { UserRolePicker } from 'app/core/components/RolePicker/UserRolePicker';
import { contextSrv } from 'app/core/core';
diff --git a/public/app/features/serviceaccounts/components/ServiceAccountTokensTable.tsx b/public/app/features/serviceaccounts/components/ServiceAccountTokensTable.tsx
index 855258be0dd..f4463033f67 100644
--- a/public/app/features/serviceaccounts/components/ServiceAccountTokensTable.tsx
+++ b/public/app/features/serviceaccounts/components/ServiceAccountTokensTable.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { dateTimeFormat, GrafanaTheme2, TimeZone } from '@grafana/data';
import { DeleteButton, Icon, Tooltip, useStyles2, useTheme2 } from '@grafana/ui';
diff --git a/public/app/features/serviceaccounts/components/ServiceAccountsListItem.tsx b/public/app/features/serviceaccounts/components/ServiceAccountsListItem.tsx
index 0aa2938cded..b6003205b7b 100644
--- a/public/app/features/serviceaccounts/components/ServiceAccountsListItem.tsx
+++ b/public/app/features/serviceaccounts/components/ServiceAccountsListItem.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { memo } from 'react';
+import { memo } from 'react';
import Skeleton from 'react-loading-skeleton';
import { GrafanaTheme2, OrgRole } from '@grafana/data';
diff --git a/public/app/features/storage/AddRootView.tsx b/public/app/features/storage/AddRootView.tsx
index c79a82b5c01..7850fa85c4e 100644
--- a/public/app/features/storage/AddRootView.tsx
+++ b/public/app/features/storage/AddRootView.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Button } from '@grafana/ui';
import { StorageView } from './types';
diff --git a/public/app/features/storage/Breadcrumb.tsx b/public/app/features/storage/Breadcrumb.tsx
index e3ff0a84809..a221ce28f42 100644
--- a/public/app/features/storage/Breadcrumb.tsx
+++ b/public/app/features/storage/Breadcrumb.tsx
@@ -1,6 +1,5 @@
import { css } from '@emotion/css';
import { uniqueId } from 'lodash';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Icon, IconName, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/storage/CreateNewFolderModal.tsx b/public/app/features/storage/CreateNewFolderModal.tsx
index 2ff4a887823..8f52939f8a7 100644
--- a/public/app/features/storage/CreateNewFolderModal.tsx
+++ b/public/app/features/storage/CreateNewFolderModal.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { SubmitHandler, Validate } from 'react-hook-form';
import { Button, Field, Input, Modal } from '@grafana/ui';
diff --git a/public/app/features/storage/FileView.tsx b/public/app/features/storage/FileView.tsx
index efdf0324e5f..653eff5717e 100644
--- a/public/app/features/storage/FileView.tsx
+++ b/public/app/features/storage/FileView.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { isString } from 'lodash';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { useAsync } from 'react-use';
import AutoSizer from 'react-virtualized-auto-sizer';
diff --git a/public/app/features/storage/FolderView.tsx b/public/app/features/storage/FolderView.tsx
index 8c48090f7f7..bd956c94387 100644
--- a/public/app/features/storage/FolderView.tsx
+++ b/public/app/features/storage/FolderView.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
import { DataFrame, GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/storage/RootView.tsx b/public/app/features/storage/RootView.tsx
index 332f2e503da..bfa87d16458 100644
--- a/public/app/features/storage/RootView.tsx
+++ b/public/app/features/storage/RootView.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
import { useAsync } from 'react-use';
import { DataFrame, GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/storage/StorageFolderPage.tsx b/public/app/features/storage/StorageFolderPage.tsx
index 63f2512ee30..b19e4b4791f 100644
--- a/public/app/features/storage/StorageFolderPage.tsx
+++ b/public/app/features/storage/StorageFolderPage.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useAsync } from 'react-use';
import { DataFrame, NavModel, NavModelItem } from '@grafana/data';
diff --git a/public/app/features/storage/StoragePage.tsx b/public/app/features/storage/StoragePage.tsx
index 8875241987c..ac37ab0c9f5 100644
--- a/public/app/features/storage/StoragePage.tsx
+++ b/public/app/features/storage/StoragePage.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
import { useAsync } from 'react-use';
import { DataFrame, GrafanaTheme2, isDataFrame, ValueLinkConfig } from '@grafana/data';
diff --git a/public/app/features/storage/UploadButton.tsx b/public/app/features/storage/UploadButton.tsx
index e9115a1a376..7d90427d1d2 100644
--- a/public/app/features/storage/UploadButton.tsx
+++ b/public/app/features/storage/UploadButton.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { FormEvent, useEffect, useState } from 'react';
+import { FormEvent, useEffect, useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { ConfirmModal, FileUpload, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/support-bundles/SupportBundles.tsx b/public/app/features/support-bundles/SupportBundles.tsx
index 989b8d4119d..be9cb8d6c63 100644
--- a/public/app/features/support-bundles/SupportBundles.tsx
+++ b/public/app/features/support-bundles/SupportBundles.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { dateTimeFormat } from '@grafana/data';
diff --git a/public/app/features/support-bundles/SupportBundlesCreate.tsx b/public/app/features/support-bundles/SupportBundlesCreate.tsx
index 11746981714..c26992e8780 100644
--- a/public/app/features/support-bundles/SupportBundlesCreate.tsx
+++ b/public/app/features/support-bundles/SupportBundlesCreate.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { Button, Field, Checkbox, LinkButton, Stack, Alert } from '@grafana/ui';
diff --git a/public/app/features/teams/CreateTeam.test.tsx b/public/app/features/teams/CreateTeam.test.tsx
index dfa891519ba..bb219be7a71 100644
--- a/public/app/features/teams/CreateTeam.test.tsx
+++ b/public/app/features/teams/CreateTeam.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { BackendSrv, setBackendSrv } from '@grafana/runtime';
diff --git a/public/app/features/teams/CreateTeam.tsx b/public/app/features/teams/CreateTeam.tsx
index 6e1a604f5ee..bd77f098fd5 100644
--- a/public/app/features/teams/CreateTeam.tsx
+++ b/public/app/features/teams/CreateTeam.tsx
@@ -1,4 +1,4 @@
-import React, { JSX, useState } from 'react';
+import { JSX, useState } from 'react';
import { useForm } from 'react-hook-form';
import { NavModelItem } from '@grafana/data';
diff --git a/public/app/features/teams/TeamGroupSync.test.tsx b/public/app/features/teams/TeamGroupSync.test.tsx
index 4486ea4d72e..d6ffc356588 100644
--- a/public/app/features/teams/TeamGroupSync.test.tsx
+++ b/public/app/features/teams/TeamGroupSync.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TeamGroup } from '../../types';
diff --git a/public/app/features/teams/TeamGroupSync.tsx b/public/app/features/teams/TeamGroupSync.tsx
index 3d8b2bbca30..64dd5b5e3ec 100644
--- a/public/app/features/teams/TeamGroupSync.tsx
+++ b/public/app/features/teams/TeamGroupSync.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { Input, Tooltip, Icon, Button, useTheme2, InlineField, InlineFieldRow } from '@grafana/ui';
diff --git a/public/app/features/teams/TeamList.test.tsx b/public/app/features/teams/TeamList.test.tsx
index c9f4dc4b686..8f444095424 100644
--- a/public/app/features/teams/TeamList.test.tsx
+++ b/public/app/features/teams/TeamList.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { contextSrv } from 'app/core/services/context_srv';
diff --git a/public/app/features/teams/TeamList.tsx b/public/app/features/teams/TeamList.tsx
index 4940ec5bb60..7faa4f46f57 100644
--- a/public/app/features/teams/TeamList.tsx
+++ b/public/app/features/teams/TeamList.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useMemo, useState } from 'react';
+import { useEffect, useMemo, useState } from 'react';
import Skeleton from 'react-loading-skeleton';
import { connect, ConnectedProps } from 'react-redux';
diff --git a/public/app/features/teams/TeamPages.test.tsx b/public/app/features/teams/TeamPages.test.tsx
index 6957986c02e..f053d113434 100644
--- a/public/app/features/teams/TeamPages.test.tsx
+++ b/public/app/features/teams/TeamPages.test.tsx
@@ -1,5 +1,4 @@
import { screen } from '@testing-library/react';
-import React from 'react';
import { Route, Router } from 'react-router-dom';
import { render } from 'test/test-utils';
diff --git a/public/app/features/teams/TeamPages.tsx b/public/app/features/teams/TeamPages.tsx
index 83bcaa76400..e2919ee3b79 100644
--- a/public/app/features/teams/TeamPages.tsx
+++ b/public/app/features/teams/TeamPages.tsx
@@ -1,5 +1,5 @@
import { createSelector } from '@reduxjs/toolkit';
-import React, { useMemo, useRef } from 'react';
+import { memo, useMemo, useRef } from 'react';
import { useParams } from 'react-router';
import { useAsync } from 'react-use';
@@ -48,7 +48,7 @@ const pageNavSelector = createSelector(
}
);
-const TeamPages = React.memo(() => {
+const TeamPages = memo(() => {
const isSyncEnabled = useRef(featureEnabled('teamsync'));
const params = useParams();
const teamId = useMemo(() => parseInt(params.id, 10), [params]);
diff --git a/public/app/features/teams/TeamPermissions.tsx b/public/app/features/teams/TeamPermissions.tsx
index 0292b98ff4e..ac7873b5ffb 100644
--- a/public/app/features/teams/TeamPermissions.tsx
+++ b/public/app/features/teams/TeamPermissions.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Permissions } from 'app/core/components/AccessControl';
import { contextSrv } from 'app/core/services/context_srv';
diff --git a/public/app/features/teams/TeamSettings.test.tsx b/public/app/features/teams/TeamSettings.test.tsx
index 08bc0ae26a4..bba0899b11f 100644
--- a/public/app/features/teams/TeamSettings.test.tsx
+++ b/public/app/features/teams/TeamSettings.test.tsx
@@ -1,6 +1,5 @@
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { Props, TeamSettings } from './TeamSettings';
import { getMockTeam } from './__mocks__/teamMocks';
diff --git a/public/app/features/teams/TeamSettings.tsx b/public/app/features/teams/TeamSettings.tsx
index 530e1f9ac1a..65e7afa6ec9 100644
--- a/public/app/features/teams/TeamSettings.tsx
+++ b/public/app/features/teams/TeamSettings.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useForm } from 'react-hook-form';
import { connect, ConnectedProps } from 'react-redux';
diff --git a/public/app/features/trails/ActionTabs/AddToFiltersGraphAction.tsx b/public/app/features/trails/ActionTabs/AddToFiltersGraphAction.tsx
index 4fbea1d2584..97ad14d6c15 100644
--- a/public/app/features/trails/ActionTabs/AddToFiltersGraphAction.tsx
+++ b/public/app/features/trails/ActionTabs/AddToFiltersGraphAction.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { DataFrame } from '@grafana/data';
import {
SceneObjectState,
diff --git a/public/app/features/trails/ActionTabs/BreakdownScene.tsx b/public/app/features/trails/ActionTabs/BreakdownScene.tsx
index a187f340b03..564506f066f 100644
--- a/public/app/features/trails/ActionTabs/BreakdownScene.tsx
+++ b/public/app/features/trails/ActionTabs/BreakdownScene.tsx
@@ -1,6 +1,5 @@
import { css } from '@emotion/css';
import { min, max, isNumber, throttle } from 'lodash';
-import React from 'react';
import { DataFrame, FieldType, GrafanaTheme2, PanelData, SelectableValue } from '@grafana/data';
import {
diff --git a/public/app/features/trails/ActionTabs/ByFrameRepeater.tsx b/public/app/features/trails/ActionTabs/ByFrameRepeater.tsx
index 34b1f13b02c..be960f6afc3 100644
--- a/public/app/features/trails/ActionTabs/ByFrameRepeater.tsx
+++ b/public/app/features/trails/ActionTabs/ByFrameRepeater.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { LoadingState, PanelData, DataFrame } from '@grafana/data';
import {
SceneObjectState,
diff --git a/public/app/features/trails/ActionTabs/LayoutSwitcher.tsx b/public/app/features/trails/ActionTabs/LayoutSwitcher.tsx
index 3bf7bafa9f1..e9382e9fa1b 100644
--- a/public/app/features/trails/ActionTabs/LayoutSwitcher.tsx
+++ b/public/app/features/trails/ActionTabs/LayoutSwitcher.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SelectableValue } from '@grafana/data';
import { SceneComponentProps, sceneGraph, SceneObject, SceneObjectBase, SceneObjectState } from '@grafana/scenes';
import { Field, RadioButtonGroup } from '@grafana/ui';
diff --git a/public/app/features/trails/ActionTabs/LogsScene.tsx b/public/app/features/trails/ActionTabs/LogsScene.tsx
index a2d7b39af49..fbd7151a958 100644
--- a/public/app/features/trails/ActionTabs/LogsScene.tsx
+++ b/public/app/features/trails/ActionTabs/LogsScene.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import {
DataSourceVariable,
PanelBuilders,
diff --git a/public/app/features/trails/ActionTabs/MetricOverviewScene.tsx b/public/app/features/trails/ActionTabs/MetricOverviewScene.tsx
index 59e9770c2c3..7d6906d21cb 100644
--- a/public/app/features/trails/ActionTabs/MetricOverviewScene.tsx
+++ b/public/app/features/trails/ActionTabs/MetricOverviewScene.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PromMetricsMetadataItem } from '@grafana/prometheus';
import {
QueryVariable,
diff --git a/public/app/features/trails/AutomaticMetricQueries/AutoVizPanel.tsx b/public/app/features/trails/AutomaticMetricQueries/AutoVizPanel.tsx
index 4572bf47f6a..17b59f21322 100644
--- a/public/app/features/trails/AutomaticMetricQueries/AutoVizPanel.tsx
+++ b/public/app/features/trails/AutomaticMetricQueries/AutoVizPanel.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SceneObjectState, SceneObjectBase, SceneComponentProps, VizPanel, SceneQueryRunner } from '@grafana/scenes';
import { RadioButtonGroup } from '@grafana/ui';
diff --git a/public/app/features/trails/BreakdownLabelSelector.tsx b/public/app/features/trails/BreakdownLabelSelector.tsx
index 25191aaa53a..b0fca78e80d 100644
--- a/public/app/features/trails/BreakdownLabelSelector.tsx
+++ b/public/app/features/trails/BreakdownLabelSelector.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { useResizeObserver } from '@react-aria/utils';
-import React, { useEffect, useRef, useState } from 'react';
+import { useEffect, useRef, useState } from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { Select, RadioButtonGroup, useStyles2, useTheme2, measureText } from '@grafana/ui';
diff --git a/public/app/features/trails/DataTrail.tsx b/public/app/features/trails/DataTrail.tsx
index 7470d6543e2..d13e890a318 100644
--- a/public/app/features/trails/DataTrail.tsx
+++ b/public/app/features/trails/DataTrail.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { AdHocVariableFilter, GrafanaTheme2, PageLayoutType, VariableHide, urlUtil } from '@grafana/data';
import { locationService } from '@grafana/runtime';
diff --git a/public/app/features/trails/DataTrailCard.tsx b/public/app/features/trails/DataTrailCard.tsx
index e441c5d3dc0..c49e55e909c 100644
--- a/public/app/features/trails/DataTrailCard.tsx
+++ b/public/app/features/trails/DataTrailCard.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { dateTimeFormat, GrafanaTheme2 } from '@grafana/data';
import { AdHocFiltersVariable, sceneGraph } from '@grafana/scenes';
diff --git a/public/app/features/trails/DataTrailSettings.tsx b/public/app/features/trails/DataTrailSettings.tsx
index 513efcc9f1f..4b9a4e7ee0a 100644
--- a/public/app/features/trails/DataTrailSettings.tsx
+++ b/public/app/features/trails/DataTrailSettings.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { SceneComponentProps, SceneObjectBase, SceneObjectState } from '@grafana/scenes';
diff --git a/public/app/features/trails/DataTrailsApp.tsx b/public/app/features/trails/DataTrailsApp.tsx
index f23361f1f51..37fc404f321 100644
--- a/public/app/features/trails/DataTrailsApp.tsx
+++ b/public/app/features/trails/DataTrailsApp.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect } from 'react';
+import { useState, useEffect } from 'react';
import { Route, Switch } from 'react-router-dom';
import { PageLayoutType } from '@grafana/data';
@@ -54,7 +54,7 @@ export class DataTrailsApp extends SceneObjectBase {
}
function DataTrailView({ trail }: { trail: DataTrail }) {
- const [isInitialized, setIsInitialized] = React.useState(false);
+ const [isInitialized, setIsInitialized] = useState(false);
useEffect(() => {
if (!isInitialized) {
diff --git a/public/app/features/trails/DataTrailsHistory.tsx b/public/app/features/trails/DataTrailsHistory.tsx
index eec93218927..ec4203ace5a 100644
--- a/public/app/features/trails/DataTrailsHistory.tsx
+++ b/public/app/features/trails/DataTrailsHistory.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import {
diff --git a/public/app/features/trails/DataTrailsHome.tsx b/public/app/features/trails/DataTrailsHome.tsx
index 4e7a81144e0..3c77390f6a7 100644
--- a/public/app/features/trails/DataTrailsHome.tsx
+++ b/public/app/features/trails/DataTrailsHome.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { Redirect } from 'react-router-dom';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/trails/DataTrailsPage.tsx b/public/app/features/trails/DataTrailsPage.tsx
index f473b90c91c..c45cf46ba88 100644
--- a/public/app/features/trails/DataTrailsPage.tsx
+++ b/public/app/features/trails/DataTrailsPage.tsx
@@ -1,6 +1,4 @@
// Libraries
-import React from 'react';
-
import { getDataTrailsApp } from './DataTrailsApp';
export function DataTrailsPage() {
diff --git a/public/app/features/trails/Integrations/DataTrailEmbedded.tsx b/public/app/features/trails/Integrations/DataTrailEmbedded.tsx
index 67b4ae6312c..cfd71a71d5a 100644
--- a/public/app/features/trails/Integrations/DataTrailEmbedded.tsx
+++ b/public/app/features/trails/Integrations/DataTrailEmbedded.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { AdHocVariableFilter } from '@grafana/data';
import { SceneComponentProps, SceneObjectBase, SceneObjectState, SceneTimeRangeLike } from '@grafana/scenes';
diff --git a/public/app/features/trails/Integrations/SceneDrawer.tsx b/public/app/features/trails/Integrations/SceneDrawer.tsx
index 0cb7a29bf35..caaad210868 100644
--- a/public/app/features/trails/Integrations/SceneDrawer.tsx
+++ b/public/app/features/trails/Integrations/SceneDrawer.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { SceneComponentProps, SceneObjectBase, SceneObject, SceneObjectState } from '@grafana/scenes';
diff --git a/public/app/features/trails/MetricCategory/MetricCategoryCascader.tsx b/public/app/features/trails/MetricCategory/MetricCategoryCascader.tsx
index 7dd6fa4c440..dc7b1e417d9 100644
--- a/public/app/features/trails/MetricCategory/MetricCategoryCascader.tsx
+++ b/public/app/features/trails/MetricCategory/MetricCategoryCascader.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { Cascader, CascaderOption } from '@grafana/ui';
diff --git a/public/app/features/trails/MetricGraphScene.tsx b/public/app/features/trails/MetricGraphScene.tsx
index 78ec601f135..256b0a68e7a 100644
--- a/public/app/features/trails/MetricGraphScene.tsx
+++ b/public/app/features/trails/MetricGraphScene.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { DashboardCursorSync, GrafanaTheme2 } from '@grafana/data';
import {
diff --git a/public/app/features/trails/MetricScene.tsx b/public/app/features/trails/MetricScene.tsx
index fb6cb6a1d79..4cb134f0e52 100644
--- a/public/app/features/trails/MetricScene.tsx
+++ b/public/app/features/trails/MetricScene.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { config } from '@grafana/runtime';
diff --git a/public/app/features/trails/MetricSelect/MetricSelectScene.tsx b/public/app/features/trails/MetricSelect/MetricSelectScene.tsx
index 062c8ab732e..bf7807612cd 100644
--- a/public/app/features/trails/MetricSelect/MetricSelectScene.tsx
+++ b/public/app/features/trails/MetricSelect/MetricSelectScene.tsx
@@ -1,6 +1,7 @@
import { css } from '@emotion/css';
import { debounce, isEqual } from 'lodash';
-import React, { useReducer } from 'react';
+import { useReducer } from 'react';
+import * as React from 'react';
import { GrafanaTheme2, RawTimeRange } from '@grafana/data';
import { isFetchError } from '@grafana/runtime';
diff --git a/public/app/features/trails/MetricSelect/SelectMetricAction.tsx b/public/app/features/trails/MetricSelect/SelectMetricAction.tsx
index 187763264a6..eaef8540716 100644
--- a/public/app/features/trails/MetricSelect/SelectMetricAction.tsx
+++ b/public/app/features/trails/MetricSelect/SelectMetricAction.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SceneObjectState, SceneObjectBase, SceneComponentProps } from '@grafana/scenes';
import { Button } from '@grafana/ui';
diff --git a/public/app/features/trails/MetricsHeader.tsx b/public/app/features/trails/MetricsHeader.tsx
index f40edb4be89..5f243bdafde 100644
--- a/public/app/features/trails/MetricsHeader.tsx
+++ b/public/app/features/trails/MetricsHeader.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Stack, Text } from '@grafana/ui';
export const MetricsHeader = () => (
diff --git a/public/app/features/trails/ShareTrailButton.tsx b/public/app/features/trails/ShareTrailButton.tsx
index 4f6ed25a429..084d2054317 100644
--- a/public/app/features/trails/ShareTrailButton.tsx
+++ b/public/app/features/trails/ShareTrailButton.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { config } from '@grafana/runtime';
import { ToolbarButton } from '@grafana/ui';
diff --git a/public/app/features/trails/StatusWrapper.tsx b/public/app/features/trails/StatusWrapper.tsx
index d9d3edc0804..831df9c035b 100644
--- a/public/app/features/trails/StatusWrapper.tsx
+++ b/public/app/features/trails/StatusWrapper.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { ReactNode } from 'react';
+import { ReactNode } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { LoadingPlaceholder, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/trails/TrailStore/utils.tsx b/public/app/features/trails/TrailStore/utils.tsx
index f56d6a47993..8c1b84d1900 100644
--- a/public/app/features/trails/TrailStore/utils.tsx
+++ b/public/app/features/trails/TrailStore/utils.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { LinkButton, Stack } from '@grafana/ui';
import { createSuccessNotification } from '../../../core/copy/appNotification';
diff --git a/public/app/features/transformers/FilterByValueTransformer/FilterByValueFilterEditor.tsx b/public/app/features/transformers/FilterByValueTransformer/FilterByValueFilterEditor.tsx
index 61dc9d3a8cf..f896c2a5759 100644
--- a/public/app/features/transformers/FilterByValueTransformer/FilterByValueFilterEditor.tsx
+++ b/public/app/features/transformers/FilterByValueTransformer/FilterByValueFilterEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { Field, SelectableValue, valueMatchers } from '@grafana/data';
import { FilterByValueFilter } from '@grafana/data/src/transformations/transformers/filterByValue';
diff --git a/public/app/features/transformers/FilterByValueTransformer/FilterByValueTransformerEditor.test.tsx b/public/app/features/transformers/FilterByValueTransformer/FilterByValueTransformerEditor.test.tsx
index fd19c7a3b8f..e9cf39d1497 100644
--- a/public/app/features/transformers/FilterByValueTransformer/FilterByValueTransformerEditor.test.tsx
+++ b/public/app/features/transformers/FilterByValueTransformer/FilterByValueTransformerEditor.test.tsx
@@ -1,5 +1,4 @@
import { render, fireEvent } from '@testing-library/react';
-import React from 'react';
import { DataFrame, FieldType, ValueMatcherID, valueMatchers } from '@grafana/data';
import { FilterByValueMatch, FilterByValueType } from '@grafana/data/src/transformations/transformers/filterByValue';
diff --git a/public/app/features/transformers/FilterByValueTransformer/FilterByValueTransformerEditor.tsx b/public/app/features/transformers/FilterByValueTransformer/FilterByValueTransformerEditor.tsx
index f342e5a96c4..683350d47b1 100644
--- a/public/app/features/transformers/FilterByValueTransformer/FilterByValueTransformerEditor.tsx
+++ b/public/app/features/transformers/FilterByValueTransformer/FilterByValueTransformerEditor.tsx
@@ -1,5 +1,5 @@
import { cloneDeep } from 'lodash';
-import React, { useMemo, useCallback } from 'react';
+import { useMemo, useCallback } from 'react';
import {
DataTransformerID,
diff --git a/public/app/features/transformers/FilterByValueTransformer/ValueMatchers/BasicMatcherEditor.tsx b/public/app/features/transformers/FilterByValueTransformer/ValueMatchers/BasicMatcherEditor.tsx
index eadbc0b50e9..3c8fb0aaa3f 100644
--- a/public/app/features/transformers/FilterByValueTransformer/ValueMatchers/BasicMatcherEditor.tsx
+++ b/public/app/features/transformers/FilterByValueTransformer/ValueMatchers/BasicMatcherEditor.tsx
@@ -1,4 +1,5 @@
-import React, { useCallback, useState } from 'react';
+import { useCallback, useState } from 'react';
+import * as React from 'react';
import { ValueMatcherID, BasicValueMatcherOptions, VariableOrigin } from '@grafana/data';
import { getTemplateSrv, config as cfg } from '@grafana/runtime';
diff --git a/public/app/features/transformers/FilterByValueTransformer/ValueMatchers/RangeMatcherEditor.tsx b/public/app/features/transformers/FilterByValueTransformer/ValueMatchers/RangeMatcherEditor.tsx
index 50076b1819f..3202d5e37eb 100644
--- a/public/app/features/transformers/FilterByValueTransformer/ValueMatchers/RangeMatcherEditor.tsx
+++ b/public/app/features/transformers/FilterByValueTransformer/ValueMatchers/RangeMatcherEditor.tsx
@@ -1,4 +1,5 @@
-import React, { useCallback, useState } from 'react';
+import { useCallback, useState } from 'react';
+import * as React from 'react';
import { ValueMatcherID, RangeValueMatcherOptions, VariableOrigin } from '@grafana/data';
import { getTemplateSrv, config as cfg } from '@grafana/runtime';
diff --git a/public/app/features/transformers/FilterByValueTransformer/ValueMatchers/RegexMatcherEditor.tsx b/public/app/features/transformers/FilterByValueTransformer/ValueMatchers/RegexMatcherEditor.tsx
index 5c15e25bf56..2c44980d7e4 100644
--- a/public/app/features/transformers/FilterByValueTransformer/ValueMatchers/RegexMatcherEditor.tsx
+++ b/public/app/features/transformers/FilterByValueTransformer/ValueMatchers/RegexMatcherEditor.tsx
@@ -1,4 +1,5 @@
-import React, { useCallback, useState } from 'react';
+import { useCallback, useState } from 'react';
+import * as React from 'react';
import { ValueMatcherID, BasicValueMatcherOptions } from '@grafana/data';
import { Input } from '@grafana/ui';
diff --git a/public/app/features/transformers/calculateHeatmap/HeatmapTransformerEditor.tsx b/public/app/features/transformers/calculateHeatmap/HeatmapTransformerEditor.tsx
index 2fb94c1dc80..a8810d11807 100644
--- a/public/app/features/transformers/calculateHeatmap/HeatmapTransformerEditor.tsx
+++ b/public/app/features/transformers/calculateHeatmap/HeatmapTransformerEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import {
PanelOptionsEditorBuilder,
diff --git a/public/app/features/transformers/calculateHeatmap/editor/AxisEditor.tsx b/public/app/features/transformers/calculateHeatmap/editor/AxisEditor.tsx
index c842aefdec7..2c9e72dc6ba 100644
--- a/public/app/features/transformers/calculateHeatmap/editor/AxisEditor.tsx
+++ b/public/app/features/transformers/calculateHeatmap/editor/AxisEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { SelectableValue, StandardEditorProps, VariableOrigin } from '@grafana/data';
import { getTemplateSrv, config as cfg } from '@grafana/runtime';
diff --git a/public/app/features/transformers/configFromQuery/ConfigFromQueryTransformerEditor.test.tsx b/public/app/features/transformers/configFromQuery/ConfigFromQueryTransformerEditor.test.tsx
index fd8e139d67f..9d8cc92fe20 100644
--- a/public/app/features/transformers/configFromQuery/ConfigFromQueryTransformerEditor.test.tsx
+++ b/public/app/features/transformers/configFromQuery/ConfigFromQueryTransformerEditor.test.tsx
@@ -1,5 +1,4 @@
import { fireEvent, render, screen } from '@testing-library/react';
-import React from 'react';
import { selectOptionInTest } from 'test/helpers/selectOptionInTest';
import { toDataFrame, FieldType } from '@grafana/data';
diff --git a/public/app/features/transformers/configFromQuery/ConfigFromQueryTransformerEditor.tsx b/public/app/features/transformers/configFromQuery/ConfigFromQueryTransformerEditor.tsx
index efe7749d3c5..0b46b136dc4 100644
--- a/public/app/features/transformers/configFromQuery/ConfigFromQueryTransformerEditor.tsx
+++ b/public/app/features/transformers/configFromQuery/ConfigFromQueryTransformerEditor.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import {
FieldMatcherID,
diff --git a/public/app/features/transformers/editors/CalculateFieldTransformerEditor/BinaryOperationOptionsEditor.tsx b/public/app/features/transformers/editors/CalculateFieldTransformerEditor/BinaryOperationOptionsEditor.tsx
index 842cf0a670a..4371dd82949 100644
--- a/public/app/features/transformers/editors/CalculateFieldTransformerEditor/BinaryOperationOptionsEditor.tsx
+++ b/public/app/features/transformers/editors/CalculateFieldTransformerEditor/BinaryOperationOptionsEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { BinaryOperationID, binaryOperators, SelectableValue } from '@grafana/data';
import {
BinaryOptions,
diff --git a/public/app/features/transformers/editors/CalculateFieldTransformerEditor/CalculateFieldTransformerEditor.tsx b/public/app/features/transformers/editors/CalculateFieldTransformerEditor/CalculateFieldTransformerEditor.tsx
index 919e95890fd..0ba6c4381f1 100644
--- a/public/app/features/transformers/editors/CalculateFieldTransformerEditor/CalculateFieldTransformerEditor.tsx
+++ b/public/app/features/transformers/editors/CalculateFieldTransformerEditor/CalculateFieldTransformerEditor.tsx
@@ -1,4 +1,5 @@
-import React, { ChangeEvent, useEffect, useState } from 'react';
+import { ChangeEvent, useEffect, useState } from 'react';
+import * as React from 'react';
import { identity, of, OperatorFunction } from 'rxjs';
import { map } from 'rxjs/operators';
diff --git a/public/app/features/transformers/editors/CalculateFieldTransformerEditor/CumulativeOptionsEditor.tsx b/public/app/features/transformers/editors/CalculateFieldTransformerEditor/CumulativeOptionsEditor.tsx
index 406a8745872..1194514bcf4 100644
--- a/public/app/features/transformers/editors/CalculateFieldTransformerEditor/CumulativeOptionsEditor.tsx
+++ b/public/app/features/transformers/editors/CalculateFieldTransformerEditor/CumulativeOptionsEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { ReducerID, SelectableValue } from '@grafana/data';
import {
CalculateFieldMode,
diff --git a/public/app/features/transformers/editors/CalculateFieldTransformerEditor/IndexOptionsEditor.tsx b/public/app/features/transformers/editors/CalculateFieldTransformerEditor/IndexOptionsEditor.tsx
index 11da52db647..c660ac21317 100644
--- a/public/app/features/transformers/editors/CalculateFieldTransformerEditor/IndexOptionsEditor.tsx
+++ b/public/app/features/transformers/editors/CalculateFieldTransformerEditor/IndexOptionsEditor.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { CalculateFieldTransformerOptions } from '@grafana/data/src/transformations/transformers/calculateField';
import { InlineField, InlineSwitch } from '@grafana/ui';
diff --git a/public/app/features/transformers/editors/CalculateFieldTransformerEditor/ReduceRowOptionsEditor.tsx b/public/app/features/transformers/editors/CalculateFieldTransformerEditor/ReduceRowOptionsEditor.tsx
index f0875f7fd7a..c48870fc36b 100644
--- a/public/app/features/transformers/editors/CalculateFieldTransformerEditor/ReduceRowOptionsEditor.tsx
+++ b/public/app/features/transformers/editors/CalculateFieldTransformerEditor/ReduceRowOptionsEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { ReducerID } from '@grafana/data';
import {
CalculateFieldTransformerOptions,
diff --git a/public/app/features/transformers/editors/CalculateFieldTransformerEditor/UnaryOperationEditor.tsx b/public/app/features/transformers/editors/CalculateFieldTransformerEditor/UnaryOperationEditor.tsx
index 849be7eb4b0..3b38248b705 100644
--- a/public/app/features/transformers/editors/CalculateFieldTransformerEditor/UnaryOperationEditor.tsx
+++ b/public/app/features/transformers/editors/CalculateFieldTransformerEditor/UnaryOperationEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { unaryOperators, SelectableValue, UnaryOperationID } from '@grafana/data';
import {
UnaryOptions,
diff --git a/public/app/features/transformers/editors/CalculateFieldTransformerEditor/WindowOptionsEditor.tsx b/public/app/features/transformers/editors/CalculateFieldTransformerEditor/WindowOptionsEditor.tsx
index 05b10b6e36c..34380f80b40 100644
--- a/public/app/features/transformers/editors/CalculateFieldTransformerEditor/WindowOptionsEditor.tsx
+++ b/public/app/features/transformers/editors/CalculateFieldTransformerEditor/WindowOptionsEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { ReducerID, SelectableValue } from '@grafana/data';
import {
CalculateFieldMode,
diff --git a/public/app/features/transformers/editors/ConcatenateTransformerEditor.tsx b/public/app/features/transformers/editors/ConcatenateTransformerEditor.tsx
index e61ddfd8a3c..8c548fb2f38 100644
--- a/public/app/features/transformers/editors/ConcatenateTransformerEditor.tsx
+++ b/public/app/features/transformers/editors/ConcatenateTransformerEditor.tsx
@@ -1,4 +1,4 @@
-import React, { ChangeEvent } from 'react';
+import { PureComponent, ChangeEvent } from 'react';
import {
DataTransformerID,
@@ -24,7 +24,7 @@ const nameModes: Array> = [
{ value: ConcatenateFrameNameMode.Drop, label: 'Ignore the frame name' },
];
-export class ConcatenateTransformerEditor extends React.PureComponent {
+export class ConcatenateTransformerEditor extends PureComponent {
constructor(props: ConcatenateTransformerEditorProps) {
super(props);
}
diff --git a/public/app/features/transformers/editors/ConvertFieldTypeTransformerEditor.tsx b/public/app/features/transformers/editors/ConvertFieldTypeTransformerEditor.tsx
index ba6793ecd76..db059c21230 100644
--- a/public/app/features/transformers/editors/ConvertFieldTypeTransformerEditor.tsx
+++ b/public/app/features/transformers/editors/ConvertFieldTypeTransformerEditor.tsx
@@ -1,4 +1,4 @@
-import React, { ChangeEvent, useCallback } from 'react';
+import { ChangeEvent, useCallback } from 'react';
import {
DataTransformerID,
diff --git a/public/app/features/transformers/editors/EnumMappingEditor.tsx b/public/app/features/transformers/editors/EnumMappingEditor.tsx
index b8ef06e2d30..15999e46f21 100644
--- a/public/app/features/transformers/editors/EnumMappingEditor.tsx
+++ b/public/app/features/transformers/editors/EnumMappingEditor.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { isEqual } from 'lodash';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd';
import { DataFrame, EnumFieldConfig, GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/transformers/editors/EnumMappingRow.tsx b/public/app/features/transformers/editors/EnumMappingRow.tsx
index 52861b7d6ce..641e9c3cd1a 100644
--- a/public/app/features/transformers/editors/EnumMappingRow.tsx
+++ b/public/app/features/transformers/editors/EnumMappingRow.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { FormEvent, useState, KeyboardEvent, useRef, useEffect } from 'react';
+import { FormEvent, useState, KeyboardEvent, useRef, useEffect } from 'react';
import { Draggable } from 'react-beautiful-dnd';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/transformers/editors/FilterByNameTransformerEditor.tsx b/public/app/features/transformers/editors/FilterByNameTransformerEditor.tsx
index cb86ff82bdf..8ac19f37e7f 100644
--- a/public/app/features/transformers/editors/FilterByNameTransformerEditor.tsx
+++ b/public/app/features/transformers/editors/FilterByNameTransformerEditor.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import {
DataTransformerID,
diff --git a/public/app/features/transformers/editors/FilterByRefIdTransformerEditor.tsx b/public/app/features/transformers/editors/FilterByRefIdTransformerEditor.tsx
index c1c13ca97f1..1a0c8a2c75a 100644
--- a/public/app/features/transformers/editors/FilterByRefIdTransformerEditor.tsx
+++ b/public/app/features/transformers/editors/FilterByRefIdTransformerEditor.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import { PureComponent } from 'react';
import {
DataTransformerID,
@@ -25,7 +25,7 @@ interface RefIdInfo {
refId: string;
count: number;
}
-export class FilterByRefIdTransformerEditor extends React.PureComponent<
+export class FilterByRefIdTransformerEditor extends PureComponent<
FilterByRefIdTransformerEditorProps,
FilterByRefIdTransformerEditorState
> {
diff --git a/public/app/features/transformers/editors/FormatStringTransformerEditor.tsx b/public/app/features/transformers/editors/FormatStringTransformerEditor.tsx
index d0af7b19da4..16587421f48 100644
--- a/public/app/features/transformers/editors/FormatStringTransformerEditor.tsx
+++ b/public/app/features/transformers/editors/FormatStringTransformerEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import {
DataTransformerID,
diff --git a/public/app/features/transformers/editors/FormatTimeTransformerEditor.tsx b/public/app/features/transformers/editors/FormatTimeTransformerEditor.tsx
index 9df14736b20..4c2a646d93f 100644
--- a/public/app/features/transformers/editors/FormatTimeTransformerEditor.tsx
+++ b/public/app/features/transformers/editors/FormatTimeTransformerEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, ChangeEvent } from 'react';
+import { useCallback, ChangeEvent } from 'react';
import {
DataTransformerID,
diff --git a/public/app/features/transformers/editors/GroupByTransformerEditor.tsx b/public/app/features/transformers/editors/GroupByTransformerEditor.tsx
index 50177ea8912..21a12c9585f 100644
--- a/public/app/features/transformers/editors/GroupByTransformerEditor.tsx
+++ b/public/app/features/transformers/editors/GroupByTransformerEditor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import {
DataTransformerID,
diff --git a/public/app/features/transformers/editors/GroupToNestedTableTransformerEditor.tsx b/public/app/features/transformers/editors/GroupToNestedTableTransformerEditor.tsx
index 2811235c460..da5db299900 100644
--- a/public/app/features/transformers/editors/GroupToNestedTableTransformerEditor.tsx
+++ b/public/app/features/transformers/editors/GroupToNestedTableTransformerEditor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import {
DataTransformerID,
diff --git a/public/app/features/transformers/editors/GroupingToMatrixTransformerEditor.tsx b/public/app/features/transformers/editors/GroupingToMatrixTransformerEditor.tsx
index 9cea0cfdc21..04648b6c7c1 100644
--- a/public/app/features/transformers/editors/GroupingToMatrixTransformerEditor.tsx
+++ b/public/app/features/transformers/editors/GroupingToMatrixTransformerEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import {
DataTransformerID,
diff --git a/public/app/features/transformers/editors/HistogramTransformerEditor.tsx b/public/app/features/transformers/editors/HistogramTransformerEditor.tsx
index 93afbfd9bc0..696f3458d59 100644
--- a/public/app/features/transformers/editors/HistogramTransformerEditor.tsx
+++ b/public/app/features/transformers/editors/HistogramTransformerEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useState } from 'react';
+import { useCallback, useState } from 'react';
import {
DataTransformerID,
diff --git a/public/app/features/transformers/editors/JoinByFieldTransformerEditor.tsx b/public/app/features/transformers/editors/JoinByFieldTransformerEditor.tsx
index 49325e65114..e0b1eea12de 100644
--- a/public/app/features/transformers/editors/JoinByFieldTransformerEditor.tsx
+++ b/public/app/features/transformers/editors/JoinByFieldTransformerEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import {
DataTransformerID,
diff --git a/public/app/features/transformers/editors/LabelsToFieldsTransformerEditor.tsx b/public/app/features/transformers/editors/LabelsToFieldsTransformerEditor.tsx
index 2e0bff17d2d..e41017a51a2 100644
--- a/public/app/features/transformers/editors/LabelsToFieldsTransformerEditor.tsx
+++ b/public/app/features/transformers/editors/LabelsToFieldsTransformerEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import {
DataTransformerID,
diff --git a/public/app/features/transformers/editors/LimitTransformerEditor.tsx b/public/app/features/transformers/editors/LimitTransformerEditor.tsx
index 087cbe633e2..94245e5ae42 100644
--- a/public/app/features/transformers/editors/LimitTransformerEditor.tsx
+++ b/public/app/features/transformers/editors/LimitTransformerEditor.tsx
@@ -1,4 +1,4 @@
-import React, { FormEvent, useCallback, useState } from 'react';
+import { FormEvent, useCallback, useState } from 'react';
import {
DataTransformerID,
diff --git a/public/app/features/transformers/editors/MergeTransformerEditor.tsx b/public/app/features/transformers/editors/MergeTransformerEditor.tsx
index f067043ea4f..cd55fbd5543 100644
--- a/public/app/features/transformers/editors/MergeTransformerEditor.tsx
+++ b/public/app/features/transformers/editors/MergeTransformerEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import {
DataTransformerID,
standardTransformers,
diff --git a/public/app/features/transformers/editors/OrganizeFieldsTransformerEditor.tsx b/public/app/features/transformers/editors/OrganizeFieldsTransformerEditor.tsx
index 40156b7cb62..c7c1b62c0a4 100644
--- a/public/app/features/transformers/editors/OrganizeFieldsTransformerEditor.tsx
+++ b/public/app/features/transformers/editors/OrganizeFieldsTransformerEditor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useCallback, useMemo } from 'react';
+import { useCallback, useMemo } from 'react';
import { DragDropContext, Draggable, Droppable, DropResult } from 'react-beautiful-dnd';
import {
diff --git a/public/app/features/transformers/editors/ReduceTransformerEditor.tsx b/public/app/features/transformers/editors/ReduceTransformerEditor.tsx
index 5e5640dbf74..fc8e10c6b7e 100644
--- a/public/app/features/transformers/editors/ReduceTransformerEditor.tsx
+++ b/public/app/features/transformers/editors/ReduceTransformerEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import {
DataTransformerID,
diff --git a/public/app/features/transformers/editors/RenameByRegexTransformer.tsx b/public/app/features/transformers/editors/RenameByRegexTransformer.tsx
index 5e63e597af8..d192c4a9ee0 100644
--- a/public/app/features/transformers/editors/RenameByRegexTransformer.tsx
+++ b/public/app/features/transformers/editors/RenameByRegexTransformer.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import {
DataTransformerID,
diff --git a/public/app/features/transformers/editors/SortByTransformerEditor.tsx b/public/app/features/transformers/editors/SortByTransformerEditor.tsx
index 49721a19edf..f0362a65ddb 100644
--- a/public/app/features/transformers/editors/SortByTransformerEditor.tsx
+++ b/public/app/features/transformers/editors/SortByTransformerEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import {
DataTransformerID,
diff --git a/public/app/features/transformers/extractFields/ExtractFieldsTransformerEditor.tsx b/public/app/features/transformers/extractFields/ExtractFieldsTransformerEditor.tsx
index c9a4647fe39..3261a77d7e2 100644
--- a/public/app/features/transformers/extractFields/ExtractFieldsTransformerEditor.tsx
+++ b/public/app/features/transformers/extractFields/ExtractFieldsTransformerEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import {
DataTransformerID,
TransformerRegistryItem,
diff --git a/public/app/features/transformers/extractFields/components/JSONPathEditor.tsx b/public/app/features/transformers/extractFields/components/JSONPathEditor.tsx
index 40bc775f32e..5d90d167bdb 100644
--- a/public/app/features/transformers/extractFields/components/JSONPathEditor.tsx
+++ b/public/app/features/transformers/extractFields/components/JSONPathEditor.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
+import * as React from 'react';
import { Button, InlineField, InlineFieldRow, IconButton, Input } from '@grafana/ui';
diff --git a/public/app/features/transformers/fieldToConfigMapping/FieldConfigMappingHandlerArgumentsEditor.test.tsx b/public/app/features/transformers/fieldToConfigMapping/FieldConfigMappingHandlerArgumentsEditor.test.tsx
index 76a81dde407..7ec37fc3e52 100644
--- a/public/app/features/transformers/fieldToConfigMapping/FieldConfigMappingHandlerArgumentsEditor.test.tsx
+++ b/public/app/features/transformers/fieldToConfigMapping/FieldConfigMappingHandlerArgumentsEditor.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { FieldConfigMappingHandlerArgumentsEditor, Props } from './FieldConfigMappingHandlerArgumentsEditor';
diff --git a/public/app/features/transformers/fieldToConfigMapping/FieldConfigMappingHandlerArgumentsEditor.tsx b/public/app/features/transformers/fieldToConfigMapping/FieldConfigMappingHandlerArgumentsEditor.tsx
index 474eeb1a0b3..150c00ef36a 100644
--- a/public/app/features/transformers/fieldToConfigMapping/FieldConfigMappingHandlerArgumentsEditor.tsx
+++ b/public/app/features/transformers/fieldToConfigMapping/FieldConfigMappingHandlerArgumentsEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { ColorPicker, Input } from '@grafana/ui';
import { HandlerArguments } from './fieldToConfigMapping';
diff --git a/public/app/features/transformers/fieldToConfigMapping/FieldToConfigMappingEditor.test.tsx b/public/app/features/transformers/fieldToConfigMapping/FieldToConfigMappingEditor.test.tsx
index 17cb3cfbfe1..99c0d8c2d0f 100644
--- a/public/app/features/transformers/fieldToConfigMapping/FieldToConfigMappingEditor.test.tsx
+++ b/public/app/features/transformers/fieldToConfigMapping/FieldToConfigMappingEditor.test.tsx
@@ -1,6 +1,5 @@
import { fireEvent, render, screen, getByText, getByLabelText } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { selectOptionInTest } from 'test/helpers/selectOptionInTest';
import { toDataFrame, FieldType } from '@grafana/data';
diff --git a/public/app/features/transformers/fieldToConfigMapping/FieldToConfigMappingEditor.tsx b/public/app/features/transformers/fieldToConfigMapping/FieldToConfigMappingEditor.tsx
index 1bcd9ab7418..3dfa9b92838 100644
--- a/public/app/features/transformers/fieldToConfigMapping/FieldToConfigMappingEditor.tsx
+++ b/public/app/features/transformers/fieldToConfigMapping/FieldToConfigMappingEditor.tsx
@@ -1,6 +1,5 @@
import { css } from '@emotion/css';
import { capitalize } from 'lodash';
-import React from 'react';
import { DataFrame, getFieldDisplayName, GrafanaTheme2, ReducerID, SelectableValue } from '@grafana/data';
import { Select, StatsPicker, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/transformers/joinByLabels/JoinByLabelsTransformerEditor.tsx b/public/app/features/transformers/joinByLabels/JoinByLabelsTransformerEditor.tsx
index ba5b48ed3dc..7f1ff442f37 100644
--- a/public/app/features/transformers/joinByLabels/JoinByLabelsTransformerEditor.tsx
+++ b/public/app/features/transformers/joinByLabels/JoinByLabelsTransformerEditor.tsx
@@ -1,4 +1,5 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
+import * as React from 'react';
import {
PluginState,
diff --git a/public/app/features/transformers/lookupGazetteer/FieldLookupTransformerEditor.tsx b/public/app/features/transformers/lookupGazetteer/FieldLookupTransformerEditor.tsx
index 056b9f70433..63e60fd7208 100644
--- a/public/app/features/transformers/lookupGazetteer/FieldLookupTransformerEditor.tsx
+++ b/public/app/features/transformers/lookupGazetteer/FieldLookupTransformerEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import {
DataTransformerID,
diff --git a/public/app/features/transformers/partitionByValues/PartitionByValuesEditor.tsx b/public/app/features/transformers/partitionByValues/PartitionByValuesEditor.tsx
index 167ba484b6e..5396f85148c 100644
--- a/public/app/features/transformers/partitionByValues/PartitionByValuesEditor.tsx
+++ b/public/app/features/transformers/partitionByValues/PartitionByValuesEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useMemo } from 'react';
+import { useCallback, useMemo } from 'react';
import {
DataTransformerID,
diff --git a/public/app/features/transformers/prepareTimeSeries/PrepareTimeSeriesEditor.tsx b/public/app/features/transformers/prepareTimeSeries/PrepareTimeSeriesEditor.tsx
index a75fa3b77e2..05c0b67a2de 100644
--- a/public/app/features/transformers/prepareTimeSeries/PrepareTimeSeriesEditor.tsx
+++ b/public/app/features/transformers/prepareTimeSeries/PrepareTimeSeriesEditor.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
+import * as React from 'react';
import {
GrafanaTheme2,
diff --git a/public/app/features/transformers/regression/regressionEditor.test.tsx b/public/app/features/transformers/regression/regressionEditor.test.tsx
index 58c91a79298..658b69029e7 100644
--- a/public/app/features/transformers/regression/regressionEditor.test.tsx
+++ b/public/app/features/transformers/regression/regressionEditor.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { FieldType, toDataFrame } from '@grafana/data';
diff --git a/public/app/features/transformers/regression/regressionEditor.tsx b/public/app/features/transformers/regression/regressionEditor.tsx
index 21f112eca8c..6c04f7ba258 100644
--- a/public/app/features/transformers/regression/regressionEditor.tsx
+++ b/public/app/features/transformers/regression/regressionEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import {
DataTransformerID,
diff --git a/public/app/features/transformers/rowsToFields/RowsToFieldsTransformerEditor.test.tsx b/public/app/features/transformers/rowsToFields/RowsToFieldsTransformerEditor.test.tsx
index bb5746b3716..ae6e7c6aa6e 100644
--- a/public/app/features/transformers/rowsToFields/RowsToFieldsTransformerEditor.test.tsx
+++ b/public/app/features/transformers/rowsToFields/RowsToFieldsTransformerEditor.test.tsx
@@ -1,5 +1,4 @@
import { fireEvent, render, screen } from '@testing-library/react';
-import React from 'react';
import { selectOptionInTest } from 'test/helpers/selectOptionInTest';
import { toDataFrame, FieldType } from '@grafana/data';
diff --git a/public/app/features/transformers/rowsToFields/RowsToFieldsTransformerEditor.tsx b/public/app/features/transformers/rowsToFields/RowsToFieldsTransformerEditor.tsx
index 5f25ebb92e8..8e4a0b5faad 100644
--- a/public/app/features/transformers/rowsToFields/RowsToFieldsTransformerEditor.tsx
+++ b/public/app/features/transformers/rowsToFields/RowsToFieldsTransformerEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PluginState, TransformerRegistryItem, TransformerUIProps, TransformerCategory } from '@grafana/data';
import { getTransformationContent } from '../docs/getTransformationContent';
diff --git a/public/app/features/transformers/spatial/SpatialTransformerEditor.tsx b/public/app/features/transformers/spatial/SpatialTransformerEditor.tsx
index 26110039d51..29d22fd4b8c 100644
--- a/public/app/features/transformers/spatial/SpatialTransformerEditor.tsx
+++ b/public/app/features/transformers/spatial/SpatialTransformerEditor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import {
DataTransformerID,
diff --git a/public/app/features/transformers/suggestionsInput/SuggestionsInput.tsx b/public/app/features/transformers/suggestionsInput/SuggestionsInput.tsx
index 81fa439d02d..bc2fc18361a 100644
--- a/public/app/features/transformers/suggestionsInput/SuggestionsInput.tsx
+++ b/public/app/features/transformers/suggestionsInput/SuggestionsInput.tsx
@@ -1,6 +1,7 @@
import { css } from '@emotion/css';
import { autoUpdate, flip, shift, useFloating } from '@floating-ui/react';
-import React, { FormEvent, useCallback, useEffect, useRef, useState } from 'react';
+import { FormEvent, useCallback, useEffect, useRef, useState } from 'react';
+import * as React from 'react';
import { GrafanaTheme2, VariableSuggestion } from '@grafana/data';
import { CustomScrollbar, FieldValidationMessage, Input, Portal, useTheme2 } from '@grafana/ui';
diff --git a/public/app/features/transformers/timeSeriesTable/TimeSeriesTableTransformEditor.tsx b/public/app/features/transformers/timeSeriesTable/TimeSeriesTableTransformEditor.tsx
index 872316bb0de..b8387e6889a 100644
--- a/public/app/features/transformers/timeSeriesTable/TimeSeriesTableTransformEditor.tsx
+++ b/public/app/features/transformers/timeSeriesTable/TimeSeriesTableTransformEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import {
PluginState,
diff --git a/public/app/features/users/TokenRevokedModal.tsx b/public/app/features/users/TokenRevokedModal.tsx
index 6f8ae9534af..c48d7a9db04 100644
--- a/public/app/features/users/TokenRevokedModal.tsx
+++ b/public/app/features/users/TokenRevokedModal.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Button, InfoBox, Portal, useStyles2, useTheme2 } from '@grafana/ui';
diff --git a/public/app/features/users/UsersActionBar.test.tsx b/public/app/features/users/UsersActionBar.test.tsx
index e9b527d5d4c..61516544a16 100644
--- a/public/app/features/users/UsersActionBar.test.tsx
+++ b/public/app/features/users/UsersActionBar.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { mockToolkitActionCreator } from 'test/core/redux/mocks';
import { config } from 'app/core/config';
diff --git a/public/app/features/users/UsersActionBar.tsx b/public/app/features/users/UsersActionBar.tsx
index c5b69c379a9..ed09f86ed88 100644
--- a/public/app/features/users/UsersActionBar.tsx
+++ b/public/app/features/users/UsersActionBar.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { RadioButtonGroup, LinkButton, FilterInput, InlineField } from '@grafana/ui';
diff --git a/public/app/features/users/UsersListPage.test.tsx b/public/app/features/users/UsersListPage.test.tsx
index 64b286a417a..4f8f88c3c4a 100644
--- a/public/app/features/users/UsersListPage.test.tsx
+++ b/public/app/features/users/UsersListPage.test.tsx
@@ -1,5 +1,4 @@
import { render } from '@testing-library/react';
-import React from 'react';
import { Provider } from 'react-redux';
import { mockToolkitActionCreator } from 'test/core/redux/mocks';
diff --git a/public/app/features/users/UsersListPage.tsx b/public/app/features/users/UsersListPage.tsx
index 2664d689ba1..357326d28bc 100644
--- a/public/app/features/users/UsersListPage.tsx
+++ b/public/app/features/users/UsersListPage.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { renderMarkdown } from '@grafana/data';
diff --git a/public/app/features/variables/adhoc/AdHocVariableEditor.tsx b/public/app/features/variables/adhoc/AdHocVariableEditor.tsx
index b99328b3f9f..3d4ffa93477 100644
--- a/public/app/features/variables/adhoc/AdHocVariableEditor.tsx
+++ b/public/app/features/variables/adhoc/AdHocVariableEditor.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { AdHocVariableModel, DataSourceInstanceSettings, getDataSourceRef } from '@grafana/data';
diff --git a/public/app/features/variables/adhoc/picker/AdHocFilter.test.tsx b/public/app/features/variables/adhoc/picker/AdHocFilter.test.tsx
index 0e73c602ef4..637a0471357 100644
--- a/public/app/features/variables/adhoc/picker/AdHocFilter.test.tsx
+++ b/public/app/features/variables/adhoc/picker/AdHocFilter.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import selectEvent from 'react-select-event';
import { AdHocVariableFilter } from '@grafana/data';
diff --git a/public/app/features/variables/adhoc/picker/AdHocFilter.tsx b/public/app/features/variables/adhoc/picker/AdHocFilter.tsx
index 8e3a34183cc..06f5757872c 100644
--- a/public/app/features/variables/adhoc/picker/AdHocFilter.tsx
+++ b/public/app/features/variables/adhoc/picker/AdHocFilter.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent, ReactNode } from 'react';
+import { Fragment, PureComponent, ReactNode } from 'react';
import { AdHocVariableFilter, DataSourceRef, SelectableValue } from '@grafana/data';
import { Segment } from '@grafana/ui';
@@ -88,7 +88,7 @@ export class AdHocFilter extends PureComponent {
renderFilterSegments(filter: AdHocVariableFilter, index: number, disabled?: boolean) {
return (
-
+
{
onValueChange={this.onChange(index, 'value')}
allFilters={this.getAllFilters()}
/>
-
+
);
}
}
diff --git a/public/app/features/variables/adhoc/picker/AdHocFilterBuilder.tsx b/public/app/features/variables/adhoc/picker/AdHocFilterBuilder.tsx
index 10511671b89..571d6786169 100644
--- a/public/app/features/variables/adhoc/picker/AdHocFilterBuilder.tsx
+++ b/public/app/features/variables/adhoc/picker/AdHocFilterBuilder.tsx
@@ -1,4 +1,5 @@
-import React, { useCallback, useState } from 'react';
+import { useCallback, useState } from 'react';
+import * as React from 'react';
import { AdHocVariableFilter, DataSourceRef, SelectableValue } from '@grafana/data';
import { t } from 'app/core/internationalization';
diff --git a/public/app/features/variables/adhoc/picker/AdHocFilterKey.tsx b/public/app/features/variables/adhoc/picker/AdHocFilterKey.tsx
index a75cc6765fa..2427fd8384c 100644
--- a/public/app/features/variables/adhoc/picker/AdHocFilterKey.tsx
+++ b/public/app/features/variables/adhoc/picker/AdHocFilterKey.tsx
@@ -1,4 +1,4 @@
-import React, { ReactElement } from 'react';
+import { ReactElement } from 'react';
import { AdHocVariableFilter, DataSourceRef, SelectableValue } from '@grafana/data';
import { Icon, SegmentAsync } from '@grafana/ui';
diff --git a/public/app/features/variables/adhoc/picker/AdHocFilterRenderer.tsx b/public/app/features/variables/adhoc/picker/AdHocFilterRenderer.tsx
index 1a5c8fd0054..6c658f5d18a 100644
--- a/public/app/features/variables/adhoc/picker/AdHocFilterRenderer.tsx
+++ b/public/app/features/variables/adhoc/picker/AdHocFilterRenderer.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { AdHocVariableFilter, DataSourceRef, SelectableValue } from '@grafana/data';
import { AdHocFilterKey } from './AdHocFilterKey';
diff --git a/public/app/features/variables/adhoc/picker/AdHocFilterValue.tsx b/public/app/features/variables/adhoc/picker/AdHocFilterValue.tsx
index 1079e892aa8..f8f18483ed6 100644
--- a/public/app/features/variables/adhoc/picker/AdHocFilterValue.tsx
+++ b/public/app/features/variables/adhoc/picker/AdHocFilterValue.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { AdHocVariableFilter, DataSourceRef, SelectableValue } from '@grafana/data';
import { SegmentAsync, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/variables/adhoc/picker/AdHocPicker.tsx b/public/app/features/variables/adhoc/picker/AdHocPicker.tsx
index 2a1b79ad7e0..b3391cd3302 100644
--- a/public/app/features/variables/adhoc/picker/AdHocPicker.tsx
+++ b/public/app/features/variables/adhoc/picker/AdHocPicker.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { AdHocVariableFilter, AdHocVariableModel } from '@grafana/data';
diff --git a/public/app/features/variables/adhoc/picker/ConditionSegment.tsx b/public/app/features/variables/adhoc/picker/ConditionSegment.tsx
index 4c47fd73433..c4db252ad26 100644
--- a/public/app/features/variables/adhoc/picker/ConditionSegment.tsx
+++ b/public/app/features/variables/adhoc/picker/ConditionSegment.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
interface Props {
label: string;
}
diff --git a/public/app/features/variables/adhoc/picker/OperatorSegment.tsx b/public/app/features/variables/adhoc/picker/OperatorSegment.tsx
index b8646b466e6..20cbd6e29ff 100644
--- a/public/app/features/variables/adhoc/picker/OperatorSegment.tsx
+++ b/public/app/features/variables/adhoc/picker/OperatorSegment.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SelectableValue } from '@grafana/data';
import { Segment } from '@grafana/ui';
diff --git a/public/app/features/variables/constant/ConstantVariableEditor.tsx b/public/app/features/variables/constant/ConstantVariableEditor.tsx
index 2f26c9ed80c..6325ef2890c 100644
--- a/public/app/features/variables/constant/ConstantVariableEditor.tsx
+++ b/public/app/features/variables/constant/ConstantVariableEditor.tsx
@@ -1,4 +1,4 @@
-import React, { FormEvent, PureComponent } from 'react';
+import { FormEvent, PureComponent } from 'react';
import { ConstantVariableModel } from '@grafana/data';
import { ConstantVariableForm } from 'app/features/dashboard-scene/settings/variables/components/ConstantVariableForm';
diff --git a/public/app/features/variables/custom/CustomVariableEditor.tsx b/public/app/features/variables/custom/CustomVariableEditor.tsx
index c2a31cf0ab4..7488326cec7 100644
--- a/public/app/features/variables/custom/CustomVariableEditor.tsx
+++ b/public/app/features/variables/custom/CustomVariableEditor.tsx
@@ -1,4 +1,4 @@
-import React, { FormEvent, PureComponent } from 'react';
+import { FormEvent, PureComponent } from 'react';
import { MapDispatchToProps, MapStateToProps } from 'react-redux';
import { CustomVariableModel, VariableWithMultiSupport } from '@grafana/data';
diff --git a/public/app/features/variables/datasource/DataSourceVariableEditor.test.tsx b/public/app/features/variables/datasource/DataSourceVariableEditor.test.tsx
index ec4c34245ea..639775dd88d 100644
--- a/public/app/features/variables/datasource/DataSourceVariableEditor.test.tsx
+++ b/public/app/features/variables/datasource/DataSourceVariableEditor.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { selectOptionInTest, getSelectParent } from 'test/helpers/selectOptionInTest';
import { DataSourceVariableEditorUnConnected as DataSourceVariableEditor } from './DataSourceVariableEditor';
diff --git a/public/app/features/variables/datasource/DataSourceVariableEditor.tsx b/public/app/features/variables/datasource/DataSourceVariableEditor.tsx
index 123465aa495..2f9116d4d7b 100644
--- a/public/app/features/variables/datasource/DataSourceVariableEditor.tsx
+++ b/public/app/features/variables/datasource/DataSourceVariableEditor.tsx
@@ -1,4 +1,4 @@
-import React, { FormEvent, PureComponent } from 'react';
+import { FormEvent, PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { DataSourceVariableModel, SelectableValue, VariableWithMultiSupport } from '@grafana/data';
diff --git a/public/app/features/variables/editor/ConfirmDeleteModal.tsx b/public/app/features/variables/editor/ConfirmDeleteModal.tsx
index 2e412d3f776..8b40c3d4adc 100644
--- a/public/app/features/variables/editor/ConfirmDeleteModal.tsx
+++ b/public/app/features/variables/editor/ConfirmDeleteModal.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { ConfirmModal } from '@grafana/ui';
diff --git a/public/app/features/variables/editor/LegacyVariableQueryEditor.tsx b/public/app/features/variables/editor/LegacyVariableQueryEditor.tsx
index 2b5f3e24317..8556ca9da52 100644
--- a/public/app/features/variables/editor/LegacyVariableQueryEditor.tsx
+++ b/public/app/features/variables/editor/LegacyVariableQueryEditor.tsx
@@ -1,5 +1,6 @@
import { useId } from '@react-aria/utils';
-import React, { useCallback, useState } from 'react';
+import { useCallback, useState } from 'react';
+import * as React from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { TextArea, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/variables/editor/SelectionOptionsEditor.tsx b/public/app/features/variables/editor/SelectionOptionsEditor.tsx
index 7e0e4f4af81..19a76027aee 100644
--- a/public/app/features/variables/editor/SelectionOptionsEditor.tsx
+++ b/public/app/features/variables/editor/SelectionOptionsEditor.tsx
@@ -1,4 +1,4 @@
-import React, { ChangeEvent, FormEvent, useCallback } from 'react';
+import { ChangeEvent, FormEvent, useCallback } from 'react';
import { VariableWithMultiSupport } from '@grafana/data';
import { SelectionOptionsForm } from 'app/features/dashboard-scene/settings/variables/components/SelectionOptionsForm';
diff --git a/public/app/features/variables/editor/VariableEditorContainer.tsx b/public/app/features/variables/editor/VariableEditorContainer.tsx
index 41ccf9daf76..213d86f849d 100644
--- a/public/app/features/variables/editor/VariableEditorContainer.tsx
+++ b/public/app/features/variables/editor/VariableEditorContainer.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { bindActionCreators } from 'redux';
diff --git a/public/app/features/variables/editor/VariableEditorEditor.tsx b/public/app/features/variables/editor/VariableEditorEditor.tsx
index 8c59ea08378..732fcd59586 100644
--- a/public/app/features/variables/editor/VariableEditorEditor.tsx
+++ b/public/app/features/variables/editor/VariableEditorEditor.tsx
@@ -1,5 +1,5 @@
import { css, keyframes } from '@emotion/css';
-import React, { FormEvent, PureComponent } from 'react';
+import { FormEvent, PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { bindActionCreators } from 'redux';
diff --git a/public/app/features/variables/editor/VariableEditorList.tsx b/public/app/features/variables/editor/VariableEditorList.tsx
index 7dc62f8e86d..a57a50b19c2 100644
--- a/public/app/features/variables/editor/VariableEditorList.tsx
+++ b/public/app/features/variables/editor/VariableEditorList.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { ReactElement } from 'react';
+import { ReactElement } from 'react';
import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd';
import { TypedVariableModel } from '@grafana/data';
diff --git a/public/app/features/variables/editor/VariableEditorListRow.tsx b/public/app/features/variables/editor/VariableEditorListRow.tsx
index befc897d5a5..15ef6fc4c90 100644
--- a/public/app/features/variables/editor/VariableEditorListRow.tsx
+++ b/public/app/features/variables/editor/VariableEditorListRow.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { ReactElement } from 'react';
+import { ReactElement } from 'react';
import { Draggable } from 'react-beautiful-dnd';
import { GrafanaTheme2, TypedVariableModel } from '@grafana/data';
diff --git a/public/app/features/variables/editor/VariableTypeSelect.tsx b/public/app/features/variables/editor/VariableTypeSelect.tsx
index 65d80f7d83e..bb3b643cc32 100644
--- a/public/app/features/variables/editor/VariableTypeSelect.tsx
+++ b/public/app/features/variables/editor/VariableTypeSelect.tsx
@@ -1,4 +1,4 @@
-import React, { PropsWithChildren, useMemo } from 'react';
+import { PropsWithChildren, useMemo } from 'react';
import { SelectableValue, VariableType } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/variables/editor/getVariableQueryEditor.tsx b/public/app/features/variables/editor/getVariableQueryEditor.tsx
index 5d2d34d4c0d..2e4177ef10d 100644
--- a/public/app/features/variables/editor/getVariableQueryEditor.tsx
+++ b/public/app/features/variables/editor/getVariableQueryEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { DataQuery, DataSourceApi, DataSourceJsonData, QueryEditorProps, StandardVariableQuery } from '@grafana/data';
import { getTemplateSrv } from '@grafana/runtime';
diff --git a/public/app/features/variables/inspect/NetworkGraph.tsx b/public/app/features/variables/inspect/NetworkGraph.tsx
index 12c2d0a843b..46d25fb3266 100644
--- a/public/app/features/variables/inspect/NetworkGraph.tsx
+++ b/public/app/features/variables/inspect/NetworkGraph.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useEffect, useRef } from 'react';
+import { useCallback, useEffect, useRef } from 'react';
import { GraphEdge, GraphNode } from './utils';
diff --git a/public/app/features/variables/inspect/NetworkGraphModal.tsx b/public/app/features/variables/inspect/NetworkGraphModal.tsx
index 2effdbb2b4e..e6efc4d953c 100644
--- a/public/app/features/variables/inspect/NetworkGraphModal.tsx
+++ b/public/app/features/variables/inspect/NetworkGraphModal.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useState } from 'react';
+import { useCallback, useState } from 'react';
import { Modal } from '@grafana/ui';
diff --git a/public/app/features/variables/inspect/VariableUsagesButton.tsx b/public/app/features/variables/inspect/VariableUsagesButton.tsx
index 5ac6ebcdd6a..ca1f9e40c79 100644
--- a/public/app/features/variables/inspect/VariableUsagesButton.tsx
+++ b/public/app/features/variables/inspect/VariableUsagesButton.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { reportInteraction } from '@grafana/runtime';
import { IconButton } from '@grafana/ui';
diff --git a/public/app/features/variables/inspect/VariablesDependenciesButton.tsx b/public/app/features/variables/inspect/VariablesDependenciesButton.tsx
index f57527a86be..a341637feb4 100644
--- a/public/app/features/variables/inspect/VariablesDependenciesButton.tsx
+++ b/public/app/features/variables/inspect/VariablesDependenciesButton.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { TypedVariableModel } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime';
diff --git a/public/app/features/variables/inspect/VariablesUnknownButton.tsx b/public/app/features/variables/inspect/VariablesUnknownButton.tsx
index 6a842225be3..ca60f473528 100644
--- a/public/app/features/variables/inspect/VariablesUnknownButton.tsx
+++ b/public/app/features/variables/inspect/VariablesUnknownButton.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { IconButton } from '@grafana/ui';
diff --git a/public/app/features/variables/inspect/VariablesUnknownTable.test.tsx b/public/app/features/variables/inspect/VariablesUnknownTable.test.tsx
index 490b65b6b75..8a8c80ce049 100644
--- a/public/app/features/variables/inspect/VariablesUnknownTable.test.tsx
+++ b/public/app/features/variables/inspect/VariablesUnknownTable.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import * as runtime from '@grafana/runtime';
diff --git a/public/app/features/variables/inspect/VariablesUnknownTable.tsx b/public/app/features/variables/inspect/VariablesUnknownTable.tsx
index 1c7e68f552c..fa788237584 100644
--- a/public/app/features/variables/inspect/VariablesUnknownTable.tsx
+++ b/public/app/features/variables/inspect/VariablesUnknownTable.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { ReactElement, useEffect, useState } from 'react';
+import { ReactElement, useEffect, useState } from 'react';
import { useAsync } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/features/variables/interval/IntervalVariableEditor.tsx b/public/app/features/variables/interval/IntervalVariableEditor.tsx
index 88504924769..50dc472ea72 100644
--- a/public/app/features/variables/interval/IntervalVariableEditor.tsx
+++ b/public/app/features/variables/interval/IntervalVariableEditor.tsx
@@ -1,4 +1,4 @@
-import React, { ChangeEvent, FormEvent } from 'react';
+import { memo, ChangeEvent, FormEvent } from 'react';
import { IntervalVariableModel, SelectableValue } from '@grafana/data';
import { IntervalVariableForm } from 'app/features/dashboard-scene/settings/variables/components/IntervalVariableForm';
@@ -7,7 +7,7 @@ import { VariableEditorProps } from '../editor/types';
export interface Props extends VariableEditorProps {}
-export const IntervalVariableEditor = React.memo(({ onPropChange, variable }: Props) => {
+export const IntervalVariableEditor = memo(({ onPropChange, variable }: Props) => {
const onAutoChange = (event: ChangeEvent) => {
onPropChange({
propName: 'auto',
diff --git a/public/app/features/variables/pickers/OptionsPicker/OptionPicker.test.tsx b/public/app/features/variables/pickers/OptionsPicker/OptionPicker.test.tsx
index 84fd2607cd4..232798e0651 100644
--- a/public/app/features/variables/pickers/OptionsPicker/OptionPicker.test.tsx
+++ b/public/app/features/variables/pickers/OptionsPicker/OptionPicker.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { Provider } from 'react-redux';
import { Store } from 'redux';
diff --git a/public/app/features/variables/pickers/OptionsPicker/OptionsPicker.tsx b/public/app/features/variables/pickers/OptionsPicker/OptionsPicker.tsx
index 16756faa5e2..7a52df41e12 100644
--- a/public/app/features/variables/pickers/OptionsPicker/OptionsPicker.tsx
+++ b/public/app/features/variables/pickers/OptionsPicker/OptionsPicker.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { ComponentType, PureComponent } from 'react';
+import { ComponentType, PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { bindActionCreators } from 'redux';
diff --git a/public/app/features/variables/pickers/PickerRenderer.tsx b/public/app/features/variables/pickers/PickerRenderer.tsx
index c410f617b9f..0b796f9c02b 100644
--- a/public/app/features/variables/pickers/PickerRenderer.tsx
+++ b/public/app/features/variables/pickers/PickerRenderer.tsx
@@ -1,4 +1,4 @@
-import React, { PropsWithChildren, ReactElement, useMemo } from 'react';
+import { PropsWithChildren, ReactElement, useMemo } from 'react';
import { TypedVariableModel, VariableHide } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/variables/pickers/shared/VariableInput.tsx b/public/app/features/variables/pickers/shared/VariableInput.tsx
index 423254ec0ca..657e7912915 100644
--- a/public/app/features/variables/pickers/shared/VariableInput.tsx
+++ b/public/app/features/variables/pickers/shared/VariableInput.tsx
@@ -1,4 +1,5 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
+import * as React from 'react';
import { t } from 'app/core/internationalization';
diff --git a/public/app/features/variables/pickers/shared/VariableLink.tsx b/public/app/features/variables/pickers/shared/VariableLink.tsx
index 206056e750c..25e6c0694e6 100644
--- a/public/app/features/variables/pickers/shared/VariableLink.tsx
+++ b/public/app/features/variables/pickers/shared/VariableLink.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { MouseEvent, useCallback } from 'react';
+import { MouseEvent, useCallback } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/variables/pickers/shared/VariableOptions.tsx b/public/app/features/variables/pickers/shared/VariableOptions.tsx
index 48576d75c86..b31905f8b1b 100644
--- a/public/app/features/variables/pickers/shared/VariableOptions.tsx
+++ b/public/app/features/variables/pickers/shared/VariableOptions.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
+import * as React from 'react';
import { GrafanaTheme2, VariableOption } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/variables/query/QueryVariableEditor.test.tsx b/public/app/features/variables/query/QueryVariableEditor.test.tsx
index b73f83b0668..a621722e2bd 100644
--- a/public/app/features/variables/query/QueryVariableEditor.test.tsx
+++ b/public/app/features/variables/query/QueryVariableEditor.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, act } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { MockDataSourceApi } from 'test/mocks/datasource_srv';
import { QueryVariableModel, VariableSupportType } from '@grafana/data';
diff --git a/public/app/features/variables/query/QueryVariableEditor.tsx b/public/app/features/variables/query/QueryVariableEditor.tsx
index 5f920f7b2de..a10700237bd 100644
--- a/public/app/features/variables/query/QueryVariableEditor.tsx
+++ b/public/app/features/variables/query/QueryVariableEditor.tsx
@@ -1,4 +1,4 @@
-import React, { FormEvent, PureComponent } from 'react';
+import { FormEvent, PureComponent } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import {
diff --git a/public/app/features/variables/query/QueryVariableRefreshSelect.tsx b/public/app/features/variables/query/QueryVariableRefreshSelect.tsx
index 88475bcc75e..8a42bec5c4b 100644
--- a/public/app/features/variables/query/QueryVariableRefreshSelect.tsx
+++ b/public/app/features/variables/query/QueryVariableRefreshSelect.tsx
@@ -1,4 +1,4 @@
-import React, { PropsWithChildren, useMemo, useState } from 'react';
+import { PropsWithChildren, useMemo, useState } from 'react';
import { VariableRefresh } from '@grafana/data';
import { Field, RadioButtonGroup, useTheme2 } from '@grafana/ui';
diff --git a/public/app/features/variables/query/QueryVariableSortSelect.tsx b/public/app/features/variables/query/QueryVariableSortSelect.tsx
index f5e70612a27..5cb287456df 100644
--- a/public/app/features/variables/query/QueryVariableSortSelect.tsx
+++ b/public/app/features/variables/query/QueryVariableSortSelect.tsx
@@ -1,4 +1,4 @@
-import React, { PropsWithChildren, useMemo } from 'react';
+import { PropsWithChildren, useMemo } from 'react';
import { SelectableValue, VariableSort } from '@grafana/data';
diff --git a/public/app/features/variables/query/actions.test.tsx b/public/app/features/variables/query/actions.test.tsx
index 9dcdddfa5a2..72cfc067092 100644
--- a/public/app/features/variables/query/actions.test.tsx
+++ b/public/app/features/variables/query/actions.test.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import {
DataSourceApi,
DataSourceRef,
diff --git a/public/app/features/variables/textbox/TextBoxVariableEditor.tsx b/public/app/features/variables/textbox/TextBoxVariableEditor.tsx
index 7a9f3ee054b..2e620b997ad 100644
--- a/public/app/features/variables/textbox/TextBoxVariableEditor.tsx
+++ b/public/app/features/variables/textbox/TextBoxVariableEditor.tsx
@@ -1,4 +1,4 @@
-import React, { FormEvent, ReactElement, useCallback } from 'react';
+import { FormEvent, ReactElement, useCallback } from 'react';
import { TextBoxVariableModel } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/features/variables/textbox/TextBoxVariablePicker.tsx b/public/app/features/variables/textbox/TextBoxVariablePicker.tsx
index 4035db8b48f..7c98afe24cc 100644
--- a/public/app/features/variables/textbox/TextBoxVariablePicker.tsx
+++ b/public/app/features/variables/textbox/TextBoxVariablePicker.tsx
@@ -1,4 +1,4 @@
-import React, { ChangeEvent, FocusEvent, KeyboardEvent, ReactElement, useCallback, useEffect, useState } from 'react';
+import { ChangeEvent, FocusEvent, KeyboardEvent, ReactElement, useCallback, useEffect, useState } from 'react';
import { TextBoxVariableModel, isEmptyObject } from '@grafana/data';
import { Input } from '@grafana/ui';
diff --git a/public/app/features/visualization/data-hover/ComplexDataHoverView.tsx b/public/app/features/visualization/data-hover/ComplexDataHoverView.tsx
index f0b505a7f9f..80918d6ee25 100644
--- a/public/app/features/visualization/data-hover/ComplexDataHoverView.tsx
+++ b/public/app/features/visualization/data-hover/ComplexDataHoverView.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { CloseButton } from 'app/core/components/CloseButton/CloseButton';
import { GeomapLayerHover } from 'app/plugins/panel/geomap/event';
diff --git a/public/app/features/visualization/data-hover/DataHoverRow.tsx b/public/app/features/visualization/data-hover/DataHoverRow.tsx
index 5c8a38a6480..609d3a68e0a 100644
--- a/public/app/features/visualization/data-hover/DataHoverRow.tsx
+++ b/public/app/features/visualization/data-hover/DataHoverRow.tsx
@@ -1,5 +1,4 @@
import { FeatureLike } from 'ol/Feature';
-import React from 'react';
import { ArrayDataFrame, DataFrame } from '@grafana/data';
diff --git a/public/app/features/visualization/data-hover/DataHoverRows.tsx b/public/app/features/visualization/data-hover/DataHoverRows.tsx
index cbd9e156aea..5d09dd5a206 100644
--- a/public/app/features/visualization/data-hover/DataHoverRows.tsx
+++ b/public/app/features/visualization/data-hover/DataHoverRows.tsx
@@ -1,7 +1,8 @@
import { css } from '@emotion/css';
import { isString } from 'lodash';
import { FeatureLike } from 'ol/Feature';
-import React, { useState } from 'react';
+import { useState } from 'react';
+import * as React from 'react';
import { DataFrame, FieldType, getFieldDisplayName, GrafanaTheme2 } from '@grafana/data';
import { Collapse, TabContent, useStyles2 } from '@grafana/ui';
diff --git a/public/app/features/visualization/data-hover/DataHoverTabs.tsx b/public/app/features/visualization/data-hover/DataHoverTabs.tsx
index 30f6d111a77..bb4efffed76 100644
--- a/public/app/features/visualization/data-hover/DataHoverTabs.tsx
+++ b/public/app/features/visualization/data-hover/DataHoverTabs.tsx
@@ -1,4 +1,4 @@
-import React, { Dispatch, SetStateAction } from 'react';
+import { Dispatch, SetStateAction } from 'react';
import { Tab, TabsBar } from '@grafana/ui';
import { GeomapLayerHover } from 'app/plugins/panel/geomap/event';
diff --git a/public/app/features/visualization/data-hover/DataHoverView.test.tsx b/public/app/features/visualization/data-hover/DataHoverView.test.tsx
index 9eb294be2e2..b5b2eef3c55 100644
--- a/public/app/features/visualization/data-hover/DataHoverView.test.tsx
+++ b/public/app/features/visualization/data-hover/DataHoverView.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { ArrayDataFrame } from '@grafana/data';
diff --git a/public/app/features/visualization/data-hover/DataHoverView.tsx b/public/app/features/visualization/data-hover/DataHoverView.tsx
index 71ebcf5f3ae..adc593a9a14 100644
--- a/public/app/features/visualization/data-hover/DataHoverView.tsx
+++ b/public/app/features/visualization/data-hover/DataHoverView.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import {
arrayUtils,
diff --git a/public/app/features/visualization/data-hover/ExemplarHoverView.tsx b/public/app/features/visualization/data-hover/ExemplarHoverView.tsx
index 42157a961f8..14b4db2dfc1 100644
--- a/public/app/features/visualization/data-hover/ExemplarHoverView.tsx
+++ b/public/app/features/visualization/data-hover/ExemplarHoverView.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2, LinkModel } from '@grafana/data';
import { DataLinkButton, useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/alertmanager/ConfigEditor.tsx b/public/app/plugins/datasource/alertmanager/ConfigEditor.tsx
index 923e44e1110..748fb691ce0 100644
--- a/public/app/plugins/datasource/alertmanager/ConfigEditor.tsx
+++ b/public/app/plugins/datasource/alertmanager/ConfigEditor.tsx
@@ -1,5 +1,5 @@
import { produce } from 'immer';
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import { Link } from 'react-router-dom';
import { SIGV4ConnectionConfig } from '@grafana/aws-sdk';
diff --git a/public/app/plugins/datasource/azuremonitor/components/ArgQueryEditor/ArgQueryEditor.test.tsx b/public/app/plugins/datasource/azuremonitor/components/ArgQueryEditor/ArgQueryEditor.test.tsx
index 92564c4c7dc..d91ddd5bbbd 100644
--- a/public/app/plugins/datasource/azuremonitor/components/ArgQueryEditor/ArgQueryEditor.test.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/ArgQueryEditor/ArgQueryEditor.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import createMockDatasource from '../../__mocks__/datasource';
import createMockQuery from '../../__mocks__/query';
diff --git a/public/app/plugins/datasource/azuremonitor/components/ArgQueryEditor/ArgQueryEditor.tsx b/public/app/plugins/datasource/azuremonitor/components/ArgQueryEditor/ArgQueryEditor.tsx
index cc0d1ce82d9..a06b3739072 100644
--- a/public/app/plugins/datasource/azuremonitor/components/ArgQueryEditor/ArgQueryEditor.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/ArgQueryEditor/ArgQueryEditor.tsx
@@ -1,5 +1,5 @@
import { intersection } from 'lodash';
-import React, { useState, useMemo } from 'react';
+import { useState, useMemo } from 'react';
import { EditorFieldGroup, EditorRow, EditorRows } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/azuremonitor/components/ArgQueryEditor/QueryField.tsx b/public/app/plugins/datasource/azuremonitor/components/ArgQueryEditor/QueryField.tsx
index 1d168835838..d6a69f3f3b4 100644
--- a/public/app/plugins/datasource/azuremonitor/components/ArgQueryEditor/QueryField.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/ArgQueryEditor/QueryField.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { CodeEditor } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/azuremonitor/components/ArgQueryEditor/SubscriptionField.tsx b/public/app/plugins/datasource/azuremonitor/components/ArgQueryEditor/SubscriptionField.tsx
index 019edbf1915..e99b1dcaf77 100644
--- a/public/app/plugins/datasource/azuremonitor/components/ArgQueryEditor/SubscriptionField.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/ArgQueryEditor/SubscriptionField.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useMemo, useState } from 'react';
+import { useEffect, useMemo, useState } from 'react';
import { SelectableValue } from '@grafana/data';
import { FieldValidationMessage, MultiSelect } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/AppRegistrationCredentials.tsx b/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/AppRegistrationCredentials.tsx
index 88ef5186df2..d953ea5829f 100644
--- a/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/AppRegistrationCredentials.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/AppRegistrationCredentials.tsx
@@ -1,4 +1,4 @@
-import React, { ChangeEvent } from 'react';
+import { ChangeEvent } from 'react';
import { SelectableValue } from '@grafana/data';
import { Field, Select, Input, Button } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/AzureCredentialsForm.test.tsx b/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/AzureCredentialsForm.test.tsx
index 8f4a820e9d1..0ebe2f2f456 100644
--- a/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/AzureCredentialsForm.test.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/AzureCredentialsForm.test.tsx
@@ -1,5 +1,4 @@
import { render, screen, waitFor } from '@testing-library/react';
-import React from 'react';
import AzureCredentialsForm, { Props } from './AzureCredentialsForm';
diff --git a/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/AzureCredentialsForm.tsx b/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/AzureCredentialsForm.tsx
index 9cdd9e0682c..92a7aa76431 100644
--- a/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/AzureCredentialsForm.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/AzureCredentialsForm.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { getAzureClouds } from '@grafana/azure-sdk';
import { SelectableValue } from '@grafana/data';
diff --git a/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/BasicLogsToggle.test.tsx b/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/BasicLogsToggle.test.tsx
index 3547987167b..69d28318934 100644
--- a/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/BasicLogsToggle.test.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/BasicLogsToggle.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { createMockInstanceSetttings } from '../../__mocks__/instanceSettings';
diff --git a/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/BasicLogsToggle.tsx b/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/BasicLogsToggle.tsx
index 7cf47c13a80..4c674701b6e 100644
--- a/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/BasicLogsToggle.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/BasicLogsToggle.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { Field, Switch, useTheme2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/ConfigEditor.test.tsx b/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/ConfigEditor.test.tsx
index 41769111071..5f9f7f79235 100644
--- a/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/ConfigEditor.test.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/ConfigEditor.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import ConfigEditor from './ConfigEditor';
diff --git a/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/ConfigEditor.tsx b/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/ConfigEditor.tsx
index 5d2c138e4c9..bf1d2b1c90d 100644
--- a/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/ConfigEditor.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/ConfigEditor.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { DataSourcePluginOptionsEditorProps, SelectableValue, updateDatasourcePluginOption } from '@grafana/data';
import { ConfigSection, DataSourceDescription } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/CurrentUserFallbackCredentials.test.tsx b/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/CurrentUserFallbackCredentials.test.tsx
index 6d83fa80a35..07ca09121f8 100644
--- a/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/CurrentUserFallbackCredentials.test.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/CurrentUserFallbackCredentials.test.tsx
@@ -1,5 +1,4 @@
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
-import React from 'react';
import { config } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/CurrentUserFallbackCredentials.tsx b/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/CurrentUserFallbackCredentials.tsx
index 2341854b810..9802c32752b 100644
--- a/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/CurrentUserFallbackCredentials.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/CurrentUserFallbackCredentials.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { SelectableValue } from '@grafana/data';
import { ConfigSection } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/DefaultSubscription.test.tsx b/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/DefaultSubscription.test.tsx
index 9b5904684cd..b10c96daa47 100644
--- a/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/DefaultSubscription.test.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/DefaultSubscription.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { createMockInstanceSetttings } from '../../__mocks__/instanceSettings';
import { selectors } from '../../e2e/selectors';
diff --git a/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/DefaultSubscription.tsx b/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/DefaultSubscription.tsx
index c7bc2b33bf8..bc8e7c79649 100644
--- a/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/DefaultSubscription.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/DefaultSubscription.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useReducer } from 'react';
+import { useEffect, useReducer } from 'react';
import { SelectableValue } from '@grafana/data';
import { Select, Button, Field } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/MonitorConfig.tsx b/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/MonitorConfig.tsx
index 698f8911123..d82b2d0aa54 100644
--- a/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/MonitorConfig.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/ConfigEditor/MonitorConfig.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
import { useEffectOnce } from 'react-use';
import { SelectableValue } from '@grafana/data';
diff --git a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/AdvancedResourcePicker.test.tsx b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/AdvancedResourcePicker.test.tsx
index 91eaa57842d..2236e773e69 100644
--- a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/AdvancedResourcePicker.test.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/AdvancedResourcePicker.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import AdvancedResourcePicker from './AdvancedResourcePicker';
diff --git a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/AdvancedResourcePicker.tsx b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/AdvancedResourcePicker.tsx
index fc5d7347507..26efe10eb20 100644
--- a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/AdvancedResourcePicker.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/AdvancedResourcePicker.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { AccessoryButton } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/AzureCheatSheet.tsx b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/AzureCheatSheet.tsx
index 5bbe2b89937..f415eb7fa56 100644
--- a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/AzureCheatSheet.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/AzureCheatSheet.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useMemo, useState } from 'react';
+import { useEffect, useMemo, useState } from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/AzureCheatSheetModal.tsx b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/AzureCheatSheetModal.tsx
index 3df12d38a8c..389611123f0 100644
--- a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/AzureCheatSheetModal.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/AzureCheatSheetModal.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { CoreApp } from '@grafana/data';
import { Modal } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/LogsManagement.test.tsx b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/LogsManagement.test.tsx
index a9a12762410..0f81976cb63 100644
--- a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/LogsManagement.test.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/LogsManagement.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import createMockDatasource from '../../__mocks__/datasource';
import createMockQuery from '../../__mocks__/query';
diff --git a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/LogsManagement.tsx b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/LogsManagement.tsx
index fb4de553c42..6d7414967bf 100644
--- a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/LogsManagement.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/LogsManagement.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { ConfirmModal, InlineField, RadioButtonGroup } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/LogsQueryEditor.test.tsx b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/LogsQueryEditor.test.tsx
index 3c55dfcba66..62bb41281bd 100644
--- a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/LogsQueryEditor.test.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/LogsQueryEditor.test.tsx
@@ -1,6 +1,5 @@
import { act, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { dateTime, LoadingState } from '@grafana/data';
diff --git a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/LogsQueryEditor.tsx b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/LogsQueryEditor.tsx
index 77da2ba7793..b4c2078a2e9 100644
--- a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/LogsQueryEditor.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/LogsQueryEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { PanelData, TimeRange } from '@grafana/data';
import { EditorFieldGroup, EditorRow, EditorRows } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/QueryField.tsx b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/QueryField.tsx
index 2c978f0a8f5..e540de2bf21 100644
--- a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/QueryField.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/QueryField.tsx
@@ -1,5 +1,5 @@
import { EngineSchema, getKustoWorker } from '@kusto/monaco-kusto';
-import React, { useCallback, useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
import { CodeEditor, Monaco, MonacoEditor } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/RawQuery.tsx b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/RawQuery.tsx
index 4d1f727e9f3..60b0d6fd765 100644
--- a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/RawQuery.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/RawQuery.tsx
@@ -1,6 +1,5 @@
import { css, cx } from '@emotion/css';
import Prism, { Grammar } from 'prismjs';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data/src';
import { useTheme2 } from '@grafana/ui/src';
diff --git a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/TimeManagement.test.tsx b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/TimeManagement.test.tsx
index a8c4b7dc6fe..5ba125daa21 100644
--- a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/TimeManagement.test.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/TimeManagement.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import createMockDatasource from '../../__mocks__/datasource';
import createMockQuery from '../../__mocks__/query';
diff --git a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/TimeManagement.tsx b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/TimeManagement.tsx
index cf910c14f0c..a8bda61a4ac 100644
--- a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/TimeManagement.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/TimeManagement.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
import { SelectableValue } from '@grafana/data';
import { InlineField, RadioButtonGroup, Select } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/AdvancedResourcePicker.test.tsx b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/AdvancedResourcePicker.test.tsx
index 8ff8908e1aa..8da6e3aca89 100644
--- a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/AdvancedResourcePicker.test.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/AdvancedResourcePicker.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import AdvancedResourcePicker from './AdvancedResourcePicker';
diff --git a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/AdvancedResourcePicker.tsx b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/AdvancedResourcePicker.tsx
index dcbc0bf216e..b052df9448c 100644
--- a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/AdvancedResourcePicker.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/AdvancedResourcePicker.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { AccessoryButton } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/AggregationField.test.tsx b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/AggregationField.test.tsx
index c4fbc01027e..13a003a20a0 100644
--- a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/AggregationField.test.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/AggregationField.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import createMockDatasource from '../../__mocks__/datasource';
import createMockQuery from '../../__mocks__/query';
diff --git a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/AggregationField.tsx b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/AggregationField.tsx
index f464a8ae92b..b148263d631 100644
--- a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/AggregationField.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/AggregationField.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { SelectableValue } from '@grafana/data';
import { Select } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/DimensionFields.test.tsx b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/DimensionFields.test.tsx
index dfc44481ba8..56c46866f8d 100644
--- a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/DimensionFields.test.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/DimensionFields.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { openMenu } from 'react-select-event';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/DimensionFields.tsx b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/DimensionFields.tsx
index 68fde041f70..b7b7c2f13d6 100644
--- a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/DimensionFields.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/DimensionFields.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useMemo, useState } from 'react';
+import { useEffect, useMemo, useState } from 'react';
import { SelectableValue, DataFrame, PanelData, Labels } from '@grafana/data';
import { EditorList, AccessoryButton } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/LegendFormatField.tsx b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/LegendFormatField.tsx
index 142fea28167..143cf2bc94f 100644
--- a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/LegendFormatField.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/LegendFormatField.tsx
@@ -1,4 +1,5 @@
-import React, { useCallback, useState } from 'react';
+import { useCallback, useState } from 'react';
+import * as React from 'react';
import { Input } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricNameField.test.tsx b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricNameField.test.tsx
index aff65cef929..72813a642b9 100644
--- a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricNameField.test.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricNameField.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import createMockDatasource from '../../__mocks__/datasource';
import createMockQuery from '../../__mocks__/query';
diff --git a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricNameField.tsx b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricNameField.tsx
index e4d0fcd4ef3..2de02b2dc75 100644
--- a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricNameField.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricNameField.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { SelectableValue } from '@grafana/data';
import { Select } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricNamespaceField.test.tsx b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricNamespaceField.test.tsx
index 0f4ccda07bd..6fd05b9979c 100644
--- a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricNamespaceField.test.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricNamespaceField.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import createMockDatasource from '../../__mocks__/datasource';
import createMockQuery from '../../__mocks__/query';
diff --git a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricNamespaceField.tsx b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricNamespaceField.tsx
index 36abff0a15d..07d0d7400c3 100644
--- a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricNamespaceField.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricNamespaceField.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { SelectableValue } from '@grafana/data';
import { Select } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricsQueryEditor.test.tsx b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricsQueryEditor.test.tsx
index f943064654f..49dc9f2a99c 100644
--- a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricsQueryEditor.test.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricsQueryEditor.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import createMockDatasource from '../../__mocks__/datasource';
import { createMockInstanceSetttings } from '../../__mocks__/instanceSettings';
diff --git a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricsQueryEditor.tsx b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricsQueryEditor.tsx
index e4dc2e2fed1..a312c2ecddd 100644
--- a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricsQueryEditor.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/MetricsQueryEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PanelData } from '@grafana/data/src/types';
import { EditorRows, EditorRow, EditorFieldGroup } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/TimeGrainField.test.tsx b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/TimeGrainField.test.tsx
index e1c0aa5bf00..a619620d06d 100644
--- a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/TimeGrainField.test.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/TimeGrainField.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import createMockDatasource from '../../__mocks__/datasource';
import createMockQuery from '../../__mocks__/query';
diff --git a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/TimeGrainField.tsx b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/TimeGrainField.tsx
index 9739f1bd4cf..c23312bcd69 100644
--- a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/TimeGrainField.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/TimeGrainField.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useMemo } from 'react';
+import { useCallback, useMemo } from 'react';
import { SelectableValue } from '@grafana/data';
import { Select } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/TopField.tsx b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/TopField.tsx
index 3996b02fce3..3010fed7438 100644
--- a/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/TopField.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/TopField.tsx
@@ -1,4 +1,5 @@
-import React, { useCallback, useState } from 'react';
+import { useCallback, useState } from 'react';
+import * as React from 'react';
import { Input } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/azuremonitor/components/QueryEditor/QueryEditor.test.tsx b/public/app/plugins/datasource/azuremonitor/components/QueryEditor/QueryEditor.test.tsx
index 744aec9063c..18cd93f66da 100644
--- a/public/app/plugins/datasource/azuremonitor/components/QueryEditor/QueryEditor.test.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/QueryEditor/QueryEditor.test.tsx
@@ -1,5 +1,4 @@
import { render, screen, waitFor } from '@testing-library/react';
-import React from 'react';
import { CoreApp } from '@grafana/data';
import { config } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/azuremonitor/components/QueryEditor/QueryEditor.tsx b/public/app/plugins/datasource/azuremonitor/components/QueryEditor/QueryEditor.tsx
index 6dfed0a2146..a993857c066 100644
--- a/public/app/plugins/datasource/azuremonitor/components/QueryEditor/QueryEditor.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/QueryEditor/QueryEditor.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { debounce } from 'lodash';
-import React, { useCallback, useMemo, useState } from 'react';
+import { useCallback, useMemo, useState } from 'react';
import { CoreApp, QueryEditorProps } from '@grafana/data';
import { config, reportInteraction } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/azuremonitor/components/QueryEditor/QueryHeader.tsx b/public/app/plugins/datasource/azuremonitor/components/QueryEditor/QueryHeader.tsx
index 262fe27e68e..737053e81db 100644
--- a/public/app/plugins/datasource/azuremonitor/components/QueryEditor/QueryHeader.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/QueryEditor/QueryHeader.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { SelectableValue } from '@grafana/data';
import { EditorHeader, InlineSelect } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/azuremonitor/components/ResourceField/ResourceField.tsx b/public/app/plugins/datasource/azuremonitor/components/ResourceField/ResourceField.tsx
index af946a07dc5..7a9d0b3553f 100644
--- a/public/app/plugins/datasource/azuremonitor/components/ResourceField/ResourceField.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/ResourceField/ResourceField.tsx
@@ -1,5 +1,6 @@
import { cx } from '@emotion/css';
-import React, { useCallback, useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
+import * as React from 'react';
import { Button, Icon, Modal, useStyles2, IconName } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/AdvancedMulti.test.tsx b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/AdvancedMulti.test.tsx
index c504d3b84c8..e3bf5830f0f 100644
--- a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/AdvancedMulti.test.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/AdvancedMulti.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import AdvancedMulti from './AdvancedMulti';
diff --git a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/AdvancedMulti.tsx b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/AdvancedMulti.tsx
index fa4d7f68def..d300576a03a 100644
--- a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/AdvancedMulti.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/AdvancedMulti.tsx
@@ -1,4 +1,5 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
+import * as React from 'react';
import { Collapse, Space } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/EntryIcon.tsx b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/EntryIcon.tsx
index aebf861dfe0..39e561b7258 100644
--- a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/EntryIcon.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/EntryIcon.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Icon } from '@grafana/ui';
import { ResourceRow, ResourceRowType } from './types';
diff --git a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/NestedEntry.test.tsx b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/NestedEntry.test.tsx
index f5c05e6066c..7aadaebac61 100644
--- a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/NestedEntry.test.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/NestedEntry.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { NestedEntry } from './NestedEntry';
import { ResourceRowType } from './types';
diff --git a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/NestedEntry.tsx b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/NestedEntry.tsx
index 5b0bea5e2e1..b1474cd7f37 100644
--- a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/NestedEntry.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/NestedEntry.tsx
@@ -1,5 +1,6 @@
import { cx } from '@emotion/css';
-import React, { useCallback, useEffect } from 'react';
+import { useCallback, useEffect } from 'react';
+import * as React from 'react';
import { Checkbox, IconButton, useStyles2, useTheme2, Space } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/NestedRow.test.tsx b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/NestedRow.test.tsx
index 683979a438b..541bd7a4b04 100644
--- a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/NestedRow.test.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/NestedRow.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import NestedRow from './NestedRow';
import { ResourceRowType } from './types';
diff --git a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/NestedRow.tsx b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/NestedRow.tsx
index 1fe2c717dd6..730f726d812 100644
--- a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/NestedRow.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/NestedRow.tsx
@@ -1,5 +1,5 @@
import { cx } from '@emotion/css';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { FadeTransition, LoadingPlaceholder, useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/ResourcePicker.test.tsx b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/ResourcePicker.test.tsx
index 63559579ef8..e425e0422c3 100644
--- a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/ResourcePicker.test.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/ResourcePicker.test.tsx
@@ -1,7 +1,6 @@
import { act, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { omit } from 'lodash';
-import React from 'react';
import createMockDatasource from '../../__mocks__/datasource';
import { createMockInstanceSetttings } from '../../__mocks__/instanceSettings';
diff --git a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/ResourcePicker.tsx b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/ResourcePicker.tsx
index 0afb25e760f..e5ed0431bd3 100644
--- a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/ResourcePicker.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/ResourcePicker.tsx
@@ -1,5 +1,6 @@
import { cx } from '@emotion/css';
-import React, { useCallback, useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
+import * as React from 'react';
import { useEffectOnce } from 'react-use';
import { Alert, Button, LoadingPlaceholder, Modal, useStyles2, Space } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/Search.tsx b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/Search.tsx
index f8621841c3c..fc0ac680dca 100644
--- a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/Search.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/Search.tsx
@@ -1,5 +1,5 @@
import { debounce } from 'lodash';
-import React, { useEffect, useMemo, useState } from 'react';
+import { useEffect, useMemo, useState } from 'react';
import { Icon, Input } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/Filter.tsx b/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/Filter.tsx
index 975eae7b181..12f985dbb92 100644
--- a/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/Filter.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/Filter.tsx
@@ -1,5 +1,6 @@
import { cx } from '@emotion/css';
-import React, { RefCallback, SyntheticEvent, useState } from 'react';
+import { RefCallback, SyntheticEvent, useState } from 'react';
+import * as React from 'react';
import { lastValueFrom } from 'rxjs';
import { CoreApp, DataFrame, getDefaultTimeRange, SelectableValue, TimeRange } from '@grafana/data';
diff --git a/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/Filters.test.tsx b/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/Filters.test.tsx
index f8900303b67..c53a21e423c 100644
--- a/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/Filters.test.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/Filters.test.tsx
@@ -1,7 +1,7 @@
import { act, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { UserEvent } from '@testing-library/user-event/dist/types/setup/setup';
-import React from 'react';
+import * as React from 'react';
import { of } from 'rxjs';
import { CoreApp } from '@grafana/data';
diff --git a/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/Filters.tsx b/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/Filters.tsx
index 64e7aa5fe85..9c8c84d1bc6 100644
--- a/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/Filters.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/Filters.tsx
@@ -1,5 +1,5 @@
import { uniq } from 'lodash';
-import React, { useEffect, useMemo, useState } from 'react';
+import { useEffect, useMemo, useState } from 'react';
import { SelectableValue } from '@grafana/data';
import { EditorList } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/TraceTypeField.test.tsx b/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/TraceTypeField.test.tsx
index f590f6dc413..07f7d50f343 100644
--- a/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/TraceTypeField.test.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/TraceTypeField.test.tsx
@@ -1,5 +1,4 @@
import { render, screen, act } from '@testing-library/react';
-import React from 'react';
import { openMenu } from 'react-select-event';
import createMockDatasource from '../../__mocks__/datasource';
diff --git a/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/TraceTypeField.tsx b/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/TraceTypeField.tsx
index ffb602a7436..0a64fc80ec4 100644
--- a/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/TraceTypeField.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/TraceTypeField.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useMemo } from 'react';
+import { useCallback, useMemo } from 'react';
import { SelectableValue } from '@grafana/data';
import { MultiSelect } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/TracesQueryEditor.test.tsx b/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/TracesQueryEditor.test.tsx
index 90df5bc9b41..8a0b647b19a 100644
--- a/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/TracesQueryEditor.test.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/TracesQueryEditor.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import createMockDatasource from '../../__mocks__/datasource';
import createMockQuery from '../../__mocks__/query';
diff --git a/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/TracesQueryEditor.tsx b/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/TracesQueryEditor.tsx
index c6573cfc22b..05c1da09822 100644
--- a/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/TracesQueryEditor.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/TracesQueryEditor.tsx
@@ -1,4 +1,5 @@
-import React, { useCallback, useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
+import * as React from 'react';
import { usePrevious } from 'react-use';
import { TimeRange } from '@grafana/data';
diff --git a/public/app/plugins/datasource/azuremonitor/components/VariableEditor/GrafanaTemplateVariableFn.tsx b/public/app/plugins/datasource/azuremonitor/components/VariableEditor/GrafanaTemplateVariableFn.tsx
index 35fd3707468..bf0c2ecda84 100644
--- a/public/app/plugins/datasource/azuremonitor/components/VariableEditor/GrafanaTemplateVariableFn.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/VariableEditor/GrafanaTemplateVariableFn.tsx
@@ -1,4 +1,4 @@
-import React, { ChangeEvent, useCallback, useEffect, useState } from 'react';
+import { ChangeEvent, useCallback, useEffect, useState } from 'react';
import { InlineField, Input } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/azuremonitor/components/VariableEditor/VariableEditor.test.tsx b/public/app/plugins/datasource/azuremonitor/components/VariableEditor/VariableEditor.test.tsx
index 9798ab24bcc..ba3def6fe35 100644
--- a/public/app/plugins/datasource/azuremonitor/components/VariableEditor/VariableEditor.test.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/VariableEditor/VariableEditor.test.tsx
@@ -1,6 +1,6 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
+import * as React from 'react';
import { select, openMenu } from 'react-select-event';
import * as ui from '@grafana/ui';
diff --git a/public/app/plugins/datasource/azuremonitor/components/VariableEditor/VariableEditor.tsx b/public/app/plugins/datasource/azuremonitor/components/VariableEditor/VariableEditor.tsx
index 6bb9c033d23..9cdbaba8ff8 100644
--- a/public/app/plugins/datasource/azuremonitor/components/VariableEditor/VariableEditor.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/VariableEditor/VariableEditor.tsx
@@ -1,5 +1,5 @@
import { get, isEqual } from 'lodash';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { useEffectOnce } from 'react-use';
import { SelectableValue } from '@grafana/data';
diff --git a/public/app/plugins/datasource/azuremonitor/components/shared/Field.tsx b/public/app/plugins/datasource/azuremonitor/components/shared/Field.tsx
index b139b377686..2657c066115 100644
--- a/public/app/plugins/datasource/azuremonitor/components/shared/Field.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/shared/Field.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { EditorField } from '@grafana/experimental';
import { InlineField } from '@grafana/ui';
import { Props as InlineFieldProps } from '@grafana/ui/src/components/Forms/InlineField';
diff --git a/public/app/plugins/datasource/azuremonitor/components/shared/FormatAsField.test.tsx b/public/app/plugins/datasource/azuremonitor/components/shared/FormatAsField.test.tsx
index 9ed897b3634..a8065be4ff4 100644
--- a/public/app/plugins/datasource/azuremonitor/components/shared/FormatAsField.test.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/shared/FormatAsField.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import createMockDatasource from '../../__mocks__/datasource';
import createMockQuery from '../../__mocks__/query';
diff --git a/public/app/plugins/datasource/azuremonitor/components/shared/FormatAsField.tsx b/public/app/plugins/datasource/azuremonitor/components/shared/FormatAsField.tsx
index ededa624ce8..2086ae3e312 100644
--- a/public/app/plugins/datasource/azuremonitor/components/shared/FormatAsField.tsx
+++ b/public/app/plugins/datasource/azuremonitor/components/shared/FormatAsField.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useMemo } from 'react';
+import { useCallback, useMemo } from 'react';
import { useEffectOnce } from 'react-use';
import { SelectableValue } from '@grafana/data';
diff --git a/public/app/plugins/datasource/azuremonitor/tsconfig.json b/public/app/plugins/datasource/azuremonitor/tsconfig.json
index 7daf2ee8aba..baaaea04185 100644
--- a/public/app/plugins/datasource/azuremonitor/tsconfig.json
+++ b/public/app/plugins/datasource/azuremonitor/tsconfig.json
@@ -1,4 +1,7 @@
{
+ "compilerOptions": {
+ "jsx": "react-jsx"
+ },
"extends": "@grafana/plugin-configs/tsconfig.json",
"include": ["."]
}
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/Aggregation.test.tsx b/public/app/plugins/datasource/cloud-monitoring/components/Aggregation.test.tsx
index 59dc781fb24..e19a5f79cb8 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/Aggregation.test.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/Aggregation.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { openMenu } from 'react-select-event';
import { MetricKind, ValueTypes } from '../types/query';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/Aggregation.tsx b/public/app/plugins/datasource/cloud-monitoring/components/Aggregation.tsx
index 69482738689..94e9afd71e4 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/Aggregation.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/Aggregation.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { SelectableValue } from '@grafana/data';
import { EditorField } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/AliasBy.tsx b/public/app/plugins/datasource/cloud-monitoring/components/AliasBy.tsx
index eef85c5e9b5..a275b89e15f 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/AliasBy.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/AliasBy.tsx
@@ -1,5 +1,6 @@
import { debounce } from 'lodash';
-import React, { useState } from 'react';
+import { useState } from 'react';
+import * as React from 'react';
import { EditorField } from '@grafana/experimental';
import { Input } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/Alignment.test.tsx b/public/app/plugins/datasource/cloud-monitoring/components/Alignment.test.tsx
index 0b33fe8005d..da990da45e9 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/Alignment.test.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/Alignment.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { openMenu } from 'react-select-event';
import { CustomVariableModel } from '@grafana/data';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/Alignment.tsx b/public/app/plugins/datasource/cloud-monitoring/components/Alignment.tsx
index f49f4fafe53..c9a313e48ed 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/Alignment.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/Alignment.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { SelectableValue } from '@grafana/data';
import { EditorField, EditorFieldGroup } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/AlignmentFunction.tsx b/public/app/plugins/datasource/cloud-monitoring/components/AlignmentFunction.tsx
index cff17497a49..5ab061d55ae 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/AlignmentFunction.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/AlignmentFunction.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { SelectableValue } from '@grafana/data';
import { Select } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/AnnotationQueryEditor.test.tsx b/public/app/plugins/datasource/cloud-monitoring/components/AnnotationQueryEditor.test.tsx
index f57cc94d839..349f07d3dfd 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/AnnotationQueryEditor.test.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/AnnotationQueryEditor.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { createMockDatasource } from '../__mocks__/cloudMonitoringDatasource';
import { createMockQuery } from '../__mocks__/cloudMonitoringQuery';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/AnnotationQueryEditor.tsx b/public/app/plugins/datasource/cloud-monitoring/components/AnnotationQueryEditor.tsx
index 984f299df68..35f524cc556 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/AnnotationQueryEditor.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/AnnotationQueryEditor.tsx
@@ -1,4 +1,5 @@
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
+import * as React from 'react';
import { useDebounce } from 'react-use';
import { QueryEditorProps, getDefaultTimeRange, toOption } from '@grafana/data';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/AnnotationsHelp.tsx b/public/app/plugins/datasource/cloud-monitoring/components/AnnotationsHelp.tsx
index 8970adbe0a2..91a81625017 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/AnnotationsHelp.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/AnnotationsHelp.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
export const AnnotationsHelp = () => {
return (
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/CloudMonitoringCheatSheet.tsx b/public/app/plugins/datasource/cloud-monitoring/components/CloudMonitoringCheatSheet.tsx
index c53e92ecfaf..65f8d6e3a4c 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/CloudMonitoringCheatSheet.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/CloudMonitoringCheatSheet.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { QueryEditorHelpProps } from '@grafana/data';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/ConfigEditor/ConfigEditor.tsx b/public/app/plugins/datasource/cloud-monitoring/components/ConfigEditor/ConfigEditor.tsx
index 19baaac47dd..02943e876ef 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/ConfigEditor/ConfigEditor.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/ConfigEditor/ConfigEditor.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { DataSourcePluginOptionsEditorProps } from '@grafana/data';
import { ConfigSection, DataSourceDescription } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/Fields.tsx b/public/app/plugins/datasource/cloud-monitoring/components/Fields.tsx
index f6cc8bb34ab..8036ae966f6 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/Fields.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/Fields.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SelectableValue } from '@grafana/data';
import { Field, Select } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/GraphPeriod.test.tsx b/public/app/plugins/datasource/cloud-monitoring/components/GraphPeriod.test.tsx
index 0c5307889cc..7080338a93b 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/GraphPeriod.test.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/GraphPeriod.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { select } from 'react-select-event';
import { GraphPeriod, Props } from './GraphPeriod';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/GraphPeriod.tsx b/public/app/plugins/datasource/cloud-monitoring/components/GraphPeriod.tsx
index 754fb5cb99a..13dd8e3d201 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/GraphPeriod.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/GraphPeriod.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SelectableValue } from '@grafana/data';
import { EditorField, EditorRow } from '@grafana/experimental';
import { HorizontalGroup, Switch } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/GroupBy.test.tsx b/public/app/plugins/datasource/cloud-monitoring/components/GroupBy.test.tsx
index 7d3bfe885aa..7342a9b0388 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/GroupBy.test.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/GroupBy.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { openMenu, select } from 'react-select-event';
import { createMockTimeSeriesList } from '../__mocks__/cloudMonitoringQuery';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/GroupBy.tsx b/public/app/plugins/datasource/cloud-monitoring/components/GroupBy.tsx
index 70dc93a0a43..d9fd0e4c70c 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/GroupBy.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/GroupBy.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { SelectableValue } from '@grafana/data';
import { EditorField, EditorFieldGroup } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/LabelFilter.test.tsx b/public/app/plugins/datasource/cloud-monitoring/components/LabelFilter.test.tsx
index 786f8fc6c5e..1171790342b 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/LabelFilter.test.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/LabelFilter.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { openMenu, select } from 'react-select-event';
import { LabelFilter } from './LabelFilter';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/LabelFilter.tsx b/public/app/plugins/datasource/cloud-monitoring/components/LabelFilter.tsx
index 414f29cb62b..102bc22ef2f 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/LabelFilter.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/LabelFilter.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { SelectableValue, toOption } from '@grafana/data';
import { AccessoryButton, EditorField, EditorList, EditorRow } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/LookbackPeriodSelect.tsx b/public/app/plugins/datasource/cloud-monitoring/components/LookbackPeriodSelect.tsx
index fcdfaaf2f07..0e7d991327a 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/LookbackPeriodSelect.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/LookbackPeriodSelect.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SelectableValue } from '@grafana/data';
import { EditorField } from '@grafana/experimental';
import { Select } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/MQLQueryEditor.tsx b/public/app/plugins/datasource/cloud-monitoring/components/MQLQueryEditor.tsx
index 6c2c635bb1e..d150565c7d5 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/MQLQueryEditor.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/MQLQueryEditor.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { TextArea } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/MetricQueryEditor.test.tsx b/public/app/plugins/datasource/cloud-monitoring/components/MetricQueryEditor.test.tsx
index b3975ad9438..187481ca913 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/MetricQueryEditor.test.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/MetricQueryEditor.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { openMenu } from 'react-select-event';
import { getDefaultTimeRange } from '@grafana/data';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/MetricQueryEditor.tsx b/public/app/plugins/datasource/cloud-monitoring/components/MetricQueryEditor.tsx
index 846ee57fb08..8a245c46503 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/MetricQueryEditor.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/MetricQueryEditor.tsx
@@ -1,4 +1,5 @@
-import React, { useCallback, useEffect } from 'react';
+import { useCallback, useEffect } from 'react';
+import * as React from 'react';
import { SelectableValue, TimeRange } from '@grafana/data';
import { EditorRows, Stack } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/PeriodSelect.tsx b/public/app/plugins/datasource/cloud-monitoring/components/PeriodSelect.tsx
index 73a2fedb4f2..20860afe3d0 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/PeriodSelect.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/PeriodSelect.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { SelectableValue } from '@grafana/data';
import { Select } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/Preprocessor.test.tsx b/public/app/plugins/datasource/cloud-monitoring/components/Preprocessor.test.tsx
index 037a375b323..aa6b89d4228 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/Preprocessor.test.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/Preprocessor.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { CustomVariableModel } from '@grafana/data';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/Preprocessor.tsx b/public/app/plugins/datasource/cloud-monitoring/components/Preprocessor.tsx
index a572bff024a..c7f6c66d355 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/Preprocessor.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/Preprocessor.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { SelectableValue } from '@grafana/data';
import { EditorField } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/Project.tsx b/public/app/plugins/datasource/cloud-monitoring/components/Project.tsx
index a36b41f2cd2..de42fbdd788 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/Project.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/Project.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useMemo, useState } from 'react';
+import { useEffect, useMemo, useState } from 'react';
import { SelectableValue } from '@grafana/data';
import { EditorField } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/PromQLEditor.tsx b/public/app/plugins/datasource/cloud-monitoring/components/PromQLEditor.tsx
index 79e81617e25..8e54fbe372c 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/PromQLEditor.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/PromQLEditor.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { SelectableValue } from '@grafana/data';
import { EditorField, EditorRow } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/QueryEditor.test.tsx b/public/app/plugins/datasource/cloud-monitoring/components/QueryEditor.test.tsx
index 91380a13173..cd3bb5d9668 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/QueryEditor.test.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/QueryEditor.test.tsx
@@ -1,5 +1,4 @@
import { render, waitFor, screen } from '@testing-library/react';
-import React from 'react';
import { select } from 'react-select-event';
import { createMockDatasource } from '../__mocks__/cloudMonitoringDatasource';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/QueryEditor.tsx b/public/app/plugins/datasource/cloud-monitoring/components/QueryEditor.tsx
index a6104921f34..9464e273ea2 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/QueryEditor.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/QueryEditor.tsx
@@ -1,6 +1,6 @@
import deepEqual from 'fast-deep-equal';
import { isEqual } from 'lodash';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { QueryEditorProps, getDefaultTimeRange, toOption } from '@grafana/data';
import { EditorRows } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/QueryHeader.test.tsx b/public/app/plugins/datasource/cloud-monitoring/components/QueryHeader.test.tsx
index e7853a0cca3..3dfbe2c2bab 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/QueryHeader.test.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/QueryHeader.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { openMenu, select } from 'react-select-event';
import { createMockQuery } from '../__mocks__/cloudMonitoringQuery';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/QueryHeader.tsx b/public/app/plugins/datasource/cloud-monitoring/components/QueryHeader.tsx
index ca4f36d6844..150bb3c1f1f 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/QueryHeader.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/QueryHeader.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { EditorHeader, FlexItem, InlineSelect } from '@grafana/experimental';
import { QUERY_TYPES } from '../constants';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/SLO.tsx b/public/app/plugins/datasource/cloud-monitoring/components/SLO.tsx
index ccb4696bee2..2e0117cfe70 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/SLO.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/SLO.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { SelectableValue } from '@grafana/data';
import { EditorField } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/SLOQueryEditor.tsx b/public/app/plugins/datasource/cloud-monitoring/components/SLOQueryEditor.tsx
index af753ae72df..0d62b1cff1e 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/SLOQueryEditor.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/SLOQueryEditor.tsx
@@ -1,4 +1,5 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
+import * as React from 'react';
import { SelectableValue } from '@grafana/data';
import { EditorField, EditorFieldGroup, EditorRow } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/Selector.tsx b/public/app/plugins/datasource/cloud-monitoring/components/Selector.tsx
index 9790fb6480e..5c59741acd4 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/Selector.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/Selector.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SelectableValue } from '@grafana/data';
import { EditorField } from '@grafana/experimental';
import { Select } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/Service.tsx b/public/app/plugins/datasource/cloud-monitoring/components/Service.tsx
index ad86d792776..35093b92a7b 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/Service.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/Service.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { SelectableValue } from '@grafana/data';
import { EditorField } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/VariableQueryEditor.test.tsx b/public/app/plugins/datasource/cloud-monitoring/components/VariableQueryEditor.test.tsx
index 814c30f689e..2290e4e9417 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/VariableQueryEditor.test.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/VariableQueryEditor.test.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-// @ts-ignore
import renderer from 'react-test-renderer';
import { VariableModel } from '@grafana/data';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/VariableQueryEditor.tsx b/public/app/plugins/datasource/cloud-monitoring/components/VariableQueryEditor.tsx
index d8614ae7b26..0b7169ae2fd 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/VariableQueryEditor.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/VariableQueryEditor.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { QueryEditorProps } from '@grafana/data';
import { getTemplateSrv } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/VisualMetricQueryEditor.test.tsx b/public/app/plugins/datasource/cloud-monitoring/components/VisualMetricQueryEditor.test.tsx
index be768bad8e2..9a5ebfb76f1 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/VisualMetricQueryEditor.test.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/VisualMetricQueryEditor.test.tsx
@@ -1,6 +1,5 @@
import { act, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { openMenu, select } from 'react-select-event';
import { CustomVariableModel, getDefaultTimeRange } from '@grafana/data';
diff --git a/public/app/plugins/datasource/cloud-monitoring/components/VisualMetricQueryEditor.tsx b/public/app/plugins/datasource/cloud-monitoring/components/VisualMetricQueryEditor.tsx
index a5d57040047..0c420bbc547 100644
--- a/public/app/plugins/datasource/cloud-monitoring/components/VisualMetricQueryEditor.tsx
+++ b/public/app/plugins/datasource/cloud-monitoring/components/VisualMetricQueryEditor.tsx
@@ -1,7 +1,8 @@
import { css } from '@emotion/css';
import debounce from 'debounce-promise';
import { startCase, uniqBy } from 'lodash';
-import React, { useCallback, useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
+import * as React from 'react';
import { GrafanaTheme2, SelectableValue, TimeRange } from '@grafana/data';
import { EditorField, EditorFieldGroup, EditorRow } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/cloud-monitoring/tsconfig.json b/public/app/plugins/datasource/cloud-monitoring/tsconfig.json
index 7daf2ee8aba..baaaea04185 100644
--- a/public/app/plugins/datasource/cloud-monitoring/tsconfig.json
+++ b/public/app/plugins/datasource/cloud-monitoring/tsconfig.json
@@ -1,4 +1,7 @@
{
+ "compilerOptions": {
+ "jsx": "react-jsx"
+ },
"extends": "@grafana/plugin-configs/tsconfig.json",
"include": ["."]
}
diff --git a/public/app/plugins/datasource/cloudwatch/components/AnnotationQueryEditor/AnnotationQueryEditor.test.tsx b/public/app/plugins/datasource/cloudwatch/components/AnnotationQueryEditor/AnnotationQueryEditor.test.tsx
index e5b62bac9b0..e9bd97a82f9 100644
--- a/public/app/plugins/datasource/cloudwatch/components/AnnotationQueryEditor/AnnotationQueryEditor.test.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/AnnotationQueryEditor/AnnotationQueryEditor.test.tsx
@@ -1,5 +1,4 @@
import { render, screen, waitFor } from '@testing-library/react';
-import React from 'react';
import '@testing-library/jest-dom';
import { QueryEditorProps } from '@grafana/data';
diff --git a/public/app/plugins/datasource/cloudwatch/components/AnnotationQueryEditor/AnnotationQueryEditor.tsx b/public/app/plugins/datasource/cloudwatch/components/AnnotationQueryEditor/AnnotationQueryEditor.tsx
index cd8c3517e52..b3ef2901dae 100644
--- a/public/app/plugins/datasource/cloudwatch/components/AnnotationQueryEditor/AnnotationQueryEditor.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/AnnotationQueryEditor/AnnotationQueryEditor.tsx
@@ -1,4 +1,4 @@
-import React, { ChangeEvent } from 'react';
+import { ChangeEvent } from 'react';
import { QueryEditorProps } from '@grafana/data';
import { EditorField, EditorHeader, EditorRow, EditorSwitch, InlineSelect } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/cloudwatch/components/CheatSheet/LogsCheatSheet.tsx b/public/app/plugins/datasource/cloudwatch/components/CheatSheet/LogsCheatSheet.tsx
index f3f3155059a..91929e6bc6f 100644
--- a/public/app/plugins/datasource/cloudwatch/components/CheatSheet/LogsCheatSheet.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/CheatSheet/LogsCheatSheet.tsx
@@ -1,7 +1,7 @@
import { css, cx } from '@emotion/css';
import { stripIndent, stripIndents } from 'common-tags';
import Prism from 'prismjs';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Collapse, useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/ConfigEditor.test.tsx b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/ConfigEditor.test.tsx
index a83e5d70d5d..6f31669098f 100644
--- a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/ConfigEditor.test.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/ConfigEditor.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { AwsAuthType } from '@grafana/aws-sdk';
import { PluginContextProvider, PluginMeta, PluginMetaInfo, PluginType } from '@grafana/data';
diff --git a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/ConfigEditor.tsx b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/ConfigEditor.tsx
index f6b551955da..2722ce628fa 100644
--- a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/ConfigEditor.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/ConfigEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { useDebounce } from 'react-use';
import { ConnectionConfig } from '@grafana/aws-sdk';
diff --git a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/SecureSocksProxySettingsNewStyling.tsx b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/SecureSocksProxySettingsNewStyling.tsx
index 0b034afc2bb..a70e01acd23 100644
--- a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/SecureSocksProxySettingsNewStyling.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/SecureSocksProxySettingsNewStyling.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { DataSourceJsonData, DataSourcePluginOptionsEditorProps } from '@grafana/data';
import { ConfigSection } from '@grafana/experimental';
import { Field, Switch } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/XrayLinkConfig.tsx b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/XrayLinkConfig.tsx
index f963a0547e3..c3c8bd677ea 100644
--- a/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/XrayLinkConfig.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/ConfigEditor/XrayLinkConfig.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2, DataSourceInstanceSettings } from '@grafana/data';
import { ConfigSection } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/cloudwatch/components/Errors/ThrottlingErrorMessage.tsx b/public/app/plugins/datasource/cloudwatch/components/Errors/ThrottlingErrorMessage.tsx
index 1e03ad21c90..7446472de2d 100644
--- a/public/app/plugins/datasource/cloudwatch/components/Errors/ThrottlingErrorMessage.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/Errors/ThrottlingErrorMessage.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
export interface Props {
region: string;
}
diff --git a/public/app/plugins/datasource/cloudwatch/components/MetaInspector/MetaInspector.tsx b/public/app/plugins/datasource/cloudwatch/components/MetaInspector/MetaInspector.tsx
index 12ca89d98a2..7f837452ccf 100644
--- a/public/app/plugins/datasource/cloudwatch/components/MetaInspector/MetaInspector.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/MetaInspector/MetaInspector.tsx
@@ -1,5 +1,5 @@
import { groupBy } from 'lodash';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { MetadataInspectorProps } from '@grafana/data';
diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/CloudWatchLink.test.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/CloudWatchLink.test.tsx
index d19f98a6e68..b070fb69a0e 100644
--- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/CloudWatchLink.test.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/CloudWatchLink.test.tsx
@@ -1,5 +1,4 @@
import { act, render, screen, waitFor } from '@testing-library/react';
-import React from 'react';
import { LoadingState } from '@grafana/data';
diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/CloudWatchLink.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/CloudWatchLink.tsx
index f7087e70654..5d07b54aed5 100644
--- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/CloudWatchLink.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/CloudWatchLink.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { usePrevious } from 'react-use';
import { PanelData } from '@grafana/data';
diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/LogsQueryEditor.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/LogsQueryEditor.tsx
index fd57a6f4587..2ed46ebd85e 100644
--- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/LogsQueryEditor.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/LogsQueryEditor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { memo } from 'react';
+import { memo } from 'react';
import { QueryEditorProps } from '@grafana/data';
import { InlineFormLabel } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/LogsQueryField.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/LogsQueryField.tsx
index 9a9865b49b6..2527565821e 100644
--- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/LogsQueryField.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/LogsQueryField.tsx
@@ -1,5 +1,5 @@
import type * as monacoType from 'monaco-editor/esm/vs/editor/editor.api';
-import React, { ReactNode, useCallback, useRef } from 'react';
+import { ReactNode, useCallback, useRef } from 'react';
import { QueryEditorProps } from '@grafana/data';
import { CodeEditor, Monaco, Themeable2, withTheme2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/DynamicLabelsField.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/DynamicLabelsField.tsx
index 7c5f9198825..b7f62593057 100644
--- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/DynamicLabelsField.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/DynamicLabelsField.tsx
@@ -1,6 +1,6 @@
import { css, cx } from '@emotion/css';
import type * as monacoType from 'monaco-editor/esm/vs/editor/editor.api';
-import React, { useCallback, useRef } from 'react';
+import { useCallback, useRef } from 'react';
import { CodeEditor, getInputStyles, Monaco, useTheme2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/MathExpressionQueryField.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/MathExpressionQueryField.tsx
index 5ac7ca8e226..6005caba145 100644
--- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/MathExpressionQueryField.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/MathExpressionQueryField.tsx
@@ -1,5 +1,6 @@
import type * as monacoType from 'monaco-editor/esm/vs/editor/editor.api';
-import React, { useCallback, useRef } from 'react';
+import { useCallback, useRef } from 'react';
+import * as React from 'react';
import { CodeEditor, Monaco } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/MetricsQueryEditor.test.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/MetricsQueryEditor.test.tsx
index 0be9d041cf2..4b9d5cc4cd1 100644
--- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/MetricsQueryEditor.test.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/MetricsQueryEditor.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import selectEvent from 'react-select-event';
import { CustomVariableModel, DataSourceInstanceSettings } from '@grafana/data';
diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/MetricsQueryEditor.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/MetricsQueryEditor.tsx
index e4a7404989f..6798f650186 100644
--- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/MetricsQueryEditor.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/MetricsQueryEditor.tsx
@@ -1,4 +1,5 @@
-import React, { ChangeEvent, useCallback, useEffect, useState } from 'react';
+import { ChangeEvent, useCallback, useEffect, useState } from 'react';
+import * as React from 'react';
import { QueryEditorProps, SelectableValue } from '@grafana/data';
import { EditorField, EditorRow, InlineSelect } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLBuilderEditor.test.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLBuilderEditor.test.tsx
index bfd11f2bc85..93292e51212 100644
--- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLBuilderEditor.test.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLBuilderEditor.test.tsx
@@ -1,5 +1,4 @@
import { render, screen, waitFor } from '@testing-library/react';
-import React from 'react';
import { setupMockedDataSource } from '../../../../__mocks__/CloudWatchDataSource';
import { QueryEditorExpressionType, QueryEditorPropertyType } from '../../../../expressions';
diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLBuilderEditor.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLBuilderEditor.tsx
index 9191fbe0abf..beefe48b358 100644
--- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLBuilderEditor.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLBuilderEditor.tsx
@@ -1,4 +1,5 @@
-import React, { useCallback, useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
+import * as React from 'react';
import { EditorField, EditorRow, EditorRows } from '@grafana/experimental';
import { Input } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLBuilderSelectRow.test.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLBuilderSelectRow.test.tsx
index 8c2c7f74366..fc8178311b0 100644
--- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLBuilderSelectRow.test.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLBuilderSelectRow.test.tsx
@@ -1,5 +1,4 @@
import { act, render, screen } from '@testing-library/react';
-import React from 'react';
import { selectOptionInTest } from 'test/helpers/selectOptionInTest';
import { setupMockedDataSource } from '../../../../__mocks__/CloudWatchDataSource';
diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLBuilderSelectRow.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLBuilderSelectRow.tsx
index d22070a9279..859031eec9a 100644
--- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLBuilderSelectRow.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLBuilderSelectRow.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useMemo } from 'react';
+import { useEffect, useMemo } from 'react';
import { SelectableValue, toOption } from '@grafana/data';
import { EditorField, EditorFieldGroup, EditorSwitch } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLFilter.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLFilter.tsx
index 6c4cfc48706..5d6794e62fd 100644
--- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLFilter.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLFilter.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
import { useAsyncFn } from 'react-use';
import { SelectableValue, toOption } from '@grafana/data';
diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLGroupBy.test.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLGroupBy.test.tsx
index dcd2bd57f82..388fe8722c6 100644
--- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLGroupBy.test.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLGroupBy.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import selectEvent from 'react-select-event';
import { setupMockedDataSource } from '../../../../__mocks__/CloudWatchDataSource';
diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLGroupBy.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLGroupBy.tsx
index 72fa72a2316..359b896ad88 100644
--- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLGroupBy.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLGroupBy.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
import { SelectableValue, toOption } from '@grafana/data';
import { AccessoryButton, EditorList, InputGroup } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLOrderByGroup.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLOrderByGroup.tsx
index 62891e19caf..2afeb342179 100644
--- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLOrderByGroup.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/SQLOrderByGroup.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SelectableValue, toOption } from '@grafana/data';
import { AccessoryButton, EditorField, EditorFieldGroup, InputGroup } from '@grafana/experimental';
import { Select } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLCodeEditor.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLCodeEditor.tsx
index 6fb14be0da3..ef09a74f47c 100644
--- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLCodeEditor.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLCodeEditor.tsx
@@ -1,5 +1,5 @@
import type * as monacoType from 'monaco-editor/esm/vs/editor/editor.api';
-import React, { useCallback, useEffect } from 'react';
+import { useCallback, useEffect } from 'react';
import { CodeEditor, Monaco } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryEditor.test.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryEditor.test.tsx
index 0027ecbb75d..7e5f2bbe9e5 100644
--- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryEditor.test.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryEditor.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { QueryEditorProps } from '@grafana/data';
import { config } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryEditor.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryEditor.tsx
index 7810e357a5b..90c4ff21a43 100644
--- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryEditor.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
import { QueryEditorProps } from '@grafana/data';
diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryHeader.test.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryHeader.test.tsx
index 3b5c309d13a..6c35f4d49dd 100644
--- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryHeader.test.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryHeader.test.tsx
@@ -1,5 +1,4 @@
import { render, screen, waitFor } from '@testing-library/react';
-import React from 'react';
import selectEvent from 'react-select-event';
import { config } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryHeader.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryHeader.tsx
index 4e0dff5e540..7e77f93b4a5 100644
--- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryHeader.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryHeader.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { CoreApp, LoadingState, QueryEditorProps, SelectableValue } from '@grafana/data';
import { EditorHeader, InlineSelect, FlexItem } from '@grafana/experimental';
import { config } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/cloudwatch/components/VariableQueryEditor/MultiFilter.test.tsx b/public/app/plugins/datasource/cloudwatch/components/VariableQueryEditor/MultiFilter.test.tsx
index 9f93308e595..b14051880fc 100644
--- a/public/app/plugins/datasource/cloudwatch/components/VariableQueryEditor/MultiFilter.test.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/VariableQueryEditor/MultiFilter.test.tsx
@@ -1,6 +1,5 @@
import { fireEvent, render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { setupMockedDataSource } from '../../__mocks__/CloudWatchDataSource';
diff --git a/public/app/plugins/datasource/cloudwatch/components/VariableQueryEditor/MultiFilter.tsx b/public/app/plugins/datasource/cloudwatch/components/VariableQueryEditor/MultiFilter.tsx
index 94668e1f9cf..00525820fd8 100644
--- a/public/app/plugins/datasource/cloudwatch/components/VariableQueryEditor/MultiFilter.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/VariableQueryEditor/MultiFilter.tsx
@@ -1,5 +1,5 @@
import { isEqual } from 'lodash';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { EditorList } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/cloudwatch/components/VariableQueryEditor/MultiFilterItem.tsx b/public/app/plugins/datasource/cloudwatch/components/VariableQueryEditor/MultiFilterItem.tsx
index f9480b4802c..ed73928d4ee 100644
--- a/public/app/plugins/datasource/cloudwatch/components/VariableQueryEditor/MultiFilterItem.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/VariableQueryEditor/MultiFilterItem.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { AccessoryButton, InputGroup } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/cloudwatch/components/VariableQueryEditor/VariableQueryEditor.test.tsx b/public/app/plugins/datasource/cloudwatch/components/VariableQueryEditor/VariableQueryEditor.test.tsx
index d91dca40a29..9f5c19be7b6 100644
--- a/public/app/plugins/datasource/cloudwatch/components/VariableQueryEditor/VariableQueryEditor.test.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/VariableQueryEditor/VariableQueryEditor.test.tsx
@@ -1,6 +1,5 @@
import { act, fireEvent, render, screen, waitFor, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { select } from 'react-select-event';
import { config } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/cloudwatch/components/VariableQueryEditor/VariableQueryEditor.tsx b/public/app/plugins/datasource/cloudwatch/components/VariableQueryEditor/VariableQueryEditor.tsx
index 7d4eb75a70a..e554875ba23 100644
--- a/public/app/plugins/datasource/cloudwatch/components/VariableQueryEditor/VariableQueryEditor.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/VariableQueryEditor/VariableQueryEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { QueryEditorProps, SelectableValue } from '@grafana/data';
import { EditorField } from '@grafana/experimental';
import { config } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/cloudwatch/components/VariableQueryEditor/VariableQueryField.tsx b/public/app/plugins/datasource/cloudwatch/components/VariableQueryEditor/VariableQueryField.tsx
index 6ab887cefba..eb1399ce9c9 100644
--- a/public/app/plugins/datasource/cloudwatch/components/VariableQueryEditor/VariableQueryField.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/VariableQueryEditor/VariableQueryField.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { EditorField } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/cloudwatch/components/VariableQueryEditor/VariableTextField.tsx b/public/app/plugins/datasource/cloudwatch/components/VariableQueryEditor/VariableTextField.tsx
index d01ebb82a6b..4313f440275 100644
--- a/public/app/plugins/datasource/cloudwatch/components/VariableQueryEditor/VariableTextField.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/VariableQueryEditor/VariableTextField.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { EditorField } from '@grafana/experimental';
import { InlineField, Input, PopoverContent } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/cloudwatch/components/shared/Account.test.tsx b/public/app/plugins/datasource/cloudwatch/components/shared/Account.test.tsx
index e2803524fd1..c2e420e21b1 100644
--- a/public/app/plugins/datasource/cloudwatch/components/shared/Account.test.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/shared/Account.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import selectEvent from 'react-select-event';
import { Account } from './Account';
diff --git a/public/app/plugins/datasource/cloudwatch/components/shared/Account.tsx b/public/app/plugins/datasource/cloudwatch/components/shared/Account.tsx
index 57cde6ac83a..8078e752db1 100644
--- a/public/app/plugins/datasource/cloudwatch/components/shared/Account.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/shared/Account.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { SelectableValue } from '@grafana/data';
import { EditorField } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/cloudwatch/components/shared/Dimensions/Dimensions.test.tsx b/public/app/plugins/datasource/cloudwatch/components/shared/Dimensions/Dimensions.test.tsx
index 846d7209a58..ee39afba589 100644
--- a/public/app/plugins/datasource/cloudwatch/components/shared/Dimensions/Dimensions.test.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/shared/Dimensions/Dimensions.test.tsx
@@ -1,6 +1,5 @@
import { fireEvent, render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { setupMockedDataSource } from '../../../__mocks__/CloudWatchDataSource';
import { CloudWatchMetricsQuery } from '../../../types';
diff --git a/public/app/plugins/datasource/cloudwatch/components/shared/Dimensions/Dimensions.tsx b/public/app/plugins/datasource/cloudwatch/components/shared/Dimensions/Dimensions.tsx
index 3909df54d84..b182714c4d8 100644
--- a/public/app/plugins/datasource/cloudwatch/components/shared/Dimensions/Dimensions.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/shared/Dimensions/Dimensions.tsx
@@ -1,5 +1,5 @@
import { isEqual } from 'lodash';
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
import { EditorList } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/cloudwatch/components/shared/Dimensions/FilterItem.test.tsx b/public/app/plugins/datasource/cloudwatch/components/shared/Dimensions/FilterItem.test.tsx
index 1ab3a166774..9ea8123bd2b 100644
--- a/public/app/plugins/datasource/cloudwatch/components/shared/Dimensions/FilterItem.test.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/shared/Dimensions/FilterItem.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { setupMockedDataSource } from '../../../__mocks__/CloudWatchDataSource';
import { CloudWatchMetricsQuery } from '../../../types';
diff --git a/public/app/plugins/datasource/cloudwatch/components/shared/Dimensions/FilterItem.tsx b/public/app/plugins/datasource/cloudwatch/components/shared/Dimensions/FilterItem.tsx
index 0610240aef8..f264c93cbcd 100644
--- a/public/app/plugins/datasource/cloudwatch/components/shared/Dimensions/FilterItem.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/shared/Dimensions/FilterItem.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { useAsyncFn } from 'react-use';
import { GrafanaTheme2, SelectableValue, toOption } from '@grafana/data';
diff --git a/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LegacyLogGroupNamesSelection.tsx b/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LegacyLogGroupNamesSelection.tsx
index 020e123b9dd..e4ee31d6c50 100644
--- a/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LegacyLogGroupNamesSelection.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LegacyLogGroupNamesSelection.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { CloudWatchDatasource } from '../../../datasource';
diff --git a/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LegacyLogGroupSelector.tsx b/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LegacyLogGroupSelector.tsx
index 8204ef25ca1..5b66c048f61 100644
--- a/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LegacyLogGroupSelector.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LegacyLogGroupSelector.tsx
@@ -1,5 +1,6 @@
import { debounce, unionBy } from 'lodash';
-import React, { useCallback, useEffect, useMemo, useState } from 'react';
+import { useCallback, useEffect, useMemo, useState } from 'react';
+import * as React from 'react';
import { AppEvents, SelectableValue, toOption } from '@grafana/data';
import { getAppEvents } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LogGroupsField.test.tsx b/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LogGroupsField.test.tsx
index b3cf4e2a489..6bf4154d9ac 100644
--- a/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LogGroupsField.test.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LogGroupsField.test.tsx
@@ -1,7 +1,6 @@
import { render, screen, waitFor } from '@testing-library/react';
// eslint-disable-next-line lodash/import-scope
import lodash from 'lodash';
-import React from 'react';
import { config } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LogGroupsField.tsx b/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LogGroupsField.tsx
index 6d97836822b..d904873cd0b 100644
--- a/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LogGroupsField.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LogGroupsField.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { config } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LogGroupsSelector.test.tsx b/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LogGroupsSelector.test.tsx
index 4f69b4dc33e..80d82444cfa 100644
--- a/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LogGroupsSelector.test.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LogGroupsSelector.test.tsx
@@ -2,7 +2,6 @@ import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
// eslint-disable-next-line lodash/import-scope
import lodash from 'lodash';
-import React from 'react';
import selectEvent from 'react-select-event';
import { ResourceResponse, LogGroupResponse } from '../../../resources/types';
diff --git a/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LogGroupsSelector.tsx b/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LogGroupsSelector.tsx
index d1720065ddd..63365a150b1 100644
--- a/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LogGroupsSelector.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LogGroupsSelector.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useMemo, useState } from 'react';
+import { useEffect, useMemo, useState } from 'react';
import { SelectableValue } from '@grafana/data';
import { EditorField } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/Search.test.tsx b/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/Search.test.tsx
index 43443dfaa90..1a14e5f0092 100644
--- a/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/Search.test.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/Search.test.tsx
@@ -2,7 +2,6 @@ import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
// eslint-disable-next-line lodash/import-scope
import lodash from 'lodash';
-import React from 'react';
import Search from './Search';
diff --git a/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/Search.tsx b/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/Search.tsx
index a7af3070bf3..25dc5bd762a 100644
--- a/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/Search.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/Search.tsx
@@ -1,5 +1,5 @@
import { debounce } from 'lodash';
-import React, { useEffect, useMemo, useState } from 'react';
+import { useEffect, useMemo, useState } from 'react';
import { Icon, Input } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/SelectedLogGroups.test.tsx b/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/SelectedLogGroups.test.tsx
index 540a6545c9f..7ad0fea4ec4 100644
--- a/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/SelectedLogGroups.test.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/SelectedLogGroups.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { LogGroup } from '../../../types';
diff --git a/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/SelectedLogGroups.tsx b/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/SelectedLogGroups.tsx
index 83a5a3c63ab..e1c20db7f50 100644
--- a/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/SelectedLogGroups.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/SelectedLogGroups.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { Button, ConfirmModal, useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/cloudwatch/components/shared/MetricStatEditor/MetricStatEditor.test.tsx b/public/app/plugins/datasource/cloudwatch/components/shared/MetricStatEditor/MetricStatEditor.test.tsx
index 0dee6c581aa..a88b4f4fd61 100644
--- a/public/app/plugins/datasource/cloudwatch/components/shared/MetricStatEditor/MetricStatEditor.test.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/shared/MetricStatEditor/MetricStatEditor.test.tsx
@@ -1,6 +1,5 @@
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import selectEvent from 'react-select-event';
import { config } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/cloudwatch/components/shared/MetricStatEditor/MetricStatEditor.tsx b/public/app/plugins/datasource/cloudwatch/components/shared/MetricStatEditor/MetricStatEditor.tsx
index 237d83fccd2..9f9ecd45fdf 100644
--- a/public/app/plugins/datasource/cloudwatch/components/shared/MetricStatEditor/MetricStatEditor.tsx
+++ b/public/app/plugins/datasource/cloudwatch/components/shared/MetricStatEditor/MetricStatEditor.tsx
@@ -1,4 +1,5 @@
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
+import * as React from 'react';
import { SelectableValue } from '@grafana/data';
import { EditorField, EditorFieldGroup, EditorRow, EditorRows, EditorSwitch } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchMetricsQueryRunner.ts b/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchMetricsQueryRunner.ts
index 44088ce2868..3fc10803226 100644
--- a/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchMetricsQueryRunner.ts
+++ b/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchMetricsQueryRunner.ts
@@ -1,5 +1,5 @@
import { isEmpty } from 'lodash';
-import React from 'react';
+import { createElement } from 'react';
import { catchError, map, Observable, of } from 'rxjs';
import {
@@ -34,7 +34,7 @@ const displayAlert = (datasourceName: string, region: string) =>
`CloudWatch request limit reached in ${region} for data source ${datasourceName}`,
'',
undefined,
- React.createElement(ThrottlingErrorMessage, { region }, null),
+ createElement(ThrottlingErrorMessage, { region }, null),
],
});
diff --git a/public/app/plugins/datasource/dashboard/DashboardQueryEditor.test.tsx b/public/app/plugins/datasource/dashboard/DashboardQueryEditor.test.tsx
index ca9d18c71c1..1798a6c1ae4 100644
--- a/public/app/plugins/datasource/dashboard/DashboardQueryEditor.test.tsx
+++ b/public/app/plugins/datasource/dashboard/DashboardQueryEditor.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { getDefaultTimeRange, LoadingState } from '@grafana/data';
import { setDataSourceSrv } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/dashboard/DashboardQueryEditor.tsx b/public/app/plugins/datasource/dashboard/DashboardQueryEditor.tsx
index fca4811b291..073cb173dd8 100644
--- a/public/app/plugins/datasource/dashboard/DashboardQueryEditor.tsx
+++ b/public/app/plugins/datasource/dashboard/DashboardQueryEditor.tsx
@@ -1,7 +1,7 @@
import { css } from '@emotion/css';
import { useId } from '@react-aria/utils';
import pluralize from 'pluralize';
-import React, { useCallback, useMemo } from 'react';
+import { useCallback, useMemo } from 'react';
import { useAsync } from 'react-use';
import { DataQuery, GrafanaTheme2, SelectableValue, DataTopic, QueryEditorProps } from '@grafana/data';
diff --git a/public/app/plugins/datasource/elasticsearch/components/AddRemove.test.tsx b/public/app/plugins/datasource/elasticsearch/components/AddRemove.test.tsx
index d968f58eb72..156cd81c904 100644
--- a/public/app/plugins/datasource/elasticsearch/components/AddRemove.test.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/AddRemove.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { AddRemove } from './AddRemove';
diff --git a/public/app/plugins/datasource/elasticsearch/components/AddRemove.tsx b/public/app/plugins/datasource/elasticsearch/components/AddRemove.tsx
index 288ef03c1f1..a353e3e4edb 100644
--- a/public/app/plugins/datasource/elasticsearch/components/AddRemove.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/AddRemove.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { Button } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/elasticsearch/components/MetricPicker.tsx b/public/app/plugins/datasource/elasticsearch/components/MetricPicker.tsx
index edd720f764a..b8a175408d7 100644
--- a/public/app/plugins/datasource/elasticsearch/components/MetricPicker.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/MetricPicker.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { SelectableValue } from '@grafana/data';
import { Segment } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/AnnotationQueryEditor.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/AnnotationQueryEditor.tsx
index 3411b611647..6743f8bb62c 100644
--- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/AnnotationQueryEditor.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/AnnotationQueryEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { AnnotationQuery } from '@grafana/data';
import { EditorField, EditorRow } from '@grafana/experimental';
import { Input, Stack } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/BucketAggregationEditor.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/BucketAggregationEditor.tsx
index ae1963dd9f8..4b9910e2c7a 100644
--- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/BucketAggregationEditor.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/BucketAggregationEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SelectableValue } from '@grafana/data';
import { InlineSegmentGroup, Segment, SegmentAsync } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/DateHistogramSettingsEditor.test.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/DateHistogramSettingsEditor.test.tsx
index 52b45832fbf..76cd65f3880 100644
--- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/DateHistogramSettingsEditor.test.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/DateHistogramSettingsEditor.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { select } from 'react-select-event';
import { useDispatch } from '../../../../hooks/useStatelessReducer';
diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/DateHistogramSettingsEditor.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/DateHistogramSettingsEditor.tsx
index 52a3081ac19..5ea427c3984 100644
--- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/DateHistogramSettingsEditor.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/DateHistogramSettingsEditor.tsx
@@ -1,5 +1,5 @@
import { uniqueId } from 'lodash';
-import React, { useCallback, useRef } from 'react';
+import { useCallback, useRef } from 'react';
import { GroupBase, OptionsOrGroups } from 'react-select';
import { InternalTimeZones, SelectableValue } from '@grafana/data';
diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/FiltersSettingsEditor/index.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/FiltersSettingsEditor/index.tsx
index ef6a38bda57..de91aadb3f7 100644
--- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/FiltersSettingsEditor/index.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/FiltersSettingsEditor/index.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { uniqueId } from 'lodash';
-import React, { useEffect, useRef } from 'react';
+import { useEffect, useRef } from 'react';
import { InlineField, Input, QueryField } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/TermsSettingsEditor.test.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/TermsSettingsEditor.test.tsx
index 97442a66f35..bbc46703aaa 100644
--- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/TermsSettingsEditor.test.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/TermsSettingsEditor.test.tsx
@@ -1,5 +1,4 @@
import { screen } from '@testing-library/react';
-import React from 'react';
import selectEvent from 'react-select-event';
import { renderWithESProvider } from '../../../../test-helpers/render';
diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/TermsSettingsEditor.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/TermsSettingsEditor.tsx
index 7b005941ab8..e6292c75396 100644
--- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/TermsSettingsEditor.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/TermsSettingsEditor.tsx
@@ -1,5 +1,5 @@
import { uniqueId } from 'lodash';
-import React, { useRef } from 'react';
+import { useRef } from 'react';
import { SelectableValue } from '@grafana/data';
import { InlineField, Select, Input } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/index.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/index.tsx
index eb3e650d73f..b46778d39d9 100644
--- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/index.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/SettingsEditor/index.tsx
@@ -1,5 +1,5 @@
import { uniqueId } from 'lodash';
-import React, { ComponentProps, useRef } from 'react';
+import { ComponentProps, useRef } from 'react';
import { InlineField, Input } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/index.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/index.tsx
index dfd631f3c59..83578fc33b4 100644
--- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/index.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/BucketAggregationsEditor/index.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Button } from '@grafana/ui';
import { useDispatch } from '../../../hooks/useStatelessReducer';
diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/ElasticsearchQueryContext.test.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/ElasticsearchQueryContext.test.tsx
index 1ba546ccac2..15bdaf6a53d 100644
--- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/ElasticsearchQueryContext.test.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/ElasticsearchQueryContext.test.tsx
@@ -1,6 +1,6 @@
import { render } from '@testing-library/react';
import { renderHook } from '@testing-library/react-hooks';
-import React, { PropsWithChildren } from 'react';
+import { PropsWithChildren } from 'react';
import { getDefaultTimeRange } from '@grafana/data';
diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/ElasticsearchQueryContext.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/ElasticsearchQueryContext.tsx
index 6c41d99a18f..b2fd49cde44 100644
--- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/ElasticsearchQueryContext.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/ElasticsearchQueryContext.tsx
@@ -1,4 +1,4 @@
-import React, { Context, createContext, PropsWithChildren, useCallback, useContext, useEffect, useState } from 'react';
+import { Context, createContext, PropsWithChildren, useCallback, useContext, useEffect, useState } from 'react';
import { TimeRange } from '@grafana/data';
diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/MetricEditor.test.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/MetricEditor.test.tsx
index 81a21af4652..64130e3ff26 100644
--- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/MetricEditor.test.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/MetricEditor.test.tsx
@@ -1,6 +1,6 @@
import { act, fireEvent, render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { PropsWithChildren } from 'react';
+import { PropsWithChildren } from 'react';
import { from } from 'rxjs';
import { getDefaultTimeRange } from '@grafana/data';
diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/MetricEditor.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/MetricEditor.tsx
index a520ae0fbbe..52a9c01617f 100644
--- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/MetricEditor.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/MetricEditor.tsx
@@ -1,5 +1,5 @@
import { cx } from '@emotion/css';
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { satisfies, SemVer } from 'semver';
import { SelectableValue } from '@grafana/data';
diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/BucketScriptSettingsEditor/index.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/BucketScriptSettingsEditor/index.tsx
index 4f8a9ebfdf8..91b148b6f67 100644
--- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/BucketScriptSettingsEditor/index.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/BucketScriptSettingsEditor/index.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { uniqueId } from 'lodash';
-import React, { Fragment, useEffect } from 'react';
+import { Fragment, useEffect } from 'react';
import { Input, InlineLabel } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/MovingAverageSettingsEditor.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/MovingAverageSettingsEditor.tsx
index b8f5a94cdda..ac4aa676fd5 100644
--- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/MovingAverageSettingsEditor.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/MovingAverageSettingsEditor.tsx
@@ -1,5 +1,6 @@
import { uniqueId } from 'lodash';
-import React, { useRef } from 'react';
+import { useRef } from 'react';
+import * as React from 'react';
import { Input, InlineField, Select, InlineSwitch } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/SettingField.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/SettingField.tsx
index 5a0d48924c1..cefb32fd682 100644
--- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/SettingField.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/SettingField.tsx
@@ -1,5 +1,5 @@
import { uniqueId } from 'lodash';
-import React, { ComponentProps, useState } from 'react';
+import { ComponentProps, useState } from 'react';
import { InlineField, Input } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/TopMetricsSettingsEditor.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/TopMetricsSettingsEditor.tsx
index 3c5bdba15d1..51da99bac0a 100644
--- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/TopMetricsSettingsEditor.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/TopMetricsSettingsEditor.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { SelectableValue } from '@grafana/data';
import { AsyncMultiSelect, InlineField, SegmentAsync, Select } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/index.test.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/index.test.tsx
index f3753a70540..f8b18d13388 100644
--- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/index.test.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/index.test.tsx
@@ -1,5 +1,4 @@
import { fireEvent, render, screen } from '@testing-library/react';
-import React from 'react';
import { getDefaultTimeRange } from '@grafana/data';
diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/index.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/index.tsx
index 83f8338903f..be8246fc0cc 100644
--- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/index.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/SettingsEditor/index.tsx
@@ -1,5 +1,6 @@
import { uniqueId } from 'lodash';
-import React, { ComponentProps, useId, useRef, useState } from 'react';
+import { ComponentProps, useId, useRef, useState } from 'react';
+import * as React from 'react';
import { InlineField, Input, InlineSwitch, Select } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/index.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/index.tsx
index 982202be9f1..cc4901eb1d1 100644
--- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/index.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/index.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Alert, Button } from '@grafana/ui';
import { useDispatch } from '../../../hooks/useStatelessReducer';
diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/QueryEditorRow.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/QueryEditorRow.tsx
index 297c8372625..76ba289ae4d 100644
--- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/QueryEditorRow.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/QueryEditorRow.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { noop } from 'lodash';
-import React, { PropsWithChildren } from 'react';
+import { PropsWithChildren } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { IconButton, InlineFieldRow, InlineLabel, InlineSegmentGroup, useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/QueryEditorSpecialMetricRow.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/QueryEditorSpecialMetricRow.tsx
index 6820e012391..ccd8ba1ffe4 100644
--- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/QueryEditorSpecialMetricRow.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/QueryEditorSpecialMetricRow.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { InlineFieldRow, InlineLabel, InlineSegmentGroup } from '@grafana/ui';
import { MetricAggregation } from '../../types';
diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/QueryTypeSelector.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/QueryTypeSelector.tsx
index 7dfa3fd2ec6..695237f706f 100644
--- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/QueryTypeSelector.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/QueryTypeSelector.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SelectableValue } from '@grafana/data';
import { RadioButtonGroup } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/SettingsEditorContainer.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/SettingsEditorContainer.tsx
index f9ec8a44278..47994ccd111 100644
--- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/SettingsEditorContainer.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/SettingsEditorContainer.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { PropsWithChildren, useState } from 'react';
+import { PropsWithChildren, useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Icon, InlineSegmentGroup, useTheme2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/index.test.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/index.test.tsx
index 67c19e51607..0a5f34abba5 100644
--- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/index.test.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/index.test.tsx
@@ -1,5 +1,4 @@
import { fireEvent, render, screen } from '@testing-library/react';
-import React from 'react';
import { ElasticDatasource } from '../../datasource';
import { ElasticsearchQuery } from '../../types';
diff --git a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/index.tsx b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/index.tsx
index d9e8ab5f80f..135734cb4f2 100644
--- a/public/app/plugins/datasource/elasticsearch/components/QueryEditor/index.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/QueryEditor/index.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useId, useState } from 'react';
+import { useEffect, useId, useState } from 'react';
import { SemVer } from 'semver';
import { getDefaultTimeRange, GrafanaTheme2, QueryEditorProps } from '@grafana/data';
diff --git a/public/app/plugins/datasource/elasticsearch/components/hooks/useCreatableSelectPersistedBehaviour.test.tsx b/public/app/plugins/datasource/elasticsearch/components/hooks/useCreatableSelectPersistedBehaviour.test.tsx
index bd4d1acd91c..a95a1b5eb0e 100644
--- a/public/app/plugins/datasource/elasticsearch/components/hooks/useCreatableSelectPersistedBehaviour.test.tsx
+++ b/public/app/plugins/datasource/elasticsearch/components/hooks/useCreatableSelectPersistedBehaviour.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { Select, InlineField } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/elasticsearch/configuration/ConfigEditor.test.tsx b/public/app/plugins/datasource/elasticsearch/configuration/ConfigEditor.test.tsx
index 8438017aa40..b6183ea3a16 100644
--- a/public/app/plugins/datasource/elasticsearch/configuration/ConfigEditor.test.tsx
+++ b/public/app/plugins/datasource/elasticsearch/configuration/ConfigEditor.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { ConfigEditor } from './ConfigEditor';
import { createDefaultConfigOptions } from './__mocks__/configOptions';
diff --git a/public/app/plugins/datasource/elasticsearch/configuration/ConfigEditor.tsx b/public/app/plugins/datasource/elasticsearch/configuration/ConfigEditor.tsx
index 1dc4aa84780..64342c5b6f6 100644
--- a/public/app/plugins/datasource/elasticsearch/configuration/ConfigEditor.tsx
+++ b/public/app/plugins/datasource/elasticsearch/configuration/ConfigEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import { SIGV4ConnectionConfig } from '@grafana/aws-sdk';
import { DataSourcePluginOptionsEditorProps } from '@grafana/data';
diff --git a/public/app/plugins/datasource/elasticsearch/configuration/DataLink.tsx b/public/app/plugins/datasource/elasticsearch/configuration/DataLink.tsx
index da2c231ad13..f3ddb9f8e87 100644
--- a/public/app/plugins/datasource/elasticsearch/configuration/DataLink.tsx
+++ b/public/app/plugins/datasource/elasticsearch/configuration/DataLink.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { Dispatch, SetStateAction, useEffect, useState } from 'react';
+import { Dispatch, SetStateAction, useEffect, useState } from 'react';
+import * as React from 'react';
import { usePrevious } from 'react-use';
import { DataSourceInstanceSettings, VariableSuggestion } from '@grafana/data';
diff --git a/public/app/plugins/datasource/elasticsearch/configuration/DataLinks.test.tsx b/public/app/plugins/datasource/elasticsearch/configuration/DataLinks.test.tsx
index a623d68e822..57656fc51ba 100644
--- a/public/app/plugins/datasource/elasticsearch/configuration/DataLinks.test.tsx
+++ b/public/app/plugins/datasource/elasticsearch/configuration/DataLinks.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { DataLinkConfig } from '../types';
diff --git a/public/app/plugins/datasource/elasticsearch/configuration/DataLinks.tsx b/public/app/plugins/datasource/elasticsearch/configuration/DataLinks.tsx
index ed340f5c044..ce1740bc8f6 100644
--- a/public/app/plugins/datasource/elasticsearch/configuration/DataLinks.tsx
+++ b/public/app/plugins/datasource/elasticsearch/configuration/DataLinks.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2, VariableOrigin, DataLinkBuiltInVars } from '@grafana/data';
import { ConfigDescriptionLink, ConfigSubSection } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/elasticsearch/configuration/ElasticDetails.test.tsx b/public/app/plugins/datasource/elasticsearch/configuration/ElasticDetails.test.tsx
index 0b7af77201d..23d2d8def31 100644
--- a/public/app/plugins/datasource/elasticsearch/configuration/ElasticDetails.test.tsx
+++ b/public/app/plugins/datasource/elasticsearch/configuration/ElasticDetails.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import selectEvent from 'react-select-event';
import { ElasticDetails } from './ElasticDetails';
diff --git a/public/app/plugins/datasource/elasticsearch/configuration/ElasticDetails.tsx b/public/app/plugins/datasource/elasticsearch/configuration/ElasticDetails.tsx
index 4b8707e465e..2a99429238b 100644
--- a/public/app/plugins/datasource/elasticsearch/configuration/ElasticDetails.tsx
+++ b/public/app/plugins/datasource/elasticsearch/configuration/ElasticDetails.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { DataSourceSettings, SelectableValue } from '@grafana/data';
import { ConfigDescriptionLink, ConfigSubSection } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/elasticsearch/configuration/LogsConfig.test.tsx b/public/app/plugins/datasource/elasticsearch/configuration/LogsConfig.test.tsx
index 97d3d130398..40e707b7ad4 100644
--- a/public/app/plugins/datasource/elasticsearch/configuration/LogsConfig.test.tsx
+++ b/public/app/plugins/datasource/elasticsearch/configuration/LogsConfig.test.tsx
@@ -1,5 +1,4 @@
import { render, screen, fireEvent } from '@testing-library/react';
-import React from 'react';
import { LogsConfig } from './LogsConfig';
import { createDefaultConfigOptions } from './__mocks__/configOptions';
diff --git a/public/app/plugins/datasource/elasticsearch/configuration/LogsConfig.tsx b/public/app/plugins/datasource/elasticsearch/configuration/LogsConfig.tsx
index 3289d2fd90a..b5b5ab3006f 100644
--- a/public/app/plugins/datasource/elasticsearch/configuration/LogsConfig.tsx
+++ b/public/app/plugins/datasource/elasticsearch/configuration/LogsConfig.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { ConfigDescriptionLink, ConfigSubSection } from '@grafana/experimental';
import { Input, InlineField } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/elasticsearch/hooks/useFields.test.tsx b/public/app/plugins/datasource/elasticsearch/hooks/useFields.test.tsx
index d977e5f4dec..5751aa51acd 100644
--- a/public/app/plugins/datasource/elasticsearch/hooks/useFields.test.tsx
+++ b/public/app/plugins/datasource/elasticsearch/hooks/useFields.test.tsx
@@ -1,5 +1,5 @@
import { renderHook } from '@testing-library/react';
-import React, { PropsWithChildren } from 'react';
+import { PropsWithChildren } from 'react';
import { from } from 'rxjs';
import { getDefaultTimeRange } from '@grafana/data';
diff --git a/public/app/plugins/datasource/elasticsearch/hooks/useNextId.test.tsx b/public/app/plugins/datasource/elasticsearch/hooks/useNextId.test.tsx
index 881d1030d73..e37c4d1e2bc 100644
--- a/public/app/plugins/datasource/elasticsearch/hooks/useNextId.test.tsx
+++ b/public/app/plugins/datasource/elasticsearch/hooks/useNextId.test.tsx
@@ -1,5 +1,5 @@
import { renderHook } from '@testing-library/react';
-import React, { PropsWithChildren } from 'react';
+import { PropsWithChildren } from 'react';
import { getDefaultTimeRange } from '@grafana/data';
diff --git a/public/app/plugins/datasource/elasticsearch/hooks/useStatelessReducer.test.tsx b/public/app/plugins/datasource/elasticsearch/hooks/useStatelessReducer.test.tsx
index 509f027d696..80d4c73e093 100644
--- a/public/app/plugins/datasource/elasticsearch/hooks/useStatelessReducer.test.tsx
+++ b/public/app/plugins/datasource/elasticsearch/hooks/useStatelessReducer.test.tsx
@@ -1,5 +1,5 @@
import { renderHook } from '@testing-library/react-hooks';
-import React, { PropsWithChildren } from 'react';
+import { PropsWithChildren } from 'react';
import { useStatelessReducer, useDispatch, DispatchContext, combineReducers } from './useStatelessReducer';
diff --git a/public/app/plugins/datasource/elasticsearch/test-helpers/render.tsx b/public/app/plugins/datasource/elasticsearch/test-helpers/render.tsx
index 236f8e65c11..85daa974d9e 100644
--- a/public/app/plugins/datasource/elasticsearch/test-helpers/render.tsx
+++ b/public/app/plugins/datasource/elasticsearch/test-helpers/render.tsx
@@ -1,5 +1,5 @@
import { render } from '@testing-library/react';
-import React, { ComponentProps, ReactNode } from 'react';
+import { ComponentProps, ReactNode } from 'react';
import { getDefaultTimeRange } from '@grafana/data';
diff --git a/public/app/plugins/datasource/grafana-postgresql-datasource/CheatSheet.tsx b/public/app/plugins/datasource/grafana-postgresql-datasource/CheatSheet.tsx
index 8608b33cd81..c3ade177b74 100644
--- a/public/app/plugins/datasource/grafana-postgresql-datasource/CheatSheet.tsx
+++ b/public/app/plugins/datasource/grafana-postgresql-datasource/CheatSheet.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/grafana-postgresql-datasource/PostgresQueryEditor.tsx b/public/app/plugins/datasource/grafana-postgresql-datasource/PostgresQueryEditor.tsx
index f1fa982ae93..22bcc5f041c 100644
--- a/public/app/plugins/datasource/grafana-postgresql-datasource/PostgresQueryEditor.tsx
+++ b/public/app/plugins/datasource/grafana-postgresql-datasource/PostgresQueryEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { QueryEditorProps } from '@grafana/data';
import { SqlQueryEditor, SQLOptions, SQLQuery, QueryHeaderProps } from '@grafana/sql';
diff --git a/public/app/plugins/datasource/grafana-postgresql-datasource/configuration/ConfigurationEditor.tsx b/public/app/plugins/datasource/grafana-postgresql-datasource/configuration/ConfigurationEditor.tsx
index 8acacf21633..3c1d5da4e40 100644
--- a/public/app/plugins/datasource/grafana-postgresql-datasource/configuration/ConfigurationEditor.tsx
+++ b/public/app/plugins/datasource/grafana-postgresql-datasource/configuration/ConfigurationEditor.tsx
@@ -1,4 +1,4 @@
-import React, { SyntheticEvent, useState } from 'react';
+import { SyntheticEvent, useState } from 'react';
import {
DataSourcePluginOptionsEditorProps,
diff --git a/public/app/plugins/datasource/grafana-postgresql-datasource/tsconfig.json b/public/app/plugins/datasource/grafana-postgresql-datasource/tsconfig.json
index 7daf2ee8aba..1690bc6f49f 100644
--- a/public/app/plugins/datasource/grafana-postgresql-datasource/tsconfig.json
+++ b/public/app/plugins/datasource/grafana-postgresql-datasource/tsconfig.json
@@ -1,4 +1,5 @@
{
+ "jsx": "react-jsx",
"extends": "@grafana/plugin-configs/tsconfig.json",
"include": ["."]
}
diff --git a/public/app/plugins/datasource/grafana-pyroscope-datasource/ConfigEditor.tsx b/public/app/plugins/datasource/grafana-pyroscope-datasource/ConfigEditor.tsx
index 1ecbab4d42b..af6467d7896 100644
--- a/public/app/plugins/datasource/grafana-pyroscope-datasource/ConfigEditor.tsx
+++ b/public/app/plugins/datasource/grafana-pyroscope-datasource/ConfigEditor.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { DataSourcePluginOptionsEditorProps, GrafanaTheme2 } from '@grafana/data';
import {
diff --git a/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/EditorField.tsx b/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/EditorField.tsx
index 56007cac05b..dd5b27f56c1 100644
--- a/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/EditorField.tsx
+++ b/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/EditorField.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { ComponentProps } from 'react';
+import { ComponentProps } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Field, Icon, PopoverContent, ReactUtils, Tooltip, useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/EditorRow.tsx b/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/EditorRow.tsx
index 5fe10a24999..a45add59216 100644
--- a/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/EditorRow.tsx
+++ b/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/EditorRow.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/EditorRows.tsx b/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/EditorRows.tsx
index ce7e38c112a..de79a2b079c 100644
--- a/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/EditorRows.tsx
+++ b/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/EditorRows.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { Stack } from './Stack';
diff --git a/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/LabelsEditor.tsx b/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/LabelsEditor.tsx
index 6c7cee86081..e8e99208811 100644
--- a/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/LabelsEditor.tsx
+++ b/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/LabelsEditor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useRef } from 'react';
+import { useEffect, useRef } from 'react';
import { useAsync, useLatest } from 'react-use';
import { CodeEditor, Monaco, useStyles2, monacoTypes } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/ProfileTypesCascader.tsx b/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/ProfileTypesCascader.tsx
index fd21bb71585..f207d6eb4eb 100644
--- a/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/ProfileTypesCascader.tsx
+++ b/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/ProfileTypesCascader.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useMemo, useState } from 'react';
+import { useEffect, useMemo, useState } from 'react';
import { TimeRange } from '@grafana/data';
import { Cascader, CascaderOption } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/QueryEditor.test.tsx b/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/QueryEditor.test.tsx
index 1f1b89830ec..1c5b2b273cf 100644
--- a/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/QueryEditor.test.tsx
+++ b/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/QueryEditor.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { CoreApp, PluginType } from '@grafana/data';
import { setPluginExtensionsHook } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/QueryEditor.tsx b/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/QueryEditor.tsx
index c62defc81ce..9d50180d538 100644
--- a/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/QueryEditor.tsx
+++ b/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/QueryEditor.tsx
@@ -1,6 +1,6 @@
import deepEqual from 'fast-deep-equal';
import { debounce } from 'lodash';
-import React, { useCallback, useEffect, useRef, useState } from 'react';
+import { useCallback, useEffect, useRef, useState } from 'react';
import { CoreApp, QueryEditorProps, TimeRange } from '@grafana/data';
import { LoadingPlaceholder } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/QueryOptionGroup.tsx b/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/QueryOptionGroup.tsx
index dfd42c81bf5..c6c3dad3719 100644
--- a/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/QueryOptionGroup.tsx
+++ b/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/QueryOptionGroup.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { useToggle } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/QueryOptions.tsx b/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/QueryOptions.tsx
index 7db169674b8..0aea051512f 100644
--- a/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/QueryOptions.tsx
+++ b/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/QueryOptions.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { CoreApp, GrafanaTheme2, SelectableValue } from '@grafana/data';
import { useStyles2, RadioButtonGroup, MultiSelect, Input } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/Stack.tsx b/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/Stack.tsx
index 51ba00444c9..483af932c05 100644
--- a/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/Stack.tsx
+++ b/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/Stack.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { CSSProperties } from 'react';
+import { CSSProperties } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/grafana-pyroscope-datasource/VariableQueryEditor.test.tsx b/public/app/plugins/datasource/grafana-pyroscope-datasource/VariableQueryEditor.test.tsx
index 4442512e00c..d11bbde8bbd 100644
--- a/public/app/plugins/datasource/grafana-pyroscope-datasource/VariableQueryEditor.test.tsx
+++ b/public/app/plugins/datasource/grafana-pyroscope-datasource/VariableQueryEditor.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { DataSourceInstanceSettings } from '@grafana/data';
import { getTemplateSrv } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/grafana-pyroscope-datasource/VariableQueryEditor.tsx b/public/app/plugins/datasource/grafana-pyroscope-datasource/VariableQueryEditor.tsx
index 27f4b2d085c..bf25fa7cda0 100644
--- a/public/app/plugins/datasource/grafana-pyroscope-datasource/VariableQueryEditor.tsx
+++ b/public/app/plugins/datasource/grafana-pyroscope-datasource/VariableQueryEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { QueryEditorProps, SelectableValue, TimeRange } from '@grafana/data';
import { InlineField, InlineFieldRow, LoadingPlaceholder, Select } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/grafana-pyroscope-datasource/tsconfig.json b/public/app/plugins/datasource/grafana-pyroscope-datasource/tsconfig.json
index 7daf2ee8aba..baaaea04185 100644
--- a/public/app/plugins/datasource/grafana-pyroscope-datasource/tsconfig.json
+++ b/public/app/plugins/datasource/grafana-pyroscope-datasource/tsconfig.json
@@ -1,4 +1,7 @@
{
+ "compilerOptions": {
+ "jsx": "react-jsx"
+ },
"extends": "@grafana/plugin-configs/tsconfig.json",
"include": ["."]
}
diff --git a/public/app/plugins/datasource/grafana-testdata-datasource/ConfigEditor.tsx b/public/app/plugins/datasource/grafana-testdata-datasource/ConfigEditor.tsx
index 9c78b849d9b..bfc85938fd9 100644
--- a/public/app/plugins/datasource/grafana-testdata-datasource/ConfigEditor.tsx
+++ b/public/app/plugins/datasource/grafana-testdata-datasource/ConfigEditor.tsx
@@ -1,5 +1,5 @@
// Libraries
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { DataSourcePluginOptionsEditorProps } from '@grafana/data';
diff --git a/public/app/plugins/datasource/grafana-testdata-datasource/MetaDataInspector.tsx b/public/app/plugins/datasource/grafana-testdata-datasource/MetaDataInspector.tsx
index 3ebf7248ef6..e9bc66cd777 100644
--- a/public/app/plugins/datasource/grafana-testdata-datasource/MetaDataInspector.tsx
+++ b/public/app/plugins/datasource/grafana-testdata-datasource/MetaDataInspector.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { MetadataInspectorProps } from '@grafana/data';
import { Stack } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/grafana-testdata-datasource/QueryEditor.test.tsx b/public/app/plugins/datasource/grafana-testdata-datasource/QueryEditor.test.tsx
index b4b0e8e8b8d..6c78486696b 100644
--- a/public/app/plugins/datasource/grafana-testdata-datasource/QueryEditor.test.tsx
+++ b/public/app/plugins/datasource/grafana-testdata-datasource/QueryEditor.test.tsx
@@ -1,6 +1,5 @@
import { fireEvent, render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/plugins/datasource/grafana-testdata-datasource/QueryEditor.tsx b/public/app/plugins/datasource/grafana-testdata-datasource/QueryEditor.tsx
index eb684d5abac..8c4e6599073 100644
--- a/public/app/plugins/datasource/grafana-testdata-datasource/QueryEditor.tsx
+++ b/public/app/plugins/datasource/grafana-testdata-datasource/QueryEditor.tsx
@@ -1,4 +1,4 @@
-import React, { FormEvent, useMemo } from 'react';
+import { FormEvent, useMemo } from 'react';
import { useAsync } from 'react-use';
import { QueryEditorProps, SelectableValue } from '@grafana/data';
diff --git a/public/app/plugins/datasource/grafana-testdata-datasource/TestInfoTab.tsx b/public/app/plugins/datasource/grafana-testdata-datasource/TestInfoTab.tsx
index 5ab58f4f621..1472eed8615 100644
--- a/public/app/plugins/datasource/grafana-testdata-datasource/TestInfoTab.tsx
+++ b/public/app/plugins/datasource/grafana-testdata-datasource/TestInfoTab.tsx
@@ -1,5 +1,5 @@
// Libraries
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { PluginConfigPageProps, DataSourcePluginMeta, DataSourceJsonData } from '@grafana/data';
import { LinkButton } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/grafana-testdata-datasource/components/CSVContentEditor.tsx b/public/app/plugins/datasource/grafana-testdata-datasource/components/CSVContentEditor.tsx
index aa6c2f85c72..1ad102b9dc3 100644
--- a/public/app/plugins/datasource/grafana-testdata-datasource/components/CSVContentEditor.tsx
+++ b/public/app/plugins/datasource/grafana-testdata-datasource/components/CSVContentEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { CodeEditor } from '@grafana/ui';
import { EditorProps } from '../QueryEditor';
diff --git a/public/app/plugins/datasource/grafana-testdata-datasource/components/CSVFileEditor.tsx b/public/app/plugins/datasource/grafana-testdata-datasource/components/CSVFileEditor.tsx
index 0ae69bd7b0c..c386602010f 100644
--- a/public/app/plugins/datasource/grafana-testdata-datasource/components/CSVFileEditor.tsx
+++ b/public/app/plugins/datasource/grafana-testdata-datasource/components/CSVFileEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SelectableValue } from '@grafana/data';
import { InlineField, InlineFieldRow, Select } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/grafana-testdata-datasource/components/CSVWaveEditor.tsx b/public/app/plugins/datasource/grafana-testdata-datasource/components/CSVWaveEditor.tsx
index 5635dd77007..20dcb00bdd8 100644
--- a/public/app/plugins/datasource/grafana-testdata-datasource/components/CSVWaveEditor.tsx
+++ b/public/app/plugins/datasource/grafana-testdata-datasource/components/CSVWaveEditor.tsx
@@ -1,4 +1,5 @@
-import React, { PureComponent, useState } from 'react';
+import { PureComponent, useState } from 'react';
+import * as React from 'react';
import { Button, InlineField, InlineFieldRow, Input } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/grafana-testdata-datasource/components/ErrorEditor.tsx b/public/app/plugins/datasource/grafana-testdata-datasource/components/ErrorEditor.tsx
index bdf61946809..921a6e952c7 100644
--- a/public/app/plugins/datasource/grafana-testdata-datasource/components/ErrorEditor.tsx
+++ b/public/app/plugins/datasource/grafana-testdata-datasource/components/ErrorEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { InlineField, InlineFieldRow, Select } from '@grafana/ui';
import { EditorProps } from '../QueryEditor';
diff --git a/public/app/plugins/datasource/grafana-testdata-datasource/components/GrafanaLiveEditor.tsx b/public/app/plugins/datasource/grafana-testdata-datasource/components/GrafanaLiveEditor.tsx
index ab4c6bff3f1..b76607cf711 100644
--- a/public/app/plugins/datasource/grafana-testdata-datasource/components/GrafanaLiveEditor.tsx
+++ b/public/app/plugins/datasource/grafana-testdata-datasource/components/GrafanaLiveEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SelectableValue } from '@grafana/data';
import { InlineField, InlineFieldRow, Select } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/grafana-testdata-datasource/components/NodeGraphEditor.tsx b/public/app/plugins/datasource/grafana-testdata-datasource/components/NodeGraphEditor.tsx
index 6c09214a47f..5a6f7a11b60 100644
--- a/public/app/plugins/datasource/grafana-testdata-datasource/components/NodeGraphEditor.tsx
+++ b/public/app/plugins/datasource/grafana-testdata-datasource/components/NodeGraphEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Input, InlineFieldRow, InlineField, Select } from '@grafana/ui';
import { NodesQuery, TestDataDataQuery } from '../dataquery';
diff --git a/public/app/plugins/datasource/grafana-testdata-datasource/components/PredictablePulseEditor.tsx b/public/app/plugins/datasource/grafana-testdata-datasource/components/PredictablePulseEditor.tsx
index 1cfab8b3a68..661dc5b3bc9 100644
--- a/public/app/plugins/datasource/grafana-testdata-datasource/components/PredictablePulseEditor.tsx
+++ b/public/app/plugins/datasource/grafana-testdata-datasource/components/PredictablePulseEditor.tsx
@@ -1,4 +1,4 @@
-import React, { ChangeEvent } from 'react';
+import { ChangeEvent } from 'react';
import { InlineField, InlineFieldRow, Input } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/grafana-testdata-datasource/components/RandomWalkEditor.tsx b/public/app/plugins/datasource/grafana-testdata-datasource/components/RandomWalkEditor.tsx
index 364b326b38a..0bdcc29f0c1 100644
--- a/public/app/plugins/datasource/grafana-testdata-datasource/components/RandomWalkEditor.tsx
+++ b/public/app/plugins/datasource/grafana-testdata-datasource/components/RandomWalkEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { selectors } from '@grafana/e2e-selectors';
import { InlineField, InlineFieldRow, Input } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/grafana-testdata-datasource/components/RawFrameEditor.tsx b/public/app/plugins/datasource/grafana-testdata-datasource/components/RawFrameEditor.tsx
index 7eea237857c..faa2fb766e6 100644
--- a/public/app/plugins/datasource/grafana-testdata-datasource/components/RawFrameEditor.tsx
+++ b/public/app/plugins/datasource/grafana-testdata-datasource/components/RawFrameEditor.tsx
@@ -1,5 +1,5 @@
import { isArray } from 'lodash';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { dataFrameToJSON, toDataFrame, toDataFrameDTO } from '@grafana/data';
import { toDataQueryResponse } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/grafana-testdata-datasource/components/SimulationQueryEditor.tsx b/public/app/plugins/datasource/grafana-testdata-datasource/components/SimulationQueryEditor.tsx
index e7e889af97d..e808ceb6178 100644
--- a/public/app/plugins/datasource/grafana-testdata-datasource/components/SimulationQueryEditor.tsx
+++ b/public/app/plugins/datasource/grafana-testdata-datasource/components/SimulationQueryEditor.tsx
@@ -1,4 +1,4 @@
-import React, { FormEvent, useMemo, useState } from 'react';
+import { FormEvent, useMemo, useState } from 'react';
import { useAsync } from 'react-use';
import { DataFrameJSON, SelectableValue } from '@grafana/data';
diff --git a/public/app/plugins/datasource/grafana-testdata-datasource/components/SimulationSchemaForm.tsx b/public/app/plugins/datasource/grafana-testdata-datasource/components/SimulationSchemaForm.tsx
index 7e33eb61eeb..fc9a9cec505 100644
--- a/public/app/plugins/datasource/grafana-testdata-datasource/components/SimulationSchemaForm.tsx
+++ b/public/app/plugins/datasource/grafana-testdata-datasource/components/SimulationSchemaForm.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { FormEvent, useState, ChangeEvent } from 'react';
+import { FormEvent, useState, ChangeEvent } from 'react';
import { DataFrameSchema, FieldSchema, GrafanaTheme2 } from '@grafana/data';
import { useStyles2, TextArea, InlineField, Input, FieldSet, InlineSwitch } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/grafana-testdata-datasource/components/StreamingClientEditor.tsx b/public/app/plugins/datasource/grafana-testdata-datasource/components/StreamingClientEditor.tsx
index 67474d9515b..bd0abd4912e 100644
--- a/public/app/plugins/datasource/grafana-testdata-datasource/components/StreamingClientEditor.tsx
+++ b/public/app/plugins/datasource/grafana-testdata-datasource/components/StreamingClientEditor.tsx
@@ -1,4 +1,4 @@
-import React, { ChangeEvent } from 'react';
+import { ChangeEvent } from 'react';
import { SelectableValue } from '@grafana/data';
import { InlineField, InlineFieldRow, Input, Select } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/grafana-testdata-datasource/components/USAQueryEditor.tsx b/public/app/plugins/datasource/grafana-testdata-datasource/components/USAQueryEditor.tsx
index 8f4866bf8ce..6a8aa544efe 100644
--- a/public/app/plugins/datasource/grafana-testdata-datasource/components/USAQueryEditor.tsx
+++ b/public/app/plugins/datasource/grafana-testdata-datasource/components/USAQueryEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SelectableValue } from '@grafana/data';
import { InlineFieldRow, InlineField, Select, MultiSelect, Input } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/grafana-testdata-datasource/tsconfig.json b/public/app/plugins/datasource/grafana-testdata-datasource/tsconfig.json
index 7daf2ee8aba..baaaea04185 100644
--- a/public/app/plugins/datasource/grafana-testdata-datasource/tsconfig.json
+++ b/public/app/plugins/datasource/grafana-testdata-datasource/tsconfig.json
@@ -1,4 +1,7 @@
{
+ "compilerOptions": {
+ "jsx": "react-jsx"
+ },
"extends": "@grafana/plugin-configs/tsconfig.json",
"include": ["."]
}
diff --git a/public/app/plugins/datasource/grafana/components/AnnotationQueryEditor.test.tsx b/public/app/plugins/datasource/grafana/components/AnnotationQueryEditor.test.tsx
index 63312c98faf..44daef9a607 100644
--- a/public/app/plugins/datasource/grafana/components/AnnotationQueryEditor.test.tsx
+++ b/public/app/plugins/datasource/grafana/components/AnnotationQueryEditor.test.tsx
@@ -1,5 +1,4 @@
import { fireEvent, render, screen } from '@testing-library/react';
-import React from 'react';
import { GrafanaAnnotationQuery, GrafanaAnnotationType, GrafanaQueryType } from '../types';
diff --git a/public/app/plugins/datasource/grafana/components/AnnotationQueryEditor.tsx b/public/app/plugins/datasource/grafana/components/AnnotationQueryEditor.tsx
index 0894f13ab2b..2314ae6a2be 100644
--- a/public/app/plugins/datasource/grafana/components/AnnotationQueryEditor.tsx
+++ b/public/app/plugins/datasource/grafana/components/AnnotationQueryEditor.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
+import * as React from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { Field, FieldSet, Select, Switch, useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/grafana/components/QueryEditor.tsx b/public/app/plugins/datasource/grafana/components/QueryEditor.tsx
index bd52ddabeaa..16707526820 100644
--- a/public/app/plugins/datasource/grafana/components/QueryEditor.tsx
+++ b/public/app/plugins/datasource/grafana/components/QueryEditor.tsx
@@ -1,6 +1,7 @@
import { css } from '@emotion/css';
import pluralize from 'pluralize';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
+import * as React from 'react';
import { DropEvent, FileRejection } from 'react-dropzone';
import {
diff --git a/public/app/plugins/datasource/grafana/components/SearchEditor.tsx b/public/app/plugins/datasource/grafana/components/SearchEditor.tsx
index dea22b8b22e..e5d102c8be4 100644
--- a/public/app/plugins/datasource/grafana/components/SearchEditor.tsx
+++ b/public/app/plugins/datasource/grafana/components/SearchEditor.tsx
@@ -1,4 +1,5 @@
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
+import * as React from 'react';
import { InlineField, Input, InlineFieldRow, CodeEditor } from '@grafana/ui';
import { SearchQuery } from 'app/features/search/service';
diff --git a/public/app/plugins/datasource/grafana/components/TimePickerInput.tsx b/public/app/plugins/datasource/grafana/components/TimePickerInput.tsx
index 6c735c45604..dbe88c64dd9 100644
--- a/public/app/plugins/datasource/grafana/components/TimePickerInput.tsx
+++ b/public/app/plugins/datasource/grafana/components/TimePickerInput.tsx
@@ -1,7 +1,6 @@
import { css, cx } from '@emotion/css';
import { Moment } from 'moment';
import TimePicker from 'rc-time-picker';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { FormInputSize, Icon, useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/grafana/components/TimeRegionEditor.tsx b/public/app/plugins/datasource/grafana/components/TimeRegionEditor.tsx
index 41a106cc77d..2a7e10588ba 100644
--- a/public/app/plugins/datasource/grafana/components/TimeRegionEditor.tsx
+++ b/public/app/plugins/datasource/grafana/components/TimeRegionEditor.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import moment, { Moment } from 'moment/moment';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { getTimeZoneInfo, GrafanaTheme2, SelectableValue } from '@grafana/data';
import { Button, Field, FieldSet, Select, Stack, TimeZonePicker, useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/graphite/components/AddGraphiteFunction.tsx b/public/app/plugins/datasource/graphite/components/AddGraphiteFunction.tsx
index 406d130e946..48477adfbba 100644
--- a/public/app/plugins/datasource/graphite/components/AddGraphiteFunction.tsx
+++ b/public/app/plugins/datasource/graphite/components/AddGraphiteFunction.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { useEffect, useMemo, useState } from 'react';
+import { useEffect, useMemo, useState } from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { Button, Segment, useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/graphite/components/AnnotationsEditor.tsx b/public/app/plugins/datasource/graphite/components/AnnotationsEditor.tsx
index e27c5afce7a..abe52b5b0de 100644
--- a/public/app/plugins/datasource/graphite/components/AnnotationsEditor.tsx
+++ b/public/app/plugins/datasource/graphite/components/AnnotationsEditor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { GrafanaTheme2, QueryEditorProps } from '@grafana/data';
import { Box, InlineField, Input, TagsInput, useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/graphite/components/FunctionEditor.test.tsx b/public/app/plugins/datasource/graphite/components/FunctionEditor.test.tsx
index b9a6d609919..25685df4fde 100644
--- a/public/app/plugins/datasource/graphite/components/FunctionEditor.test.tsx
+++ b/public/app/plugins/datasource/graphite/components/FunctionEditor.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { FuncInstance } from '../gfunc';
diff --git a/public/app/plugins/datasource/graphite/components/FunctionEditor.tsx b/public/app/plugins/datasource/graphite/components/FunctionEditor.tsx
index 44ced255c2d..19212b9f304 100644
--- a/public/app/plugins/datasource/graphite/components/FunctionEditor.tsx
+++ b/public/app/plugins/datasource/graphite/components/FunctionEditor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import { memo } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Icon, Tooltip, useStyles2, type PopoverContent } from '@grafana/ui';
@@ -58,7 +58,7 @@ const FunctionEditor = ({ onMoveLeft, onMoveRight, func, ...props }: FunctionEdi
);
};
-const TooltipContent = React.memo(() => {
+const TooltipContent = memo(() => {
return (
This function is not supported. Check your function for typos and{' '}
diff --git a/public/app/plugins/datasource/graphite/components/FunctionEditorControls.tsx b/public/app/plugins/datasource/graphite/components/FunctionEditorControls.tsx
index d4d41da7206..18c4ba93c52 100644
--- a/public/app/plugins/datasource/graphite/components/FunctionEditorControls.tsx
+++ b/public/app/plugins/datasource/graphite/components/FunctionEditorControls.tsx
@@ -1,4 +1,4 @@
-import React, { Suspense } from 'react';
+import { lazy, Suspense } from 'react';
import { Icon, Tooltip } from '@grafana/ui';
@@ -10,7 +10,7 @@ export interface FunctionEditorControlsProps {
onRemove: (func: FuncInstance) => void;
}
-const FunctionDescription = React.lazy(async () => {
+const FunctionDescription = lazy(async () => {
return {
default(props: { description?: string }) {
return {props.description}
;
diff --git a/public/app/plugins/datasource/graphite/components/FunctionParamEditor.tsx b/public/app/plugins/datasource/graphite/components/FunctionParamEditor.tsx
index d3306f4aab9..dfaffe8fe93 100644
--- a/public/app/plugins/datasource/graphite/components/FunctionParamEditor.tsx
+++ b/public/app/plugins/datasource/graphite/components/FunctionParamEditor.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { Segment, SegmentInput, useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/graphite/components/FunctionsSection.tsx b/public/app/plugins/datasource/graphite/components/FunctionsSection.tsx
index 0cbf5fb67a9..1db2a1471a2 100644
--- a/public/app/plugins/datasource/graphite/components/FunctionsSection.tsx
+++ b/public/app/plugins/datasource/graphite/components/FunctionsSection.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SegmentSection } from '@grafana/ui';
import { FuncDefs, FuncInstance } from '../gfunc';
diff --git a/public/app/plugins/datasource/graphite/components/GraphiteFunctionEditor.tsx b/public/app/plugins/datasource/graphite/components/GraphiteFunctionEditor.tsx
index 6132b92a604..78599d8bfc7 100644
--- a/public/app/plugins/datasource/graphite/components/GraphiteFunctionEditor.tsx
+++ b/public/app/plugins/datasource/graphite/components/GraphiteFunctionEditor.tsx
@@ -1,8 +1,8 @@
import { css, cx } from '@emotion/css';
-import React, { useState } from 'react';
+import { Fragment, useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
-import { HorizontalGroup, InlineLabel, useStyles2 } from '@grafana/ui';
+import { Stack, InlineLabel, useStyles2 } from '@grafana/ui';
import { FuncInstance } from '../gfunc';
import { actions } from '../state/actions';
@@ -42,7 +42,7 @@ export function GraphiteFunctionEditor({ func }: FunctionEditorProps) {
onMouseOver={() => setIsMouseOver(true)}
onMouseOut={() => setIsMouseOver(false)}
>
-
+
{
@@ -55,10 +55,12 @@ export function GraphiteFunctionEditor({ func }: FunctionEditorProps) {
dispatch(actions.removeFunction({ func }));
}}
/>
- (
+
+ (
+
{params.map((editableParam: EditableParam, index: number) => {
return (
-
+
{index !== params.length - 1 ? ',' : ''}
-
+
);
})}
- )
-
+
+ )
+
+
);
}
diff --git a/public/app/plugins/datasource/graphite/components/GraphiteQueryEditor.tsx b/public/app/plugins/datasource/graphite/components/GraphiteQueryEditor.tsx
index 2e0947bb503..0b9ca32a13d 100644
--- a/public/app/plugins/datasource/graphite/components/GraphiteQueryEditor.tsx
+++ b/public/app/plugins/datasource/graphite/components/GraphiteQueryEditor.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Button, useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/graphite/components/GraphiteTextEditor.tsx b/public/app/plugins/datasource/graphite/components/GraphiteTextEditor.tsx
index 849b2477936..896f41c9668 100644
--- a/public/app/plugins/datasource/graphite/components/GraphiteTextEditor.tsx
+++ b/public/app/plugins/datasource/graphite/components/GraphiteTextEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { QueryField } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/graphite/components/GraphiteVariableEditor.tsx b/public/app/plugins/datasource/graphite/components/GraphiteVariableEditor.tsx
index fdf421e27ca..ae240af2b90 100644
--- a/public/app/plugins/datasource/graphite/components/GraphiteVariableEditor.tsx
+++ b/public/app/plugins/datasource/graphite/components/GraphiteVariableEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { InlineField, Input, Select } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/graphite/components/MetricSegment.tsx b/public/app/plugins/datasource/graphite/components/MetricSegment.tsx
index af66dbfb5bf..92382d1b260 100644
--- a/public/app/plugins/datasource/graphite/components/MetricSegment.tsx
+++ b/public/app/plugins/datasource/graphite/components/MetricSegment.tsx
@@ -1,5 +1,5 @@
import { debounce } from 'lodash';
-import React, { useCallback, useMemo } from 'react';
+import { useCallback, useMemo } from 'react';
import { SelectableValue } from '@grafana/data';
import { SegmentAsync } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/graphite/components/MetricTankMetaInspector.tsx b/public/app/plugins/datasource/graphite/components/MetricTankMetaInspector.tsx
index d0fd82f1e53..1b45fc14593 100644
--- a/public/app/plugins/datasource/graphite/components/MetricTankMetaInspector.tsx
+++ b/public/app/plugins/datasource/graphite/components/MetricTankMetaInspector.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { MetadataInspectorProps, rangeUtil } from '@grafana/data';
import { stylesFactory } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/graphite/components/MetricsSection.tsx b/public/app/plugins/datasource/graphite/components/MetricsSection.tsx
index b4075036cdf..d6340c17a7b 100644
--- a/public/app/plugins/datasource/graphite/components/MetricsSection.tsx
+++ b/public/app/plugins/datasource/graphite/components/MetricsSection.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { GraphiteQueryEditorState } from '../state/store';
import { GraphiteSegment } from '../types';
diff --git a/public/app/plugins/datasource/graphite/components/PlayButton.tsx b/public/app/plugins/datasource/graphite/components/PlayButton.tsx
index 18d76fefe7b..6530acb445b 100644
--- a/public/app/plugins/datasource/graphite/components/PlayButton.tsx
+++ b/public/app/plugins/datasource/graphite/components/PlayButton.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { Button } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/graphite/components/SeriesSection.tsx b/public/app/plugins/datasource/graphite/components/SeriesSection.tsx
index 5b76e2d897c..0ea93363cb2 100644
--- a/public/app/plugins/datasource/graphite/components/SeriesSection.tsx
+++ b/public/app/plugins/datasource/graphite/components/SeriesSection.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SegmentSection } from '@grafana/ui';
import { GraphiteQueryEditorState } from '../state/store';
diff --git a/public/app/plugins/datasource/graphite/components/TagEditor.tsx b/public/app/plugins/datasource/graphite/components/TagEditor.tsx
index fe69a1bbad6..4e5d7d1d8df 100644
--- a/public/app/plugins/datasource/graphite/components/TagEditor.tsx
+++ b/public/app/plugins/datasource/graphite/components/TagEditor.tsx
@@ -1,5 +1,5 @@
import { debounce } from 'lodash';
-import React, { useCallback, useMemo } from 'react';
+import { useCallback, useMemo } from 'react';
import { Segment, SegmentAsync } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/graphite/components/TagsSection.tsx b/public/app/plugins/datasource/graphite/components/TagsSection.tsx
index 3e1160b07e5..c5646c4f08f 100644
--- a/public/app/plugins/datasource/graphite/components/TagsSection.tsx
+++ b/public/app/plugins/datasource/graphite/components/TagsSection.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { debounce } from 'lodash';
-import React, { useCallback, useMemo } from 'react';
+import { useCallback, useMemo } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Button, SegmentAsync, useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/graphite/configuration/ConfigEditor.tsx b/public/app/plugins/datasource/graphite/configuration/ConfigEditor.tsx
index 7cfb530ab0b..9106c32eb60 100644
--- a/public/app/plugins/datasource/graphite/configuration/ConfigEditor.tsx
+++ b/public/app/plugins/datasource/graphite/configuration/ConfigEditor.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import {
DataSourcePluginOptionsEditorProps,
diff --git a/public/app/plugins/datasource/graphite/configuration/MappingsConfiguration.tsx b/public/app/plugins/datasource/graphite/configuration/MappingsConfiguration.tsx
index 10de5f75ddd..0df6363a7ce 100644
--- a/public/app/plugins/datasource/graphite/configuration/MappingsConfiguration.tsx
+++ b/public/app/plugins/datasource/graphite/configuration/MappingsConfiguration.tsx
@@ -1,4 +1,4 @@
-import React, { ChangeEvent, useState } from 'react';
+import { ChangeEvent, useState } from 'react';
import { Box, Button, Icon, InlineField, InlineFieldRow, Input } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/graphite/configuration/MappingsHelp.tsx b/public/app/plugins/datasource/graphite/configuration/MappingsHelp.tsx
index a3b7b4f0dac..37a93580ca1 100644
--- a/public/app/plugins/datasource/graphite/configuration/MappingsHelp.tsx
+++ b/public/app/plugins/datasource/graphite/configuration/MappingsHelp.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Alert } from '@grafana/ui';
type Props = {
diff --git a/public/app/plugins/datasource/graphite/state/context.tsx b/public/app/plugins/datasource/graphite/state/context.tsx
index ba48d3a759d..a15853875a7 100644
--- a/public/app/plugins/datasource/graphite/state/context.tsx
+++ b/public/app/plugins/datasource/graphite/state/context.tsx
@@ -1,5 +1,5 @@
import { AnyAction } from '@reduxjs/toolkit';
-import React, { createContext, Dispatch, PropsWithChildren, useContext, useEffect, useMemo, useState } from 'react';
+import { createContext, Dispatch, PropsWithChildren, useContext, useEffect, useMemo, useState } from 'react';
import { usePrevious } from 'react-use';
import { QueryEditorProps } from '@grafana/data';
diff --git a/public/app/plugins/datasource/influxdb/components/editor/annotation/AnnotationEditor.tsx b/public/app/plugins/datasource/influxdb/components/editor/annotation/AnnotationEditor.tsx
index 91d289c1755..e77183eac0a 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/annotation/AnnotationEditor.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/annotation/AnnotationEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { QueryEditorProps } from '@grafana/data/src';
import { InlineFormLabel, Input, Stack } from '@grafana/ui/src';
diff --git a/public/app/plugins/datasource/influxdb/components/editor/config/ConfigEditor.test.tsx b/public/app/plugins/datasource/influxdb/components/editor/config/ConfigEditor.test.tsx
index ccf2646b950..5964465b0c9 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/config/ConfigEditor.test.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/config/ConfigEditor.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { InfluxVersion } from '../../../types';
diff --git a/public/app/plugins/datasource/influxdb/components/editor/config/ConfigEditor.tsx b/public/app/plugins/datasource/influxdb/components/editor/config/ConfigEditor.tsx
index f93f5c8e2af..db1296ae12c 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/config/ConfigEditor.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/config/ConfigEditor.tsx
@@ -1,5 +1,5 @@
import { uniqueId } from 'lodash';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import {
DataSourcePluginOptionsEditorProps,
diff --git a/public/app/plugins/datasource/influxdb/components/editor/config/InfluxFluxConfig.tsx b/public/app/plugins/datasource/influxdb/components/editor/config/InfluxFluxConfig.tsx
index 442e6f85f81..61a009e0798 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/config/InfluxFluxConfig.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/config/InfluxFluxConfig.tsx
@@ -1,5 +1,4 @@
import { uniqueId } from 'lodash';
-import React from 'react';
import {
DataSourcePluginOptionsEditorProps,
diff --git a/public/app/plugins/datasource/influxdb/components/editor/config/InfluxInfluxQLConfig.tsx b/public/app/plugins/datasource/influxdb/components/editor/config/InfluxInfluxQLConfig.tsx
index e811a69fc9b..bdde3be2533 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/config/InfluxInfluxQLConfig.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/config/InfluxInfluxQLConfig.tsx
@@ -1,6 +1,5 @@
import { css } from '@emotion/css';
import { uniqueId } from 'lodash';
-import React from 'react';
import {
DataSourcePluginOptionsEditorProps,
diff --git a/public/app/plugins/datasource/influxdb/components/editor/config/InfluxSQLConfig.tsx b/public/app/plugins/datasource/influxdb/components/editor/config/InfluxSQLConfig.tsx
index defdb0b0eab..fb0b5edf8e0 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/config/InfluxSQLConfig.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/config/InfluxSQLConfig.tsx
@@ -1,6 +1,5 @@
import { css } from '@emotion/css';
import { uniqueId } from 'lodash';
-import React from 'react';
import {
DataSourcePluginOptionsEditorProps,
diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/QueryEditor.tsx b/public/app/plugins/datasource/influxdb/components/editor/query/QueryEditor.tsx
index 7976e9edf9c..acb8d949f4c 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/query/QueryEditor.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/query/QueryEditor.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { QueryEditorProps } from '@grafana/data/src';
diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/flux/FluxQueryEditor.tsx b/public/app/plugins/datasource/influxdb/components/editor/query/flux/FluxQueryEditor.tsx
index 56102fdac15..1ad454e7b86 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/query/flux/FluxQueryEditor.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/query/flux/FluxQueryEditor.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data/src';
import { getTemplateSrv } from '@grafana/runtime/src';
diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/fsql/FSQLEditor.tsx b/public/app/plugins/datasource/influxdb/components/editor/query/fsql/FSQLEditor.tsx
index 90c08ff26ab..f63b3778dd2 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/query/fsql/FSQLEditor.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/query/fsql/FSQLEditor.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { GrafanaTheme2 } from '@grafana/data/src';
import { SQLQuery, SqlQueryEditor, applyQueryDefaults } from '@grafana/sql';
diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/InfluxCheatSheet.tsx b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/InfluxCheatSheet.tsx
index 40f5731691f..d1ad573f92d 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/InfluxCheatSheet.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/InfluxCheatSheet.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/InfluxStartPage.tsx b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/InfluxStartPage.tsx
index 10f35190d08..ccb6596b6b9 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/InfluxStartPage.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/InfluxStartPage.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { InfluxCheatSheet } from './InfluxCheatSheet';
export function InfluxStartPage() {
diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/QueryEditorModeSwitcher.tsx b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/QueryEditorModeSwitcher.tsx
index 539ee63f4d5..7bc5dcf6a6e 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/QueryEditorModeSwitcher.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/QueryEditorModeSwitcher.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { Button, ConfirmModal } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/code/RawInfluxQLEditor.test.tsx b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/code/RawInfluxQLEditor.test.tsx
index c704a7e9946..91faafbf260 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/code/RawInfluxQLEditor.test.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/code/RawInfluxQLEditor.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { selectOptionInTest } from 'test/helpers/selectOptionInTest';
import { InfluxQuery } from '../../../../../types';
diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/code/RawInfluxQLEditor.tsx b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/code/RawInfluxQLEditor.tsx
index 0df57b7b26d..0098e8eb0af 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/code/RawInfluxQLEditor.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/code/RawInfluxQLEditor.tsx
@@ -1,6 +1,6 @@
-import React, { useId } from 'react';
+import { useId } from 'react';
-import { HorizontalGroup, InlineFormLabel, Input, Select, TextArea } from '@grafana/ui';
+import { Stack, InlineField, Input, Select, TextArea } from '@grafana/ui';
import { InfluxQuery } from '../../../../../types';
import { DEFAULT_RESULT_FORMAT, RESULT_FORMATS } from '../../../constants';
@@ -34,7 +34,7 @@ export const RawInfluxQLEditor = ({ query, onChange, onRunQuery }: Props): JSX.E
};
return (
-
+
-
- Format as
- {
- onChange({ ...query, resultFormat: v.value });
- onRunQuery();
- }}
- value={resultFormat}
- options={RESULT_FORMATS}
- />
- Alias by
- {
- setCurrentAlias(e.currentTarget.value);
- }}
- value={currentAlias ?? ''}
- />
-
-
+
+
+ {
+ onChange({ ...query, resultFormat: v.value });
+ onRunQuery();
+ }}
+ value={resultFormat}
+ options={RESULT_FORMATS}
+ />
+
+
+ {
+ setCurrentAlias(e.currentTarget.value);
+ }}
+ value={currentAlias ?? ''}
+ />
+
+
+
);
};
diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/AddButton.tsx b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/AddButton.tsx
index 8175891393d..7123f816f22 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/AddButton.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/AddButton.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SelectableValue } from '@grafana/data';
import { unwrap } from '../utils/unwrap';
diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/FormatAsSection.tsx b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/FormatAsSection.tsx
index 521681fac21..6bf005185f4 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/FormatAsSection.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/FormatAsSection.tsx
@@ -1,5 +1,4 @@
import { cx } from '@emotion/css';
-import React from 'react';
import { Select } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/FromSection.tsx b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/FromSection.tsx
index b0c8f42a432..458f2eb9176 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/FromSection.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/FromSection.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { AccessoryButton } from '@grafana/experimental';
import { DEFAULT_POLICY } from '../../../../../types';
diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/InputSection.tsx b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/InputSection.tsx
index 71b9fad90d3..bb197aedd2d 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/InputSection.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/InputSection.tsx
@@ -1,5 +1,4 @@
import { cx } from '@emotion/css';
-import React from 'react';
import { Input } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/OrderByTimeSection.tsx b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/OrderByTimeSection.tsx
index f7c594130bb..eab1943a4ea 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/OrderByTimeSection.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/OrderByTimeSection.tsx
@@ -1,5 +1,4 @@
import { cx } from '@emotion/css';
-import React from 'react';
import { SelectableValue } from '@grafana/data';
import { Select } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/PartListSection.tsx b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/PartListSection.tsx
index a86df9df784..3bb380ee126 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/PartListSection.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/PartListSection.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { Fragment, useMemo } from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { AccessoryButton } from '@grafana/experimental';
@@ -77,7 +77,7 @@ const Part = ({ name, params, onChange }: PartProps): JSX.Element => {
const loadOptions =
options !== null ? () => options().then((items) => items.map(toSelectableValue)) : undefined;
return (
-
+
{
}}
/>
{!isLast && ','}
-
+
);
})}
)
@@ -106,7 +106,7 @@ export const PartListSection = ({
return (
<>
{parts.map((part, index) => (
-
+
-
+
))}
>
diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/Seg.tsx b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/Seg.tsx
index 28b679fd5e3..47b24fcecf6 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/Seg.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/Seg.tsx
@@ -1,6 +1,6 @@
import { css, cx } from '@emotion/css';
import debouncePromise from 'debounce-promise';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { useAsyncFn } from 'react-use';
import { SelectableValue } from '@grafana/data';
diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/TagsSection.test.tsx b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/TagsSection.test.tsx
index fe6b0e57c5e..e65968073ce 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/TagsSection.test.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/TagsSection.test.tsx
@@ -1,5 +1,4 @@
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react';
-import React from 'react';
import { InfluxQueryTag } from '../../../../../types';
diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/TagsSection.tsx b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/TagsSection.tsx
index b290a231bb2..9079bc056c7 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/TagsSection.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/TagsSection.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SelectableValue } from '@grafana/data';
import { AccessoryButton } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/VisualInfluxQLEditor.tags.test.tsx b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/VisualInfluxQLEditor.tags.test.tsx
index 7a89362d515..7d6b19d637f 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/VisualInfluxQLEditor.tags.test.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/VisualInfluxQLEditor.tags.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import InfluxDatasource from '../../../../../datasource';
import * as mockedMeta from '../../../../../influxql_metadata_query';
diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/VisualInfluxQLEditor.test.tsx b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/VisualInfluxQLEditor.test.tsx
index 90c6d9723cb..7f6f4c13306 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/VisualInfluxQLEditor.test.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/VisualInfluxQLEditor.test.tsx
@@ -1,5 +1,4 @@
import { render, waitFor } from '@testing-library/react';
-import React from 'react';
import { getMockInfluxDS, getMockDSInstanceSettings } from '../../../../../__mocks__/datasource';
import InfluxDatasource from '../../../../../datasource';
diff --git a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/VisualInfluxQLEditor.tsx b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/VisualInfluxQLEditor.tsx
index 374da6b752a..4a1b879242d 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/VisualInfluxQLEditor.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/query/influxql/visual/VisualInfluxQLEditor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useId, useMemo } from 'react';
+import { useId, useMemo } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { InlineLabel, SegmentSection, useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/influxdb/components/editor/variable/VariableQueryEditor.tsx b/public/app/plugins/datasource/influxdb/components/editor/variable/VariableQueryEditor.tsx
index 5cab87fe886..e7381c5a399 100644
--- a/public/app/plugins/datasource/influxdb/components/editor/variable/VariableQueryEditor.tsx
+++ b/public/app/plugins/datasource/influxdb/components/editor/variable/VariableQueryEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { QueryEditorProps } from '@grafana/data';
import { InlineFieldRow, Input, TextArea } from '@grafana/ui';
import { InlineField } from '@grafana/ui/';
diff --git a/public/app/plugins/datasource/jaeger/CheatSheet.tsx b/public/app/plugins/datasource/jaeger/CheatSheet.tsx
index 89329d94e66..db27736458b 100644
--- a/public/app/plugins/datasource/jaeger/CheatSheet.tsx
+++ b/public/app/plugins/datasource/jaeger/CheatSheet.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/jaeger/components/QueryEditor.tsx b/public/app/plugins/datasource/jaeger/components/QueryEditor.tsx
index 22c98352296..53f7e351f95 100644
--- a/public/app/plugins/datasource/jaeger/components/QueryEditor.tsx
+++ b/public/app/plugins/datasource/jaeger/components/QueryEditor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { QueryEditorProps } from '@grafana/data';
import {
diff --git a/public/app/plugins/datasource/jaeger/components/SearchForm.test.tsx b/public/app/plugins/datasource/jaeger/components/SearchForm.test.tsx
index bc1bae92086..533f5b900eb 100644
--- a/public/app/plugins/datasource/jaeger/components/SearchForm.test.tsx
+++ b/public/app/plugins/datasource/jaeger/components/SearchForm.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { of } from 'rxjs';
import { DataQueryRequest, DataSourceInstanceSettings, dateTime, PluginMetaInfo, PluginType } from '@grafana/data';
diff --git a/public/app/plugins/datasource/jaeger/components/SearchForm.tsx b/public/app/plugins/datasource/jaeger/components/SearchForm.tsx
index 229a709e4d7..f0eee728f38 100644
--- a/public/app/plugins/datasource/jaeger/components/SearchForm.tsx
+++ b/public/app/plugins/datasource/jaeger/components/SearchForm.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useCallback, useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
import { SelectableValue, toOption } from '@grafana/data';
import { TemporaryAlert } from '@grafana/o11y-ds-frontend';
diff --git a/public/app/plugins/datasource/jaeger/configuration/ConfigEditor.tsx b/public/app/plugins/datasource/jaeger/configuration/ConfigEditor.tsx
index 5517e272c3c..c032084fbb2 100644
--- a/public/app/plugins/datasource/jaeger/configuration/ConfigEditor.tsx
+++ b/public/app/plugins/datasource/jaeger/configuration/ConfigEditor.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { DataSourcePluginOptionsEditorProps, GrafanaTheme2 } from '@grafana/data';
import {
diff --git a/public/app/plugins/datasource/jaeger/configuration/TraceIdTimeParams.tsx b/public/app/plugins/datasource/jaeger/configuration/TraceIdTimeParams.tsx
index 52b2888045f..94dc28005ba 100644
--- a/public/app/plugins/datasource/jaeger/configuration/TraceIdTimeParams.tsx
+++ b/public/app/plugins/datasource/jaeger/configuration/TraceIdTimeParams.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import {
DataSourceJsonData,
diff --git a/public/app/plugins/datasource/jaeger/tsconfig.json b/public/app/plugins/datasource/jaeger/tsconfig.json
index a7a33a2fc32..d05071dbf1d 100644
--- a/public/app/plugins/datasource/jaeger/tsconfig.json
+++ b/public/app/plugins/datasource/jaeger/tsconfig.json
@@ -1,5 +1,6 @@
{
"compilerOptions": {
+ "jsx": "react-jsx",
"types": ["jest", "@testing-library/jest-dom"]
},
"extends": "@grafana/plugin-configs/tsconfig.json",
diff --git a/public/app/plugins/datasource/loki/components/AnnotationsQueryEditor.tsx b/public/app/plugins/datasource/loki/components/AnnotationsQueryEditor.tsx
index 670288224aa..907c1f48177 100644
--- a/public/app/plugins/datasource/loki/components/AnnotationsQueryEditor.tsx
+++ b/public/app/plugins/datasource/loki/components/AnnotationsQueryEditor.tsx
@@ -1,5 +1,5 @@
// Libraries
-import React, { memo } from 'react';
+import { memo } from 'react';
import { AnnotationQuery } from '@grafana/data';
import { EditorField, EditorRow } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/loki/components/LokiCheatSheet.test.tsx b/public/app/plugins/datasource/loki/components/LokiCheatSheet.test.tsx
index c7074790d1e..37014c16664 100644
--- a/public/app/plugins/datasource/loki/components/LokiCheatSheet.test.tsx
+++ b/public/app/plugins/datasource/loki/components/LokiCheatSheet.test.tsx
@@ -1,5 +1,5 @@
import { render, screen } from '@testing-library/react';
-import React, { ComponentProps } from 'react';
+import { ComponentProps } from 'react';
import { LokiDatasource } from '../datasource';
import { LokiQuery } from '../types';
diff --git a/public/app/plugins/datasource/loki/components/LokiCheatSheet.tsx b/public/app/plugins/datasource/loki/components/LokiCheatSheet.tsx
index 412d876658e..dce5bc0221c 100644
--- a/public/app/plugins/datasource/loki/components/LokiCheatSheet.tsx
+++ b/public/app/plugins/datasource/loki/components/LokiCheatSheet.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { shuffle } from 'lodash';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { GrafanaTheme2, QueryEditorHelpProps } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/loki/components/LokiContextUi.test.tsx b/public/app/plugins/datasource/loki/components/LokiContextUi.test.tsx
index 7d9d7220877..b9b53f65dc1 100644
--- a/public/app/plugins/datasource/loki/components/LokiContextUi.test.tsx
+++ b/public/app/plugins/datasource/loki/components/LokiContextUi.test.tsx
@@ -1,6 +1,5 @@
import { act, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { select } from 'react-select-event';
import { LogRowModel, dateTime } from '@grafana/data';
diff --git a/public/app/plugins/datasource/loki/components/LokiContextUi.tsx b/public/app/plugins/datasource/loki/components/LokiContextUi.tsx
index fe181e08ea8..a44f6c37a7e 100644
--- a/public/app/plugins/datasource/loki/components/LokiContextUi.tsx
+++ b/public/app/plugins/datasource/loki/components/LokiContextUi.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useCallback, useEffect, useMemo, useState } from 'react';
+import { useRef, useCallback, useEffect, useMemo, useState } from 'react';
import { useAsync } from 'react-use';
import { dateTime, GrafanaTheme2, LogRowModel, renderMarkdown, SelectableValue } from '@grafana/data';
@@ -126,9 +126,9 @@ export function LokiContextUi(props: LokiContextUiProps) {
window.localStorage.getItem(SHOULD_INCLUDE_PIPELINE_OPERATIONS) === 'true'
);
- const timerHandle = React.useRef();
- const previousInitialized = React.useRef(false);
- const previousContextFilters = React.useRef([]);
+ const timerHandle = useRef();
+ const previousInitialized = useRef(false);
+ const previousContextFilters = useRef([]);
const isInitialState = useMemo(() => {
// Initial query has all regular labels enabled and all parsed labels disabled
diff --git a/public/app/plugins/datasource/loki/components/LokiLabelBrowser.test.tsx b/public/app/plugins/datasource/loki/components/LokiLabelBrowser.test.tsx
index 5090172f64e..58b37c46664 100644
--- a/public/app/plugins/datasource/loki/components/LokiLabelBrowser.test.tsx
+++ b/public/app/plugins/datasource/loki/components/LokiLabelBrowser.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { createTheme } from '@grafana/data';
diff --git a/public/app/plugins/datasource/loki/components/LokiLabelBrowser.tsx b/public/app/plugins/datasource/loki/components/LokiLabelBrowser.tsx
index cbc8930bfa5..c11bf73054d 100644
--- a/public/app/plugins/datasource/loki/components/LokiLabelBrowser.tsx
+++ b/public/app/plugins/datasource/loki/components/LokiLabelBrowser.tsx
@@ -1,6 +1,7 @@
import { css, cx } from '@emotion/css';
import { sortBy } from 'lodash';
-import React, { ChangeEvent } from 'react';
+import { ChangeEvent } from 'react';
+import * as React from 'react';
import { FixedSizeList } from 'react-window';
import { CoreApp, GrafanaTheme2, TimeRange } from '@grafana/data';
diff --git a/public/app/plugins/datasource/loki/components/LokiOptionFields.test.tsx b/public/app/plugins/datasource/loki/components/LokiOptionFields.test.tsx
index 3ebb0adb02f..e82312af944 100644
--- a/public/app/plugins/datasource/loki/components/LokiOptionFields.test.tsx
+++ b/public/app/plugins/datasource/loki/components/LokiOptionFields.test.tsx
@@ -1,5 +1,4 @@
import { render, screen, waitFor, fireEvent } from '@testing-library/react';
-import React from 'react';
import { LokiOptionFieldsProps, LokiOptionFields, preprocessMaxLines } from './LokiOptionFields';
diff --git a/public/app/plugins/datasource/loki/components/LokiOptionFields.tsx b/public/app/plugins/datasource/loki/components/LokiOptionFields.tsx
index 8bada9ae24e..c90c05eb7b7 100644
--- a/public/app/plugins/datasource/loki/components/LokiOptionFields.tsx
+++ b/public/app/plugins/datasource/loki/components/LokiOptionFields.tsx
@@ -1,6 +1,7 @@
// Libraries
import { map } from 'lodash';
-import React, { memo } from 'react';
+import { memo } from 'react';
+import * as React from 'react';
// Types
import { SelectableValue } from '@grafana/data';
diff --git a/public/app/plugins/datasource/loki/components/LokiQueryEditor.test.tsx b/public/app/plugins/datasource/loki/components/LokiQueryEditor.test.tsx
index c2720a046bf..bb41f4cdf47 100644
--- a/public/app/plugins/datasource/loki/components/LokiQueryEditor.test.tsx
+++ b/public/app/plugins/datasource/loki/components/LokiQueryEditor.test.tsx
@@ -1,7 +1,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { cloneDeep, defaultsDeep } from 'lodash';
-import React from 'react';
import { CoreApp } from '@grafana/data';
import { QueryEditorMode } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/loki/components/LokiQueryEditor.tsx b/public/app/plugins/datasource/loki/components/LokiQueryEditor.tsx
index d0c9f84529a..eba24c05762 100644
--- a/public/app/plugins/datasource/loki/components/LokiQueryEditor.tsx
+++ b/public/app/plugins/datasource/loki/components/LokiQueryEditor.tsx
@@ -1,5 +1,5 @@
import { isEqual } from 'lodash';
-import React, { SyntheticEvent, useCallback, useEffect, useId, useState } from 'react';
+import { memo, SyntheticEvent, useCallback, useEffect, useId, useState } from 'react';
import { usePrevious } from 'react-use';
import { CoreApp, LoadingState } from '@grafana/data';
@@ -33,7 +33,7 @@ export const testIds = {
export const lokiQueryEditorExplainKey = 'LokiQueryEditorExplainDefault';
-export const LokiQueryEditor = React.memo((props) => {
+export const LokiQueryEditor = memo((props) => {
const id = useId();
const { onChange, onRunQuery, onAddQuery, data, app, queries, datasource, range: timeRange } = props;
const [parseModalOpen, setParseModalOpen] = useState(false);
diff --git a/public/app/plugins/datasource/loki/components/LokiQueryEditorByApp.test.tsx b/public/app/plugins/datasource/loki/components/LokiQueryEditorByApp.test.tsx
index 171644d2802..c36399ea7dc 100644
--- a/public/app/plugins/datasource/loki/components/LokiQueryEditorByApp.test.tsx
+++ b/public/app/plugins/datasource/loki/components/LokiQueryEditorByApp.test.tsx
@@ -1,6 +1,5 @@
import { render, RenderResult, screen } from '@testing-library/react';
import { noop } from 'lodash';
-import React from 'react';
import { CoreApp } from '@grafana/data';
diff --git a/public/app/plugins/datasource/loki/components/LokiQueryEditorByApp.tsx b/public/app/plugins/datasource/loki/components/LokiQueryEditorByApp.tsx
index 0306583a312..770ca087577 100644
--- a/public/app/plugins/datasource/loki/components/LokiQueryEditorByApp.tsx
+++ b/public/app/plugins/datasource/loki/components/LokiQueryEditorByApp.tsx
@@ -1,4 +1,4 @@
-import React, { memo } from 'react';
+import { memo } from 'react';
import { CoreApp } from '@grafana/data';
diff --git a/public/app/plugins/datasource/loki/components/LokiQueryEditorForAlerting.tsx b/public/app/plugins/datasource/loki/components/LokiQueryEditorForAlerting.tsx
index 7e31f9fb175..4336cdbc03a 100644
--- a/public/app/plugins/datasource/loki/components/LokiQueryEditorForAlerting.tsx
+++ b/public/app/plugins/datasource/loki/components/LokiQueryEditorForAlerting.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { LokiQueryField } from './LokiQueryField';
import { LokiQueryEditorProps } from './types';
diff --git a/public/app/plugins/datasource/loki/components/LokiQueryField.test.tsx b/public/app/plugins/datasource/loki/components/LokiQueryField.test.tsx
index 17b2fd47e6f..c9412197892 100644
--- a/public/app/plugins/datasource/loki/components/LokiQueryField.test.tsx
+++ b/public/app/plugins/datasource/loki/components/LokiQueryField.test.tsx
@@ -1,5 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
-import React, { ComponentProps } from 'react';
+import { ComponentProps } from 'react';
import { dateTime } from '@grafana/data';
diff --git a/public/app/plugins/datasource/loki/components/LokiQueryField.tsx b/public/app/plugins/datasource/loki/components/LokiQueryField.tsx
index 237e2bff418..11006e99993 100644
--- a/public/app/plugins/datasource/loki/components/LokiQueryField.tsx
+++ b/public/app/plugins/datasource/loki/components/LokiQueryField.tsx
@@ -1,4 +1,4 @@
-import React, { ReactNode } from 'react';
+import { PureComponent, ReactNode } from 'react';
import { QueryEditorProps } from '@grafana/data';
@@ -18,7 +18,7 @@ interface LokiQueryFieldState {
labelsLoaded: boolean;
}
-export class LokiQueryField extends React.PureComponent {
+export class LokiQueryField extends PureComponent {
_isMounted = false;
constructor(props: LokiQueryFieldProps) {
diff --git a/public/app/plugins/datasource/loki/components/VariableQueryEditor.test.tsx b/public/app/plugins/datasource/loki/components/VariableQueryEditor.test.tsx
index 758dfc7055c..7644c76bb79 100644
--- a/public/app/plugins/datasource/loki/components/VariableQueryEditor.test.tsx
+++ b/public/app/plugins/datasource/loki/components/VariableQueryEditor.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { select } from 'react-select-event';
import { TimeRange, dateTime } from '@grafana/data';
diff --git a/public/app/plugins/datasource/loki/components/VariableQueryEditor.tsx b/public/app/plugins/datasource/loki/components/VariableQueryEditor.tsx
index 63246b73657..fcafcc01ae6 100644
--- a/public/app/plugins/datasource/loki/components/VariableQueryEditor.tsx
+++ b/public/app/plugins/datasource/loki/components/VariableQueryEditor.tsx
@@ -1,4 +1,4 @@
-import React, { FormEvent, useState, useEffect } from 'react';
+import { FormEvent, useState, useEffect } from 'react';
import { usePrevious } from 'react-use';
import { QueryEditorProps, SelectableValue } from '@grafana/data';
diff --git a/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoFieldWrapper.test.tsx b/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoFieldWrapper.test.tsx
index e98e694f093..dadb297a1a4 100644
--- a/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoFieldWrapper.test.tsx
+++ b/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoFieldWrapper.test.tsx
@@ -1,5 +1,4 @@
import { render, screen, waitFor } from '@testing-library/react';
-import React from 'react';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoQueryField.test.tsx b/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoQueryField.test.tsx
index 6d003381237..71b59d08bb1 100644
--- a/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoQueryField.test.tsx
+++ b/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoQueryField.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoQueryField.tsx b/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoQueryField.tsx
index 96bb9c4fbae..c74b66ba42a 100644
--- a/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoQueryField.tsx
+++ b/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoQueryField.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { debounce } from 'lodash';
-import React, { useRef, useEffect } from 'react';
+import { useRef, useEffect } from 'react';
import { useLatest } from 'react-use';
import { v4 as uuidv4 } from 'uuid';
diff --git a/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoQueryFieldLazy.tsx b/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoQueryFieldLazy.tsx
index aeb6c14c904..594bd2a11eb 100644
--- a/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoQueryFieldLazy.tsx
+++ b/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoQueryFieldLazy.tsx
@@ -1,8 +1,8 @@
-import React, { Suspense } from 'react';
+import { lazy, Suspense } from 'react';
import { Props } from './MonacoQueryFieldProps';
-const Field = React.lazy(() => import(/* webpackChunkName: "loki-query-field" */ './MonacoQueryField'));
+const Field = lazy(() => import(/* webpackChunkName: "loki-query-field" */ './MonacoQueryField'));
export const MonacoQueryFieldLazy = (props: Props) => {
return (
diff --git a/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoQueryFieldWrapper.tsx b/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoQueryFieldWrapper.tsx
index 0ca7d70f018..418ab68d51a 100644
--- a/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoQueryFieldWrapper.tsx
+++ b/public/app/plugins/datasource/loki/components/monaco-query-field/MonacoQueryFieldWrapper.tsx
@@ -1,4 +1,4 @@
-import React, { useRef } from 'react';
+import { useRef } from 'react';
import { MonacoQueryFieldLazy } from './MonacoQueryFieldLazy';
import { Props as MonacoProps } from './MonacoQueryFieldProps';
diff --git a/public/app/plugins/datasource/loki/configuration/AlertingSettings.test.tsx b/public/app/plugins/datasource/loki/configuration/AlertingSettings.test.tsx
index 73686c4b3af..d5bf01737f8 100644
--- a/public/app/plugins/datasource/loki/configuration/AlertingSettings.test.tsx
+++ b/public/app/plugins/datasource/loki/configuration/AlertingSettings.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { createDefaultConfigOptions } from '../__mocks__/datasource';
diff --git a/public/app/plugins/datasource/loki/configuration/AlertingSettings.tsx b/public/app/plugins/datasource/loki/configuration/AlertingSettings.tsx
index d9c4c439ed2..7e3bcc24d54 100644
--- a/public/app/plugins/datasource/loki/configuration/AlertingSettings.tsx
+++ b/public/app/plugins/datasource/loki/configuration/AlertingSettings.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { DataSourcePluginOptionsEditorProps } from '@grafana/data';
import { ConfigDescriptionLink, ConfigSubSection } from '@grafana/experimental';
import { InlineField, InlineSwitch } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/loki/configuration/ConfigEditor.test.tsx b/public/app/plugins/datasource/loki/configuration/ConfigEditor.test.tsx
index 8afc34bc0b1..214c68854c0 100644
--- a/public/app/plugins/datasource/loki/configuration/ConfigEditor.test.tsx
+++ b/public/app/plugins/datasource/loki/configuration/ConfigEditor.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { createDefaultConfigOptions } from '../__mocks__/datasource';
diff --git a/public/app/plugins/datasource/loki/configuration/ConfigEditor.tsx b/public/app/plugins/datasource/loki/configuration/ConfigEditor.tsx
index fe57f47d35c..2908238f7b6 100644
--- a/public/app/plugins/datasource/loki/configuration/ConfigEditor.tsx
+++ b/public/app/plugins/datasource/loki/configuration/ConfigEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { DataSourcePluginOptionsEditorProps, DataSourceSettings } from '@grafana/data';
import {
diff --git a/public/app/plugins/datasource/loki/configuration/DebugSection.test.tsx b/public/app/plugins/datasource/loki/configuration/DebugSection.test.tsx
index 8600c84362c..ce7b093f42e 100644
--- a/public/app/plugins/datasource/loki/configuration/DebugSection.test.tsx
+++ b/public/app/plugins/datasource/loki/configuration/DebugSection.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { DebugSection } from './DebugSection';
diff --git a/public/app/plugins/datasource/loki/configuration/DebugSection.tsx b/public/app/plugins/datasource/loki/configuration/DebugSection.tsx
index 15bb53aa3cb..bb1c87f44d9 100644
--- a/public/app/plugins/datasource/loki/configuration/DebugSection.tsx
+++ b/public/app/plugins/datasource/loki/configuration/DebugSection.tsx
@@ -1,4 +1,4 @@
-import React, { ReactNode, useState } from 'react';
+import { ReactNode, useState } from 'react';
import { getTemplateSrv } from '@grafana/runtime';
import { InlineField, TextArea } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/loki/configuration/DerivedField.test.tsx b/public/app/plugins/datasource/loki/configuration/DerivedField.test.tsx
index c708e74bc10..c8ab5d5eb0a 100644
--- a/public/app/plugins/datasource/loki/configuration/DerivedField.test.tsx
+++ b/public/app/plugins/datasource/loki/configuration/DerivedField.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { DataSourceInstanceSettings, DataSourcePluginMeta } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/plugins/datasource/loki/configuration/DerivedField.tsx b/public/app/plugins/datasource/loki/configuration/DerivedField.tsx
index c135c1458fe..15ec011f9db 100644
--- a/public/app/plugins/datasource/loki/configuration/DerivedField.tsx
+++ b/public/app/plugins/datasource/loki/configuration/DerivedField.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { ChangeEvent, useEffect, useState } from 'react';
+import { ChangeEvent, useEffect, useState } from 'react';
+import * as React from 'react';
import { usePrevious } from 'react-use';
import { GrafanaTheme2, DataSourceInstanceSettings, VariableSuggestion } from '@grafana/data';
diff --git a/public/app/plugins/datasource/loki/configuration/DerivedFields.test.tsx b/public/app/plugins/datasource/loki/configuration/DerivedFields.test.tsx
index f8e5bc24d4f..ee13dc4174c 100644
--- a/public/app/plugins/datasource/loki/configuration/DerivedFields.test.tsx
+++ b/public/app/plugins/datasource/loki/configuration/DerivedFields.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { DerivedFields } from './DerivedFields';
diff --git a/public/app/plugins/datasource/loki/configuration/DerivedFields.tsx b/public/app/plugins/datasource/loki/configuration/DerivedFields.tsx
index a8c28adb780..2d6bbaf7d2b 100644
--- a/public/app/plugins/datasource/loki/configuration/DerivedFields.tsx
+++ b/public/app/plugins/datasource/loki/configuration/DerivedFields.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useCallback, useState } from 'react';
+import { useCallback, useState } from 'react';
import { GrafanaTheme2, VariableOrigin, DataLinkBuiltInVars } from '@grafana/data';
import { ConfigDescriptionLink, ConfigSubSection } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/loki/configuration/QuerySettings.tsx b/public/app/plugins/datasource/loki/configuration/QuerySettings.tsx
index 7cdbc8a2777..c5f956bf472 100644
--- a/public/app/plugins/datasource/loki/configuration/QuerySettings.tsx
+++ b/public/app/plugins/datasource/loki/configuration/QuerySettings.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { ConfigDescriptionLink, ConfigSubSection } from '@grafana/experimental';
import { config } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/loki/querybuilder/components/LabelBrowserModal.test.tsx b/public/app/plugins/datasource/loki/querybuilder/components/LabelBrowserModal.test.tsx
index 16ef915193a..6d298cc267e 100644
--- a/public/app/plugins/datasource/loki/querybuilder/components/LabelBrowserModal.test.tsx
+++ b/public/app/plugins/datasource/loki/querybuilder/components/LabelBrowserModal.test.tsx
@@ -1,5 +1,4 @@
import { render, screen, waitFor } from '@testing-library/react';
-import React from 'react';
import { createLokiDatasource } from '../../__mocks__/datasource';
import { LokiDatasource } from '../../datasource';
diff --git a/public/app/plugins/datasource/loki/querybuilder/components/LabelBrowserModal.tsx b/public/app/plugins/datasource/loki/querybuilder/components/LabelBrowserModal.tsx
index c1bf43f385c..b1cc1d41ece 100644
--- a/public/app/plugins/datasource/loki/querybuilder/components/LabelBrowserModal.tsx
+++ b/public/app/plugins/datasource/loki/querybuilder/components/LabelBrowserModal.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState, useEffect } from 'react';
+import { useState, useEffect } from 'react';
import { CoreApp, GrafanaTheme2, LocalStorageValueProvider, TimeRange } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/loki/querybuilder/components/LabelParamEditor.test.tsx b/public/app/plugins/datasource/loki/querybuilder/components/LabelParamEditor.test.tsx
index d6745f0ba89..853039fdd64 100644
--- a/public/app/plugins/datasource/loki/querybuilder/components/LabelParamEditor.test.tsx
+++ b/public/app/plugins/datasource/loki/querybuilder/components/LabelParamEditor.test.tsx
@@ -1,6 +1,6 @@
import { screen, render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { ComponentProps } from 'react';
+import { ComponentProps } from 'react';
import { DataSourceApi } from '@grafana/data';
import { QueryBuilderOperation, QueryBuilderOperationParamDef } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/loki/querybuilder/components/LabelParamEditor.tsx b/public/app/plugins/datasource/loki/querybuilder/components/LabelParamEditor.tsx
index b92c3bec3b2..f691a652e72 100644
--- a/public/app/plugins/datasource/loki/querybuilder/components/LabelParamEditor.tsx
+++ b/public/app/plugins/datasource/loki/querybuilder/components/LabelParamEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { DataSourceApi, SelectableValue } from '@grafana/data';
import {
diff --git a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilder.test.tsx b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilder.test.tsx
index d7a5b3318b3..2fa9d9f1801 100644
--- a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilder.test.tsx
+++ b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilder.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, getAllByRole, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { dateTime } from '@grafana/data';
import { config } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilder.tsx b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilder.tsx
index 1e0fee2efed..d364ae12dce 100644
--- a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilder.tsx
+++ b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilder.tsx
@@ -1,5 +1,5 @@
import { isEqual } from 'lodash';
-import React, { useEffect, useMemo, useState } from 'react';
+import { memo, useEffect, useMemo, useState } from 'react';
import { usePrevious } from 'react-use';
import { DataSourceApi, getDefaultTimeRange, LoadingState, PanelData, SelectableValue, TimeRange } from '@grafana/data';
@@ -39,172 +39,170 @@ export interface Props {
onChange: (update: LokiVisualQuery) => void;
onRunQuery: () => void;
}
-export const LokiQueryBuilder = React.memo(
- ({ datasource, query, onChange, onRunQuery, showExplain, timeRange }) => {
- const [sampleData, setSampleData] = useState();
- const [highlightedOp, setHighlightedOp] = useState(undefined);
- const prevQuery = usePrevious(query);
- const prevTimeRange = usePrevious(timeRange);
+export const LokiQueryBuilder = memo(({ datasource, query, onChange, onRunQuery, showExplain, timeRange }) => {
+ const [sampleData, setSampleData] = useState();
+ const [highlightedOp, setHighlightedOp] = useState(undefined);
+ const prevQuery = usePrevious(query);
+ const prevTimeRange = usePrevious(timeRange);
- const onChangeLabels = (labels: QueryBuilderLabelFilter[]) => {
- onChange({ ...query, labels });
- };
+ const onChangeLabels = (labels: QueryBuilderLabelFilter[]) => {
+ onChange({ ...query, labels });
+ };
- const withTemplateVariableOptions = async (optionsPromise: Promise): Promise => {
- const options = await optionsPromise;
- return [...datasource.getVariables(), ...options].map((value) => ({ label: value, value }));
- };
+ const withTemplateVariableOptions = async (optionsPromise: Promise): Promise => {
+ const options = await optionsPromise;
+ return [...datasource.getVariables(), ...options].map((value) => ({ label: value, value }));
+ };
- const onGetLabelNames = async (forLabel: Partial): Promise => {
- const labelsToConsider = query.labels.filter((x) => x !== forLabel);
+ const onGetLabelNames = async (forLabel: Partial): Promise => {
+ const labelsToConsider = query.labels.filter((x) => x !== forLabel);
- const hasEqualityOperation = labelsToConsider.find(
- (filter) => filter.op === '=' || (filter.op === '=~' && new RegExp(filter.value).test('') === false)
- );
- if (labelsToConsider.length === 0 || !hasEqualityOperation) {
- return await datasource.languageProvider.fetchLabels({ timeRange });
- }
+ const hasEqualityOperation = labelsToConsider.find(
+ (filter) => filter.op === '=' || (filter.op === '=~' && new RegExp(filter.value).test('') === false)
+ );
+ if (labelsToConsider.length === 0 || !hasEqualityOperation) {
+ return await datasource.languageProvider.fetchLabels({ timeRange });
+ }
+ const streamSelector = lokiQueryModeller.renderLabels(labelsToConsider);
+ const possibleLabelNames = await datasource.languageProvider.fetchLabels({
+ streamSelector,
+ timeRange,
+ });
+ const labelsNamesToConsider = labelsToConsider.map((l) => l.label);
+
+ // Filter out label names that are already selected
+ return possibleLabelNames.filter((label) => !labelsNamesToConsider.includes(label)).sort();
+ };
+
+ const onGetLabelValues = async (forLabel: Partial) => {
+ if (!forLabel.label) {
+ return [];
+ }
+
+ let values;
+ const labelsToConsider = query.labels.filter((x) => x !== forLabel);
+ // If we have no equality/regex operation with .*, we can't fetch series as it will throw an error, so we fetch label values
+ const hasEqualityOperation = labelsToConsider.find(
+ (filter) => filter.op === '=' || (filter.op === '=~' && new RegExp(filter.value).test('') === false)
+ );
+ if (labelsToConsider.length === 0 || !hasEqualityOperation) {
+ values = await datasource.languageProvider.fetchLabelValues(forLabel.label, { timeRange });
+ } else {
const streamSelector = lokiQueryModeller.renderLabels(labelsToConsider);
- const possibleLabelNames = await datasource.languageProvider.fetchLabels({
+ values = await datasource.languageProvider.fetchLabelValues(forLabel.label, {
streamSelector,
timeRange,
});
- const labelsNamesToConsider = labelsToConsider.map((l) => l.label);
+ }
- // Filter out label names that are already selected
- return possibleLabelNames.filter((label) => !labelsNamesToConsider.includes(label)).sort();
+ return values ? values.map((v) => escapeLabelValueInSelector(v, forLabel.op)) : []; // Escape values in return
+ };
+
+ const labelFilterRequired: boolean = useMemo(() => {
+ const { labels, operations: op } = query;
+ if (!labels.length && op.length) {
+ // Filter is required when operations are present (empty line contains operation is exception)
+ if (op.length === 1 && op[0].id === LokiOperationId.LineContains && op[0].params[0] === '') {
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }, [query]);
+
+ useEffect(() => {
+ const onGetSampleData = async () => {
+ const lokiQuery = { expr: lokiQueryModeller.renderQuery(query), refId: 'data-samples' };
+ const range = timeRange ?? getDefaultTimeRange();
+ const series = await datasource.getDataSamples(lokiQuery, range);
+ const sampleData = { series, state: LoadingState.Done, timeRange: range };
+ setSampleData(sampleData);
};
- const onGetLabelValues = async (forLabel: Partial) => {
- if (!forLabel.label) {
- return [];
- }
+ const updateBasedOnChangedTimeRange =
+ prevTimeRange &&
+ timeRange &&
+ (Math.abs(timeRange.to.valueOf() - prevTimeRange.to.valueOf()) > TIME_SPAN_TO_TRIGGER_SAMPLES ||
+ Math.abs(timeRange.from.valueOf() - prevTimeRange.from.valueOf()) > TIME_SPAN_TO_TRIGGER_SAMPLES);
+ const updateBasedOnChangedQuery = !isEqual(prevQuery, query);
+ if (config.featureToggles.lokiQueryHints && (updateBasedOnChangedTimeRange || updateBasedOnChangedQuery)) {
+ onGetSampleData().catch(console.error);
+ }
+ }, [datasource, query, timeRange, prevQuery, prevTimeRange]);
- let values;
- const labelsToConsider = query.labels.filter((x) => x !== forLabel);
- // If we have no equality/regex operation with .*, we can't fetch series as it will throw an error, so we fetch label values
- const hasEqualityOperation = labelsToConsider.find(
- (filter) => filter.op === '=' || (filter.op === '=~' && new RegExp(filter.value).test('') === false)
- );
- if (labelsToConsider.length === 0 || !hasEqualityOperation) {
- values = await datasource.languageProvider.fetchLabelValues(forLabel.label, { timeRange });
- } else {
- const streamSelector = lokiQueryModeller.renderLabels(labelsToConsider);
- values = await datasource.languageProvider.fetchLabelValues(forLabel.label, {
- streamSelector,
- timeRange,
- });
- }
-
- return values ? values.map((v) => escapeLabelValueInSelector(v, forLabel.op)) : []; // Escape values in return
- };
-
- const labelFilterRequired: boolean = useMemo(() => {
- const { labels, operations: op } = query;
- if (!labels.length && op.length) {
- // Filter is required when operations are present (empty line contains operation is exception)
- if (op.length === 1 && op[0].id === LokiOperationId.LineContains && op[0].params[0] === '') {
- return false;
- }
- return true;
- }
- return false;
- }, [query]);
-
- useEffect(() => {
- const onGetSampleData = async () => {
- const lokiQuery = { expr: lokiQueryModeller.renderQuery(query), refId: 'data-samples' };
- const range = timeRange ?? getDefaultTimeRange();
- const series = await datasource.getDataSamples(lokiQuery, range);
- const sampleData = { series, state: LoadingState.Done, timeRange: range };
- setSampleData(sampleData);
- };
-
- const updateBasedOnChangedTimeRange =
- prevTimeRange &&
- timeRange &&
- (Math.abs(timeRange.to.valueOf() - prevTimeRange.to.valueOf()) > TIME_SPAN_TO_TRIGGER_SAMPLES ||
- Math.abs(timeRange.from.valueOf() - prevTimeRange.from.valueOf()) > TIME_SPAN_TO_TRIGGER_SAMPLES);
- const updateBasedOnChangedQuery = !isEqual(prevQuery, query);
- if (config.featureToggles.lokiQueryHints && (updateBasedOnChangedTimeRange || updateBasedOnChangedQuery)) {
- onGetSampleData().catch(console.error);
- }
- }, [datasource, query, timeRange, prevQuery, prevTimeRange]);
-
- const lang = { grammar: logqlGrammar, name: 'logql' };
- return (
-
-
- ) =>
- withTemplateVariableOptions(onGetLabelNames(forLabel))
- }
- onGetLabelValues={(forLabel: Partial) =>
- withTemplateVariableOptions(onGetLabelValues(forLabel))
- }
- labelsFilters={query.labels}
- onChange={onChangeLabels}
- labelFilterRequired={labelFilterRequired}
- />
-
- {showExplain && (
- }
- >
- {EXPLAIN_LABEL_FILTER_CONTENT}
-
- )}
-
-
- operation.id === LokiOperationId.LabelFilter && isConflictingFilter(operation, otherOperations)
- }
- />
-
- datasource={datasource}
- query={query}
- onChange={onChange}
- data={sampleData}
- queryModeller={lokiQueryModeller}
- buildVisualQueryFromString={buildVisualQueryFromString}
- buildDataQueryFromQueryString={(queryString) => ({ expr: queryString, refId: 'hints' })}
- buildQueryStringFromDataQuery={(query) => query.expr}
- />
-
- {showExplain && (
-
- stepNumber={2}
- queryModeller={lokiQueryModeller}
- query={query}
- language={lang}
- onMouseEnter={(op) => {
- setHighlightedOp(op);
- }}
- onMouseLeave={() => {
- setHighlightedOp(undefined);
- }}
- />
- )}
- {query.binaryQueries && query.binaryQueries.length > 0 && (
-
- )}
-
- );
- }
-);
+ const lang = { grammar: logqlGrammar, name: 'logql' };
+ return (
+
+
+ ) =>
+ withTemplateVariableOptions(onGetLabelNames(forLabel))
+ }
+ onGetLabelValues={(forLabel: Partial) =>
+ withTemplateVariableOptions(onGetLabelValues(forLabel))
+ }
+ labelsFilters={query.labels}
+ onChange={onChangeLabels}
+ labelFilterRequired={labelFilterRequired}
+ />
+
+ {showExplain && (
+ }
+ >
+ {EXPLAIN_LABEL_FILTER_CONTENT}
+
+ )}
+
+
+ operation.id === LokiOperationId.LabelFilter && isConflictingFilter(operation, otherOperations)
+ }
+ />
+
+ datasource={datasource}
+ query={query}
+ onChange={onChange}
+ data={sampleData}
+ queryModeller={lokiQueryModeller}
+ buildVisualQueryFromString={buildVisualQueryFromString}
+ buildDataQueryFromQueryString={(queryString) => ({ expr: queryString, refId: 'hints' })}
+ buildQueryStringFromDataQuery={(query) => query.expr}
+ />
+
+ {showExplain && (
+
+ stepNumber={2}
+ queryModeller={lokiQueryModeller}
+ query={query}
+ language={lang}
+ onMouseEnter={(op) => {
+ setHighlightedOp(op);
+ }}
+ onMouseLeave={() => {
+ setHighlightedOp(undefined);
+ }}
+ />
+ )}
+ {query.binaryQueries && query.binaryQueries.length > 0 && (
+
+ )}
+
+ );
+});
LokiQueryBuilder.displayName = 'LokiQueryBuilder';
diff --git a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderContainer.test.tsx b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderContainer.test.tsx
index 783155fdab8..29425688459 100644
--- a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderContainer.test.tsx
+++ b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderContainer.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor, findAllByRole } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { createLokiDatasource } from '../../__mocks__/datasource';
diff --git a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderContainer.tsx b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderContainer.tsx
index b4715fee0a4..8063cb6d0bb 100644
--- a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderContainer.tsx
+++ b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderContainer.tsx
@@ -1,5 +1,5 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
-import React, { useEffect, useReducer } from 'react';
+import { useEffect, useReducer } from 'react';
import { TimeRange } from '@grafana/data';
diff --git a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderExplained.tsx b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderExplained.tsx
index 68430e8c2cb..5af777c20e7 100644
--- a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderExplained.tsx
+++ b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderExplained.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import { memo } from 'react';
import { OperationExplainedBox, OperationListExplained, RawQuery } from '@grafana/experimental';
import { Stack } from '@grafana/ui';
@@ -14,7 +14,7 @@ export interface Props {
query: string;
}
-export const LokiQueryBuilderExplained = React.memo(({ query }) => {
+export const LokiQueryBuilderExplained = memo(({ query }) => {
const visQuery = buildVisualQueryFromString(query || '').query;
const lang = { grammar: lokiGrammar, name: 'lokiql' };
diff --git a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderOptions.test.tsx b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderOptions.test.tsx
index cdc80221e9f..fff5a79e352 100644
--- a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderOptions.test.tsx
+++ b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderOptions.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { LokiQuery, LokiQueryType } from '../../types';
diff --git a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderOptions.tsx b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderOptions.tsx
index ad9b7ae80f1..ec5ed3a8569 100644
--- a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderOptions.tsx
+++ b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilderOptions.tsx
@@ -1,5 +1,6 @@
import { trim } from 'lodash';
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
+import * as React from 'react';
import { CoreApp, isValidDuration, isValidGrafanaDuration, SelectableValue } from '@grafana/data';
import { EditorField, EditorRow, QueryOptionGroup } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryCodeEditor.test.tsx b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryCodeEditor.test.tsx
index efa2c070d1f..c1ceab32eea 100644
--- a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryCodeEditor.test.tsx
+++ b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryCodeEditor.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryCodeEditor.tsx b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryCodeEditor.tsx
index fba03b1185a..05877c529b9 100644
--- a/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryCodeEditor.tsx
+++ b/public/app/plugins/datasource/loki/querybuilder/components/LokiQueryCodeEditor.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/loki/querybuilder/components/NestedQuery.test.tsx b/public/app/plugins/datasource/loki/querybuilder/components/NestedQuery.test.tsx
index 2c3a586fb00..768560002e3 100644
--- a/public/app/plugins/datasource/loki/querybuilder/components/NestedQuery.test.tsx
+++ b/public/app/plugins/datasource/loki/querybuilder/components/NestedQuery.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { createLokiDatasource } from '../../__mocks__/datasource';
import { LokiVisualQueryBinary } from '../types';
diff --git a/public/app/plugins/datasource/loki/querybuilder/components/NestedQuery.tsx b/public/app/plugins/datasource/loki/querybuilder/components/NestedQuery.tsx
index dd08f32be0b..7ab95dcb781 100644
--- a/public/app/plugins/datasource/loki/querybuilder/components/NestedQuery.tsx
+++ b/public/app/plugins/datasource/loki/querybuilder/components/NestedQuery.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import { memo } from 'react';
import { GrafanaTheme2, toOption } from '@grafana/data';
import { EditorRows, FlexItem } from '@grafana/experimental';
@@ -21,7 +21,7 @@ export interface Props {
onRunQuery: () => void;
}
-export const NestedQuery = React.memo(
+export const NestedQuery = memo(
({ nestedQuery, index, datasource, onChange, onRemove, onRunQuery, showExplain }) => {
const styles = useStyles2(getStyles);
diff --git a/public/app/plugins/datasource/loki/querybuilder/components/NestedQueryList.test.tsx b/public/app/plugins/datasource/loki/querybuilder/components/NestedQueryList.test.tsx
index 623a44cbea8..ce281f06b43 100644
--- a/public/app/plugins/datasource/loki/querybuilder/components/NestedQueryList.test.tsx
+++ b/public/app/plugins/datasource/loki/querybuilder/components/NestedQueryList.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { createLokiDatasource } from '../../__mocks__/datasource';
import { LokiDatasource } from '../../datasource';
diff --git a/public/app/plugins/datasource/loki/querybuilder/components/NestedQueryList.tsx b/public/app/plugins/datasource/loki/querybuilder/components/NestedQueryList.tsx
index 4bf7af82923..d5986c2aff3 100644
--- a/public/app/plugins/datasource/loki/querybuilder/components/NestedQueryList.tsx
+++ b/public/app/plugins/datasource/loki/querybuilder/components/NestedQueryList.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { Stack } from '@grafana/ui';
import { LokiDatasource } from '../../datasource';
diff --git a/public/app/plugins/datasource/loki/querybuilder/components/QueryPattern.tsx b/public/app/plugins/datasource/loki/querybuilder/components/QueryPattern.tsx
index 3407c447345..27fe4fe9831 100644
--- a/public/app/plugins/datasource/loki/querybuilder/components/QueryPattern.tsx
+++ b/public/app/plugins/datasource/loki/querybuilder/components/QueryPattern.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { RawQuery } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/loki/querybuilder/components/QueryPatternsModal.test.tsx b/public/app/plugins/datasource/loki/querybuilder/components/QueryPatternsModal.test.tsx
index b6e986c1079..8a65ba2ac29 100644
--- a/public/app/plugins/datasource/loki/querybuilder/components/QueryPatternsModal.test.tsx
+++ b/public/app/plugins/datasource/loki/querybuilder/components/QueryPatternsModal.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { lokiQueryModeller } from '../LokiQueryModeller';
import { LokiQueryPatternType } from '../types';
diff --git a/public/app/plugins/datasource/loki/querybuilder/components/QueryPatternsModal.tsx b/public/app/plugins/datasource/loki/querybuilder/components/QueryPatternsModal.tsx
index a8e0748cf22..7453341218f 100644
--- a/public/app/plugins/datasource/loki/querybuilder/components/QueryPatternsModal.tsx
+++ b/public/app/plugins/datasource/loki/querybuilder/components/QueryPatternsModal.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { capitalize } from 'lodash';
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
import { CoreApp, GrafanaTheme2, getNextRefId } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/loki/querybuilder/components/QueryPreview.tsx b/public/app/plugins/datasource/loki/querybuilder/components/QueryPreview.tsx
index 04fffba21ae..e5f5b51a482 100644
--- a/public/app/plugins/datasource/loki/querybuilder/components/QueryPreview.tsx
+++ b/public/app/plugins/datasource/loki/querybuilder/components/QueryPreview.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { EditorRow, EditorFieldGroup, RawQuery } from '@grafana/experimental';
import { lokiGrammar } from '../../syntax';
diff --git a/public/app/plugins/datasource/loki/querybuilder/components/UnwrapParamEditor.test.tsx b/public/app/plugins/datasource/loki/querybuilder/components/UnwrapParamEditor.test.tsx
index 3c5f98e2cbe..467808c92a1 100644
--- a/public/app/plugins/datasource/loki/querybuilder/components/UnwrapParamEditor.test.tsx
+++ b/public/app/plugins/datasource/loki/querybuilder/components/UnwrapParamEditor.test.tsx
@@ -1,6 +1,6 @@
import { screen, render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { ComponentProps } from 'react';
+import { ComponentProps } from 'react';
import { DataFrame, DataSourceApi, FieldType, toDataFrame } from '@grafana/data';
import { QueryBuilderOperation, QueryBuilderOperationParamDef } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/loki/querybuilder/components/UnwrapParamEditor.tsx b/public/app/plugins/datasource/loki/querybuilder/components/UnwrapParamEditor.tsx
index 030b3235666..c50b8b5ae54 100644
--- a/public/app/plugins/datasource/loki/querybuilder/components/UnwrapParamEditor.tsx
+++ b/public/app/plugins/datasource/loki/querybuilder/components/UnwrapParamEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { SelectableValue, getDefaultTimeRange, toOption } from '@grafana/data';
import { QueryBuilderOperationParamEditorProps, VisualQueryModeller } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/mssql/CheatSheet.tsx b/public/app/plugins/datasource/mssql/CheatSheet.tsx
index 73849ec7a31..8ca5aeeed24 100644
--- a/public/app/plugins/datasource/mssql/CheatSheet.tsx
+++ b/public/app/plugins/datasource/mssql/CheatSheet.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/mssql/azureauth/AzureAuthSettings.tsx b/public/app/plugins/datasource/mssql/azureauth/AzureAuthSettings.tsx
index a47198c7548..9e2271e720c 100644
--- a/public/app/plugins/datasource/mssql/azureauth/AzureAuthSettings.tsx
+++ b/public/app/plugins/datasource/mssql/azureauth/AzureAuthSettings.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { useEffectOnce } from 'react-use';
import { config } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/mssql/azureauth/AzureCredentialsForm.tsx b/public/app/plugins/datasource/mssql/azureauth/AzureCredentialsForm.tsx
index 5c6e31af1b3..86d28a6c825 100644
--- a/public/app/plugins/datasource/mssql/azureauth/AzureCredentialsForm.tsx
+++ b/public/app/plugins/datasource/mssql/azureauth/AzureCredentialsForm.tsx
@@ -1,4 +1,4 @@
-import React, { ChangeEvent } from 'react';
+import { ChangeEvent } from 'react';
import { SelectableValue } from '@grafana/data';
import { Button, Field, Select, Input } from '@grafana/ui/src/components';
diff --git a/public/app/plugins/datasource/mssql/configuration/ConfigurationEditor.tsx b/public/app/plugins/datasource/mssql/configuration/ConfigurationEditor.tsx
index be0ed607137..1fc0152f8e7 100644
--- a/public/app/plugins/datasource/mssql/configuration/ConfigurationEditor.tsx
+++ b/public/app/plugins/datasource/mssql/configuration/ConfigurationEditor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { SyntheticEvent } from 'react';
+import { SyntheticEvent } from 'react';
import {
DataSourcePluginOptionsEditorProps,
diff --git a/public/app/plugins/datasource/mssql/configuration/Kerberos.tsx b/public/app/plugins/datasource/mssql/configuration/Kerberos.tsx
index a73b6eb1a19..f5dfc8759c3 100644
--- a/public/app/plugins/datasource/mssql/configuration/Kerberos.tsx
+++ b/public/app/plugins/datasource/mssql/configuration/Kerberos.tsx
@@ -1,4 +1,4 @@
-import React, { SyntheticEvent } from 'react';
+import { SyntheticEvent } from 'react';
import { DataSourcePluginOptionsEditorProps, updateDatasourcePluginJsonDataOption } from '@grafana/data';
import { ConfigSubSection } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/mysql/CheatSheet.tsx b/public/app/plugins/datasource/mysql/CheatSheet.tsx
index febfdbdad2a..daa76e45685 100644
--- a/public/app/plugins/datasource/mysql/CheatSheet.tsx
+++ b/public/app/plugins/datasource/mysql/CheatSheet.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/mysql/configuration/ConfigurationEditor.tsx b/public/app/plugins/datasource/mysql/configuration/ConfigurationEditor.tsx
index c0feed4629b..95dabda1c76 100644
--- a/public/app/plugins/datasource/mysql/configuration/ConfigurationEditor.tsx
+++ b/public/app/plugins/datasource/mysql/configuration/ConfigurationEditor.tsx
@@ -1,4 +1,4 @@
-import React, { SyntheticEvent, useState } from 'react';
+import { SyntheticEvent, useState } from 'react';
import {
DataSourcePluginOptionsEditorProps,
diff --git a/public/app/plugins/datasource/mysql/tsconfig.json b/public/app/plugins/datasource/mysql/tsconfig.json
index 7daf2ee8aba..baaaea04185 100644
--- a/public/app/plugins/datasource/mysql/tsconfig.json
+++ b/public/app/plugins/datasource/mysql/tsconfig.json
@@ -1,4 +1,7 @@
{
+ "compilerOptions": {
+ "jsx": "react-jsx"
+ },
"extends": "@grafana/plugin-configs/tsconfig.json",
"include": ["."]
}
diff --git a/public/app/plugins/datasource/opentsdb/components/AnnotationEditor.tsx b/public/app/plugins/datasource/opentsdb/components/AnnotationEditor.tsx
index 80c69846b8a..d6fbfd8b8c4 100644
--- a/public/app/plugins/datasource/opentsdb/components/AnnotationEditor.tsx
+++ b/public/app/plugins/datasource/opentsdb/components/AnnotationEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { QueryEditorProps } from '@grafana/data';
import { InlineFormLabel, Input, InlineSwitch } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/opentsdb/components/ConfigEditor.tsx b/public/app/plugins/datasource/opentsdb/components/ConfigEditor.tsx
index aa0feefac35..70e2e870ed4 100644
--- a/public/app/plugins/datasource/opentsdb/components/ConfigEditor.tsx
+++ b/public/app/plugins/datasource/opentsdb/components/ConfigEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { DataSourcePluginOptionsEditorProps } from '@grafana/data';
import { config } from '@grafana/runtime';
import { DataSourceHttpSettings } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/opentsdb/components/DownSample.test.tsx b/public/app/plugins/datasource/opentsdb/components/DownSample.test.tsx
index 3f903d10ec4..1a3a12c063b 100644
--- a/public/app/plugins/datasource/opentsdb/components/DownSample.test.tsx
+++ b/public/app/plugins/datasource/opentsdb/components/DownSample.test.tsx
@@ -1,5 +1,4 @@
import { fireEvent, render, screen } from '@testing-library/react';
-import React from 'react';
import { OpenTsdbQuery } from '../types';
diff --git a/public/app/plugins/datasource/opentsdb/components/DownSample.tsx b/public/app/plugins/datasource/opentsdb/components/DownSample.tsx
index 74911259d50..b4058908832 100644
--- a/public/app/plugins/datasource/opentsdb/components/DownSample.tsx
+++ b/public/app/plugins/datasource/opentsdb/components/DownSample.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { toOption } from '@grafana/data';
import { InlineLabel, Select, Input, InlineFormLabel, InlineSwitch, Stack } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/opentsdb/components/FilterSection.test.tsx b/public/app/plugins/datasource/opentsdb/components/FilterSection.test.tsx
index 09a45fb9ec3..607145fe338 100644
--- a/public/app/plugins/datasource/opentsdb/components/FilterSection.test.tsx
+++ b/public/app/plugins/datasource/opentsdb/components/FilterSection.test.tsx
@@ -1,5 +1,4 @@
import { fireEvent, render, screen } from '@testing-library/react';
-import React from 'react';
import { OpenTsdbQuery } from '../types';
diff --git a/public/app/plugins/datasource/opentsdb/components/FilterSection.tsx b/public/app/plugins/datasource/opentsdb/components/FilterSection.tsx
index 86c1d0a917f..9fbe719a366 100644
--- a/public/app/plugins/datasource/opentsdb/components/FilterSection.tsx
+++ b/public/app/plugins/datasource/opentsdb/components/FilterSection.tsx
@@ -1,6 +1,6 @@
import debounce from 'debounce-promise';
import { size } from 'lodash';
-import React, { useCallback, useState } from 'react';
+import { useCallback, useState } from 'react';
import { SelectableValue, toOption } from '@grafana/data';
import {
diff --git a/public/app/plugins/datasource/opentsdb/components/MetricSection.test.tsx b/public/app/plugins/datasource/opentsdb/components/MetricSection.test.tsx
index f95c5b9860f..93f1f3c84e6 100644
--- a/public/app/plugins/datasource/opentsdb/components/MetricSection.test.tsx
+++ b/public/app/plugins/datasource/opentsdb/components/MetricSection.test.tsx
@@ -1,5 +1,4 @@
import { fireEvent, render, screen } from '@testing-library/react';
-import React from 'react';
import { OpenTsdbQuery } from '../types';
diff --git a/public/app/plugins/datasource/opentsdb/components/MetricSection.tsx b/public/app/plugins/datasource/opentsdb/components/MetricSection.tsx
index a76ff1b4422..5c62f2ecf06 100644
--- a/public/app/plugins/datasource/opentsdb/components/MetricSection.tsx
+++ b/public/app/plugins/datasource/opentsdb/components/MetricSection.tsx
@@ -1,5 +1,4 @@
import debounce from 'debounce-promise';
-import React from 'react';
import { SelectableValue, toOption } from '@grafana/data';
import { Select, Input, InlineFormLabel, AsyncSelect, Stack, InlineLabel } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/opentsdb/components/OpenTsdbDetails.tsx b/public/app/plugins/datasource/opentsdb/components/OpenTsdbDetails.tsx
index fa7c5955d25..ba45bde7b29 100644
--- a/public/app/plugins/datasource/opentsdb/components/OpenTsdbDetails.tsx
+++ b/public/app/plugins/datasource/opentsdb/components/OpenTsdbDetails.tsx
@@ -1,4 +1,4 @@
-import React, { SyntheticEvent, useId } from 'react';
+import { SyntheticEvent, useId } from 'react';
import { DataSourceSettings, SelectableValue } from '@grafana/data';
import { Select, Input, Field, FieldSet } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/opentsdb/components/OpenTsdbQueryEditor.test.tsx b/public/app/plugins/datasource/opentsdb/components/OpenTsdbQueryEditor.test.tsx
index ca0e6107130..9e12e1ab69e 100644
--- a/public/app/plugins/datasource/opentsdb/components/OpenTsdbQueryEditor.test.tsx
+++ b/public/app/plugins/datasource/opentsdb/components/OpenTsdbQueryEditor.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import OpenTsDatasource from '../datasource';
import { OpenTsdbQuery } from '../types';
diff --git a/public/app/plugins/datasource/opentsdb/components/OpenTsdbQueryEditor.tsx b/public/app/plugins/datasource/opentsdb/components/OpenTsdbQueryEditor.tsx
index bdf57dbfbb4..742701d9feb 100644
--- a/public/app/plugins/datasource/opentsdb/components/OpenTsdbQueryEditor.tsx
+++ b/public/app/plugins/datasource/opentsdb/components/OpenTsdbQueryEditor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { GrafanaTheme2, QueryEditorProps, textUtil } from '@grafana/data';
import { useStyles2, Stack } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/opentsdb/components/RateSection.test.tsx b/public/app/plugins/datasource/opentsdb/components/RateSection.test.tsx
index a5b8bf07ee0..1c4e05e5d2c 100644
--- a/public/app/plugins/datasource/opentsdb/components/RateSection.test.tsx
+++ b/public/app/plugins/datasource/opentsdb/components/RateSection.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { OpenTsdbQuery } from '../types';
diff --git a/public/app/plugins/datasource/opentsdb/components/RateSection.tsx b/public/app/plugins/datasource/opentsdb/components/RateSection.tsx
index e2f9e221eeb..e9e2c54dda1 100644
--- a/public/app/plugins/datasource/opentsdb/components/RateSection.tsx
+++ b/public/app/plugins/datasource/opentsdb/components/RateSection.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { InlineLabel, Input, InlineFormLabel, InlineSwitch, Stack } from '@grafana/ui';
import { OpenTsdbQuery } from '../types';
diff --git a/public/app/plugins/datasource/opentsdb/components/TagSection.test.tsx b/public/app/plugins/datasource/opentsdb/components/TagSection.test.tsx
index 65d181d3a9d..56c438bb841 100644
--- a/public/app/plugins/datasource/opentsdb/components/TagSection.test.tsx
+++ b/public/app/plugins/datasource/opentsdb/components/TagSection.test.tsx
@@ -1,5 +1,4 @@
import { fireEvent, render, screen } from '@testing-library/react';
-import React from 'react';
import { OpenTsdbQuery } from '../types';
diff --git a/public/app/plugins/datasource/opentsdb/components/TagSection.tsx b/public/app/plugins/datasource/opentsdb/components/TagSection.tsx
index 6ffe4b0fc61..0675056a498 100644
--- a/public/app/plugins/datasource/opentsdb/components/TagSection.tsx
+++ b/public/app/plugins/datasource/opentsdb/components/TagSection.tsx
@@ -1,6 +1,6 @@
import debounce from 'debounce-promise';
import { has, size } from 'lodash';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { SelectableValue, toOption } from '@grafana/data';
import {
diff --git a/public/app/plugins/datasource/parca/ConfigEditor.tsx b/public/app/plugins/datasource/parca/ConfigEditor.tsx
index 9332d4cea4d..32d61acd0b7 100644
--- a/public/app/plugins/datasource/parca/ConfigEditor.tsx
+++ b/public/app/plugins/datasource/parca/ConfigEditor.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { DataSourcePluginOptionsEditorProps, GrafanaTheme2 } from '@grafana/data';
import {
diff --git a/public/app/plugins/datasource/parca/QueryEditor/EditorRow.tsx b/public/app/plugins/datasource/parca/QueryEditor/EditorRow.tsx
index 5fe10a24999..a45add59216 100644
--- a/public/app/plugins/datasource/parca/QueryEditor/EditorRow.tsx
+++ b/public/app/plugins/datasource/parca/QueryEditor/EditorRow.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/parca/QueryEditor/EditorRows.tsx b/public/app/plugins/datasource/parca/QueryEditor/EditorRows.tsx
index ce7e38c112a..de79a2b079c 100644
--- a/public/app/plugins/datasource/parca/QueryEditor/EditorRows.tsx
+++ b/public/app/plugins/datasource/parca/QueryEditor/EditorRows.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { Stack } from './Stack';
diff --git a/public/app/plugins/datasource/parca/QueryEditor/LabelsEditor.tsx b/public/app/plugins/datasource/parca/QueryEditor/LabelsEditor.tsx
index d9e0c34c833..3f97efc01a0 100644
--- a/public/app/plugins/datasource/parca/QueryEditor/LabelsEditor.tsx
+++ b/public/app/plugins/datasource/parca/QueryEditor/LabelsEditor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useRef } from 'react';
+import { useEffect, useRef } from 'react';
import { useLatest } from 'react-use';
import { CodeEditor, Monaco, useStyles2, monacoTypes } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/parca/QueryEditor/QueryEditor.test.tsx b/public/app/plugins/datasource/parca/QueryEditor/QueryEditor.test.tsx
index d9bcac8a2f1..fce58dec7fd 100644
--- a/public/app/plugins/datasource/parca/QueryEditor/QueryEditor.test.tsx
+++ b/public/app/plugins/datasource/parca/QueryEditor/QueryEditor.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { of } from 'rxjs';
import { CoreApp, DataSourcePluginMeta, PluginType } from '@grafana/data';
diff --git a/public/app/plugins/datasource/parca/QueryEditor/QueryEditor.tsx b/public/app/plugins/datasource/parca/QueryEditor/QueryEditor.tsx
index d470a5d5e0d..cab66185f53 100644
--- a/public/app/plugins/datasource/parca/QueryEditor/QueryEditor.tsx
+++ b/public/app/plugins/datasource/parca/QueryEditor/QueryEditor.tsx
@@ -1,5 +1,5 @@
import { defaults } from 'lodash';
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
import { useMount } from 'react-use';
import { CoreApp, QueryEditorProps } from '@grafana/data';
diff --git a/public/app/plugins/datasource/parca/QueryEditor/QueryOptions.tsx b/public/app/plugins/datasource/parca/QueryEditor/QueryOptions.tsx
index e6cecc4a43a..ab8b50c69cf 100644
--- a/public/app/plugins/datasource/parca/QueryEditor/QueryOptions.tsx
+++ b/public/app/plugins/datasource/parca/QueryEditor/QueryOptions.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { useToggle } from 'react-use';
import { CoreApp, GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/plugins/datasource/parca/QueryEditor/Stack.tsx b/public/app/plugins/datasource/parca/QueryEditor/Stack.tsx
index 51ba00444c9..483af932c05 100644
--- a/public/app/plugins/datasource/parca/QueryEditor/Stack.tsx
+++ b/public/app/plugins/datasource/parca/QueryEditor/Stack.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { CSSProperties } from 'react';
+import { CSSProperties } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/parca/tsconfig.json b/public/app/plugins/datasource/parca/tsconfig.json
index 7daf2ee8aba..baaaea04185 100644
--- a/public/app/plugins/datasource/parca/tsconfig.json
+++ b/public/app/plugins/datasource/parca/tsconfig.json
@@ -1,4 +1,7 @@
{
+ "compilerOptions": {
+ "jsx": "react-jsx"
+ },
"extends": "@grafana/plugin-configs/tsconfig.json",
"include": ["."]
}
diff --git a/public/app/plugins/datasource/prometheus/configuration/AzureAuthSettings.tsx b/public/app/plugins/datasource/prometheus/configuration/AzureAuthSettings.tsx
index a0bc389ac23..95df6d3eaf5 100644
--- a/public/app/plugins/datasource/prometheus/configuration/AzureAuthSettings.tsx
+++ b/public/app/plugins/datasource/prometheus/configuration/AzureAuthSettings.tsx
@@ -1,5 +1,5 @@
import { cx } from '@emotion/css';
-import React, { FormEvent, useMemo, useState } from 'react';
+import { FormEvent, useMemo, useState } from 'react';
import { useEffectOnce } from 'react-use';
import { config } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/prometheus/configuration/AzureCredentialsForm.test.tsx b/public/app/plugins/datasource/prometheus/configuration/AzureCredentialsForm.test.tsx
index ee4b0e3f6ec..30ead47840b 100644
--- a/public/app/plugins/datasource/prometheus/configuration/AzureCredentialsForm.test.tsx
+++ b/public/app/plugins/datasource/prometheus/configuration/AzureCredentialsForm.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import AzureCredentialsForm, { Props } from './AzureCredentialsForm';
diff --git a/public/app/plugins/datasource/prometheus/configuration/AzureCredentialsForm.tsx b/public/app/plugins/datasource/prometheus/configuration/AzureCredentialsForm.tsx
index 7140dc34b62..9bd461a8311 100644
--- a/public/app/plugins/datasource/prometheus/configuration/AzureCredentialsForm.tsx
+++ b/public/app/plugins/datasource/prometheus/configuration/AzureCredentialsForm.tsx
@@ -1,5 +1,5 @@
import { cx } from '@emotion/css';
-import React, { ChangeEvent, useEffect, useMemo, useReducer, useState } from 'react';
+import { ChangeEvent, useEffect, useMemo, useReducer, useState } from 'react';
import { SelectableValue } from '@grafana/data';
import { config } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/prometheus/configuration/ConfigEditorPackage.tsx b/public/app/plugins/datasource/prometheus/configuration/ConfigEditorPackage.tsx
index 1353f033e38..1625122eb24 100644
--- a/public/app/plugins/datasource/prometheus/configuration/ConfigEditorPackage.tsx
+++ b/public/app/plugins/datasource/prometheus/configuration/ConfigEditorPackage.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { SIGV4ConnectionConfig } from '@grafana/aws-sdk';
import { DataSourcePluginOptionsEditorProps, DataSourceSettings, GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/plugins/datasource/prometheus/configuration/DataSourceHttpSettingsOverhaulPackage.tsx b/public/app/plugins/datasource/prometheus/configuration/DataSourceHttpSettingsOverhaulPackage.tsx
index 5054e96de51..3f32a9c6035 100644
--- a/public/app/plugins/datasource/prometheus/configuration/DataSourceHttpSettingsOverhaulPackage.tsx
+++ b/public/app/plugins/datasource/prometheus/configuration/DataSourceHttpSettingsOverhaulPackage.tsx
@@ -1,4 +1,5 @@
-import React, { ReactElement, useState } from 'react';
+import { ReactElement, useState } from 'react';
+import * as React from 'react';
import { DataSourceSettings } from '@grafana/data';
import { Auth, ConnectionSettings, convertLegacyAuthProps, AuthMethod } from '@grafana/experimental';
diff --git a/public/app/plugins/datasource/tempo/CheatSheet.tsx b/public/app/plugins/datasource/tempo/CheatSheet.tsx
index a8d98f51f10..01d54075b54 100644
--- a/public/app/plugins/datasource/tempo/CheatSheet.tsx
+++ b/public/app/plugins/datasource/tempo/CheatSheet.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { config, reportInteraction } from '@grafana/runtime';
import { TextLink } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/tempo/QueryField.tsx b/public/app/plugins/datasource/tempo/QueryField.tsx
index 0884e297bd9..a2b89b415bb 100644
--- a/public/app/plugins/datasource/tempo/QueryField.tsx
+++ b/public/app/plugins/datasource/tempo/QueryField.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import { PureComponent } from 'react';
import { QueryEditorProps, SelectableValue } from '@grafana/data';
import { config, reportInteraction } from '@grafana/runtime';
@@ -35,7 +35,7 @@ interface State {
// data link should open the traceql tab and run a search based on the configured query.
const DEFAULT_QUERY_TYPE: TempoQueryType = 'traceql';
-class TempoQueryFieldComponent extends React.PureComponent {
+class TempoQueryFieldComponent extends PureComponent {
constructor(props: Props) {
super(props);
this.state = {
diff --git a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/DurationInput.tsx b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/DurationInput.tsx
index deea6014dab..9e4463d35c4 100644
--- a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/DurationInput.tsx
+++ b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/DurationInput.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { Select, HorizontalGroup, Input, useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/GroupByField.test.tsx b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/GroupByField.test.tsx
index 914289d63f9..02e8b7190fc 100644
--- a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/GroupByField.test.tsx
+++ b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/GroupByField.test.tsx
@@ -1,6 +1,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { TraceqlSearchScope } from '../dataquery.gen';
import { TempoDatasource } from '../datasource';
diff --git a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/GroupByField.tsx b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/GroupByField.tsx
index 4f93c941b18..dc1c3565d4f 100644
--- a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/GroupByField.tsx
+++ b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/GroupByField.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import { v4 as uuidv4 } from 'uuid';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/InlineSearchField.tsx b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/InlineSearchField.tsx
index abe948dddcd..d4b0678069f 100644
--- a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/InlineSearchField.tsx
+++ b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/InlineSearchField.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { InlineFieldRow, InlineField } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/SearchField.test.tsx b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/SearchField.test.tsx
index 6870c0533e0..65bfe28381f 100644
--- a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/SearchField.test.tsx
+++ b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/SearchField.test.tsx
@@ -1,6 +1,5 @@
import { act, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { LanguageProvider } from '@grafana/data';
diff --git a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/SearchField.tsx b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/SearchField.tsx
index fc558e0c581..049ab7a41b8 100644
--- a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/SearchField.tsx
+++ b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/SearchField.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { uniq } from 'lodash';
-import React, { useState, useEffect, useMemo } from 'react';
+import { useState, useEffect, useMemo } from 'react';
import useAsync from 'react-use/lib/useAsync';
import { SelectableValue } from '@grafana/data';
diff --git a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/TagsInput.test.tsx b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/TagsInput.test.tsx
index 1552be76f29..bc896a39a89 100644
--- a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/TagsInput.test.tsx
+++ b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/TagsInput.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TraceqlFilter, TraceqlSearchScope } from '../dataquery.gen';
import { TempoDatasource } from '../datasource';
diff --git a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/TagsInput.tsx b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/TagsInput.tsx
index 5b4541960dc..31afd82f7c6 100644
--- a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/TagsInput.tsx
+++ b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/TagsInput.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useCallback, useEffect } from 'react';
+import { useCallback, useEffect } from 'react';
import { v4 as uuidv4 } from 'uuid';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/TraceQLSearch.test.tsx b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/TraceQLSearch.test.tsx
index 698009d24f2..696529261a6 100644
--- a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/TraceQLSearch.test.tsx
+++ b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/TraceQLSearch.test.tsx
@@ -1,6 +1,6 @@
import { act, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { config } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/TraceQLSearch.tsx b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/TraceQLSearch.tsx
index 5494ca18b99..64adda814ac 100644
--- a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/TraceQLSearch.tsx
+++ b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/TraceQLSearch.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useCallback, useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
import { CoreApp, GrafanaTheme2 } from '@grafana/data';
import { TemporaryAlert } from '@grafana/o11y-ds-frontend';
@@ -18,7 +18,7 @@ import { GroupByField } from './GroupByField';
import InlineSearchField from './InlineSearchField';
import SearchField from './SearchField';
import TagsInput from './TagsInput';
-import { filterScopedTag, filterTitle, generateQueryFromFilters, replaceAt } from './utils';
+import { filterScopedTag, filterTitle, generateQueryFromFilters, interpolateFilters, replaceAt } from './utils';
interface Props {
datasource: TempoDatasource;
@@ -62,9 +62,10 @@ const TraceQLSearch = ({ datasource, query, onChange, onClearResults, app, addVa
onChange({ ...query, filters: query.filters.filter((f) => f.id !== s.id) });
};
+ const templateVariables = getTemplateSrv().getVariables();
useEffect(() => {
- setTraceQlQuery(generateQueryFromFilters(query.filters || []));
- }, [query]);
+ setTraceQlQuery(generateQueryFromFilters(interpolateFilters(query.filters || [])));
+ }, [query, templateVariables]);
const findFilter = useCallback((id: string) => query.filters?.find((f) => f.id === id), [query.filters]);
diff --git a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/utils.ts b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/utils.ts
index 378076ed50b..7191e90f6ed 100644
--- a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/utils.ts
+++ b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/utils.ts
@@ -1,11 +1,33 @@
import { startCase, uniq } from 'lodash';
-import { AdHocVariableFilter, SelectableValue } from '@grafana/data';
+import { AdHocVariableFilter, ScopedVars, SelectableValue } from '@grafana/data';
+import { getTemplateSrv } from '@grafana/runtime';
+import { VariableFormatID } from '@grafana/schema';
import { TraceqlFilter, TraceqlSearchScope } from '../dataquery.gen';
import { intrinsics } from '../traceql/traceql';
import { Scope } from '../types';
+export const interpolateFilters = (filters: TraceqlFilter[], scopedVars?: ScopedVars) => {
+ const interpolatedFilters = filters.map((filter) => {
+ const updatedFilter = {
+ ...filter,
+ tag: getTemplateSrv().replace(filter.tag ?? '', scopedVars ?? {}),
+ };
+
+ if (filter.value) {
+ updatedFilter.value =
+ typeof filter.value === 'string'
+ ? getTemplateSrv().replace(filter.value ?? '', scopedVars ?? {}, VariableFormatID.Pipe)
+ : filter.value.map((v) => getTemplateSrv().replace(v ?? '', scopedVars ?? {}, VariableFormatID.Pipe));
+ }
+
+ return updatedFilter;
+ });
+
+ return interpolatedFilters;
+};
+
export const generateQueryFromFilters = (filters: TraceqlFilter[]) => {
return `{${filters
.filter((f) => f.tag && f.operator && f.value?.length)
diff --git a/public/app/plugins/datasource/tempo/ServiceGraphSection.tsx b/public/app/plugins/datasource/tempo/ServiceGraphSection.tsx
index 6b770fb5c19..0879eaadc28 100644
--- a/public/app/plugins/datasource/tempo/ServiceGraphSection.tsx
+++ b/public/app/plugins/datasource/tempo/ServiceGraphSection.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import useAsync from 'react-use/lib/useAsync';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/plugins/datasource/tempo/VariableQueryEditor.test.tsx b/public/app/plugins/datasource/tempo/VariableQueryEditor.test.tsx
index 3d5554775a5..700c2defc36 100644
--- a/public/app/plugins/datasource/tempo/VariableQueryEditor.test.tsx
+++ b/public/app/plugins/datasource/tempo/VariableQueryEditor.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { TemplateSrv } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/tempo/VariableQueryEditor.tsx b/public/app/plugins/datasource/tempo/VariableQueryEditor.tsx
index b150c7e3381..5681134baed 100644
--- a/public/app/plugins/datasource/tempo/VariableQueryEditor.tsx
+++ b/public/app/plugins/datasource/tempo/VariableQueryEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { DataQuery, SelectableValue } from '@grafana/data';
import { InlineField, InlineFieldRow, Select } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/AdHocFilter.tsx b/public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/AdHocFilter.tsx
index 8e3a34183cc..06f5757872c 100644
--- a/public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/AdHocFilter.tsx
+++ b/public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/AdHocFilter.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent, ReactNode } from 'react';
+import { Fragment, PureComponent, ReactNode } from 'react';
import { AdHocVariableFilter, DataSourceRef, SelectableValue } from '@grafana/data';
import { Segment } from '@grafana/ui';
@@ -88,7 +88,7 @@ export class AdHocFilter extends PureComponent {
renderFilterSegments(filter: AdHocVariableFilter, index: number, disabled?: boolean) {
return (
-
+
{
onValueChange={this.onChange(index, 'value')}
allFilters={this.getAllFilters()}
/>
-
+
);
}
}
diff --git a/public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/AdHocFilterBuilder.tsx b/public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/AdHocFilterBuilder.tsx
index 956b2568201..816f09b8d69 100644
--- a/public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/AdHocFilterBuilder.tsx
+++ b/public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/AdHocFilterBuilder.tsx
@@ -1,5 +1,6 @@
import i18n from 'i18next';
-import React, { useCallback, useState } from 'react';
+import { useCallback, useState } from 'react';
+import * as React from 'react';
import { AdHocVariableFilter, DataSourceRef, SelectableValue } from '@grafana/data';
diff --git a/public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/AdHocFilterKey.tsx b/public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/AdHocFilterKey.tsx
index fb57eb9d7f8..8acc4ae685e 100644
--- a/public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/AdHocFilterKey.tsx
+++ b/public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/AdHocFilterKey.tsx
@@ -1,4 +1,4 @@
-import React, { ReactElement } from 'react';
+import { ReactElement } from 'react';
import { AdHocVariableFilter, DataSourceRef, SelectableValue } from '@grafana/data';
import { getDataSourceSrv } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/AdHocFilterRenderer.tsx b/public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/AdHocFilterRenderer.tsx
index 1a5c8fd0054..6c658f5d18a 100644
--- a/public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/AdHocFilterRenderer.tsx
+++ b/public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/AdHocFilterRenderer.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { AdHocVariableFilter, DataSourceRef, SelectableValue } from '@grafana/data';
import { AdHocFilterKey } from './AdHocFilterKey';
diff --git a/public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/AdHocFilterValue.tsx b/public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/AdHocFilterValue.tsx
index 3c2e23dbd7c..09a44d50e5d 100644
--- a/public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/AdHocFilterValue.tsx
+++ b/public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/AdHocFilterValue.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { AdHocVariableFilter, DataSourceRef, SelectableValue, getDefaultTimeRange } from '@grafana/data';
// import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
import { getDataSourceSrv } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/ConditionSegment.tsx b/public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/ConditionSegment.tsx
index 4c47fd73433..c4db252ad26 100644
--- a/public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/ConditionSegment.tsx
+++ b/public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/ConditionSegment.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
interface Props {
label: string;
}
diff --git a/public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/OperatorSegment.tsx b/public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/OperatorSegment.tsx
index b8646b466e6..20cbd6e29ff 100644
--- a/public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/OperatorSegment.tsx
+++ b/public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/OperatorSegment.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SelectableValue } from '@grafana/data';
import { Segment } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/tempo/_importedDependencies/datasources/prometheus/QueryOptionGroup.tsx b/public/app/plugins/datasource/tempo/_importedDependencies/datasources/prometheus/QueryOptionGroup.tsx
index d2187f26dde..f8b6a4273a3 100644
--- a/public/app/plugins/datasource/tempo/_importedDependencies/datasources/prometheus/QueryOptionGroup.tsx
+++ b/public/app/plugins/datasource/tempo/_importedDependencies/datasources/prometheus/QueryOptionGroup.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { useToggle } from 'react-use';
import { getValueFormat, GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/plugins/datasource/tempo/_importedDependencies/datasources/prometheus/RawQuery.tsx b/public/app/plugins/datasource/tempo/_importedDependencies/datasources/prometheus/RawQuery.tsx
index 4d1f727e9f3..60b0d6fd765 100644
--- a/public/app/plugins/datasource/tempo/_importedDependencies/datasources/prometheus/RawQuery.tsx
+++ b/public/app/plugins/datasource/tempo/_importedDependencies/datasources/prometheus/RawQuery.tsx
@@ -1,6 +1,5 @@
import { css, cx } from '@emotion/css';
import Prism, { Grammar } from 'prismjs';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data/src';
import { useTheme2 } from '@grafana/ui/src';
diff --git a/public/app/plugins/datasource/tempo/configuration/ConfigEditor.tsx b/public/app/plugins/datasource/tempo/configuration/ConfigEditor.tsx
index 324627f5875..6dcca3cea3d 100644
--- a/public/app/plugins/datasource/tempo/configuration/ConfigEditor.tsx
+++ b/public/app/plugins/datasource/tempo/configuration/ConfigEditor.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { DataSourcePluginOptionsEditorProps, GrafanaTheme2 } from '@grafana/data';
import {
diff --git a/public/app/plugins/datasource/tempo/configuration/QuerySettings.tsx b/public/app/plugins/datasource/tempo/configuration/QuerySettings.tsx
index 85adf08d72d..c2e8ed53964 100644
--- a/public/app/plugins/datasource/tempo/configuration/QuerySettings.tsx
+++ b/public/app/plugins/datasource/tempo/configuration/QuerySettings.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { DataSourcePluginOptionsEditorProps, GrafanaTheme2, updateDatasourcePluginJsonDataOption } from '@grafana/data';
import { IntervalInput, invalidTimeShiftError } from '@grafana/o11y-ds-frontend';
diff --git a/public/app/plugins/datasource/tempo/configuration/SearchSettings.tsx b/public/app/plugins/datasource/tempo/configuration/SearchSettings.tsx
index e8cb9280859..620ec9bd1e2 100644
--- a/public/app/plugins/datasource/tempo/configuration/SearchSettings.tsx
+++ b/public/app/plugins/datasource/tempo/configuration/SearchSettings.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { DataSourcePluginOptionsEditorProps, updateDatasourcePluginJsonDataOption } from '@grafana/data';
import { InlineField, InlineFieldRow, InlineSwitch, useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/tempo/configuration/ServiceGraphSettings.tsx b/public/app/plugins/datasource/tempo/configuration/ServiceGraphSettings.tsx
index b19515e9fc6..31016057bd4 100644
--- a/public/app/plugins/datasource/tempo/configuration/ServiceGraphSettings.tsx
+++ b/public/app/plugins/datasource/tempo/configuration/ServiceGraphSettings.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import {
DataSourceInstanceSettings,
DataSourcePluginOptionsEditorProps,
diff --git a/public/app/plugins/datasource/tempo/configuration/TraceQLSearchSettings.tsx b/public/app/plugins/datasource/tempo/configuration/TraceQLSearchSettings.tsx
index 3cc7390b501..929dc92a4ac 100644
--- a/public/app/plugins/datasource/tempo/configuration/TraceQLSearchSettings.tsx
+++ b/public/app/plugins/datasource/tempo/configuration/TraceQLSearchSettings.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import useAsync from 'react-use/lib/useAsync';
import { DataSourcePluginOptionsEditorProps, updateDatasourcePluginJsonDataOption } from '@grafana/data';
diff --git a/public/app/plugins/datasource/tempo/configuration/TraceQLSearchTags.tsx b/public/app/plugins/datasource/tempo/configuration/TraceQLSearchTags.tsx
index aa8ce1924bc..3df13d4e565 100644
--- a/public/app/plugins/datasource/tempo/configuration/TraceQLSearchTags.tsx
+++ b/public/app/plugins/datasource/tempo/configuration/TraceQLSearchTags.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useEffect } from 'react';
+import { useCallback, useEffect } from 'react';
import useAsync from 'react-use/lib/useAsync';
import { DataSourcePluginOptionsEditorProps, updateDatasourcePluginJsonDataOption } from '@grafana/data';
diff --git a/public/app/plugins/datasource/tempo/datasource.test.ts b/public/app/plugins/datasource/tempo/datasource.test.ts
index 2cc8f39594e..771220631ee 100644
--- a/public/app/plugins/datasource/tempo/datasource.test.ts
+++ b/public/app/plugins/datasource/tempo/datasource.test.ts
@@ -112,7 +112,7 @@ describe('Tempo data source', () => {
config.liveEnabled = true;
const ds = new TempoDatasource(defaultSettings, templateSrv);
await lastValueFrom(ds.query(traceqlSearchQuery as DataQueryRequest));
- expect(handleStreamingSearch).toHaveBeenCalledTimes(2);
+ expect(handleStreamingSearch).toHaveBeenCalledTimes(1);
expect(request).toHaveBeenCalledTimes(0);
});
@@ -120,7 +120,7 @@ describe('Tempo data source', () => {
config.liveEnabled = false;
const ds = new TempoDatasource(defaultSettings, templateSrv);
await lastValueFrom(ds.query(traceqlQuery as DataQueryRequest));
- expect(handleStreamingSearch).toHaveBeenCalledTimes(2);
+ expect(handleStreamingSearch).toHaveBeenCalledTimes(1);
expect(request).toHaveBeenCalledTimes(1);
});
@@ -128,8 +128,8 @@ describe('Tempo data source', () => {
config.liveEnabled = false;
const ds = new TempoDatasource(defaultSettings, templateSrv);
await lastValueFrom(ds.query(traceqlSearchQuery as DataQueryRequest));
- expect(handleStreamingSearch).toHaveBeenCalledTimes(2);
- expect(request).toHaveBeenCalledTimes(2);
+ expect(handleStreamingSearch).toHaveBeenCalledTimes(1);
+ expect(request).toHaveBeenCalledTimes(1);
});
});
diff --git a/public/app/plugins/datasource/tempo/datasource.ts b/public/app/plugins/datasource/tempo/datasource.ts
index b7ae4f1c77d..d287cae6459 100644
--- a/public/app/plugins/datasource/tempo/datasource.ts
+++ b/public/app/plugins/datasource/tempo/datasource.ts
@@ -34,7 +34,11 @@ import {
} from '@grafana/runtime';
import { BarGaugeDisplayMode, TableCellDisplayMode, VariableFormatID } from '@grafana/schema';
-import { generateQueryFromAdHocFilters, generateQueryFromFilters } from './SearchTraceQLEditor/utils';
+import {
+ generateQueryFromAdHocFilters,
+ generateQueryFromFilters,
+ interpolateFilters,
+} from './SearchTraceQLEditor/utils';
import { TempoVariableQuery, TempoVariableQueryType } from './VariableQueryEditor';
import { PrometheusDatasource, PromQuery } from './_importedDependencies/datasources/prometheus/types';
import { TraceqlFilter, TraceqlSearchScope } from './dataquery.gen';
@@ -470,21 +474,7 @@ export class TempoDatasource extends DataSourceWithBackend {
- const updatedFilter = {
- ...filter,
- tag: this.templateSrv.replace(filter.tag ?? '', scopedVars),
- };
-
- if (filter.value) {
- updatedFilter.value =
- typeof filter.value === 'string'
- ? this.templateSrv.replace(filter.value ?? '', scopedVars, VariableFormatID.Pipe)
- : filter.value.map((v) => this.templateSrv.replace(v ?? '', scopedVars, VariableFormatID.Pipe));
- }
-
- return updatedFilter;
- });
+ expandedQuery.filters = interpolateFilters(query.filters, scopedVars);
}
if (query.groupBy) {
diff --git a/public/app/plugins/datasource/tempo/language_provider.ts b/public/app/plugins/datasource/tempo/language_provider.ts
index 968259d6326..a91cd899d06 100644
--- a/public/app/plugins/datasource/tempo/language_provider.ts
+++ b/public/app/plugins/datasource/tempo/language_provider.ts
@@ -1,4 +1,6 @@
import { LanguageProvider, SelectableValue } from '@grafana/data';
+import { getTemplateSrv } from '@grafana/runtime';
+import { VariableFormatID } from '@grafana/schema';
import { getAllTags, getTagsByScope, getUnscopedTags } from './SearchTraceQLEditor/utils';
import { TraceqlSearchScope } from './dataquery.gen';
@@ -132,7 +134,10 @@ export default class TempoLanguageProvider extends LanguageProvider {
async getOptionsV2(tag: string, query?: string): Promise>> {
const encodedTag = this.encodeTag(tag);
- const response = await this.request(`/api/v2/search/tag/${encodedTag}/values`, query ? { q: query } : {});
+ const response = await this.request(
+ `/api/v2/search/tag/${encodedTag}/values`,
+ query ? { q: getTemplateSrv().replace(query, {}, VariableFormatID.Pipe) } : {}
+ );
let options: Array> = [];
if (response && response.tagValues) {
response.tagValues.forEach((v: { type: string; value?: string }) => {
diff --git a/public/app/plugins/datasource/tempo/traceql/QueryEditor.tsx b/public/app/plugins/datasource/tempo/traceql/QueryEditor.tsx
index 7e5f7e024e8..1259a9becc0 100644
--- a/public/app/plugins/datasource/tempo/traceql/QueryEditor.tsx
+++ b/public/app/plugins/datasource/tempo/traceql/QueryEditor.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { defaults } from 'lodash';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { GrafanaTheme2, QueryEditorProps } from '@grafana/data';
import { config, reportInteraction } from '@grafana/runtime';
diff --git a/public/app/plugins/datasource/tempo/traceql/TempoQueryBuilderOptions.tsx b/public/app/plugins/datasource/tempo/traceql/TempoQueryBuilderOptions.tsx
index d4e40701ffb..5723032aae2 100644
--- a/public/app/plugins/datasource/tempo/traceql/TempoQueryBuilderOptions.tsx
+++ b/public/app/plugins/datasource/tempo/traceql/TempoQueryBuilderOptions.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { EditorField, EditorRow } from '@grafana/experimental';
import { AutoSizeInput, RadioButtonGroup } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/tempo/traceql/TraceQLEditor.tsx b/public/app/plugins/datasource/tempo/traceql/TraceQLEditor.tsx
index 3f40bc006ac..18ccc82b0dc 100644
--- a/public/app/plugins/datasource/tempo/traceql/TraceQLEditor.tsx
+++ b/public/app/plugins/datasource/tempo/traceql/TraceQLEditor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useRef, useState } from 'react';
+import { useEffect, useRef, useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { TemporaryAlert } from '@grafana/o11y-ds-frontend';
diff --git a/public/app/plugins/datasource/tempo/traceql/highlighting.test.ts b/public/app/plugins/datasource/tempo/traceql/highlighting.test.ts
index e9b1d2a80ed..335983a824b 100644
--- a/public/app/plugins/datasource/tempo/traceql/highlighting.test.ts
+++ b/public/app/plugins/datasource/tempo/traceql/highlighting.test.ts
@@ -102,7 +102,7 @@ describe('Highlighting', () => {
['{span.http.status_code = 200} &&', 'Invalid spanset expression after spanset combining operator.'],
[
'{span.http.status_code = 200} && {span.http.status_code = 200} | foo() > 3',
- 'Invalid aggregation operator after pipepile operator.',
+ 'Invalid aggregation operator after pipeline operator.',
],
[
'{span.http.status_code = 200} && {span.http.status_code = 200} | avg() > 3',
@@ -134,9 +134,9 @@ describe('Highlighting', () => {
['{ span. }', 'Invalid expression for spanset.'],
['{.foo=}', 'Invalid value after comparison or arithmetic operator.'],
['{.foo="}', 'Invalid value after comparison or arithmetic operator.'],
- ['{.foo=300} |', 'Invalid aggregation operator after pipepile operator.'],
- ['{.foo=300} && {.bar=200} |', 'Invalid aggregation operator after pipepile operator.'],
- ['{.foo=300} && {.bar=300} && {.foo=300} |', 'Invalid aggregation operator after pipepile operator.'],
+ ['{.foo=300} |', 'Invalid aggregation operator after pipeline operator.'],
+ ['{.foo=300} && {.bar=200} |', 'Invalid aggregation operator after pipeline operator.'],
+ ['{.foo=300} && {.bar=300} && {.foo=300} |', 'Invalid aggregation operator after pipeline operator.'],
['{.foo=300} | avg(.value)', 'Invalid comparison operator after aggregator operator.'],
['{.foo=300} && {.foo=300} | avg(.value)', 'Invalid comparison operator after aggregator operator.'],
['{.foo=300} | avg(.value) =', 'Invalid value after comparison operator.'],
diff --git a/public/app/plugins/datasource/tempo/traceql/highlighting.ts b/public/app/plugins/datasource/tempo/traceql/highlighting.ts
index a8fbefc23ce..21e17c9aba8 100644
--- a/public/app/plugins/datasource/tempo/traceql/highlighting.ts
+++ b/public/app/plugins/datasource/tempo/traceql/highlighting.ts
@@ -52,7 +52,7 @@ export const computeErrorMessage = (errorNode: SyntaxNode) => {
case SpansetPipelineExpression:
return 'Invalid spanset combining operator after spanset expression.';
case Pipe:
- return 'Invalid aggregation operator after pipepile operator.';
+ return 'Invalid aggregation operator after pipeline operator.';
default:
return 'Invalid spanset expression after spanset combining operator.';
}
diff --git a/public/app/plugins/datasource/tempo/tsconfig.json b/public/app/plugins/datasource/tempo/tsconfig.json
index 6dc8a770cba..40352099203 100644
--- a/public/app/plugins/datasource/tempo/tsconfig.json
+++ b/public/app/plugins/datasource/tempo/tsconfig.json
@@ -1,5 +1,6 @@
{
"compilerOptions": {
+ "jsx": "react-jsx",
"types": ["node", "jest", "@testing-library/jest-dom"]
},
"extends": "@grafana/plugin-configs/tsconfig.json",
diff --git a/public/app/plugins/datasource/zipkin/ConfigEditor.tsx b/public/app/plugins/datasource/zipkin/ConfigEditor.tsx
index bb9c440aafe..f66965bd452 100644
--- a/public/app/plugins/datasource/zipkin/ConfigEditor.tsx
+++ b/public/app/plugins/datasource/zipkin/ConfigEditor.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { DataSourcePluginOptionsEditorProps, GrafanaTheme2 } from '@grafana/data';
import {
diff --git a/public/app/plugins/datasource/zipkin/QueryField.test.tsx b/public/app/plugins/datasource/zipkin/QueryField.test.tsx
index ee8c90b6a56..04f638e3688 100644
--- a/public/app/plugins/datasource/zipkin/QueryField.test.tsx
+++ b/public/app/plugins/datasource/zipkin/QueryField.test.tsx
@@ -1,5 +1,4 @@
import { act, render, renderHook, screen, waitFor } from '@testing-library/react';
-import React from 'react';
import { CascaderOption } from '@grafana/ui';
diff --git a/public/app/plugins/datasource/zipkin/QueryField.tsx b/public/app/plugins/datasource/zipkin/QueryField.tsx
index 40e04968c60..c79ee92307b 100644
--- a/public/app/plugins/datasource/zipkin/QueryField.tsx
+++ b/public/app/plugins/datasource/zipkin/QueryField.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { fromPairs } from 'lodash';
-import React, { useCallback, useEffect, useMemo, useState } from 'react';
+import { useCallback, useEffect, useMemo, useState } from 'react';
import { useAsyncFn, useMount, useMountedState } from 'react-use';
import { AsyncState } from 'react-use/lib/useAsyncFn';
diff --git a/public/app/plugins/datasource/zipkin/tsconfig.json b/public/app/plugins/datasource/zipkin/tsconfig.json
index 6dc8a770cba..40352099203 100644
--- a/public/app/plugins/datasource/zipkin/tsconfig.json
+++ b/public/app/plugins/datasource/zipkin/tsconfig.json
@@ -1,5 +1,6 @@
{
"compilerOptions": {
+ "jsx": "react-jsx",
"types": ["node", "jest", "@testing-library/jest-dom"]
},
"extends": "@grafana/plugin-configs/tsconfig.json",
diff --git a/public/app/plugins/panel/alertlist/AlertInstances.tsx b/public/app/plugins/panel/alertlist/AlertInstances.tsx
index c7b289690c6..be32a39d5ef 100644
--- a/public/app/plugins/panel/alertlist/AlertInstances.tsx
+++ b/public/app/plugins/panel/alertlist/AlertInstances.tsx
@@ -1,7 +1,7 @@
import { css, cx } from '@emotion/css';
import { noop } from 'lodash';
import pluralize from 'pluralize';
-import React, { useCallback, useEffect, useMemo, useState } from 'react';
+import { useCallback, useEffect, useMemo, useState } from 'react';
import { GrafanaTheme2, PanelProps } from '@grafana/data';
import { Button, clearButtonStyles, Icon, useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/panel/alertlist/GroupByWithLoading.tsx b/public/app/plugins/panel/alertlist/GroupByWithLoading.tsx
index dcf90a7f5b0..30b54432538 100644
--- a/public/app/plugins/panel/alertlist/GroupByWithLoading.tsx
+++ b/public/app/plugins/panel/alertlist/GroupByWithLoading.tsx
@@ -1,5 +1,5 @@
import { isEmpty, uniq } from 'lodash';
-import React, { useEffect, useMemo } from 'react';
+import { useEffect, useMemo } from 'react';
import { SelectableValue } from '@grafana/data';
import { Icon, MultiSelect } from '@grafana/ui';
diff --git a/public/app/plugins/panel/alertlist/UnifiedAlertList.tsx b/public/app/plugins/panel/alertlist/UnifiedAlertList.tsx
index c6676c6ad42..0e0b3ce4fc6 100644
--- a/public/app/plugins/panel/alertlist/UnifiedAlertList.tsx
+++ b/public/app/plugins/panel/alertlist/UnifiedAlertList.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { sortBy } from 'lodash';
-import React, { useEffect, useMemo } from 'react';
+import { useEffect, useMemo } from 'react';
import { useEffectOnce, useToggle } from 'react-use';
import { GrafanaTheme2, PanelProps } from '@grafana/data';
diff --git a/public/app/plugins/panel/alertlist/UnifiedalertList.test.tsx b/public/app/plugins/panel/alertlist/UnifiedalertList.test.tsx
index bc8430d453a..203dfa5ae20 100644
--- a/public/app/plugins/panel/alertlist/UnifiedalertList.test.tsx
+++ b/public/app/plugins/panel/alertlist/UnifiedalertList.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { Provider } from 'react-redux';
import { byRole, byText } from 'testing-library-selector';
diff --git a/public/app/plugins/panel/alertlist/module.tsx b/public/app/plugins/panel/alertlist/module.tsx
index 23b2f000b5a..9ec66e40984 100644
--- a/public/app/plugins/panel/alertlist/module.tsx
+++ b/public/app/plugins/panel/alertlist/module.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { DataSourceInstanceSettings, PanelPlugin } from '@grafana/data';
import { Button, Stack } from '@grafana/ui';
import { OldFolderPicker } from 'app/core/components/Select/OldFolderPicker';
diff --git a/public/app/plugins/panel/alertlist/unified-alerting/GroupedView.test.tsx b/public/app/plugins/panel/alertlist/unified-alerting/GroupedView.test.tsx
index 148c0c9f485..c7d2cb17d6b 100644
--- a/public/app/plugins/panel/alertlist/unified-alerting/GroupedView.test.tsx
+++ b/public/app/plugins/panel/alertlist/unified-alerting/GroupedView.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { CombinedRuleWithLocation } from 'app/types/unified-alerting';
import { PromRuleType } from 'app/types/unified-alerting-dto';
diff --git a/public/app/plugins/panel/alertlist/unified-alerting/GroupedView.tsx b/public/app/plugins/panel/alertlist/unified-alerting/GroupedView.tsx
index fbdb1b71db6..9af4dc430b8 100644
--- a/public/app/plugins/panel/alertlist/unified-alerting/GroupedView.tsx
+++ b/public/app/plugins/panel/alertlist/unified-alerting/GroupedView.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { useStyles2 } from '@grafana/ui';
import { AlertLabel } from 'app/features/alerting/unified/components/AlertLabel';
diff --git a/public/app/plugins/panel/alertlist/unified-alerting/UngroupedView.tsx b/public/app/plugins/panel/alertlist/unified-alerting/UngroupedView.tsx
index bfa92a15ec0..0790e77cd07 100644
--- a/public/app/plugins/panel/alertlist/unified-alerting/UngroupedView.tsx
+++ b/public/app/plugins/panel/alertlist/unified-alerting/UngroupedView.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import { useLocation } from 'react-use';
import { GrafanaTheme2, intervalToAbbreviatedDurationString } from '@grafana/data';
diff --git a/public/app/plugins/panel/annolist/AnnoListPanel.test.tsx b/public/app/plugins/panel/annolist/AnnoListPanel.test.tsx
index a96e2c1fe03..1c9dbd45abc 100644
--- a/public/app/plugins/panel/annolist/AnnoListPanel.test.tsx
+++ b/public/app/plugins/panel/annolist/AnnoListPanel.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { AnnotationEvent, FieldConfigSource, getDefaultTimeRange, LoadingState } from '@grafana/data';
import { locationService } from '@grafana/runtime';
diff --git a/public/app/plugins/panel/annolist/AnnoListPanel.tsx b/public/app/plugins/panel/annolist/AnnoListPanel.tsx
index b43aae06250..b188cb5e228 100644
--- a/public/app/plugins/panel/annolist/AnnoListPanel.tsx
+++ b/public/app/plugins/panel/annolist/AnnoListPanel.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { PureComponent } from 'react';
+import { createRef, PureComponent } from 'react';
import { Subscription } from 'rxjs';
import {
@@ -38,7 +38,7 @@ interface State {
export class AnnoListPanel extends PureComponent {
style = getStyles(config.theme2);
subs = new Subscription();
- tagListRef = React.createRef();
+ tagListRef = createRef();
constructor(props: Props) {
super(props);
diff --git a/public/app/plugins/panel/annolist/AnnotationListItem.tsx b/public/app/plugins/panel/annolist/AnnotationListItem.tsx
index a90fc53ce03..4731081b03a 100644
--- a/public/app/plugins/panel/annolist/AnnotationListItem.tsx
+++ b/public/app/plugins/panel/annolist/AnnotationListItem.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { MouseEvent } from 'react';
+import { MouseEvent } from 'react';
import { AnnotationEvent, DateTimeInput, GrafanaTheme2, PanelProps } from '@grafana/data';
import { Card, TagList, Tooltip, RenderUserContentAsHTML, useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/panel/annolist/module.tsx b/public/app/plugins/panel/annolist/module.tsx
index e914b3fad98..2c402b7da94 100644
--- a/public/app/plugins/panel/annolist/module.tsx
+++ b/public/app/plugins/panel/annolist/module.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PanelModel, PanelPlugin } from '@grafana/data';
import { TagsInput } from '@grafana/ui';
diff --git a/public/app/plugins/panel/barchart/BarChartLegend.tsx b/public/app/plugins/panel/barchart/BarChartLegend.tsx
index a5230e096d0..dd13d2301ba 100644
--- a/public/app/plugins/panel/barchart/BarChartLegend.tsx
+++ b/public/app/plugins/panel/barchart/BarChartLegend.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import { memo } from 'react';
import { DataFrame, Field, getFieldSeriesColor } from '@grafana/data';
import { VizLegendOptions, AxisPlacement } from '@grafana/schema';
@@ -28,7 +28,7 @@ export function hasVisibleLegendSeries(config: UPlotConfigBuilder, data: DataFra
// });
}
-export const BarChartLegend = React.memo(
+export const BarChartLegend = memo(
({ data, placement, calcs, displayMode, colorField, ...vizLayoutLegendProps }: BarChartLegend2Props) => {
const theme = useTheme2();
diff --git a/public/app/plugins/panel/barchart/BarChartPanel.tsx b/public/app/plugins/panel/barchart/BarChartPanel.tsx
index 4088029f4f4..ec7296fcb73 100644
--- a/public/app/plugins/panel/barchart/BarChartPanel.tsx
+++ b/public/app/plugins/panel/barchart/BarChartPanel.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { PanelProps, VizOrientation } from '@grafana/data';
import { PanelDataErrorView } from '@grafana/runtime';
diff --git a/public/app/plugins/panel/barchart/TickSpacingEditor.tsx b/public/app/plugins/panel/barchart/TickSpacingEditor.tsx
index 8f30cb8ff40..123e058e956 100644
--- a/public/app/plugins/panel/barchart/TickSpacingEditor.tsx
+++ b/public/app/plugins/panel/barchart/TickSpacingEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SelectableValue, StandardEditorProps } from '@grafana/data';
import { Checkbox, HorizontalGroup, RadioButtonGroup, Tooltip } from '@grafana/ui';
diff --git a/public/app/plugins/panel/bargauge/BarGaugePanel.test.tsx b/public/app/plugins/panel/bargauge/BarGaugePanel.test.tsx
index af4c44203b3..35df060a347 100644
--- a/public/app/plugins/panel/bargauge/BarGaugePanel.test.tsx
+++ b/public/app/plugins/panel/bargauge/BarGaugePanel.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import { uniqueId } from 'lodash';
-import React from 'react';
import { dateMath, dateTime, EventBus, LoadingState, TimeRange, toDataFrame, VizOrientation } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/plugins/panel/bargauge/BarGaugePanel.tsx b/public/app/plugins/panel/bargauge/BarGaugePanel.tsx
index a76285a0799..035f9f9b69a 100644
--- a/public/app/plugins/panel/bargauge/BarGaugePanel.tsx
+++ b/public/app/plugins/panel/bargauge/BarGaugePanel.tsx
@@ -1,5 +1,5 @@
import { isNumber } from 'lodash';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import {
DisplayValueAlignmentFactors,
diff --git a/public/app/plugins/panel/candlestick/CandlestickPanel.tsx b/public/app/plugins/panel/candlestick/CandlestickPanel.tsx
index cd2f5de2387..319b127b227 100644
--- a/public/app/plugins/panel/candlestick/CandlestickPanel.tsx
+++ b/public/app/plugins/panel/candlestick/CandlestickPanel.tsx
@@ -1,7 +1,7 @@
// this file is pretty much a copy-paste of TimeSeriesPanel.tsx :(
// with some extra renderers passed to the component
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
import uPlot from 'uplot';
import { Field, getDisplayProcessor, PanelProps } from '@grafana/data';
diff --git a/public/app/plugins/panel/canvas/CanvasPanel.tsx b/public/app/plugins/panel/canvas/CanvasPanel.tsx
index 0a30af8d86c..cd48d2ed8dd 100644
--- a/public/app/plugins/panel/canvas/CanvasPanel.tsx
+++ b/public/app/plugins/panel/canvas/CanvasPanel.tsx
@@ -1,4 +1,5 @@
-import React, { Component } from 'react';
+import { Component } from 'react';
+import * as React from 'react';
import { ReplaySubject, Subscription } from 'rxjs';
import { PanelProps } from '@grafana/data';
diff --git a/public/app/plugins/panel/canvas/components/CanvasContextMenu.tsx b/public/app/plugins/panel/canvas/components/CanvasContextMenu.tsx
index b2b3d55833f..ea0dffe4c2a 100644
--- a/public/app/plugins/panel/canvas/components/CanvasContextMenu.tsx
+++ b/public/app/plugins/panel/canvas/components/CanvasContextMenu.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useCallback, useEffect, useState } from 'react';
+import { useCallback, useEffect, useState } from 'react';
+import * as React from 'react';
import { first } from 'rxjs/operators';
import { SelectableValue } from '@grafana/data';
diff --git a/public/app/plugins/panel/canvas/components/CanvasTooltip.tsx b/public/app/plugins/panel/canvas/components/CanvasTooltip.tsx
index 13cd8169daa..aba956850fd 100644
--- a/public/app/plugins/panel/canvas/components/CanvasTooltip.tsx
+++ b/public/app/plugins/panel/canvas/components/CanvasTooltip.tsx
@@ -1,7 +1,7 @@
import { css } from '@emotion/css';
import { useDialog } from '@react-aria/dialog';
import { useOverlay } from '@react-aria/overlays';
-import React, { createRef } from 'react';
+import { createRef } from 'react';
import { GrafanaTheme2, LinkModel } from '@grafana/data/src';
import { LinkButton, Portal, Stack, useStyles2, VizTooltipContainer } from '@grafana/ui';
diff --git a/public/app/plugins/panel/canvas/components/SetBackground.tsx b/public/app/plugins/panel/canvas/components/SetBackground.tsx
index 60284cfefee..7d33b53df2a 100644
--- a/public/app/plugins/panel/canvas/components/SetBackground.tsx
+++ b/public/app/plugins/panel/canvas/components/SetBackground.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { ResourceDimensionMode } from '@grafana/schema';
diff --git a/public/app/plugins/panel/canvas/components/connections/ConnectionAnchors.tsx b/public/app/plugins/panel/canvas/components/connections/ConnectionAnchors.tsx
index f8c0535e893..ddf67e154f0 100644
--- a/public/app/plugins/panel/canvas/components/connections/ConnectionAnchors.tsx
+++ b/public/app/plugins/panel/canvas/components/connections/ConnectionAnchors.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useRef } from 'react';
+import { useRef } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/panel/canvas/components/connections/ConnectionSVG.tsx b/public/app/plugins/panel/canvas/components/connections/ConnectionSVG.tsx
index e1c2dc37a00..ae0d934b73d 100644
--- a/public/app/plugins/panel/canvas/components/connections/ConnectionSVG.tsx
+++ b/public/app/plugins/panel/canvas/components/connections/ConnectionSVG.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useMemo, useRef, useState } from 'react';
+import { useEffect, useMemo, useRef, useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/panel/canvas/components/connections/Connections.tsx b/public/app/plugins/panel/canvas/components/connections/Connections.tsx
index f1ed0042875..d2e9a76fba9 100644
--- a/public/app/plugins/panel/canvas/components/connections/Connections.tsx
+++ b/public/app/plugins/panel/canvas/components/connections/Connections.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { BehaviorSubject } from 'rxjs';
import { config } from '@grafana/runtime';
diff --git a/public/app/plugins/panel/canvas/editor/LineStyleEditor.tsx b/public/app/plugins/panel/canvas/editor/LineStyleEditor.tsx
index 75af1e03fd5..53251621d57 100644
--- a/public/app/plugins/panel/canvas/editor/LineStyleEditor.tsx
+++ b/public/app/plugins/panel/canvas/editor/LineStyleEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { SelectableValue, StandardEditorProps } from '@grafana/data';
import { Field, RadioButtonGroup, Switch } from '@grafana/ui/src';
diff --git a/public/app/plugins/panel/canvas/editor/element/APIEditor.tsx b/public/app/plugins/panel/canvas/editor/element/APIEditor.tsx
index 537122ed659..2aaba7bf09f 100644
--- a/public/app/plugins/panel/canvas/editor/element/APIEditor.tsx
+++ b/public/app/plugins/panel/canvas/editor/element/APIEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import {
StandardEditorProps,
diff --git a/public/app/plugins/panel/canvas/editor/element/ButtonStyleEditor.tsx b/public/app/plugins/panel/canvas/editor/element/ButtonStyleEditor.tsx
index b3b345cf195..e2a7fe599ed 100644
--- a/public/app/plugins/panel/canvas/editor/element/ButtonStyleEditor.tsx
+++ b/public/app/plugins/panel/canvas/editor/element/ButtonStyleEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { SelectableValue, StandardEditorProps } from '@grafana/data';
import { ButtonVariant, InlineField, InlineFieldRow, Select } from '@grafana/ui';
diff --git a/public/app/plugins/panel/canvas/editor/element/ConstraintSelectionBox.tsx b/public/app/plugins/panel/canvas/editor/element/ConstraintSelectionBox.tsx
index 7a534bf7d53..3e124cae0be 100644
--- a/public/app/plugins/panel/canvas/editor/element/ConstraintSelectionBox.tsx
+++ b/public/app/plugins/panel/canvas/editor/element/ConstraintSelectionBox.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/panel/canvas/editor/element/ParamsEditor.tsx b/public/app/plugins/panel/canvas/editor/element/ParamsEditor.tsx
index 7d4bafd85b1..c23df5f2348 100644
--- a/public/app/plugins/panel/canvas/editor/element/ParamsEditor.tsx
+++ b/public/app/plugins/panel/canvas/editor/element/ParamsEditor.tsx
@@ -1,4 +1,5 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
+import * as React from 'react';
import { IconButton, Input, Stack } from '@grafana/ui';
diff --git a/public/app/plugins/panel/canvas/editor/element/PlacementEditor.tsx b/public/app/plugins/panel/canvas/editor/element/PlacementEditor.tsx
index 568eeb41fcf..51668f7c4bd 100644
--- a/public/app/plugins/panel/canvas/editor/element/PlacementEditor.tsx
+++ b/public/app/plugins/panel/canvas/editor/element/PlacementEditor.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { useObservable } from 'react-use';
import { Subject } from 'rxjs';
diff --git a/public/app/plugins/panel/canvas/editor/element/QuickPositioning.tsx b/public/app/plugins/panel/canvas/editor/element/QuickPositioning.tsx
index 52a14a1ef26..9333b64d60d 100644
--- a/public/app/plugins/panel/canvas/editor/element/QuickPositioning.tsx
+++ b/public/app/plugins/panel/canvas/editor/element/QuickPositioning.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data/src';
import { IconButton, useStyles2 } from '@grafana/ui/src';
diff --git a/public/app/plugins/panel/canvas/editor/inline/InlineEdit.tsx b/public/app/plugins/panel/canvas/editor/inline/InlineEdit.tsx
index 636d9403178..49ff4fe511b 100644
--- a/public/app/plugins/panel/canvas/editor/inline/InlineEdit.tsx
+++ b/public/app/plugins/panel/canvas/editor/inline/InlineEdit.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { SyntheticEvent, useEffect, useRef, useState } from 'react';
+import { SyntheticEvent, useEffect, useRef, useState } from 'react';
import Draggable, { DraggableEventHandler } from 'react-draggable';
import { Resizable, ResizeCallbackData } from 'react-resizable';
diff --git a/public/app/plugins/panel/canvas/editor/inline/InlineEditBody.tsx b/public/app/plugins/panel/canvas/editor/inline/InlineEditBody.tsx
index e45303e75dd..07f71b7b3d5 100644
--- a/public/app/plugins/panel/canvas/editor/inline/InlineEditBody.tsx
+++ b/public/app/plugins/panel/canvas/editor/inline/InlineEditBody.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { get as lodashGet } from 'lodash';
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
import { useObservable } from 'react-use';
import { DataFrame, GrafanaTheme2, PanelOptionsEditorBuilder, StandardEditorContext } from '@grafana/data';
diff --git a/public/app/plugins/panel/canvas/editor/inline/TabsEditor.tsx b/public/app/plugins/panel/canvas/editor/inline/TabsEditor.tsx
index 620646518b2..ce6b5da4932 100644
--- a/public/app/plugins/panel/canvas/editor/inline/TabsEditor.tsx
+++ b/public/app/plugins/panel/canvas/editor/inline/TabsEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { Tab, TabsBar } from '@grafana/ui/src';
diff --git a/public/app/plugins/panel/canvas/editor/layer/TreeNavigationEditor.tsx b/public/app/plugins/panel/canvas/editor/layer/TreeNavigationEditor.tsx
index 8f1a75617b8..b78c1ab9fe6 100644
--- a/public/app/plugins/panel/canvas/editor/layer/TreeNavigationEditor.tsx
+++ b/public/app/plugins/panel/canvas/editor/layer/TreeNavigationEditor.tsx
@@ -1,7 +1,7 @@
import { css } from '@emotion/css';
import { Global } from '@emotion/react';
import Tree, { TreeNodeProps } from 'rc-tree';
-import React, { Key, useEffect, useMemo, useState } from 'react';
+import { Key, useEffect, useMemo, useState } from 'react';
import { GrafanaTheme2, StandardEditorProps } from '@grafana/data';
import { config } from '@grafana/runtime';
diff --git a/public/app/plugins/panel/canvas/editor/layer/TreeNodeTitle.tsx b/public/app/plugins/panel/canvas/editor/layer/TreeNodeTitle.tsx
index dd983f1cfc0..4995f960fcc 100644
--- a/public/app/plugins/panel/canvas/editor/layer/TreeNodeTitle.tsx
+++ b/public/app/plugins/panel/canvas/editor/layer/TreeNodeTitle.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { IconButton, useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/panel/canvas/editor/panZoomHelp.tsx b/public/app/plugins/panel/canvas/editor/panZoomHelp.tsx
index e36131f12ce..a6e22d1d4e4 100644
--- a/public/app/plugins/panel/canvas/editor/panZoomHelp.tsx
+++ b/public/app/plugins/panel/canvas/editor/panZoomHelp.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { StandardEditorProps, GrafanaTheme2 } from '@grafana/data';
import { Alert, Icon, Stack, useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/panel/dashlist/DashList.tsx b/public/app/plugins/panel/dashlist/DashList.tsx
index 66db02bf561..ad97d09a57a 100644
--- a/public/app/plugins/panel/dashlist/DashList.tsx
+++ b/public/app/plugins/panel/dashlist/DashList.tsx
@@ -1,5 +1,6 @@
import { take } from 'lodash';
-import React, { useEffect, useMemo, useState } from 'react';
+import { useEffect, useMemo, useState } from 'react';
+import * as React from 'react';
import {
DataLinkBuiltInVars,
diff --git a/public/app/plugins/panel/dashlist/module.tsx b/public/app/plugins/panel/dashlist/module.tsx
index a7169752418..8cb3c286e16 100644
--- a/public/app/plugins/panel/dashlist/module.tsx
+++ b/public/app/plugins/panel/dashlist/module.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PanelPlugin } from '@grafana/data';
import { TagsInput } from '@grafana/ui';
import { FolderPicker } from 'app/core/components/Select/FolderPicker';
diff --git a/public/app/plugins/panel/datagrid/DataGridPanel.tsx b/public/app/plugins/panel/datagrid/DataGridPanel.tsx
index ebed01c9ab0..36153080e80 100644
--- a/public/app/plugins/panel/datagrid/DataGridPanel.tsx
+++ b/public/app/plugins/panel/datagrid/DataGridPanel.tsx
@@ -8,7 +8,7 @@ import DataEditor, {
Rectangle,
HeaderClickedEventArgs,
} from '@glideapps/glide-data-grid';
-import React, { useEffect, useReducer } from 'react';
+import { useEffect, useReducer } from 'react';
import { Field, PanelProps, FieldType, DataFrame } from '@grafana/data';
import { PanelDataErrorView, reportInteraction } from '@grafana/runtime';
diff --git a/public/app/plugins/panel/datagrid/components/AddColumn.tsx b/public/app/plugins/panel/datagrid/components/AddColumn.tsx
index 215b902cbb1..96353fc430e 100644
--- a/public/app/plugins/panel/datagrid/components/AddColumn.tsx
+++ b/public/app/plugins/panel/datagrid/components/AddColumn.tsx
@@ -1,4 +1,5 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
+import * as React from 'react';
import { SimpleInput } from './SimpleInput';
diff --git a/public/app/plugins/panel/datagrid/components/DatagridContextMenu.tsx b/public/app/plugins/panel/datagrid/components/DatagridContextMenu.tsx
index 3dfcdc30bb8..f750c71d4a7 100644
--- a/public/app/plugins/panel/datagrid/components/DatagridContextMenu.tsx
+++ b/public/app/plugins/panel/datagrid/components/DatagridContextMenu.tsx
@@ -1,6 +1,6 @@
import { GridSelection } from '@glideapps/glide-data-grid';
import { capitalize } from 'lodash';
-import React from 'react';
+import * as React from 'react';
import { DataFrame, FieldType } from '@grafana/data';
import { convertFieldType } from '@grafana/data/src/transformations/transformers/convertFieldType';
diff --git a/public/app/plugins/panel/datagrid/components/RenameColumnCell.tsx b/public/app/plugins/panel/datagrid/components/RenameColumnCell.tsx
index 27ea203ee0f..9b2c046fb63 100644
--- a/public/app/plugins/panel/datagrid/components/RenameColumnCell.tsx
+++ b/public/app/plugins/panel/datagrid/components/RenameColumnCell.tsx
@@ -1,4 +1,5 @@
-import React, { useLayoutEffect, useRef, useState } from 'react';
+import { useLayoutEffect, useRef, useState } from 'react';
+import * as React from 'react';
import { Portal } from '@grafana/ui';
diff --git a/public/app/plugins/panel/datagrid/components/SimpleInput.tsx b/public/app/plugins/panel/datagrid/components/SimpleInput.tsx
index 8d8e4e77a7d..c8094556965 100644
--- a/public/app/plugins/panel/datagrid/components/SimpleInput.tsx
+++ b/public/app/plugins/panel/datagrid/components/SimpleInput.tsx
@@ -1,4 +1,5 @@
-import React, { useRef, useEffect } from 'react';
+import { useRef, useEffect } from 'react';
+import * as React from 'react';
interface InputProps {
onBlur: (e: React.FocusEvent) => void;
diff --git a/public/app/plugins/panel/debug/CursorView.tsx b/public/app/plugins/panel/debug/CursorView.tsx
index 3b8dac26732..92e2c429d3a 100644
--- a/public/app/plugins/panel/debug/CursorView.tsx
+++ b/public/app/plugins/panel/debug/CursorView.tsx
@@ -1,4 +1,4 @@
-import React, { Component } from 'react';
+import { Component } from 'react';
import { Subscription } from 'rxjs';
import {
diff --git a/public/app/plugins/panel/debug/DebugPanel.tsx b/public/app/plugins/panel/debug/DebugPanel.tsx
index de966b146ab..9efe9f6211b 100644
--- a/public/app/plugins/panel/debug/DebugPanel.tsx
+++ b/public/app/plugins/panel/debug/DebugPanel.tsx
@@ -1,4 +1,4 @@
-import React, { Component } from 'react';
+import { Component } from 'react';
import { PanelProps } from '@grafana/data';
diff --git a/public/app/plugins/panel/debug/EventBusLogger.tsx b/public/app/plugins/panel/debug/EventBusLogger.tsx
index 32bedcf6bd9..60db004e48a 100644
--- a/public/app/plugins/panel/debug/EventBusLogger.tsx
+++ b/public/app/plugins/panel/debug/EventBusLogger.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { PartialObserver, Unsubscribable } from 'rxjs';
import {
diff --git a/public/app/plugins/panel/debug/RenderInfoViewer.tsx b/public/app/plugins/panel/debug/RenderInfoViewer.tsx
index a18fe4231f8..663a7dd7c98 100644
--- a/public/app/plugins/panel/debug/RenderInfoViewer.tsx
+++ b/public/app/plugins/panel/debug/RenderInfoViewer.tsx
@@ -1,4 +1,4 @@
-import React, { Component } from 'react';
+import { Component } from 'react';
import {
compareArrayValues,
diff --git a/public/app/plugins/panel/debug/StateView.tsx b/public/app/plugins/panel/debug/StateView.tsx
index 2dc4529c029..1b7309d00fe 100644
--- a/public/app/plugins/panel/debug/StateView.tsx
+++ b/public/app/plugins/panel/debug/StateView.tsx
@@ -1,4 +1,4 @@
-import React, { FormEvent } from 'react';
+import { FormEvent } from 'react';
import { PanelOptionsEditorProps, PanelProps } from '@grafana/data';
import { Field, Input, usePanelContext } from '@grafana/ui';
diff --git a/public/app/plugins/panel/flamegraph/FlameGraphPanel.tsx b/public/app/plugins/panel/flamegraph/FlameGraphPanel.tsx
index a284ee92d82..de45d52375f 100644
--- a/public/app/plugins/panel/flamegraph/FlameGraphPanel.tsx
+++ b/public/app/plugins/panel/flamegraph/FlameGraphPanel.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { CoreApp, PanelProps } from '@grafana/data';
import { FlameGraph, checkFields, getMessageCheckFieldsResult } from '@grafana/flamegraph';
import { PanelDataErrorView, reportInteraction, config } from '@grafana/runtime';
diff --git a/public/app/plugins/panel/gauge/GaugePanel.tsx b/public/app/plugins/panel/gauge/GaugePanel.tsx
index 7b798f63402..cb64ba49844 100644
--- a/public/app/plugins/panel/gauge/GaugePanel.tsx
+++ b/public/app/plugins/panel/gauge/GaugePanel.tsx
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { FieldDisplay, getDisplayProcessor, getFieldDisplayValues, PanelProps } from '@grafana/data';
import { BarGaugeSizing, VizOrientation } from '@grafana/schema';
diff --git a/public/app/plugins/panel/geomap/GeomapOverlay.tsx b/public/app/plugins/panel/geomap/GeomapOverlay.tsx
index d7135e00682..c0cf49e1745 100644
--- a/public/app/plugins/panel/geomap/GeomapOverlay.tsx
+++ b/public/app/plugins/panel/geomap/GeomapOverlay.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { CSSProperties } from 'react';
+import { CSSProperties } from 'react';
+import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/panel/geomap/GeomapPanel.tsx b/public/app/plugins/panel/geomap/GeomapPanel.tsx
index a7729d8a754..bbbb0eb3510 100644
--- a/public/app/plugins/panel/geomap/GeomapPanel.tsx
+++ b/public/app/plugins/panel/geomap/GeomapPanel.tsx
@@ -8,7 +8,8 @@ import { Coordinate } from 'ol/coordinate';
import { isEmpty } from 'ol/extent';
import MouseWheelZoom from 'ol/interaction/MouseWheelZoom';
import { fromLonLat } from 'ol/proj';
-import React, { Component, ReactNode } from 'react';
+import { Component, ReactNode } from 'react';
+import * as React from 'react';
import { Subscription } from 'rxjs';
import { DataHoverEvent, PanelData, PanelProps } from '@grafana/data';
diff --git a/public/app/plugins/panel/geomap/GeomapTooltip.tsx b/public/app/plugins/panel/geomap/GeomapTooltip.tsx
index a3ee8782b95..6c5991b8727 100644
--- a/public/app/plugins/panel/geomap/GeomapTooltip.tsx
+++ b/public/app/plugins/panel/geomap/GeomapTooltip.tsx
@@ -1,6 +1,6 @@
import { useDialog } from '@react-aria/dialog';
import { useOverlay } from '@react-aria/overlays';
-import React, { createRef } from 'react';
+import { createRef } from 'react';
import { Portal, VizTooltipContainer } from '@grafana/ui';
import { ComplexDataHoverView } from 'app/features/visualization/data-hover/ComplexDataHoverView';
diff --git a/public/app/plugins/panel/geomap/components/DebugOverlay.tsx b/public/app/plugins/panel/geomap/components/DebugOverlay.tsx
index c30b7a66832..8122f87680e 100644
--- a/public/app/plugins/panel/geomap/components/DebugOverlay.tsx
+++ b/public/app/plugins/panel/geomap/components/DebugOverlay.tsx
@@ -2,7 +2,7 @@ import { css } from '@emotion/css';
import { Map } from 'ol';
import { Coordinate } from 'ol/coordinate';
import { transform } from 'ol/proj';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import tinycolor from 'tinycolor2';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/plugins/panel/geomap/components/MarkersLegend.tsx b/public/app/plugins/panel/geomap/components/MarkersLegend.tsx
index a322627b7fb..2d6cdabfc5d 100644
--- a/public/app/plugins/panel/geomap/components/MarkersLegend.tsx
+++ b/public/app/plugins/panel/geomap/components/MarkersLegend.tsx
@@ -1,6 +1,6 @@
import { css, cx } from '@emotion/css';
import BaseLayer from 'ol/layer/Base';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { useObservable } from 'react-use';
import { of } from 'rxjs';
diff --git a/public/app/plugins/panel/geomap/components/MeasureOverlay.tsx b/public/app/plugins/panel/geomap/components/MeasureOverlay.tsx
index 600b813e8a7..2502a4786ef 100644
--- a/public/app/plugins/panel/geomap/components/MeasureOverlay.tsx
+++ b/public/app/plugins/panel/geomap/components/MeasureOverlay.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import Map from 'ol/Map';
-import React, { useMemo, useRef, useState } from 'react';
+import { useMemo, useRef, useState } from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { Button, IconButton, RadioButtonGroup, Select } from '@grafana/ui';
diff --git a/public/app/plugins/panel/geomap/components/ObservablePropsWrapper.tsx b/public/app/plugins/panel/geomap/components/ObservablePropsWrapper.tsx
index 9d34e202c05..7b110841872 100644
--- a/public/app/plugins/panel/geomap/components/ObservablePropsWrapper.tsx
+++ b/public/app/plugins/panel/geomap/components/ObservablePropsWrapper.tsx
@@ -1,4 +1,5 @@
-import React, { Component } from 'react';
+import { Component } from 'react';
+import * as React from 'react';
import { Observable, Unsubscribable } from 'rxjs';
interface Props {
diff --git a/public/app/plugins/panel/geomap/editor/CoordinatesMapViewEditor.tsx b/public/app/plugins/panel/geomap/editor/CoordinatesMapViewEditor.tsx
index ea83b7f72a1..0774d472a9f 100644
--- a/public/app/plugins/panel/geomap/editor/CoordinatesMapViewEditor.tsx
+++ b/public/app/plugins/panel/geomap/editor/CoordinatesMapViewEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { InlineFieldRow, InlineField } from '@grafana/ui';
import { NumberInput } from 'app/core/components/OptionsUI/NumberInput';
diff --git a/public/app/plugins/panel/geomap/editor/FitMapViewEditor.tsx b/public/app/plugins/panel/geomap/editor/FitMapViewEditor.tsx
index a88529a45ea..51817507c8a 100644
--- a/public/app/plugins/panel/geomap/editor/FitMapViewEditor.tsx
+++ b/public/app/plugins/panel/geomap/editor/FitMapViewEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useMemo } from 'react';
+import { useCallback, useMemo } from 'react';
import { SelectableValue, StandardEditorContext } from '@grafana/data';
import { InlineFieldRow, InlineField, RadioButtonGroup, Select } from '@grafana/ui';
diff --git a/public/app/plugins/panel/geomap/editor/FrameSelectionEditor.tsx b/public/app/plugins/panel/geomap/editor/FrameSelectionEditor.tsx
index 8f19c7f2f03..88eabf2ed1b 100644
--- a/public/app/plugins/panel/geomap/editor/FrameSelectionEditor.tsx
+++ b/public/app/plugins/panel/geomap/editor/FrameSelectionEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { FrameMatcherID, MatcherConfig, StandardEditorProps } from '@grafana/data';
import { RefIDPicker } from '@grafana/ui/src/components/MatchersUI/FieldsByFrameRefIdMatcher';
diff --git a/public/app/plugins/panel/geomap/editor/GeomapStyleRulesEditor.tsx b/public/app/plugins/panel/geomap/editor/GeomapStyleRulesEditor.tsx
index 3d3e32e6430..336077d8b47 100644
--- a/public/app/plugins/panel/geomap/editor/GeomapStyleRulesEditor.tsx
+++ b/public/app/plugins/panel/geomap/editor/GeomapStyleRulesEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { StandardEditorProps, StandardEditorsRegistryItem } from '@grafana/data';
import { Button, useTheme2 } from '@grafana/ui';
diff --git a/public/app/plugins/panel/geomap/editor/LayersEditor.tsx b/public/app/plugins/panel/geomap/editor/LayersEditor.tsx
index 63753e24d76..9a1c0f48504 100644
--- a/public/app/plugins/panel/geomap/editor/LayersEditor.tsx
+++ b/public/app/plugins/panel/geomap/editor/LayersEditor.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { DropResult } from 'react-beautiful-dnd';
import { StandardEditorProps } from '@grafana/data';
diff --git a/public/app/plugins/panel/geomap/editor/MapViewEditor.tsx b/public/app/plugins/panel/geomap/editor/MapViewEditor.tsx
index fa45d02e69c..52d5140c304 100644
--- a/public/app/plugins/panel/geomap/editor/MapViewEditor.tsx
+++ b/public/app/plugins/panel/geomap/editor/MapViewEditor.tsx
@@ -1,5 +1,5 @@
import { toLonLat } from 'ol/proj';
-import React, { useMemo, useCallback } from 'react';
+import { useMemo, useCallback } from 'react';
import { StandardEditorProps, SelectableValue } from '@grafana/data';
import { Button, InlineField, InlineFieldRow, Select, VerticalGroup } from '@grafana/ui';
diff --git a/public/app/plugins/panel/geomap/editor/StyleEditor.tsx b/public/app/plugins/panel/geomap/editor/StyleEditor.tsx
index e11b5d895e6..5ac29dfe977 100644
--- a/public/app/plugins/panel/geomap/editor/StyleEditor.tsx
+++ b/public/app/plugins/panel/geomap/editor/StyleEditor.tsx
@@ -1,5 +1,5 @@
import { capitalize } from 'lodash';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { useObservable } from 'react-use';
import { Observable, of } from 'rxjs';
diff --git a/public/app/plugins/panel/geomap/editor/StyleRuleEditor.tsx b/public/app/plugins/panel/geomap/editor/StyleRuleEditor.tsx
index 728c20295fe..840a91413fc 100644
--- a/public/app/plugins/panel/geomap/editor/StyleRuleEditor.tsx
+++ b/public/app/plugins/panel/geomap/editor/StyleRuleEditor.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { FeatureLike } from 'ol/Feature';
-import React, { useCallback, useMemo } from 'react';
+import { useCallback, useMemo } from 'react';
import { useObservable } from 'react-use';
import { Observable } from 'rxjs';
diff --git a/public/app/plugins/panel/geomap/layers/data/markersLayer.tsx b/public/app/plugins/panel/geomap/layers/data/markersLayer.tsx
index 90581083596..9e4ef519d24 100644
--- a/public/app/plugins/panel/geomap/layers/data/markersLayer.tsx
+++ b/public/app/plugins/panel/geomap/layers/data/markersLayer.tsx
@@ -2,7 +2,7 @@ import { isNumber } from 'lodash';
import { FeatureLike } from 'ol/Feature';
import Map from 'ol/Map';
import VectorImage from 'ol/layer/VectorImage';
-import React, { ReactNode } from 'react';
+import { ReactNode } from 'react';
import { ReplaySubject } from 'rxjs';
import {
diff --git a/public/app/plugins/panel/geomap/layers/data/networkLayer.tsx b/public/app/plugins/panel/geomap/layers/data/networkLayer.tsx
index 1ec70a41b70..733c938fd95 100644
--- a/public/app/plugins/panel/geomap/layers/data/networkLayer.tsx
+++ b/public/app/plugins/panel/geomap/layers/data/networkLayer.tsx
@@ -6,7 +6,7 @@ import { Geometry, LineString, Point, SimpleGeometry } from 'ol/geom';
import VectorImage from 'ol/layer/VectorImage';
import { Fill, Stroke, Style, Text } from 'ol/style';
import FlowLine from 'ol-ext/style/FlowLine';
-import React, { ReactNode } from 'react';
+import { ReactNode } from 'react';
import { ReplaySubject } from 'rxjs';
import tinycolor from 'tinycolor2';
diff --git a/public/app/plugins/panel/geomap/module.tsx b/public/app/plugins/panel/geomap/module.tsx
index b2a37446b46..993fda575ba 100644
--- a/public/app/plugins/panel/geomap/module.tsx
+++ b/public/app/plugins/panel/geomap/module.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { PanelPlugin } from '@grafana/data';
import { config } from '@grafana/runtime';
import { commonOptionsBuilder } from '@grafana/ui';
diff --git a/public/app/plugins/panel/geomap/utils/uiUtils.tsx b/public/app/plugins/panel/geomap/utils/uiUtils.tsx
index 97b9e965b64..ad0a86abe62 100644
--- a/public/app/plugins/panel/geomap/utils/uiUtils.tsx
+++ b/public/app/plugins/panel/geomap/utils/uiUtils.tsx
@@ -1,5 +1,5 @@
import { cx } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { isUrl } from './utils';
diff --git a/public/app/plugins/panel/gettingstarted/GettingStarted.tsx b/public/app/plugins/panel/gettingstarted/GettingStarted.tsx
index 88e16179335..33c27cc9e77 100644
--- a/public/app/plugins/panel/gettingstarted/GettingStarted.tsx
+++ b/public/app/plugins/panel/gettingstarted/GettingStarted.tsx
@@ -1,6 +1,6 @@
// Libraries
import { css, cx } from '@emotion/css';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { PanelProps } from '@grafana/data';
import { config, reportInteraction } from '@grafana/runtime';
diff --git a/public/app/plugins/panel/gettingstarted/components/DocsCard.tsx b/public/app/plugins/panel/gettingstarted/components/DocsCard.tsx
index 39871c408e7..ac35ab82388 100644
--- a/public/app/plugins/panel/gettingstarted/components/DocsCard.tsx
+++ b/public/app/plugins/panel/gettingstarted/components/DocsCard.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime';
diff --git a/public/app/plugins/panel/gettingstarted/components/Step.tsx b/public/app/plugins/panel/gettingstarted/components/Step.tsx
index e76a73e36fa..e796fbb0b93 100644
--- a/public/app/plugins/panel/gettingstarted/components/Step.tsx
+++ b/public/app/plugins/panel/gettingstarted/components/Step.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/panel/gettingstarted/components/TutorialCard.tsx b/public/app/plugins/panel/gettingstarted/components/TutorialCard.tsx
index 029f8844a64..f55a7aa4bc4 100644
--- a/public/app/plugins/panel/gettingstarted/components/TutorialCard.tsx
+++ b/public/app/plugins/panel/gettingstarted/components/TutorialCard.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { MouseEvent } from 'react';
+import { MouseEvent } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime';
diff --git a/public/app/plugins/panel/graph/Legend/Legend.tsx b/public/app/plugins/panel/graph/Legend/Legend.tsx
index 984d2af5b8b..6c527552eb6 100644
--- a/public/app/plugins/panel/graph/Legend/Legend.tsx
+++ b/public/app/plugins/panel/graph/Legend/Legend.tsx
@@ -1,5 +1,6 @@
import { sortBy as _sortBy } from 'lodash';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
+import * as React from 'react';
import { CustomScrollbar, Icon } from '@grafana/ui';
import { TimeSeries } from 'app/core/core';
diff --git a/public/app/plugins/panel/graph/Legend/LegendSeriesItem.tsx b/public/app/plugins/panel/graph/Legend/LegendSeriesItem.tsx
index 62a597d4515..6d568168f2c 100644
--- a/public/app/plugins/panel/graph/Legend/LegendSeriesItem.tsx
+++ b/public/app/plugins/panel/graph/Legend/LegendSeriesItem.tsx
@@ -1,5 +1,5 @@
import classNames from 'classnames';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { selectors } from '@grafana/e2e-selectors';
import { SeriesColorPicker, SeriesIcon } from '@grafana/ui';
diff --git a/public/app/plugins/panel/graph/graph.ts b/public/app/plugins/panel/graph/graph.ts
index ec4d93dfe5c..5ebc2fe8c52 100644
--- a/public/app/plugins/panel/graph/graph.ts
+++ b/public/app/plugins/panel/graph/graph.ts
@@ -10,7 +10,7 @@ import './jquery.flot.events';
import $ from 'jquery';
import { clone, find, flatten, isUndefined, map, max as _max, min as _min, sortBy as _sortBy, toNumber } from 'lodash';
-import React from 'react';
+import { createElement } from 'react';
import { createRoot, Root } from 'react-dom/client';
import {
@@ -162,7 +162,7 @@ class GraphElement {
renderCallback: this.renderPanel.bind(this),
};
- const legendReactElem = React.createElement(LegendWithThemeProvider, legendProps);
+ const legendReactElem = createElement(LegendWithThemeProvider, legendProps);
// render callback isn't supported in react 18+, see: https://github.com/reactwg/react-18/discussions/5
this.legendElemRoot.render(legendReactElem);
diff --git a/public/app/plugins/panel/heatmap/ExemplarModalHeader.tsx b/public/app/plugins/panel/heatmap/ExemplarModalHeader.tsx
index e2110122ab3..4d66229d940 100644
--- a/public/app/plugins/panel/heatmap/ExemplarModalHeader.tsx
+++ b/public/app/plugins/panel/heatmap/ExemplarModalHeader.tsx
@@ -1,4 +1,5 @@
-import React, { CSSProperties } from 'react';
+import { CSSProperties } from 'react';
+import * as React from 'react';
import { CloseButton } from 'app/core/components/CloseButton/CloseButton';
diff --git a/public/app/plugins/panel/heatmap/HeatmapPanel.tsx b/public/app/plugins/panel/heatmap/HeatmapPanel.tsx
index b7ce5ab2be9..a3a9896b251 100644
--- a/public/app/plugins/panel/heatmap/HeatmapPanel.tsx
+++ b/public/app/plugins/panel/heatmap/HeatmapPanel.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo, useRef, useState } from 'react';
+import { useMemo, useRef, useState } from 'react';
import { DashboardCursorSync, PanelProps, TimeRange } from '@grafana/data';
import { PanelDataErrorView } from '@grafana/runtime';
diff --git a/public/app/plugins/panel/heatmap/HeatmapTooltip.tsx b/public/app/plugins/panel/heatmap/HeatmapTooltip.tsx
index 63cd3374997..ebb3a860587 100644
--- a/public/app/plugins/panel/heatmap/HeatmapTooltip.tsx
+++ b/public/app/plugins/panel/heatmap/HeatmapTooltip.tsx
@@ -1,4 +1,5 @@
-import React, { ReactElement, useEffect, useRef, useState, ReactNode } from 'react';
+import { ReactElement, useEffect, useRef, useState, ReactNode } from 'react';
+import * as React from 'react';
import uPlot from 'uplot';
import {
diff --git a/public/app/plugins/panel/heatmap/module.tsx b/public/app/plugins/panel/heatmap/module.tsx
index 660e71e7261..f01bc07e514 100644
--- a/public/app/plugins/panel/heatmap/module.tsx
+++ b/public/app/plugins/panel/heatmap/module.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { FieldConfigProperty, FieldType, identityOverrideProcessor, PanelPlugin } from '@grafana/data';
import { config } from '@grafana/runtime';
import {
diff --git a/public/app/plugins/panel/histogram/Histogram.tsx b/public/app/plugins/panel/histogram/Histogram.tsx
index 517069b2d94..794fb6a7212 100644
--- a/public/app/plugins/panel/histogram/Histogram.tsx
+++ b/public/app/plugins/panel/histogram/Histogram.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import uPlot, { AlignedData } from 'uplot';
import {
diff --git a/public/app/plugins/panel/histogram/HistogramPanel.tsx b/public/app/plugins/panel/histogram/HistogramPanel.tsx
index d0355b5524b..9786531c552 100644
--- a/public/app/plugins/panel/histogram/HistogramPanel.tsx
+++ b/public/app/plugins/panel/histogram/HistogramPanel.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { PanelProps, buildHistogram, getHistogramFields } from '@grafana/data';
import { histogramFieldsToFrame } from '@grafana/data/src/transformations/transformers/histogram';
diff --git a/public/app/plugins/panel/histogram/HistogramTooltip.tsx b/public/app/plugins/panel/histogram/HistogramTooltip.tsx
index e61b243d395..0a8f5979cc6 100644
--- a/public/app/plugins/panel/histogram/HistogramTooltip.tsx
+++ b/public/app/plugins/panel/histogram/HistogramTooltip.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { ReactNode, useMemo } from 'react';
+import { ReactNode, useMemo } from 'react';
import { DataFrame, formattedValueToString } from '@grafana/data';
import { SortOrder, TooltipDisplayMode } from '@grafana/schema/dist/esm/common/common.gen';
diff --git a/public/app/plugins/panel/live/LiveChannelEditor.tsx b/public/app/plugins/panel/live/LiveChannelEditor.tsx
index 1252d48debd..08bb3d63766 100644
--- a/public/app/plugins/panel/live/LiveChannelEditor.tsx
+++ b/public/app/plugins/panel/live/LiveChannelEditor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useEffect, useMemo, useState } from 'react';
+import { useEffect, useMemo, useState } from 'react';
import {
LiveChannelScope,
diff --git a/public/app/plugins/panel/live/LivePanel.tsx b/public/app/plugins/panel/live/LivePanel.tsx
index 7bb237d0a11..c2f2a54b6d9 100644
--- a/public/app/plugins/panel/live/LivePanel.tsx
+++ b/public/app/plugins/panel/live/LivePanel.tsx
@@ -1,6 +1,6 @@
import { css, cx } from '@emotion/css';
import { isEqual } from 'lodash';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import { Unsubscribable, PartialObserver } from 'rxjs';
import {
diff --git a/public/app/plugins/panel/live/LivePublish.tsx b/public/app/plugins/panel/live/LivePublish.tsx
index 6d7e8b148ff..dcc3073843e 100644
--- a/public/app/plugins/panel/live/LivePublish.tsx
+++ b/public/app/plugins/panel/live/LivePublish.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { LiveChannelAddress, isValidLiveChannelAddress } from '@grafana/data';
import { getBackendSrv, getGrafanaLiveSrv } from '@grafana/runtime';
diff --git a/public/app/plugins/panel/logs/LogsPanel.test.tsx b/public/app/plugins/panel/logs/LogsPanel.test.tsx
index 7cb4124fe43..88e875ae0ed 100644
--- a/public/app/plugins/panel/logs/LogsPanel.test.tsx
+++ b/public/app/plugins/panel/logs/LogsPanel.test.tsx
@@ -1,6 +1,6 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { ComponentProps } from 'react';
+import { ComponentProps } from 'react';
import { DatasourceSrvMock, MockDataSourceApi } from 'test/mocks/datasource_srv';
import {
diff --git a/public/app/plugins/panel/logs/LogsPanel.tsx b/public/app/plugins/panel/logs/LogsPanel.tsx
index d2cefdae7ce..a03c2719210 100644
--- a/public/app/plugins/panel/logs/LogsPanel.tsx
+++ b/public/app/plugins/panel/logs/LogsPanel.tsx
@@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
-import React, { useCallback, useLayoutEffect, useMemo, useRef, useState } from 'react';
+import { useCallback, useLayoutEffect, useMemo, useRef, useState } from 'react';
+import * as React from 'react';
import {
CoreApp,
diff --git a/public/app/plugins/panel/news/NewsPanel.tsx b/public/app/plugins/panel/news/NewsPanel.tsx
index 127db56465c..68599b2cead 100644
--- a/public/app/plugins/panel/news/NewsPanel.tsx
+++ b/public/app/plugins/panel/news/NewsPanel.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect } from 'react';
+import { useEffect } from 'react';
import { PanelProps } from '@grafana/data';
import { RefreshEvent } from '@grafana/runtime';
diff --git a/public/app/plugins/panel/news/component/News.tsx b/public/app/plugins/panel/news/component/News.tsx
index c47f1d1ade7..09cce50f314 100644
--- a/public/app/plugins/panel/news/component/News.tsx
+++ b/public/app/plugins/panel/news/component/News.tsx
@@ -1,5 +1,4 @@
import { css, cx } from '@emotion/css';
-import React from 'react';
import Skeleton from 'react-loading-skeleton';
import { DataFrameView, GrafanaTheme2, textUtil, dateTimeFormat } from '@grafana/data';
diff --git a/public/app/plugins/panel/nodeGraph/Edge.tsx b/public/app/plugins/panel/nodeGraph/Edge.tsx
index f7ecf818e86..405d07f1a9e 100644
--- a/public/app/plugins/panel/nodeGraph/Edge.tsx
+++ b/public/app/plugins/panel/nodeGraph/Edge.tsx
@@ -1,4 +1,4 @@
-import React, { MouseEvent, memo } from 'react';
+import { MouseEvent, memo } from 'react';
import { EdgeArrowMarker } from './EdgeArrowMarker';
import { computeNodeCircumferenceStrokeWidth, nodeR } from './Node';
diff --git a/public/app/plugins/panel/nodeGraph/EdgeArrowMarker.tsx b/public/app/plugins/panel/nodeGraph/EdgeArrowMarker.tsx
index ac53e42a78b..67e07935e9c 100644
--- a/public/app/plugins/panel/nodeGraph/EdgeArrowMarker.tsx
+++ b/public/app/plugins/panel/nodeGraph/EdgeArrowMarker.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { defaultEdgeColor } from './Edge';
/**
diff --git a/public/app/plugins/panel/nodeGraph/EdgeLabel.tsx b/public/app/plugins/panel/nodeGraph/EdgeLabel.tsx
index 3c2bb5fc381..e2f29d8689e 100644
--- a/public/app/plugins/panel/nodeGraph/EdgeLabel.tsx
+++ b/public/app/plugins/panel/nodeGraph/EdgeLabel.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { memo } from 'react';
+import { memo } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/panel/nodeGraph/Legend.test.tsx b/public/app/plugins/panel/nodeGraph/Legend.test.tsx
index d0e3e6699ed..3fc1a1c0513 100644
--- a/public/app/plugins/panel/nodeGraph/Legend.test.tsx
+++ b/public/app/plugins/panel/nodeGraph/Legend.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { FieldColorModeId } from '@grafana/data';
diff --git a/public/app/plugins/panel/nodeGraph/Legend.tsx b/public/app/plugins/panel/nodeGraph/Legend.tsx
index 75984b1c102..a899a0fb383 100644
--- a/public/app/plugins/panel/nodeGraph/Legend.tsx
+++ b/public/app/plugins/panel/nodeGraph/Legend.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { Field, FieldColorModeId, GrafanaTheme2 } from '@grafana/data';
import { LegendDisplayMode } from '@grafana/schema';
diff --git a/public/app/plugins/panel/nodeGraph/Marker.tsx b/public/app/plugins/panel/nodeGraph/Marker.tsx
index 2a427b43eea..c08967bb6a9 100644
--- a/public/app/plugins/panel/nodeGraph/Marker.tsx
+++ b/public/app/plugins/panel/nodeGraph/Marker.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { MouseEvent, memo } from 'react';
+import { MouseEvent, memo } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/panel/nodeGraph/Node.test.tsx b/public/app/plugins/panel/nodeGraph/Node.test.tsx
index c6fe4e91750..a73f0b8334e 100644
--- a/public/app/plugins/panel/nodeGraph/Node.test.tsx
+++ b/public/app/plugins/panel/nodeGraph/Node.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { FieldType } from '@grafana/data/src';
diff --git a/public/app/plugins/panel/nodeGraph/Node.tsx b/public/app/plugins/panel/nodeGraph/Node.tsx
index f87da31b7ac..42c6bd6485a 100644
--- a/public/app/plugins/panel/nodeGraph/Node.tsx
+++ b/public/app/plugins/panel/nodeGraph/Node.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import cx from 'classnames';
-import React, { MouseEvent, memo } from 'react';
+import { MouseEvent, memo } from 'react';
import tinycolor from 'tinycolor2';
import { Field, getFieldColorModeForField, GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/plugins/panel/nodeGraph/NodeGraph.test.tsx b/public/app/plugins/panel/nodeGraph/NodeGraph.test.tsx
index 6b1f3939bc0..4acfcb9edb4 100644
--- a/public/app/plugins/panel/nodeGraph/NodeGraph.test.tsx
+++ b/public/app/plugins/panel/nodeGraph/NodeGraph.test.tsx
@@ -1,6 +1,5 @@
import { render, screen, fireEvent, waitFor, getByText } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React from 'react';
import { NodeGraph } from './NodeGraph';
import { makeEdgesDataFrame, makeNodesDataFrame } from './utils';
diff --git a/public/app/plugins/panel/nodeGraph/NodeGraph.tsx b/public/app/plugins/panel/nodeGraph/NodeGraph.tsx
index e9fe37dda65..b2fca164129 100644
--- a/public/app/plugins/panel/nodeGraph/NodeGraph.tsx
+++ b/public/app/plugins/panel/nodeGraph/NodeGraph.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import cx from 'classnames';
-import React, { memo, MouseEvent, useCallback, useEffect, useMemo, useState } from 'react';
+import { memo, MouseEvent, useCallback, useEffect, useMemo, useState } from 'react';
import useMeasure from 'react-use/lib/useMeasure';
import { DataFrame, GrafanaTheme2, LinkModel } from '@grafana/data';
diff --git a/public/app/plugins/panel/nodeGraph/NodeGraphPanel.tsx b/public/app/plugins/panel/nodeGraph/NodeGraphPanel.tsx
index feb7e18e160..9ee64616c17 100644
--- a/public/app/plugins/panel/nodeGraph/NodeGraphPanel.tsx
+++ b/public/app/plugins/panel/nodeGraph/NodeGraphPanel.tsx
@@ -1,5 +1,5 @@
import memoizeOne from 'memoize-one';
-import React, { useId } from 'react';
+import { useId } from 'react';
import { PanelProps } from '@grafana/data';
diff --git a/public/app/plugins/panel/nodeGraph/ViewControls.tsx b/public/app/plugins/panel/nodeGraph/ViewControls.tsx
index a6f7f435999..b80b09af624 100644
--- a/public/app/plugins/panel/nodeGraph/ViewControls.tsx
+++ b/public/app/plugins/panel/nodeGraph/ViewControls.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { Button, HorizontalGroup, useStyles2, VerticalGroup } from '@grafana/ui';
diff --git a/public/app/plugins/panel/nodeGraph/editor/ArcOptionsEditor.tsx b/public/app/plugins/panel/nodeGraph/editor/ArcOptionsEditor.tsx
index 1e4427cc398..e13773bdf9b 100644
--- a/public/app/plugins/panel/nodeGraph/editor/ArcOptionsEditor.tsx
+++ b/public/app/plugins/panel/nodeGraph/editor/ArcOptionsEditor.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { Field, StandardEditorProps } from '@grafana/data';
import { Button, ColorPicker, useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/panel/nodeGraph/useContextMenu.tsx b/public/app/plugins/panel/nodeGraph/useContextMenu.tsx
index 31ec9c96d67..2aeb57981aa 100644
--- a/public/app/plugins/panel/nodeGraph/useContextMenu.tsx
+++ b/public/app/plugins/panel/nodeGraph/useContextMenu.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { MouseEvent, useCallback, useState } from 'react';
+import { MouseEvent, useCallback, useState } from 'react';
+import * as React from 'react';
import { DataFrame, Field, GrafanaTheme2, LinkModel } from '@grafana/data';
import { ContextMenu, MenuGroup, MenuItem, useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/panel/piechart/PieChart.tsx b/public/app/plugins/panel/piechart/PieChart.tsx
index 674af3e1cf9..3b980dd9543 100644
--- a/public/app/plugins/panel/piechart/PieChart.tsx
+++ b/public/app/plugins/panel/piechart/PieChart.tsx
@@ -5,7 +5,8 @@ import { Group } from '@visx/group';
import Pie, { PieArcDatum, ProvidedProps } from '@visx/shape/lib/shapes/Pie';
import { useTooltip, useTooltipInPortal } from '@visx/tooltip';
import { UseTooltipParams } from '@visx/tooltip/lib/hooks/useTooltip';
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
+import * as React from 'react';
import tinycolor from 'tinycolor2';
import {
diff --git a/public/app/plugins/panel/piechart/PieChartPanel.test.tsx b/public/app/plugins/panel/piechart/PieChartPanel.test.tsx
index 99b3d73e1c1..059877f28bb 100644
--- a/public/app/plugins/panel/piechart/PieChartPanel.test.tsx
+++ b/public/app/plugins/panel/piechart/PieChartPanel.test.tsx
@@ -1,6 +1,6 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import React, { ComponentProps } from 'react';
+import { ComponentProps } from 'react';
import {
FieldConfigSource,
diff --git a/public/app/plugins/panel/piechart/PieChartPanel.tsx b/public/app/plugins/panel/piechart/PieChartPanel.tsx
index a9126a492ca..5d2ab75b69d 100644
--- a/public/app/plugins/panel/piechart/PieChartPanel.tsx
+++ b/public/app/plugins/panel/piechart/PieChartPanel.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { Subscription } from 'rxjs';
import {
diff --git a/public/app/plugins/panel/stat/StatPanel.tsx b/public/app/plugins/panel/stat/StatPanel.tsx
index 2092b8d2989..0dc6a22124b 100644
--- a/public/app/plugins/panel/stat/StatPanel.tsx
+++ b/public/app/plugins/panel/stat/StatPanel.tsx
@@ -1,5 +1,5 @@
import { isNumber } from 'lodash';
-import React, { PureComponent } from 'react';
+import { PureComponent } from 'react';
import {
DisplayValueAlignmentFactors,
diff --git a/public/app/plugins/panel/state-timeline/StateTimelinePanel.tsx b/public/app/plugins/panel/state-timeline/StateTimelinePanel.tsx
index 10175fb0999..8739b3790bb 100644
--- a/public/app/plugins/panel/state-timeline/StateTimelinePanel.tsx
+++ b/public/app/plugins/panel/state-timeline/StateTimelinePanel.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
import { DashboardCursorSync, PanelProps } from '@grafana/data';
import { getLastStreamingDataFramePacket } from '@grafana/data/src/dataframe/StreamingDataFrame';
diff --git a/public/app/plugins/panel/state-timeline/StateTimelineTooltip2.tsx b/public/app/plugins/panel/state-timeline/StateTimelineTooltip2.tsx
index c46f6298e18..d60aad35d23 100644
--- a/public/app/plugins/panel/state-timeline/StateTimelineTooltip2.tsx
+++ b/public/app/plugins/panel/state-timeline/StateTimelineTooltip2.tsx
@@ -1,4 +1,4 @@
-import React, { ReactNode } from 'react';
+import { ReactNode } from 'react';
import { FieldType, TimeRange } from '@grafana/data';
import { SortOrder } from '@grafana/schema/dist/esm/common/common.gen';
diff --git a/public/app/plugins/panel/status-history/StatusHistoryPanel.tsx b/public/app/plugins/panel/status-history/StatusHistoryPanel.tsx
index 716445e784b..475ad75556f 100644
--- a/public/app/plugins/panel/status-history/StatusHistoryPanel.tsx
+++ b/public/app/plugins/panel/status-history/StatusHistoryPanel.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
import { DashboardCursorSync, PanelProps } from '@grafana/data';
import { EventBusPlugin, TooltipDisplayMode, TooltipPlugin2, usePanelContext, useTheme2 } from '@grafana/ui';
diff --git a/public/app/plugins/panel/table/PaginationEditor.tsx b/public/app/plugins/panel/table/PaginationEditor.tsx
index 5d25249d845..0bfa20b565b 100644
--- a/public/app/plugins/panel/table/PaginationEditor.tsx
+++ b/public/app/plugins/panel/table/PaginationEditor.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { StandardEditorProps } from '@grafana/data';
import { Switch } from '@grafana/ui';
diff --git a/public/app/plugins/panel/table/TableCellOptionEditor.tsx b/public/app/plugins/panel/table/TableCellOptionEditor.tsx
index c4b90e9812a..a2822246832 100644
--- a/public/app/plugins/panel/table/TableCellOptionEditor.tsx
+++ b/public/app/plugins/panel/table/TableCellOptionEditor.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { merge } from 'lodash';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import { TableCellOptions } from '@grafana/schema';
diff --git a/public/app/plugins/panel/table/TablePanel.tsx b/public/app/plugins/panel/table/TablePanel.tsx
index e3d9d9f774d..4b0a386e6a9 100644
--- a/public/app/plugins/panel/table/TablePanel.tsx
+++ b/public/app/plugins/panel/table/TablePanel.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import {
DashboardCursorSync,
diff --git a/public/app/plugins/panel/table/cells/AutoCellOptionsEditor.tsx b/public/app/plugins/panel/table/cells/AutoCellOptionsEditor.tsx
index f760709adb6..5603832de95 100644
--- a/public/app/plugins/panel/table/cells/AutoCellOptionsEditor.tsx
+++ b/public/app/plugins/panel/table/cells/AutoCellOptionsEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { TableAutoCellOptions, TableColorTextCellOptions } from '@grafana/schema';
import { Field, Switch, Badge, Label } from '@grafana/ui';
diff --git a/public/app/plugins/panel/table/cells/BarGaugeCellOptionsEditor.tsx b/public/app/plugins/panel/table/cells/BarGaugeCellOptionsEditor.tsx
index 59bf1e617a7..57e6b9703ee 100644
--- a/public/app/plugins/panel/table/cells/BarGaugeCellOptionsEditor.tsx
+++ b/public/app/plugins/panel/table/cells/BarGaugeCellOptionsEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SelectableValue } from '@grafana/data';
import { BarGaugeDisplayMode, BarGaugeValueMode, TableBarGaugeCellOptions } from '@grafana/schema';
import { Field, RadioButtonGroup, Stack } from '@grafana/ui';
diff --git a/public/app/plugins/panel/table/cells/ColorBackgroundCellOptionsEditor.tsx b/public/app/plugins/panel/table/cells/ColorBackgroundCellOptionsEditor.tsx
index 99069cd8c75..0cd943b5cf6 100644
--- a/public/app/plugins/panel/table/cells/ColorBackgroundCellOptionsEditor.tsx
+++ b/public/app/plugins/panel/table/cells/ColorBackgroundCellOptionsEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { SelectableValue } from '@grafana/data';
import { TableCellBackgroundDisplayMode, TableColoredBackgroundCellOptions } from '@grafana/schema';
import { Field, RadioButtonGroup, Switch, Label, Badge } from '@grafana/ui';
diff --git a/public/app/plugins/panel/table/cells/SparklineCellOptionsEditor.tsx b/public/app/plugins/panel/table/cells/SparklineCellOptionsEditor.tsx
index 61799c51c18..6a5a41d4189 100644
--- a/public/app/plugins/panel/table/cells/SparklineCellOptionsEditor.tsx
+++ b/public/app/plugins/panel/table/cells/SparklineCellOptionsEditor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { createFieldConfigRegistry, SetFieldConfigOptionsArgs } from '@grafana/data';
import { GraphFieldConfig, TableSparklineCellOptions } from '@grafana/schema';
diff --git a/public/app/plugins/panel/text/TextPanel.test.tsx b/public/app/plugins/panel/text/TextPanel.test.tsx
index ccebf02f1bc..08f034dc3df 100644
--- a/public/app/plugins/panel/text/TextPanel.test.tsx
+++ b/public/app/plugins/panel/text/TextPanel.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { dateTime, LoadingState, EventBusSrv } from '@grafana/data';
diff --git a/public/app/plugins/panel/text/TextPanel.tsx b/public/app/plugins/panel/text/TextPanel.tsx
index 1d040905cdb..98762f4a106 100644
--- a/public/app/plugins/panel/text/TextPanel.tsx
+++ b/public/app/plugins/panel/text/TextPanel.tsx
@@ -1,6 +1,6 @@
import { css, cx } from '@emotion/css';
import DangerouslySetHtmlContent from 'dangerously-set-html-content';
-import React, { useState } from 'react';
+import { useState } from 'react';
import { useDebounce } from 'react-use';
import { GrafanaTheme2, PanelProps, renderTextPanelMarkdown, textUtil, InterpolateFunction } from '@grafana/data';
diff --git a/public/app/plugins/panel/text/TextPanelEditor.tsx b/public/app/plugins/panel/text/TextPanelEditor.tsx
index 5c8f3718dd9..29fb1d3687f 100644
--- a/public/app/plugins/panel/text/TextPanelEditor.tsx
+++ b/public/app/plugins/panel/text/TextPanelEditor.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
import { GrafanaTheme2, StandardEditorProps } from '@grafana/data';
diff --git a/public/app/plugins/panel/timeseries/InsertNullsEditor.tsx b/public/app/plugins/panel/timeseries/InsertNullsEditor.tsx
index a9c11c28a01..868393ca497 100644
--- a/public/app/plugins/panel/timeseries/InsertNullsEditor.tsx
+++ b/public/app/plugins/panel/timeseries/InsertNullsEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { StandardEditorProps, SelectableValue } from '@grafana/data';
import { HorizontalGroup, RadioButtonGroup } from '@grafana/ui';
diff --git a/public/app/plugins/panel/timeseries/LineStyleEditor.tsx b/public/app/plugins/panel/timeseries/LineStyleEditor.tsx
index cd90f9bdcc9..f5f3d14bc5e 100644
--- a/public/app/plugins/panel/timeseries/LineStyleEditor.tsx
+++ b/public/app/plugins/panel/timeseries/LineStyleEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { StandardEditorProps, SelectableValue } from '@grafana/data';
import { LineStyle } from '@grafana/schema';
diff --git a/public/app/plugins/panel/timeseries/NullsThresholdInput.tsx b/public/app/plugins/panel/timeseries/NullsThresholdInput.tsx
index 8d9df298714..3e83be1cb25 100644
--- a/public/app/plugins/panel/timeseries/NullsThresholdInput.tsx
+++ b/public/app/plugins/panel/timeseries/NullsThresholdInput.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { rangeUtil } from '@grafana/data';
import { Input } from '@grafana/ui';
diff --git a/public/app/plugins/panel/timeseries/SpanNullsEditor.tsx b/public/app/plugins/panel/timeseries/SpanNullsEditor.tsx
index 5344dc8a528..f7ac5d4ebc2 100644
--- a/public/app/plugins/panel/timeseries/SpanNullsEditor.tsx
+++ b/public/app/plugins/panel/timeseries/SpanNullsEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { StandardEditorProps, SelectableValue } from '@grafana/data';
import { HorizontalGroup, RadioButtonGroup } from '@grafana/ui';
diff --git a/public/app/plugins/panel/timeseries/ThresholdsStyleEditor.tsx b/public/app/plugins/panel/timeseries/ThresholdsStyleEditor.tsx
index bd67c199106..af4048c9c6a 100644
--- a/public/app/plugins/panel/timeseries/ThresholdsStyleEditor.tsx
+++ b/public/app/plugins/panel/timeseries/ThresholdsStyleEditor.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback } from 'react';
+import { useCallback } from 'react';
import { StandardEditorProps, SelectableValue } from '@grafana/data';
import { GraphThresholdsStyleMode } from '@grafana/schema';
diff --git a/public/app/plugins/panel/timeseries/TimeSeriesPanel.tsx b/public/app/plugins/panel/timeseries/TimeSeriesPanel.tsx
index 22fae4f81ff..32ec1c7b62a 100644
--- a/public/app/plugins/panel/timeseries/TimeSeriesPanel.tsx
+++ b/public/app/plugins/panel/timeseries/TimeSeriesPanel.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
import { PanelProps, DataFrameType, DashboardCursorSync } from '@grafana/data';
import { PanelDataErrorView } from '@grafana/runtime';
diff --git a/public/app/plugins/panel/timeseries/TimeSeriesTooltip.tsx b/public/app/plugins/panel/timeseries/TimeSeriesTooltip.tsx
index f9982d9898c..49f8a3262bb 100644
--- a/public/app/plugins/panel/timeseries/TimeSeriesTooltip.tsx
+++ b/public/app/plugins/panel/timeseries/TimeSeriesTooltip.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { ReactNode } from 'react';
+import { ReactNode } from 'react';
import { DataFrame, Field, FieldType, formattedValueToString } from '@grafana/data';
import { SortOrder, TooltipDisplayMode } from '@grafana/schema/dist/esm/common/common.gen';
diff --git a/public/app/plugins/panel/timeseries/TimezonesEditor.tsx b/public/app/plugins/panel/timeseries/TimezonesEditor.tsx
index 4e47a88b30d..d62a538aebf 100644
--- a/public/app/plugins/panel/timeseries/TimezonesEditor.tsx
+++ b/public/app/plugins/panel/timeseries/TimezonesEditor.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2, InternalTimeZones, StandardEditorProps } from '@grafana/data';
import { OptionsWithTimezones } from '@grafana/schema';
diff --git a/public/app/plugins/panel/timeseries/plugins/AnnotationsPlugin2.tsx b/public/app/plugins/panel/timeseries/plugins/AnnotationsPlugin2.tsx
index 945af93ca6c..6e915bd3671 100644
--- a/public/app/plugins/panel/timeseries/plugins/AnnotationsPlugin2.tsx
+++ b/public/app/plugins/panel/timeseries/plugins/AnnotationsPlugin2.tsx
@@ -1,5 +1,6 @@
import { css } from '@emotion/css';
-import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, useReducer } from 'react';
+import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, useReducer } from 'react';
+import * as React from 'react';
import { createPortal } from 'react-dom';
import tinycolor from 'tinycolor2';
import uPlot from 'uplot';
diff --git a/public/app/plugins/panel/timeseries/plugins/ExemplarMarker.tsx b/public/app/plugins/panel/timeseries/plugins/ExemplarMarker.tsx
index 04c1c95b574..fec87618709 100644
--- a/public/app/plugins/panel/timeseries/plugins/ExemplarMarker.tsx
+++ b/public/app/plugins/panel/timeseries/plugins/ExemplarMarker.tsx
@@ -9,7 +9,8 @@ import {
useHover,
useInteractions,
} from '@floating-ui/react';
-import React, { CSSProperties, useCallback, useEffect, useState } from 'react';
+import { CSSProperties, useCallback, useEffect, useState } from 'react';
+import * as React from 'react';
import { DataFrame, DataFrameFieldIndex, Field, formattedValueToString, GrafanaTheme2, LinkModel } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
diff --git a/public/app/plugins/panel/timeseries/plugins/ExemplarsPlugin.tsx b/public/app/plugins/panel/timeseries/plugins/ExemplarsPlugin.tsx
index 754e052c7b9..c741f821f88 100644
--- a/public/app/plugins/panel/timeseries/plugins/ExemplarsPlugin.tsx
+++ b/public/app/plugins/panel/timeseries/plugins/ExemplarsPlugin.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useLayoutEffect, useRef, useState } from 'react';
+import { useCallback, useLayoutEffect, useRef, useState } from 'react';
import uPlot from 'uplot';
import {
diff --git a/public/app/plugins/panel/timeseries/plugins/OutsideRangePlugin.tsx b/public/app/plugins/panel/timeseries/plugins/OutsideRangePlugin.tsx
index d802f85def4..5dea52b23f8 100644
--- a/public/app/plugins/panel/timeseries/plugins/OutsideRangePlugin.tsx
+++ b/public/app/plugins/panel/timeseries/plugins/OutsideRangePlugin.tsx
@@ -1,4 +1,4 @@
-import React, { useLayoutEffect, useRef, useState } from 'react';
+import { useLayoutEffect, useRef, useState } from 'react';
import uPlot, { TypedArray, Scale } from 'uplot';
import { AbsoluteTimeRange } from '@grafana/data';
diff --git a/public/app/plugins/panel/timeseries/plugins/ThresholdControlsPlugin.tsx b/public/app/plugins/panel/timeseries/plugins/ThresholdControlsPlugin.tsx
index a286ce7612f..76ff1c3b3eb 100644
--- a/public/app/plugins/panel/timeseries/plugins/ThresholdControlsPlugin.tsx
+++ b/public/app/plugins/panel/timeseries/plugins/ThresholdControlsPlugin.tsx
@@ -1,4 +1,4 @@
-import React, { useState, useLayoutEffect, useMemo, useRef } from 'react';
+import { useState, useLayoutEffect, useMemo, useRef } from 'react';
import uPlot from 'uplot';
import { FieldConfigSource, ThresholdsConfig, getValueFormat, FieldType } from '@grafana/data';
diff --git a/public/app/plugins/panel/timeseries/plugins/ThresholdDragHandle.tsx b/public/app/plugins/panel/timeseries/plugins/ThresholdDragHandle.tsx
index 133e10415e2..d7da47bd24d 100644
--- a/public/app/plugins/panel/timeseries/plugins/ThresholdDragHandle.tsx
+++ b/public/app/plugins/panel/timeseries/plugins/ThresholdDragHandle.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
import { noop } from 'lodash';
-import React, { useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
import Draggable, { DraggableBounds } from 'react-draggable';
import { Threshold, GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/plugins/panel/timeseries/plugins/annotations2/AnnotationEditor2.tsx b/public/app/plugins/panel/timeseries/plugins/annotations2/AnnotationEditor2.tsx
index 21f998ce696..dde832c1fe1 100644
--- a/public/app/plugins/panel/timeseries/plugins/annotations2/AnnotationEditor2.tsx
+++ b/public/app/plugins/panel/timeseries/plugins/annotations2/AnnotationEditor2.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useRef } from 'react';
+import { useRef } from 'react';
import { Controller } from 'react-hook-form';
import { useAsyncFn, useClickAway } from 'react-use';
diff --git a/public/app/plugins/panel/timeseries/plugins/annotations2/AnnotationMarker2.tsx b/public/app/plugins/panel/timeseries/plugins/annotations2/AnnotationMarker2.tsx
index 2353971f734..513a620c985 100644
--- a/public/app/plugins/panel/timeseries/plugins/annotations2/AnnotationMarker2.tsx
+++ b/public/app/plugins/panel/timeseries/plugins/annotations2/AnnotationMarker2.tsx
@@ -1,7 +1,8 @@
import { css } from '@emotion/css';
import { flip, shift, autoUpdate } from '@floating-ui/dom';
import { useFloating } from '@floating-ui/react';
-import React, { useState } from 'react';
+import { useState } from 'react';
+import * as React from 'react';
import { createPortal } from 'react-dom';
import { GrafanaTheme2 } from '@grafana/data';
diff --git a/public/app/plugins/panel/timeseries/plugins/annotations2/AnnotationTooltip2.tsx b/public/app/plugins/panel/timeseries/plugins/annotations2/AnnotationTooltip2.tsx
index b7c7f5290eb..d6994245f4e 100644
--- a/public/app/plugins/panel/timeseries/plugins/annotations2/AnnotationTooltip2.tsx
+++ b/public/app/plugins/panel/timeseries/plugins/annotations2/AnnotationTooltip2.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React from 'react';
+import * as React from 'react';
import { GrafanaTheme2, dateTimeFormat, systemDateFormats, textUtil } from '@grafana/data';
import { HorizontalGroup, IconButton, Tag, usePanelContext, useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/panel/traces/TracesPanel.test.tsx b/public/app/plugins/panel/traces/TracesPanel.test.tsx
index 8eb3a49094f..a94cc637936 100644
--- a/public/app/plugins/panel/traces/TracesPanel.test.tsx
+++ b/public/app/plugins/panel/traces/TracesPanel.test.tsx
@@ -1,5 +1,4 @@
import { render, screen } from '@testing-library/react';
-import React from 'react';
import { LoadingState, PanelProps } from '@grafana/data';
diff --git a/public/app/plugins/panel/traces/TracesPanel.tsx b/public/app/plugins/panel/traces/TracesPanel.tsx
index f33e04f64eb..3053413e053 100644
--- a/public/app/plugins/panel/traces/TracesPanel.tsx
+++ b/public/app/plugins/panel/traces/TracesPanel.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo, createRef } from 'react';
+import { useMemo, createRef } from 'react';
import { useAsync } from 'react-use';
import { Field, LinkModel, PanelProps } from '@grafana/data';
diff --git a/public/app/plugins/panel/trend/TrendPanel.tsx b/public/app/plugins/panel/trend/TrendPanel.tsx
index 522c231eb08..757789d7e87 100644
--- a/public/app/plugins/panel/trend/TrendPanel.tsx
+++ b/public/app/plugins/panel/trend/TrendPanel.tsx
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { DataFrame, FieldMatcherID, fieldMatchers, FieldType, PanelProps, TimeRange } from '@grafana/data';
import { isLikelyAscendingVector } from '@grafana/data/src/transformations/transformers/joinDataFrames';
diff --git a/public/app/plugins/panel/welcome/Welcome.tsx b/public/app/plugins/panel/welcome/Welcome.tsx
index b427770b63b..708678032c0 100644
--- a/public/app/plugins/panel/welcome/Welcome.tsx
+++ b/public/app/plugins/panel/welcome/Welcome.tsx
@@ -1,5 +1,4 @@
import { css } from '@emotion/css';
-import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
diff --git a/public/app/plugins/panel/xychart/AutoEditor.tsx b/public/app/plugins/panel/xychart/AutoEditor.tsx
index 82a346fd3f0..3ceb607b321 100644
--- a/public/app/plugins/panel/xychart/AutoEditor.tsx
+++ b/public/app/plugins/panel/xychart/AutoEditor.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import {
SelectableValue,
diff --git a/public/app/plugins/panel/xychart/ManualEditor.tsx b/public/app/plugins/panel/xychart/ManualEditor.tsx
index f86ff255393..6459e778fe9 100644
--- a/public/app/plugins/panel/xychart/ManualEditor.tsx
+++ b/public/app/plugins/panel/xychart/ManualEditor.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { useState, useEffect, useMemo } from 'react';
+import { useState, useEffect, useMemo } from 'react';
import {
GrafanaTheme2,
diff --git a/public/app/plugins/panel/xychart/ScatterSeriesEditor.tsx b/public/app/plugins/panel/xychart/ScatterSeriesEditor.tsx
index a100d919807..f1283135229 100644
--- a/public/app/plugins/panel/xychart/ScatterSeriesEditor.tsx
+++ b/public/app/plugins/panel/xychart/ScatterSeriesEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { StandardEditorProps, FieldNamePickerBaseNameMode } from '@grafana/data';
import { Field } from '@grafana/ui';
import { FieldNamePicker } from '@grafana/ui/src/components/MatchersUI/FieldNamePicker';
diff --git a/public/app/plugins/panel/xychart/SymbolEditor.tsx b/public/app/plugins/panel/xychart/SymbolEditor.tsx
index b7112613385..b0f176054cf 100644
--- a/public/app/plugins/panel/xychart/SymbolEditor.tsx
+++ b/public/app/plugins/panel/xychart/SymbolEditor.tsx
@@ -1,5 +1,3 @@
-import React from 'react';
-
import { StandardEditorProps } from '@grafana/data';
import { ResourceDimensionConfig, ResourceDimensionMode } from '@grafana/schema';
import { RadioButtonGroup } from '@grafana/ui';
diff --git a/public/app/plugins/panel/xychart/XYChartPanel.tsx b/public/app/plugins/panel/xychart/XYChartPanel.tsx
index a15e8a77f8d..7fc3ca9d7c1 100644
--- a/public/app/plugins/panel/xychart/XYChartPanel.tsx
+++ b/public/app/plugins/panel/xychart/XYChartPanel.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useState, useEffect, useCallback } from 'react';
+import { useState, useEffect, useCallback } from 'react';
import { usePrevious } from 'react-use';
import { PanelProps } from '@grafana/data';
diff --git a/public/app/plugins/panel/xychart/XYChartTooltip.test.tsx b/public/app/plugins/panel/xychart/XYChartTooltip.test.tsx
index b8999620597..5ea82819990 100644
--- a/public/app/plugins/panel/xychart/XYChartTooltip.test.tsx
+++ b/public/app/plugins/panel/xychart/XYChartTooltip.test.tsx
@@ -1,5 +1,4 @@
import { render } from '@testing-library/react';
-import React from 'react';
import { DataFrame, FieldType, ValueLinkConfig, LinkTarget } from '@grafana/data';
import { SortOrder, VisibilityMode } from '@grafana/schema';
diff --git a/public/app/plugins/panel/xychart/XYChartTooltip.tsx b/public/app/plugins/panel/xychart/XYChartTooltip.tsx
index 9012ccca99c..06f40f45228 100644
--- a/public/app/plugins/panel/xychart/XYChartTooltip.tsx
+++ b/public/app/plugins/panel/xychart/XYChartTooltip.tsx
@@ -1,4 +1,4 @@
-import React, { ReactNode } from 'react';
+import { ReactNode } from 'react';
import { DataFrame, Field, getFieldDisplayName } from '@grafana/data';
import { alpha } from '@grafana/data/src/themes/colorManipulator';
diff --git a/public/app/plugins/panel/xychart/v2/SeriesEditor.tsx b/public/app/plugins/panel/xychart/v2/SeriesEditor.tsx
index b76b0d16b66..7fe1f777b45 100644
--- a/public/app/plugins/panel/xychart/v2/SeriesEditor.tsx
+++ b/public/app/plugins/panel/xychart/v2/SeriesEditor.tsx
@@ -1,5 +1,5 @@
import { css, cx } from '@emotion/css';
-import React, { Fragment, useState } from 'react';
+import { Fragment, useState } from 'react';
import { usePrevious } from 'react-use';
import {
diff --git a/public/app/plugins/panel/xychart/v2/XYChartPanel.tsx b/public/app/plugins/panel/xychart/v2/XYChartPanel.tsx
index 8ee5098ac9c..cbc2c80c656 100644
--- a/public/app/plugins/panel/xychart/v2/XYChartPanel.tsx
+++ b/public/app/plugins/panel/xychart/v2/XYChartPanel.tsx
@@ -1,5 +1,5 @@
import { css } from '@emotion/css';
-import React, { useMemo } from 'react';
+import { useMemo } from 'react';
import { FALLBACK_COLOR, PanelProps } from '@grafana/data';
import { alpha } from '@grafana/data/src/themes/colorManipulator';
diff --git a/public/app/plugins/panel/xychart/v2/XYChartTooltip.tsx b/public/app/plugins/panel/xychart/v2/XYChartTooltip.tsx
index 932fc21a0b3..c35a964f832 100644
--- a/public/app/plugins/panel/xychart/v2/XYChartTooltip.tsx
+++ b/public/app/plugins/panel/xychart/v2/XYChartTooltip.tsx
@@ -1,4 +1,4 @@
-import React, { ReactNode } from 'react';
+import { ReactNode } from 'react';
import { DataFrame } from '@grafana/data';
import { alpha } from '@grafana/data/src/themes/colorManipulator';
diff --git a/public/app/routes/routes.tsx b/public/app/routes/routes.tsx
index 34d3ade4622..397958a2107 100644
--- a/public/app/routes/routes.tsx
+++ b/public/app/routes/routes.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { Redirect, RouteComponentProps } from 'react-router-dom';
import { isTruthy } from '@grafana/data';
diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json
index 00a8a74492a..cb90d9da176 100644
--- a/public/locales/en-US/grafana.json
+++ b/public/locales/en-US/grafana.json
@@ -797,6 +797,18 @@
"success": "Library panel saved"
}
},
+ "link": {
+ "share": {
+ "config-alert-description": "Updating your settings will modify the default copy link to include these changes.",
+ "config-alert-title": "Link configuration",
+ "config-description": "Create a personalized, direct link to share your dashboard within your organization, with the following customization settings:",
+ "copy-link-button": "Copy link",
+ "copy-to-clipboard": "Link copied to clipboard",
+ "short-url-label": "Shorten link",
+ "time-range-description": "Change the current relative time range to an absolute time range",
+ "time-range-label": "Lock time range"
+ }
+ },
"login": {
"error": {
"blocked": "You have exceeded the number of login attempts for this user. Please try again later.",
@@ -1587,6 +1599,9 @@
"delete": "Delete permanently",
"restore": "Restore"
},
+ "page": {
+ "empty-state": "You haven't deleted any dashboards recently."
+ },
"permanently-delete-modal": {
"confirm-text": "Delete",
"delete-button": "Delete",
@@ -1642,6 +1657,7 @@
"title": "Select scopes"
},
"suggestedDashboards": {
+ "clear": "Clear search",
"loading": "Loading dashboards",
"search": "Search",
"toggle": {
@@ -1701,7 +1717,9 @@
"share-internally-description": "Advanced settings",
"share-internally-title": "Share internally",
"share-snapshot-title": "Share snapshot"
- }
+ },
+ "share-button": "Share",
+ "share-button-tooltip": "Copy shortened link"
},
"share-drawer": {
"confirm-action": {
diff --git a/public/locales/pseudo-LOCALE/grafana.json b/public/locales/pseudo-LOCALE/grafana.json
index 4c3eecbe49f..b7a08ac4f46 100644
--- a/public/locales/pseudo-LOCALE/grafana.json
+++ b/public/locales/pseudo-LOCALE/grafana.json
@@ -797,6 +797,18 @@
"success": "Ŀįþřäřy päʼnęľ şävęđ"
}
},
+ "link": {
+ "share": {
+ "config-alert-description": "Ůpđäŧįʼnģ yőūř şęŧŧįʼnģş ŵįľľ mőđįƒy ŧĥę đęƒäūľŧ čőpy ľįʼnĸ ŧő įʼnčľūđę ŧĥęşę čĥäʼnģęş.",
+ "config-alert-title": "Ŀįʼnĸ čőʼnƒįģūřäŧįőʼn",
+ "config-description": "Cřęäŧę ä pęřşőʼnäľįžęđ, đįřęčŧ ľįʼnĸ ŧő şĥäřę yőūř đäşĥþőäřđ ŵįŧĥįʼn yőūř őřģäʼnįžäŧįőʼn, ŵįŧĥ ŧĥę ƒőľľőŵįʼnģ čūşŧőmįžäŧįőʼn şęŧŧįʼnģş:",
+ "copy-link-button": "Cőpy ľįʼnĸ",
+ "copy-to-clipboard": "Ŀįʼnĸ čőpįęđ ŧő čľįpþőäřđ",
+ "short-url-label": "Ŝĥőřŧęʼn ľįʼnĸ",
+ "time-range-description": "Cĥäʼnģę ŧĥę čūřřęʼnŧ řęľäŧįvę ŧįmę řäʼnģę ŧő äʼn äþşőľūŧę ŧįmę řäʼnģę",
+ "time-range-label": "Ŀőčĸ ŧįmę řäʼnģę"
+ }
+ },
"login": {
"error": {
"blocked": "Ÿőū ĥävę ęχčęęđęđ ŧĥę ʼnūmþęř őƒ ľőģįʼn äŧŧęmpŧş ƒőř ŧĥįş ūşęř. Pľęäşę ŧřy äģäįʼn ľäŧęř.",
@@ -1587,6 +1599,9 @@
"delete": "Đęľęŧę pęřmäʼnęʼnŧľy",
"restore": "Ŗęşŧőřę"
},
+ "page": {
+ "empty-state": "Ÿőū ĥävęʼn'ŧ đęľęŧęđ äʼny đäşĥþőäřđş řęčęʼnŧľy."
+ },
"permanently-delete-modal": {
"confirm-text": "Đęľęŧę",
"delete-button": "Đęľęŧę",
@@ -1642,6 +1657,7 @@
"title": "Ŝęľęčŧ şčőpęş"
},
"suggestedDashboards": {
+ "clear": "Cľęäř şęäřčĥ",
"loading": "Ŀőäđįʼnģ đäşĥþőäřđş",
"search": "Ŝęäřčĥ",
"toggle": {
@@ -1701,7 +1717,9 @@
"share-internally-description": "Åđväʼnčęđ şęŧŧįʼnģş",
"share-internally-title": "Ŝĥäřę įʼnŧęřʼnäľľy",
"share-snapshot-title": "Ŝĥäřę şʼnäpşĥőŧ"
- }
+ },
+ "share-button": "Ŝĥäřę",
+ "share-button-tooltip": "Cőpy şĥőřŧęʼnęđ ľįʼnĸ"
},
"share-drawer": {
"confirm-action": {
diff --git a/public/openapi3.json b/public/openapi3.json
index 51ca81746f9..715243edd83 100644
--- a/public/openapi3.json
+++ b/public/openapi3.json
@@ -7009,7 +7009,9 @@
"status": {
"enum": [
"OK",
- "ERROR"
+ "ERROR",
+ "PENDING",
+ "UNKNOWN"
],
"type": "string"
},
@@ -15527,6 +15529,26 @@
"get": {
"operationId": "getSnapshot",
"parameters": [
+ {
+ "description": "ResultPage is used for pagination with ResultLimit",
+ "in": "query",
+ "name": "resultPage",
+ "schema": {
+ "default": 1,
+ "format": "int64",
+ "type": "integer"
+ }
+ },
+ {
+ "description": "Max limit for snapshot results returned.",
+ "in": "query",
+ "name": "resultLimit",
+ "schema": {
+ "default": 100,
+ "format": "int64",
+ "type": "integer"
+ }
+ },
{
"description": "Session UID of a session",
"in": "path",
@@ -15667,11 +15689,11 @@
"operationId": "getShapshotList",
"parameters": [
{
- "description": "Offset is used for pagination with limit",
+ "description": "Page is used for pagination with limit",
"in": "query",
- "name": "offset",
+ "name": "page",
"schema": {
- "default": 0,
+ "default": 1,
"format": "int64",
"type": "integer"
}
diff --git a/public/test/helpers/TestProvider.tsx b/public/test/helpers/TestProvider.tsx
index bd29e06b3bc..7fc3861693c 100644
--- a/public/test/helpers/TestProvider.tsx
+++ b/public/test/helpers/TestProvider.tsx
@@ -1,5 +1,5 @@
import { Store } from '@reduxjs/toolkit';
-import React from 'react';
+import * as React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
diff --git a/public/test/helpers/alertingRuleEditor.tsx b/public/test/helpers/alertingRuleEditor.tsx
index 272e3fb4868..adf840775bd 100644
--- a/public/test/helpers/alertingRuleEditor.tsx
+++ b/public/test/helpers/alertingRuleEditor.tsx
@@ -1,5 +1,4 @@
import { render } from '@testing-library/react';
-import React from 'react';
import { Route } from 'react-router-dom';
import { byRole, byTestId, byText } from 'testing-library-selector';
diff --git a/public/test/mocks/react-inlinesvg.tsx b/public/test/mocks/react-inlinesvg.tsx
index f05d3cfa8c1..79bcf2c6cb9 100644
--- a/public/test/mocks/react-inlinesvg.tsx
+++ b/public/test/mocks/react-inlinesvg.tsx
@@ -1,4 +1,4 @@
-import React, { Ref } from 'react';
+import { Ref } from 'react';
export default function ReactInlineSVG({
src,
diff --git a/public/test/test-utils.tsx b/public/test/test-utils.tsx
index 102bcfa2569..8083093c7a4 100644
--- a/public/test/test-utils.tsx
+++ b/public/test/test-utils.tsx
@@ -2,7 +2,8 @@ import { Store } from '@reduxjs/toolkit';
import { render, RenderOptions } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { createMemoryHistory, MemoryHistoryBuildOptions } from 'history';
-import React, { Fragment, PropsWithChildren } from 'react';
+import { Fragment, PropsWithChildren } from 'react';
+import * as React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router-dom';
import { getGrafanaContextMock } from 'test/mocks/getGrafanaContextMock';
diff --git a/scripts/webpack/webpack.dev.js b/scripts/webpack/webpack.dev.js
index eca2fd0c9d6..aea468e7959 100644
--- a/scripts/webpack/webpack.dev.js
+++ b/scripts/webpack/webpack.dev.js
@@ -18,6 +18,7 @@ const esbuildTargets = resolveToEsbuildTarget(browserslist(), { printUnknownTarg
const esbuildOptions = {
target: esbuildTargets,
format: undefined,
+ jsx: 'automatic',
};
// To speed up webpack and prevent unnecessary rebuilds we ignore decoupled packages
@@ -45,7 +46,7 @@ module.exports = (env = {}) => {
resolve: {
alias: {
// Packages linked for development need react to be resolved from the same location
- react: require.resolve('react'),
+ react: path.resolve('./node_modules/react'),
// Also Grafana packages need to be resolved from the same location so they share
// the same singletons
diff --git a/scripts/webpack/webpack.prod.js b/scripts/webpack/webpack.prod.js
index a94550fd0a5..c275250cf72 100644
--- a/scripts/webpack/webpack.prod.js
+++ b/scripts/webpack/webpack.prod.js
@@ -18,6 +18,7 @@ const esbuildTargets = resolveToEsbuildTarget(browserslist(), { printUnknownTarg
const esbuildOptions = {
target: esbuildTargets,
format: undefined,
+ jsx: 'automatic',
};
module.exports = (env = {}) =>
diff --git a/tsconfig.json b/tsconfig.json
index 40bee96229b..3a26dd6e12d 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,6 +1,6 @@
{
"compilerOptions": {
- "jsx": "react",
+ "jsx": "react-jsx",
"baseUrl": "public/",
"outDir": "public/dist",
"rootDirs": ["public/"],