diff --git a/.betterer.eslint.config.js b/.betterer.eslint.config.js
index 1be44601a3c..349ee612837 100644
--- a/.betterer.eslint.config.js
+++ b/.betterer.eslint.config.js
@@ -113,6 +113,7 @@ module.exports = [
ignores: ['public/app/plugins/**', '**/*.story.tsx', '**/*.{test,spec}.{ts,tsx}', '**/__mocks__/', 'public/test'],
rules: {
'@grafana/no-untranslated-strings': 'error',
+ '@grafana/no-translation-top-level': 'error',
},
},
];
diff --git a/.betterer.results b/.betterer.results
index d5ac5c018d3..1e0cc343e3b 100644
--- a/.betterer.results
+++ b/.betterer.results
@@ -549,6 +549,11 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
],
+ "packages/grafana-ui/src/components/DataSourceSettings/DataSourceHttpSettings.tsx:5381": [
+ [0, 0, 0, "Do not use the t() function outside of a component or function", "0"],
+ [0, 0, 0, "Do not use the t() function outside of a component or function", "1"],
+ [0, 0, 0, "Do not use the t() function outside of a component or function", "2"]
+ ],
"packages/grafana-ui/src/components/DataSourceSettings/types.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
@@ -3044,7 +3049,8 @@ exports[`better eslint`] = {
[0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"]
],
"public/app/features/connections/tabs/ConnectData/Search/Search.tsx:5381": [
- [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"]
+ [0, 0, 0, "Do not use the t() function outside of a component or function", "0"],
+ [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"]
],
"public/app/features/connections/tabs/ConnectData/Search/index.tsx:5381": [
[0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"]
@@ -4568,9 +4574,18 @@ exports[`better eslint`] = {
[0, 0, 0, "No untranslated strings. Wrap text with ", "2"],
[0, 0, 0, "No untranslated strings. Wrap text with ", "3"]
],
+ "public/app/features/explore/RichHistory/RichHistorySettingsTab.tsx:5381": [
+ [0, 0, 0, "Do not use the t() function outside of a component or function", "0"],
+ [0, 0, 0, "Do not use the t() function outside of a component or function", "1"],
+ [0, 0, 0, "Do not use the t() function outside of a component or function", "2"],
+ [0, 0, 0, "Do not use the t() function outside of a component or function", "3"]
+ ],
"public/app/features/explore/RichHistory/RichHistoryStarredTab.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with ", "0"]
],
+ "public/app/features/explore/ShortLinkButtonMenu.tsx:5381": [
+ [0, 0, 0, "Do not use the t() function outside of a component or function", "0"]
+ ],
"public/app/features/explore/SupplementaryResultError.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with ", "0"]
],
@@ -4929,8 +4944,14 @@ exports[`better eslint`] = {
[0, 0, 0, "No untranslated strings. Wrap text with ", "4"]
],
"public/app/features/inspector/InspectJSONTab.tsx:5381": [
- [0, 0, 0, "No untranslated strings. Wrap text with ", "0"],
- [0, 0, 0, "No untranslated strings. Wrap text with ", "1"]
+ [0, 0, 0, "Do not use the t() function outside of a component or function", "0"],
+ [0, 0, 0, "Do not use the t() function outside of a component or function", "1"],
+ [0, 0, 0, "Do not use the t() function outside of a component or function", "2"],
+ [0, 0, 0, "Do not use the t() function outside of a component or function", "3"],
+ [0, 0, 0, "Do not use the t() function outside of a component or function", "4"],
+ [0, 0, 0, "Do not use the t() function outside of a component or function", "5"],
+ [0, 0, 0, "No untranslated strings. Wrap text with ", "6"],
+ [0, 0, 0, "No untranslated strings. Wrap text with ", "7"]
],
"public/app/features/inspector/InspectStatsTab.tsx:5381": [
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "0"]
diff --git a/.vale.ini b/.vale.ini
index cf4c71392dc..37e764e6d0f 100644
--- a/.vale.ini
+++ b/.vale.ini
@@ -1,5 +1,5 @@
MinAlertLevel = warning
-[*]
+[*.md]
BasedOnStyles = Grafana
TokenIgnores = (+?), \*\*[^\n]+\*\*
diff --git a/docs/sources/alerting/_index.md b/docs/sources/alerting/_index.md
index 601ae34e4e1..8362360d188 100644
--- a/docs/sources/alerting/_index.md
+++ b/docs/sources/alerting/_index.md
@@ -25,7 +25,7 @@ cards:
items:
- title: Introduction
href: ./fundamentals/
- description: Learn more about the fundamentals and available features that help you create, manage, and respond to alerts; and improve your team’s ability to resolve issues quickly.
+ description: Learn more about the fundamentals and available features that help you create, manage, and respond to alerts; and improve your team's ability to resolve issues quickly.
height: 24
- title: Configure alert rules
href: ./alerting-rules/
@@ -55,7 +55,8 @@ Monitor your incoming metrics data or log entries and set up your Grafana Alerti
In this way, you eliminate the need for manual monitoring and provide a first line of defense against system outages or changes that could turn into major incidents.
-Using Grafana Alerting, you create queries and expressions from multiple data sources — no matter where your data is stored — giving you the flexibility to combine your data and alert on your metrics and logs in new and unique ways. You can then create, manage, and take action on your alerts from a single, consolidated view, and improve your team’s ability to identify and resolve issues quickly.
+Using Grafana Alerting, you create queries and expressions from multiple data sources, no matter where you store your data, giving you the flexibility to combine your data and alert on your metrics and logs in new and unique ways.
+You can then create, manage, and take action on your alerts from a single, consolidated view, and improve your team's ability to identify and resolve issues quickly.
## Explore
diff --git a/docs/sources/alerting/alerting-rules/create-grafana-managed-rule.md b/docs/sources/alerting/alerting-rules/create-grafana-managed-rule.md
index 41c9150b52c..3b30819b328 100644
--- a/docs/sources/alerting/alerting-rules/create-grafana-managed-rule.md
+++ b/docs/sources/alerting/alerting-rules/create-grafana-managed-rule.md
@@ -118,15 +118,17 @@ refs:
# Configure Grafana-managed alert rules
-Grafana-managed rules can query data from multiple data sources in a single alert rule. They are the most flexible [alert rule type](ref:alert-rules). You can also add expressions to transform your data, set alert conditions, and images in alert notifications.
+Grafana-managed rules can query data from multiple data sources in a single alert rule.
+They're the most flexible [alert rule type](ref:alert-rules).
+You can also add expressions to transform your data, set alert conditions, and images in alert notifications.
-{{% admonition type="note" %}}
+{{< admonition type="note" >}}
In Grafana Cloud, the number of Grafana-managed alert rules you can create depends on your Grafana Cloud plan.
- Free Forever plan: You can create up to 100 free alert rules, with each alert rule having a maximum of 1000 alert instances.
- All paid plans (Pro and Advanced): They have a soft limit of 2000 alert rules and support unlimited alert instances. To increase the limit, open a support ticket from the [Cloud portal](/docs/grafana-cloud/account-management/support/).
-{{% /admonition %}}
+{{< /admonition >}}
To create or edit Grafana-managed alert rules, follow the instructions below. For a practical example, check out our [tutorial on getting started with Grafana alerting](http://grafana.com/tutorials/alerting-get-started/).
@@ -144,9 +146,11 @@ Only users with **Edit** permissions for the folder storing the rules can edit o
You can use default or advanced options for Grafana-managed alert rule creation. The default options streamline rule creation with a cleaner header and a single query and condition. For more complex rules, use advanced options to add multiple queries and expressions.
-You can toggle between the two options. Once you have created an alert rule, the system defaults to your previous choice for the next alert rule.
+You can toggle between the two options.
+After you have created an alert rule, the system defaults to your previous choice for the next alert rule.
-Switching from advanced to default may result in queries and expressions that cannot be converted. In this case, a warning message asks if you want to continue to reset to default settings.
+Switching from advanced to default may result in queries and expressions that can't be converted.
+In this case, a warning message asks if you want to continue to reset to default settings.
{{< docs/shared lookup="alerts/configure-alert-rule-name.md" source="grafana" version="" >}}
@@ -169,9 +173,10 @@ You can toggle between **Default** and **Advanced** options. If the [Default vs.
{{< collapse title="Advanced options" >}}
1. Select a data source.
-1. From the **Options** dropdown, specify a [time range](ref:time-units-and-relative-ranges).
+1. From the **Options** drop-down menu, specify a [time range](ref:time-units-and-relative-ranges).
- Note that Grafana Alerting only supports fixed relative time ranges, for example, `now-24hr: now`. It does not support absolute time ranges: `2021-12-02 00:00:00 to 2021-12-05 23:59:592` or semi-relative time ranges: `now/d to: now`.
+ Note that Grafana Alerting only supports fixed relative time ranges, for example, `now-24hr: now`.
+ It doesn't support absolute time ranges: `2021-12-02 00:00:00 to 2021-12-05 23:59:592` or semi-relative time ranges: `now/d to: now`.
1. Add a query.
@@ -222,7 +227,8 @@ To do this, you need to make sure that your alert rule is in the right evaluatio
The pending period is the period in which an alert rule can be in breach of the condition until it fires.
- Once a condition is met, the alert goes into the **Pending** state. If the condition remains active for the duration specified, the alert transitions to the **Firing** state, else it reverts to the **Normal** state.
+ After a condition is met, the alert goes into the **Pending** state.
+ If the condition remains active for the duration specified, the alert transitions to the **Firing** state, else it reverts to the **Normal** state.
1. Turn on pause alert notifications, if required.
@@ -253,7 +259,7 @@ Complete the following steps to set up notifications.
1. Choose this option to select an existing [contact point](ref:contact-points).
- All notifications for this alert rule are sent to this contact point automatically and notification policies are not used.
+ All notifications for this alert rule are sent to this contact point automatically and notification policies aren't used.
1. You can also optionally select a mute timing as well as groupings and timings to define when not to send notifications.
@@ -261,7 +267,8 @@ Complete the following steps to set up notifications.
1. Choose this option to use the [notification policy tree](ref:notification-policies) to handle alert notifications.
- All notifications for this alert rule are managed by the notification policy tree, which routes alerts based on their labels. If an alert does not match a specific policy, the default notification policy applies, ensuring all alerts are handled.
+ All notifications for this alert rule are managed by the notification policy tree, which routes alerts based on their labels.
+ If an alert doesn't match a specific policy, the default notification policy applies, ensuring all alerts are handled.
1. Preview your alert instance routing set up.
diff --git a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md
index f40ad6a1766..7ceb0dc3460 100644
--- a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md
+++ b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md
@@ -226,6 +226,7 @@ Experimental features might be changed or removed without prior notice.
| `datasourceConnectionsTab` | Shows defined connections for a data source in the plugins detail page |
| `newLogsPanel` | Enables the new logs panel in Explore |
| `pluginsCDNSyncLoader` | Load plugins from CDN synchronously |
+| `assetSriChecks` | Enables SRI checks for Grafana JavaScript assets |
## Development feature toggles
diff --git a/package.json b/package.json
index 1c9393c4bd9..3708b2b49ac 100644
--- a/package.json
+++ b/package.json
@@ -248,6 +248,7 @@
"webpack-livereload-plugin": "3.0.2",
"webpack-manifest-plugin": "5.0.0",
"webpack-merge": "6.0.1",
+ "webpack-subresource-integrity": "^5.2.0-rc.1",
"webpackbar": "^7.0.0",
"yaml": "^2.0.0",
"yargs": "^17.5.1"
diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts
index 87c5ff7c0d1..7e3ac0d6dba 100644
--- a/packages/grafana-data/src/types/featureToggles.gen.ts
+++ b/packages/grafana-data/src/types/featureToggles.gen.ts
@@ -254,4 +254,5 @@ export interface FeatureToggles {
alertingRuleVersionHistoryRestore?: boolean;
newShareReportDrawer?: boolean;
rendererDisableAppPluginsPreload?: boolean;
+ assetSriChecks?: boolean;
}
diff --git a/packages/grafana-eslint-rules/README.md b/packages/grafana-eslint-rules/README.md
index 2f73d46a529..e57e2ec09a1 100644
--- a/packages/grafana-eslint-rules/README.md
+++ b/packages/grafana-eslint-rules/README.md
@@ -156,7 +156,18 @@ const SearchTitle = ({ term }) => (
#### How to translate props or attributes
-Right now, we only check if a string is wrapped up by the `Trans` tag. We currently do not apply this rule to props, attributes or similar, but we also ask for them to be translated with the `t()` function.
+This rule checks if a string is wrapped up by the `Trans` tag, or if certain props contain untranslated strings.
+We ask for such props to be translated with the `t()` function.
+
+The below props are checked for untranslated strings:
+
+- `label`
+- `description`
+- `placeholder`
+- `aria-label`
+- `title`
+- `text`
+- `tooltip`
```tsx
// Bad ❌
@@ -168,3 +179,50 @@ return ;
```
Check more info about how translations work in Grafana in [Internationalization.md](https://github.com/grafana/grafana/blob/main/contribute/internationalization.md)
+
+### `no-translation-top-level`
+
+Ensure that `t()` translation method is not used at the top level of a file, outside of a component of method.
+This is to prevent calling the translation method before it's been instantiated.
+
+This does not cause an error if a file is lazily loaded, but refactors can cause errors, and it can cause problems in tests.
+Fix the
+
+```tsx
+// Bad ❌
+const someTranslatedText = t('some.key', 'Some text');
+const SomeComponent = () => {
+ return ;
+};
+
+// Good ✅
+const SomeComponent = () => {
+ const someTranslatedText = t('some.key', 'Some text');
+ return ;
+};
+
+// Bad ❌
+const someConfigThatHasToBeShared = [{ foo: t('some.key', 'Some text') }];
+const SomeComponent = () => {
+ return (
+