Merge branch 'main' into adela/decouple_hide_from

pull/106857/head
Adela Almasan 2 days ago
commit fc172be5fc
  1. 15
      .betterer.results
  2. 6
      .drone.yml
  3. 1
      .github/renovate.json5
  4. 2
      apps/iam/pkg/apis/iam_manifest.go
  5. 8
      contribute/developer-guide.md
  6. 8
      contribute/style-guides/e2e-plugins.md
  7. 465
      devenv/dev-dashboards/panel-table/table_kitchen_sink.json
  8. 1
      devenv/jsonnet/dev-dashboards.libsonnet
  9. 97
      docs/sources/administration/grafana-advisor/_index.md
  10. 2
      docs/sources/alerting/best-practices/_index.md
  11. 4
      docs/sources/setup-grafana/configure-security/configure-authentication/azuread/index.md
  12. 8
      e2e-playwright/dashboards-suite/dashboard-browse-nested.spec.ts
  13. 18
      e2e-playwright/dashboards-suite/dashboard-live-streaming.spec.ts
  14. 21
      e2e-playwright/panels-suite/geomap-spatial-operations-transform.spec.ts
  15. 8
      e2e-playwright/panels-suite/panelEdit_base.spec.ts
  16. 331
      e2e-playwright/panels-suite/table-kitchenSink.spec.ts
  17. 29
      e2e-playwright/panels-suite/table-sparkline.spec.ts
  18. 12
      e2e-playwright/plugin-e2e/plugin-e2e-api-tests/as-admin-user/panelEditPage.spec.ts
  19. 5
      e2e-playwright/start-server
  20. 8
      e2e-playwright/various-suite/frontend-sandbox-app.spec.ts
  21. 10
      e2e-playwright/various-suite/visualization-suggestions.spec.ts
  22. 2
      e2e/dashboards-suite/dashboard-live-streaming.spec.ts
  23. 2
      e2e/old-arch/dashboards-suite/dashboard-live-streaming.spec.ts
  24. 8
      e2e/old-arch/panels-suite/geomap-spatial-operations-transform.spec.ts
  25. 2
      e2e/old-arch/panels-suite/panelEdit_base.spec.ts
  26. 2
      e2e/old-arch/various-suite/visualization-suggestions.spec.ts
  27. 8
      e2e/panels-suite/geomap-spatial-operations-transform.spec.ts
  28. 2
      e2e/panels-suite/panelEdit_base.spec.ts
  29. 2
      e2e/various-suite/visualization-suggestions.spec.ts
  30. 2
      go.mod
  31. 4
      go.sum
  32. 2
      go.work
  33. 24
      package.json
  34. 2
      packages/grafana-alerting/package.json
  35. 4
      packages/grafana-data/package.json
  36. 4
      packages/grafana-data/src/types/featureToggles.gen.ts
  37. 2
      packages/grafana-e2e-selectors/package.json
  38. 13
      packages/grafana-e2e-selectors/src/selectors/components.ts
  39. 2
      packages/grafana-eslint-rules/package.json
  40. 8
      packages/grafana-flamegraph/package.json
  41. 2
      packages/grafana-plugin-configs/package.json
  42. 2
      packages/grafana-prometheus/package.json
  43. 386
      packages/grafana-prometheus/src/locales/de-DE/grafana-prometheus.json
  44. 386
      packages/grafana-prometheus/src/locales/hu-HU/grafana-prometheus.json
  45. 384
      packages/grafana-prometheus/src/locales/id-ID/grafana-prometheus.json
  46. 384
      packages/grafana-prometheus/src/locales/ja-JP/grafana-prometheus.json
  47. 2
      packages/grafana-runtime/package.json
  48. 2
      packages/grafana-schema/package.json
  49. 1
      packages/grafana-schema/src/raw/composable/logs/panelcfg/x/LogsPanelCfg_types.gen.ts
  50. 108
      packages/grafana-sql/src/locales/de-DE/grafana-sql.json
  51. 108
      packages/grafana-sql/src/locales/hu-HU/grafana-sql.json
  52. 108
      packages/grafana-sql/src/locales/id-ID/grafana-sql.json
  53. 108
      packages/grafana-sql/src/locales/ja-JP/grafana-sql.json
  54. 6
      packages/grafana-ui/package.json
  55. 5
      packages/grafana-ui/src/components/DateTimePickers/RelativeTimeRangePicker/RelativeTimeRangePicker.tsx
  56. 4
      packages/grafana-ui/src/components/DateTimePickers/TimeRangeInput.tsx
  57. 4
      packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker.tsx
  58. 4
      packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimePickerFooter.tsx
  59. 177
      packages/grafana-ui/src/components/DateTimePickers/options.ts
  60. 48
      packages/grafana-ui/src/components/MatchersUI/FieldTypeMatcherEditor.tsx
  61. 16
      packages/grafana-ui/src/components/MatchersUI/FieldsByFrameRefIdMatcher.tsx
  62. 2
      packages/grafana-ui/src/components/Table/TableNG/Filter/Filter.tsx
  63. 6
      packages/grafana-ui/src/components/Table/TableNG/Filter/FilterList.tsx
  64. 7
      packages/grafana-ui/src/components/Table/TableNG/Filter/FilterPopup.tsx
  65. 2
      packages/grafana-ui/src/internal/index.ts
  66. 14
      pkg/api/login.go
  67. 91
      pkg/api/user_token_test.go
  68. 9
      pkg/build/e2e-playwright/e2e.go
  69. 1
      pkg/build/e2e-playwright/main.go
  70. 7
      pkg/expr/nodes.go
  71. 15
      pkg/middleware/org_redirect.go
  72. 17
      pkg/middleware/org_redirect_test.go
  73. 2
      pkg/registry/apis/dashboard/register.go
  74. 2
      pkg/registry/apis/dashboard/search.go
  75. 23
      pkg/registry/apis/iam/register.go
  76. 47
      pkg/registry/apis/provisioning/register.go
  77. 21
      pkg/registry/apis/provisioning/repository/git/mutator.go
  78. 125
      pkg/registry/apis/provisioning/repository/git/mutator_test.go
  79. 3
      pkg/registry/apis/provisioning/repository/github/factory.go
  80. 10
      pkg/registry/apis/provisioning/repository/github/mutator.go
  81. 68
      pkg/registry/apis/provisioning/repository/github/mutator_test.go
  82. 5
      pkg/registry/apis/provisioning/repository/github/repository.go
  83. 7
      pkg/registry/apis/provisioning/secrets/repository.go
  84. 24
      pkg/registry/apis/provisioning/test.go
  85. 78
      pkg/registry/apis/provisioning/usage.go
  86. 85
      pkg/registry/apis/provisioning/usage/usage.go
  87. 5
      pkg/services/apiserver/auth/authorizer/authorizer.go
  88. 5
      pkg/services/apiserver/client/client.go
  89. 2
      pkg/services/apiserver/service.go
  90. 9
      pkg/services/dashboards/service/client/client.go
  91. 2
      pkg/services/dashboards/service/dashboard_service.go
  92. 1
      pkg/services/dashboardversion/dashverimpl/dashver.go
  93. 8
      pkg/services/featuremgmt/registry.go
  94. 1
      pkg/services/featuremgmt/toggles_gen.csv
  95. 4
      pkg/services/featuremgmt/toggles_gen.go
  96. 36
      pkg/services/featuremgmt/toggles_gen.json
  97. 2
      pkg/services/folder/folderimpl/folder.go
  98. 2
      pkg/services/folder/folderimpl/folder_unifiedstorage_test.go
  99. 20
      pkg/services/mtdsclient/mt_datasource_client_builder.go
  100. 59
      pkg/services/ngalert/api/tooling/definitions/alertmanager.go
  101. Some files were not shown because too many files have changed in this diff Show More

@ -3628,6 +3628,19 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "2"],
[0, 0, 0, "Unexpected any. Specify a different type.", "3"]
],
"public/app/plugins/datasource/tempo/traceql/traceql.test.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
[0, 0, 0, "Unexpected any. Specify a different type.", "2"],
[0, 0, 0, "Unexpected any. Specify a different type.", "3"],
[0, 0, 0, "Unexpected any. Specify a different type.", "4"],
[0, 0, 0, "Unexpected any. Specify a different type.", "5"],
[0, 0, 0, "Unexpected any. Specify a different type.", "6"],
[0, 0, 0, "Unexpected any. Specify a different type.", "7"],
[0, 0, 0, "Unexpected any. Specify a different type.", "8"],
[0, 0, 0, "Unexpected any. Specify a different type.", "9"],
[0, 0, 0, "Unexpected any. Specify a different type.", "10"]
],
"public/app/plugins/datasource/zipkin/QueryField.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
@ -3882,7 +3895,7 @@ exports[`better eslint`] = {
"public/app/plugins/panel/table/table-new/cells/ColorBackgroundCellOptionsEditor.tsx:5381": [
[0, 0, 0, "Add noMargin prop to Field components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "0"],
[0, 0, 0, "Add noMargin prop to Field components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "1"],
[0, 0, 0, "Add noMargin prop to Field components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "2"]
[0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "2"]
],
"public/app/plugins/panel/table/table-new/cells/ImageCellOptionsEditor.tsx:5381": [
[0, 0, 0, "Add noMargin prop to Field components to remove built-in margins. Use layout components like Stack or Grid with the gap prop instead for consistent spacing.", "0"],

@ -289,7 +289,7 @@ steps:
- commands:
- npx wait-on@7.0.1 http://$HOST:$PORT
- yarn playwright install --with-deps chromium
- yarn e2e:playwright --grep @plugins
- GRAFANA_URL=http://$HOST:$PORT yarn e2e:playwright --grep @plugins
depends_on:
- grafana-server
- build-test-plugins
@ -761,7 +761,7 @@ steps:
- commands:
- npx wait-on@7.0.1 http://$HOST:$PORT
- yarn playwright install --with-deps chromium
- yarn e2e:playwright --grep @plugins
- GRAFANA_URL=http://$HOST:$PORT yarn e2e:playwright --grep @plugins
depends_on:
- grafana-server
- build-test-plugins
@ -2986,6 +2986,6 @@ kind: secret
name: gcr_credentials
---
kind: signature
hmac: d20f1d6e2e8347701f82114ad352f53db57dc95b5b3831941fa93d063a92b9d8
hmac: 70e5888d6be34ca57086672bc58d6de7de0029210e4485190571452972774e54
...

@ -28,7 +28,6 @@
postUpdateOptions: ["yarnDedupeHighest"],
packageRules: [
{
automerge: true,
matchCurrentVersion: "!/^0/",
matchUpdateTypes: ["patch"],
matchPackageNames: ["!/^@?storybook/", "!/^@locker/"],

@ -14,8 +14,6 @@ import (
v0alpha1 "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1"
)
var ()
var appManifestData = app.ManifestData{
AppName: "iam",
Group: "iam.grafana.app",

@ -251,18 +251,20 @@ Each version of Playwright needs specific versions of browser binaries to operat
yarn playwright install chromium
```
To run all tests in a headless Chromium browser and display results in the terminal. This assumes you have Grafana running on port 3000.
The following script starts a Grafana [development server](https://github.com/grafana/grafana/blob/main/scripts/grafana-server/start-server) (same server that is being used when running e2e tests in CI) on port 3001 and runs all the Playwright tests. The development server is provisioned with the [devenv](https://github.com/grafana/grafana/blob/main/contribute/developer-guide.md#add-data-sources) dashboards, data sources and apps.
```
yarn e2e:playwright
```
The following script starts a Grafana [development server](https://github.com/grafana/grafana/blob/main/scripts/grafana-server/start-server) (same server that is being used when running e2e tests in Drone CI) on port 3001 and runs the Playwright tests. The development server is provisioned with the [devenv](https://github.com/grafana/grafana/blob/main/contribute/developer-guide.md#add-data-sources) dashboards, data sources and apps.
You can run against an arbitrary instance by setting the `GRAFANA_URL` environment variable:
```
yarn e2e:playwright:server
GRAFANA_URL=http://localhost:3000 yarn e2e:playwright
```
Note this will not start a development server, so you must ensure that Grafana is running and accessible at the specified URL.
## Configure Grafana for development
The default configuration, `defaults.ini`, is located in the `conf` directory.

@ -32,10 +32,12 @@ You can add Playwright end-to-end tests for plugins to the [`e2e-playwright/plug
- `yarn e2e:playwright` runs all Playwright tests. Optionally, you can provide the `--project mysql` argument to run tests in a specific project.
The `yarn e2e:playwright` script assumes you have Grafana running on `localhost:3000`. You may change this with an environment variable:
The `yarn e2e:playwright` command starts a Grafana [development server](https://github.com/grafana/grafana/blob/main/scripts/grafana-server/start-server) on port 3001 and runs the Playwright tests.
`HOST=127.0.0.1 PORT=3001 yarn e2e:playwright`
You can run against an arbitrary instance by setting the `GRAFANA_URL` environment variable:
The `yarn e2e:playwright:server` starts a Grafana [development server](https://github.com/grafana/grafana/blob/main/scripts/grafana-server/start-server) on port 3001 and runs the Playwright tests.
`GRAFANA_URL=http://localhost:3000 yarn e2e:playwright`
Note this will not start a development server, so you must ensure that Grafana is running and accessible at the specified URL.
- You can provision the development server with the [devenv](https://github.com/grafana/grafana/blob/main/contribute/developer-guide.md#add-data-sources) dashboards, data sources, and apps.

@ -0,0 +1,465 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 138,
"links": [],
"panels": [
{
"datasource": {
"type": "grafana-testdata-datasource",
"uid": "PD8C576611E62080A"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"custom": {
"align": "auto",
"cellOptions": {
"type": "auto",
"wrapText": false
},
"filterable": true,
"inspect": false,
"wrapHeaderText": false
},
"fieldMinMax": true,
"links": [],
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": 0
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": [
{
"matcher": {
"id": "byName",
"options": "A"
},
"properties": [
{
"id": "custom.cellOptions",
"value": {
"mode": "lcd",
"type": "gauge"
}
},
{
"id": "min",
"value": 0
},
{
"id": "max",
"value": 100
},
{
"id": "custom.width",
"value": 300
}
]
},
{
"matcher": {
"id": "byName",
"options": "Info"
},
"properties": [
{
"id": "links",
"value": [
{
"targetBlank": true,
"title": "Google this term",
"url": "https://google.com/search?q=${__value:percentencode}"
}
]
}
]
},
{
"matcher": {
"id": "byName",
"options": "Min"
},
"properties": []
},
{
"matcher": {
"id": "byName",
"options": "Max"
},
"properties": []
},
{
"matcher": {
"id": "byName",
"options": "State"
},
"properties": []
},
{
"matcher": {
"id": "byName",
"options": "Time"
},
"properties": [
{
"id": "custom.cellOptions",
"value": {
"type": "auto"
}
},
{
"id": "unit",
"value": "dateTimeFromNow"
}
]
},
{
"matcher": {
"id": "byName",
"options": "Image"
},
"properties": [
{
"id": "custom.cellOptions",
"value": {
"alt": "${__value}",
"type": "image"
}
}
]
},
{
"matcher": {
"id": "byRegexp",
"options": "/(Time|Min|Max|Info|State|Image)/"
},
"properties": [
{
"id": "custom.width",
"value": 110
}
]
},
{
"matcher": {
"id": "byName",
"options": "Info"
},
"properties": [
{
"id": "custom.cellOptions",
"value": {
"type": "color-text"
}
},
{
"id": "mappings",
"value": [
{
"options": {
"pattern": "up",
"result": {
"color": "green",
"index": 0
}
},
"type": "regex"
},
{
"options": {
"pattern": "down",
"result": {
"color": "red",
"index": 1
}
},
"type": "regex"
}
]
}
]
},
{
"matcher": {
"id": "byName",
"options": "Min"
},
"properties": [
{
"id": "custom.cellOptions",
"value": {
"mode": "basic",
"type": "color-background"
}
},
{
"id": "color",
"value": {
"fixedColor": "blue",
"mode": "continuous-YlRd"
}
}
]
},
{
"matcher": {
"id": "byName",
"options": "Max"
},
"properties": [
{
"id": "custom.cellOptions",
"value": {
"mode": "gradient",
"type": "color-background"
}
},
{
"id": "color",
"value": {
"mode": "continuous-purples"
}
}
]
},
{
"matcher": {
"id": "byName",
"options": "State"
},
"properties": [
{
"id": "displayName",
"value": "State"
},
{
"id": "custom.hidden",
"value": true
}
]
},
{
"matcher": {
"id": "byName",
"options": "Long Text"
},
"properties": [
{
"id": "custom.cellOptions",
"value": {
"type": "auto",
"wrapText": true
}
}
]
}
]
},
"gridPos": {
"h": 18,
"w": 24,
"x": 0,
"y": 0
},
"id": 1,
"options": {
"cellHeight": "sm",
"footer": {
"countRows": false,
"enablePagination": false,
"fields": "",
"reducer": [
"max"
],
"show": true
},
"frameIndex": 0,
"showHeader": true,
"sortBy": []
},
"pluginVersion": "12.1.0-pre",
"targets": [
{
"datasource": {
"type": "grafana-testdata-datasource",
"uid": "PD8C576611E62080A"
},
"refId": "A",
"scenarioId": "random_walk_table"
},
{
"csvContent": "Info,Image,Long Text\ndown,https://placecats.com/millie/300/300,\"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse tempus et augue et lacinia. Interdum et malesuada fames ac ante ipsum primis in faucibus. Donec eu pretium tortor. Cras venenatis sapien sed mauris gravida, ut scelerisque est fringilla. Cras lorem diam, facilisis nec malesuada in, vulputate vel enim. Etiam fringilla nisi quis felis blandit tincidunt. Cras id lacus ornare, ullamcorper nisl eget, bibendum odio. Pellentesque imperdiet, leo a imperdiet venenatis, ligula risus venenatis quam, vel euismod magna nisi sit amet leo.\"\nup,https://placecats.com/neo/300/300,\"Sed imperdiet eget diam sit amet fringilla. Curabitur quis lacus blandit, mollis diam non, accumsan tortor. Aliquam ac tellus eget dui facilisis tempor eu id nulla. Maecenas ultrices turpis eu elementum imperdiet. Fusce eget rhoncus mi, et egestas lectus. Mauris facilisis auctor enim sed malesuada. Maecenas placerat ultricies metus vitae viverra. In hac habitasse platea dictumst. Mauris ipsum nisl, dictum eu aliquam eleifend, rutrum id orci. Nullam eget dui et odio eleifend porttitor.\"\nup fast,https://placecats.com/bella/300/300,\"Proin ac libero vulputate ex vulputate pharetra ut vel lacus. Phasellus quis dolor sed leo finibus scelerisque. Ut vel finibus leo, sed viverra ipsum. Suspendisse vitae rutrum arcu. Donec sed tellus vel lectus bibendum vestibulum. Sed eu felis non velit dictum pulvinar eu et leo. Aenean et dignissim arcu. Nam luctus at neque quis efficitur. Fusce tempus at nibh a imperdiet. Nullam malesuada ac magna at facilisis. Duis pretium aliquam eros. Donec pharetra dignissim dolor non bibendum. Ut gravida mi id urna tempus, at ullamcorper felis vulputate. Duis congue augue ex, sed finibus leo ornare ut. Mauris non quam sodales, dignissim lorem eget, tincidunt mauris. Aliquam ut velit auctor, vestibulum metus sed, mollis massa.\"\ndown fast,https://placecats.com/neo_2/300/300,\"Nullam in pulvinar justo. Nunc dictum arcu ac pellentesque bibendum. Sed in erat turpis. Vestibulum eu orci ac ligula lobortis tempus. Fusce consectetur feugiat magna, eu tempor nibh vestibulum ac. Aliquam erat volutpat. Vivamus sit amet viverra enim. Quisque mollis odio nulla, nec vulputate sem placerat in. Etiam dolor sapien, pulvinar in accumsan at, consequat eget nisi. Nunc condimentum neque magna, congue consectetur dui efficitur interdum. Nam lobortis fringilla maximus. Vestibulum eu dui a velit condimentum eleifend consequat nec lectus.\"",
"datasource": {
"type": "grafana-testdata-datasource",
"uid": "PD8C576611E62080A"
},
"refId": "B",
"scenarioId": "csv_content"
}
],
"title": "Table - Kitchen Sink",
"transformations": [
{
"id": "joinByField",
"options": {
"byField": "Info",
"mode": "outerTabular"
}
},
{
"id": "organize",
"options": {
"excludeByName": {
"A": false
},
"includeByName": {},
"indexByName": {
"A": 7,
"Image": 5,
"Info": 1,
"Long Text": 6,
"Max A": 3,
"Min A": 2,
"State A": 4,
"Time A": 0
},
"orderBy": [],
"orderByMode": "manual",
"renameByName": {
"A": "Gauge",
"Info": "",
"Max A": "Max",
"Min A": "Min",
"State A": "State",
"Time": "Some really long title that requires wrapping",
"Time A": "Time",
"img_url": "Cat"
}
}
}
],
"type": "table"
},
{
"id": 2,
"type": "table",
"title": "Empty Table Panel",
"gridPos": {
"x": 0,
"y": 0,
"h": 6,
"w": 24
},
"fieldConfig": {
"defaults": {
"custom": {
"align": "auto",
"cellOptions": {
"type": "auto"
},
"inspect": false,
"wrapHeaderText": false
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"value": null,
"color": "green"
},
{
"value": 80,
"color": "red"
}
]
},
"color": {
"mode": "thresholds"
}
},
"overrides": []
},
"pluginVersion": "12.1.0-pre",
"targets": [
{
"scenarioId": "csv_content",
"refId": "A",
"csvContent": "a,b,c"
}
],
"datasource": {
"uid": "PD8C576611E62080A",
"type": "grafana-testdata-datasource"
},
"options": {
"showHeader": true,
"cellHeight": "sm",
"footer": {
"show": false,
"reducer": [
"sum"
],
"countRows": false,
"fields": ""
}
}
}
],
"preload": false,
"schemaVersion": 41,
"tags": [],
"templating": {
"list": [
{
"baseFilters": [],
"datasource": {
"type": "grafana-testdata-datasource",
"uid": "PD8C576611E62080A"
},
"filters": [],
"name": "Filters",
"type": "adhoc"
}
]
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "Panel Tests - Table - Kitchen Sink",
"uid": "dcb9f5e9-8066-4397-889e-864b99555dbb",
"version": 1
}

@ -93,6 +93,7 @@
"rows-to-fields": (import '../dev-dashboards/transforms/rows-to-fields.json'),
"shared_queries": (import '../dev-dashboards/panel-common/shared_queries.json'),
"slow_queries_and_annotations": (import '../dev-dashboards/scenarios/slow_queries_and_annotations.json'),
"table_kitchen_sink": (import '../dev-dashboards/panel-table/table_kitchen_sink.json'),
"table_pagination": (import '../dev-dashboards/panel-table/table_pagination.json'),
"table_sparkline_cell": (import '../dev-dashboards/panel-table/table_sparkline_cell.json'),
"table_tests": (import '../dev-dashboards/panel-table/table_tests.json'),

@ -106,3 +106,100 @@ To resolve issues flagged by Grafana Advisor and maintain system reliability, fo
- **Immediate Action:** Address "Action needed" items promptly to ensure system reliability
- **Systematic Review:** After fixing flagged issues, use the "Refresh" button to confirm all checks pass
- **Proactive Updates:** Address plugin update recommendations under "Investigation needed" even if they haven't caused failures yet
## How to create an alert based on Advisor results
This guide walks you through creating a Grafana alert that monitors Advisor check results and triggers when failures are detected.
### Step 1: Create a service account and token
1. Navigate to **Administration → Users and access → Service accounts** in your Grafana instance
2. Click **Add service account**
3. Provide a name (for example, "advisor-alert-service-account")
4. Set the role to **Admin** to ensure proper permissions
5. Click **Create**
6. In the service account details, click **Add service account token**
7. Provide a token name and set an appropriate expiration date
8. Click **Generate token**
> **Important**: Copy the token value immediately and store it securely - you won't be able to see it again
### Step 2: Set up the Grafana Infinity data source
> **Important**: Use Infinity plugin >=v3.3.0 for the JQ parser used later.
1. Go to **Connections → Add new connection**
2. Search for "Infinity"
3. If not installed, click **Install**. Wait for the plugin to be installed.
4. From the plugin page, click **Add new data source**.
5. Configure the data source:
- **Name**: Give it a descriptive name (e.g., "Advisor API")
- **Setup Authentication**: In the **Auth type**, select **Bearer Token**. In the **Auth details** section, paste the service account token from Step 1 and in the **Allowed hosts** section, write your Grafana app URL and click the "Add" button (e.g., `https://your-grafana-host.com`).
6. Click **Save & test** to verify the connection
### Step 3: Create the alert rule
Now you have everything you need to create an alert based on Advisor results.
1. Navigate to **Alerting → Alert rules**
2. Click **New alert rule**
3. Provide a rule name (e.g., "Advisor Failures Alert")
#### Configure the query
1. **Data source**: Select the Infinity data source created in Step 3
2. Configure the query settings:
- **Type**: JSON
- **Parser**: JQ
- **Source**: URL
- **Format**: Table
- **Method**: GET
- **URL**: Get this from the Advisor interface:
- Visit the Advisor in your Grafana instance
- Open browser Developer Tools (F12) → Network tab
- Look for a request ending with `/checks`
- Copy the full URL (format: `https://<your_grafana_host>/apis/advisor.grafana.app/v0alpha1/namespaces/<your_namespace>/checks`)
#### Configure parsing options
**Rows/Root** (paste this JQ expression):
```jq
.items | map({
type: .metadata.labels["advisor.grafana.app/type"],
creationTimestamp: .metadata.creationTimestamp,
failuresCount: (.status.report.failures | length)
}) | group_by(.type) | map(sort_by(.creationTimestamp) | last)
```
This JQ query processes Grafana Advisor check data to get the most recent result for each check type. It transforms each check into a simplified object with type, timestamp, and failure count.
The result is a clean array showing the current state of each check type (data source, plugin, configuration, etc.) with their failure counts, perfect for alerting when any type has failures > 0.
**Columns** (add these three columns):
- **Selector**: `creationTimestamp`, **Format**: Time
- **Selector**: `failuresCount`, **Format**: Number
- **Selector**: `type`, **Format**: String
#### Optional: Filter by check type
If you want to alert only for specific check types:
1. In the **Computed columns, Filter, Group by** section
2. Add a **Filter**: `type == "license"` (replace "license" with your desired check type)
#### Set alert condition
- **Alert condition**: Select "WHEN Last OF QUERY Is above 0"
- This will trigger when any check type has failures.
- Click on "Preview alert rule condition" to see the result of the query.
#### Complete alert configuration
Select your preferred evaluation (e.g. every 24 hours) and notification settings.
### Step 4: Save the alert rule
Click **Save** and check the alert is being triggered.
Your alert is now configured to monitor Advisor results and notify you when failures are detected!

@ -8,7 +8,7 @@ labels:
- cloud
- enterprise
- oss
menuTitle: Best Practices
menuTitle: Best practices
title: Grafana Alerting best practices
weight: 170
---

@ -271,6 +271,10 @@ resource "grafana_sso_settings" "azuread_sso_settings" {
allow_assign_grafana_admin = false
skip_org_role_sync = false
use_pkce = true
custom = {
domain_hint = "contoso.com"
force_use_graph_api = "true"
}
}
}
```

@ -7,6 +7,12 @@ const NUM_ROOT_DASHBOARDS = 60;
const NUM_NESTED_FOLDERS = 60;
const NUM_NESTED_DASHBOARDS = 60;
test.use({
featureToggles: {
tableNextGen: true,
},
});
// TODO change this test so it doesn't conflict with the existing dashboard browse test
// probably needs a separate user
test.describe.skip(
@ -101,7 +107,7 @@ test.describe.skip(
await expect(page.getByText('Nested folder 00')).toBeVisible();
// Get the table body container for scrolling
const tableBody = page.getByTestId(selectors.pages.BrowseDashboards.table.body).locator('> div');
const tableBody = page.getByRole('grid');
// Scroll the page and check visibility of next set of items
await tableBody.evaluate((el) => el.scrollTo(0, 2100));

@ -2,6 +2,12 @@ import { test, expect } from '@grafana/plugin-e2e';
import testDashboard from '../dashboards/DashboardLiveTest.json';
test.use({
featureToggles: {
tableNextGen: true,
},
});
test.describe(
'Dashboard Live streaming support',
{
@ -31,18 +37,10 @@ test.describe(
}
});
test('Should receive streaming data', async ({ gotoDashboardPage, selectors }) => {
test('Should receive streaming data', async ({ gotoDashboardPage, selectors, page }) => {
const dashboardPage = await gotoDashboardPage({ uid: dashboardUID });
await expect(dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('Live'))).toBeVisible();
await expect
.poll(
async () =>
await dashboardPage
.getByGrafanaSelector(selectors.components.Panels.Visualization.Table.body)
.getByRole('row')
.count()
)
.toBeGreaterThan(5);
await expect.poll(async () => await page.getByRole('grid').getByRole('row').count()).toBeGreaterThan(5);
});
}
);

@ -2,13 +2,19 @@ import { test, expect } from '@grafana/plugin-e2e';
const DASHBOARD_ID = 'P2jR04WVk';
test.use({
featureToggles: {
tableNextGen: true,
},
});
test.describe(
'Panels test: Geomap spatial operations',
{
tag: ['@panels'],
},
() => {
test('Tests location auto option', async ({ gotoDashboardPage, selectors }) => {
test('Tests location auto option', async ({ gotoDashboardPage, selectors, page }) => {
const dashboardPage = await gotoDashboardPage({
uid: DASHBOARD_ID,
queryParams: new URLSearchParams({ editPanel: '1' }),
@ -40,12 +46,12 @@ test.describe(
await locationInput.press('Enter');
await dashboardPage.getByGrafanaSelector(selectors.components.PanelEditor.toggleTableView).click({ force: true });
const tableHeader = dashboardPage.getByGrafanaSelector(selectors.components.Panels.Visualization.Table.header);
const tableHeader = page.getByRole('grid').getByRole('row').first();
await expect(tableHeader).toBeVisible();
await expect(tableHeader.getByText('Point')).toBeVisible();
});
test('Tests location coords option', async ({ gotoDashboardPage, dashboardPage, selectors }) => {
test('Tests location coords option', async ({ gotoDashboardPage, dashboardPage, selectors, page }) => {
await gotoDashboardPage({ uid: DASHBOARD_ID, queryParams: new URLSearchParams({ editPanel: '1' }) });
await dashboardPage.getByGrafanaSelector(selectors.components.Tab.title('Transformations')).click();
@ -90,7 +96,7 @@ test.describe(
await longitudeInput.press('Enter');
await dashboardPage.getByGrafanaSelector(selectors.components.PanelEditor.toggleTableView).click({ force: true });
const tableHeader = dashboardPage.getByGrafanaSelector(selectors.components.Panels.Visualization.Table.header);
const tableHeader = page.getByRole('grid').getByRole('row').first();
await expect(tableHeader).toBeVisible();
await expect(tableHeader.getByText('Point')).toBeVisible();
});
@ -99,6 +105,7 @@ test.describe(
gotoDashboardPage,
dashboardPage,
selectors,
page,
}) => {
await gotoDashboardPage({ uid: DASHBOARD_ID, queryParams: new URLSearchParams({ editPanel: '1' }) });
@ -136,12 +143,12 @@ test.describe(
await geohashFieldInput.press('Enter');
await dashboardPage.getByGrafanaSelector(selectors.components.PanelEditor.toggleTableView).click({ force: true });
const tableHeader = dashboardPage.getByGrafanaSelector(selectors.components.Panels.Visualization.Table.header);
const tableHeader = page.getByRole('grid').getByRole('row').first();
await expect(tableHeader).toBeVisible();
await expect(tableHeader.getByText('State 1')).toBeVisible();
});
test('Tests location lookup option', async ({ gotoDashboardPage, dashboardPage, selectors }) => {
test('Tests location lookup option', async ({ gotoDashboardPage, dashboardPage, selectors, page }) => {
await gotoDashboardPage({ uid: DASHBOARD_ID, queryParams: new URLSearchParams({ editPanel: '1' }) });
await dashboardPage.getByGrafanaSelector(selectors.components.Tab.title('Transformations')).click();
@ -186,7 +193,7 @@ test.describe(
await gazetteerFieldInput.press('Enter');
await dashboardPage.getByGrafanaSelector(selectors.components.PanelEditor.toggleTableView).click({ force: true });
const tableHeader = dashboardPage.getByGrafanaSelector(selectors.components.Panels.Visualization.Table.header);
const tableHeader = page.getByRole('grid').getByRole('row').first();
await expect(tableHeader).toBeVisible();
await expect(tableHeader.getByText('Geometry')).toBeVisible();
});

@ -2,6 +2,12 @@ import { test, expect } from '@grafana/plugin-e2e';
const PANEL_UNDER_TEST = 'Lines 500 data points';
test.use({
featureToggles: {
tableNextGen: true,
},
});
test.describe(
'Panels test: Panel edit base',
{
@ -65,7 +71,7 @@ test.describe(
// Check that table view works
await expect(dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.loadingBar(''))).toHaveCount(0);
await dashboardPage.getByGrafanaSelector(selectors.components.PanelEditor.toggleTableView).click({ force: true });
const tableHeader = dashboardPage.getByGrafanaSelector(selectors.components.Panels.Visualization.Table.header);
const tableHeader = page.getByRole('grid').getByRole('row').first();
await expect(tableHeader).toBeVisible();
await expect(tableHeader.getByText('A-series')).toBeVisible();

@ -0,0 +1,331 @@
import { Page, Locator } from '@playwright/test';
import { test, expect } from '@grafana/plugin-e2e';
test.use({
viewport: { width: 1600, height: 1080 },
featureToggles: {
tableNextGen: true,
},
});
// helper utils
const getCell = async (loc: Page | Locator, rowIdx: number, colIdx: number) =>
loc
.getByRole('row')
.nth(rowIdx)
.getByRole(rowIdx === 0 ? 'columnheader' : 'gridcell')
.nth(colIdx);
const getCellHeight = async (loc: Page | Locator, rowIdx: number, colIdx: number) => {
const cell = await getCell(loc, rowIdx, colIdx);
return (await cell.boundingBox())?.height ?? 0;
};
test.describe(
'Panels test: Table - Kitchen Sink',
{
tag: ['@panels'],
},
() => {
test('Tests word wrap, hover overflow, and cell inspect', async ({ gotoDashboardPage, selectors, page }) => {
const dashboardPage = await gotoDashboardPage({
uid: 'dcb9f5e9-8066-4397-889e-864b99555dbb',
queryParams: new URLSearchParams({ editPanel: '1' }),
});
await expect(
dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('Table - Kitchen Sink'))
).toBeVisible();
// text wrapping is enabled by default on this panel.
await expect(getCellHeight(page, 1, 5)).resolves.toBeGreaterThan(100);
// toggle the lorem ipsum column's wrap text toggle and confirm that the height shrinks.
await dashboardPage
.getByGrafanaSelector(selectors.components.PanelEditor.OptionsPane.fieldLabel('Wrap text'))
.last()
.click();
await expect(getCellHeight(page, 1, 5)).resolves.toBeLessThan(100);
// test that hover overflow works.
const loremIpsumCell = await getCell(page, 1, 5);
await loremIpsumCell.hover();
await expect(getCellHeight(page, 1, 5)).resolves.toBeGreaterThan(100);
await (await getCell(page, 1, 6)).hover();
await expect(getCellHeight(page, 1, 5)).resolves.toBeLessThan(100);
// enable cell inspect, confirm that hover no longer triggers.
await dashboardPage
.getByGrafanaSelector(
selectors.components.PanelEditor.OptionsPane.fieldLabel('Cell options Cell value inspect')
)
.first()
.locator('label[for="custom.inspect"]')
.click();
await loremIpsumCell.hover();
await expect(getCellHeight(page, 1, 5)).resolves.toBeLessThan(100);
// click cell inspect, check that cell inspection pops open in the side as we'd expect.
await loremIpsumCell.getByLabel('Inspect value').click();
const loremIpsumText = await loremIpsumCell.textContent();
expect(loremIpsumText).toBeDefined();
await expect(page.getByRole('dialog').getByText(loremIpsumText!)).toBeVisible();
});
test('Tests visibility and display name via overrides', async ({ gotoDashboardPage, selectors, page }) => {
const dashboardPage = await gotoDashboardPage({
uid: 'dcb9f5e9-8066-4397-889e-864b99555dbb',
queryParams: new URLSearchParams({ editPanel: '1' }),
});
await expect(
dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('Table - Kitchen Sink'))
).toBeVisible();
// confirm that "State" column is hidden by default.
expect(page.getByRole('row').nth(0)).not.toContainText('State');
// toggle the "State" column visibility and test that it appears before re-hiding it.
// FIXME this selector is utterly godawful, but there's no way to give testIds or aria-labels or anything to
// the panel editor builder. we should fix that to make e2e's easier to write for our team.
const hideStateColumnSwitch = page.locator('[id="Override 12"]').locator('label').last();
await hideStateColumnSwitch.click();
expect(page.getByRole('row').nth(0)).toContainText('State');
// now change the display name of the "State" column.
// FIXME it would be good to have a better selector here too.
const displayNameInput = page.locator('[id="Override 12"]').locator('input[value="State"]').last();
await displayNameInput.fill('State (renamed)');
await displayNameInput.press('Enter');
expect(page.getByRole('row').nth(0)).toContainText('State (renamed)');
});
// we test niche cases for sorting, filtering, pagination, etc. in a unit tests already.
// we mainly want to test the happiest paths for these in e2es as well to check for integration
// issues, but the unit tests can confirm that the internal logic works as expected much more quickly and thoroughly.
// hashtag testing pyramid.
test('Tests sorting by column', async ({ gotoDashboardPage, selectors, page }) => {
const dashboardPage = await gotoDashboardPage({
uid: 'dcb9f5e9-8066-4397-889e-864b99555dbb',
queryParams: new URLSearchParams({ editPanel: '1' }),
});
await expect(
dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('Table - Kitchen Sink'))
).toBeVisible();
// click the "State" column header to sort it.
const stateColumnHeader = await getCell(page, 0, 1);
await stateColumnHeader.getByText('Info').click();
await expect(stateColumnHeader).toHaveAttribute('aria-sort', 'ascending');
expect(getCell(page, 1, 1)).resolves.toContainText('down'); // down or down fast
await stateColumnHeader.getByText('Info').click();
await expect(stateColumnHeader).toHaveAttribute('aria-sort', 'descending');
expect(getCell(page, 1, 1)).resolves.toContainText('up'); // up or up fast
await stateColumnHeader.getByText('Info').click();
await expect(stateColumnHeader).not.toHaveAttribute('aria-sort');
});
test('Tests filtering within a column', async ({ gotoDashboardPage, selectors, page }) => {
const dashboardPage = await gotoDashboardPage({
uid: 'dcb9f5e9-8066-4397-889e-864b99555dbb',
queryParams: new URLSearchParams({ editPanel: '1' }),
});
await expect(
dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('Table - Kitchen Sink'))
).toBeVisible();
const stateColumnHeader = page.getByRole('columnheader').filter({ hasText: 'Info' });
// get the first value in the "State" column, filter it out, then check that it went away.
const firstStateValue = (await (await getCell(page, 1, 1)).textContent())!;
await stateColumnHeader
.getByTestId(selectors.components.Panels.Visualization.TableNG.Filters.HeaderButton)
.click();
const filterContainer = dashboardPage.getByGrafanaSelector(
selectors.components.Panels.Visualization.TableNG.Filters.Container
);
await expect(filterContainer).toBeVisible();
// select all, then click the first value to unselect it, filtering it out.
await filterContainer.getByTestId(selectors.components.Panels.Visualization.TableNG.Filters.SelectAll).click();
await filterContainer.getByTitle(firstStateValue, { exact: true }).locator('label').click();
await filterContainer.getByRole('button', { name: 'Ok' }).click();
// make sure the filter container closed when we clicked "Ok".
await expect(filterContainer).not.toBeVisible();
// did it actually filter out our value?
await expect(getCell(page, 1, 1)).resolves.not.toHaveText(firstStateValue);
});
test('Tests pagination, row height adjustment', async ({ gotoDashboardPage, selectors, page }) => {
const rowRe = /([\d]+) - ([\d]+) of ([\d]+) rows/;
const getRowStatus = async (page: Page | Locator) => {
const text = (await page.getByText(rowRe).textContent()) ?? '';
const match = text.match(rowRe);
return {
start: parseInt(match?.[1] ?? '0', 10),
end: parseInt(match?.[2] ?? '0', 10),
total: parseInt(match?.[3] ?? '0', 10),
};
};
const dashboardPage = await gotoDashboardPage({
uid: 'dcb9f5e9-8066-4397-889e-864b99555dbb',
queryParams: new URLSearchParams({ editPanel: '1' }),
});
await expect(
dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('Table - Kitchen Sink'))
).toBeVisible();
await page
.getByLabel(selectors.components.PanelEditor.OptionsPane.fieldLabel(`Enable pagination`), { exact: true })
.click();
// because of text wrapping, we're guaranteed to only be showing a single row when we enable pagination.
await expect(page.getByText(/([\d]+) - ([\d]+) of ([\d]+) rows/)).toBeVisible();
// disable text wrap and see the number of rows.
await dashboardPage
.getByGrafanaSelector(selectors.components.PanelEditor.OptionsPane.fieldLabel('Wrap text'))
.last()
.click();
// any number of rows that is not "1" is allowed here, we don't want to police the exact number of rows that
// are rendered since there are tons of factors which could effect this. we do want to grab this number for comparison
// in a second, though.
const smallRowStatus = await getRowStatus(page);
expect(smallRowStatus.end).toBeGreaterThan(1);
expect(page.getByRole('grid').getByRole('row')).toHaveCount(smallRowStatus.end + 1);
// change cell height to Large
await dashboardPage
.getByGrafanaSelector(selectors.components.PanelEditor.OptionsPane.fieldLabel('Table Cell height'))
.locator('input')
.last()
.click();
const largeRowStatus = await getRowStatus(page);
expect(largeRowStatus.end).toBeLessThan(smallRowStatus.end);
expect(page.getByRole('grid').getByRole('row')).toHaveCount(largeRowStatus.end + 1);
// click a page over with the directional nav
await page.getByLabel('next page').click();
const nextPageStatus = await getRowStatus(page);
expect(nextPageStatus.start).toBe(largeRowStatus.end + 1);
expect(nextPageStatus.end).toBe(largeRowStatus.end * 2);
expect(nextPageStatus.total).toBe(largeRowStatus.total);
// click a page number
await page
.getByTestId('data-testid panel content')
.getByRole('navigation')
.getByText('4', { exact: true })
.click();
const fourthPageStatus = await getRowStatus(page);
expect(fourthPageStatus.start).toBe(largeRowStatus.end * 3 + 1);
expect(fourthPageStatus.end).toBe(largeRowStatus.end * 4);
expect(fourthPageStatus.total).toBe(largeRowStatus.total);
});
test('Tests DataLinks (single and multi) and actions', async ({ gotoDashboardPage, selectors, page }) => {
const addDataLink = async (title: string, url: string) => {
await dashboardPage
.getByGrafanaSelector(
selectors.components.PanelEditor.OptionsPane.fieldLabel('Data links and actions Data links')
)
.locator('button')
.filter({ hasText: 'Add link' })
.click();
// DataLinks dialog has popped open - fill it in and add a global datalink.
await expect(page.getByRole('dialog')).toBeVisible();
await page.getByRole('dialog').locator('#link-title').fill(title);
await page.getByRole('dialog').locator('#data-link-input [contenteditable="true"]').focus();
await page.getByRole('dialog').locator('#data-link-input [contenteditable="true"]').fill(url);
await page.getByRole('dialog').locator('#data-link-input [contenteditable="true"]').blur();
await page.getByRole('dialog').getByRole('button', { name: 'Save' }).click();
await expect(page.getByRole('dialog')).not.toBeVisible();
};
const dashboardPage = await gotoDashboardPage({
uid: 'dcb9f5e9-8066-4397-889e-864b99555dbb',
queryParams: new URLSearchParams({ editPanel: '1' }),
});
await expect(
dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('Table - Kitchen Sink'))
).toBeVisible();
// disable text wrapping for this test to make it easier to click the links, the long lorem ipsum
// can push the links off the screen.
await dashboardPage
.getByGrafanaSelector(selectors.components.PanelEditor.OptionsPane.fieldLabel('Wrap text'))
.last()
.click();
// Info column has a single DataLink by default.
const infoCell = await getCell(page, 1, 1);
await expect(infoCell.locator('a')).toBeVisible();
expect(infoCell.locator('a')).toHaveAttribute('href');
expect(infoCell.locator('a')).not.toHaveAttribute('aria-haspopup');
// now, add a DataLink to the whole table
await addDataLink('Test link', 'https://grafana.com');
// add a DataLink to the whole table, all cells will now have a single link.
const colCount = await page.getByRole('row').nth(1).getByRole('gridcell').count();
for (let colIdx = 0; colIdx < colCount; colIdx++) {
const cell = await getCell(page, 1, colIdx);
await expect(cell.locator('a')).toBeVisible();
expect(cell.locator('a')).toHaveAttribute('href');
expect(cell.locator('a')).not.toHaveAttribute('aria-haspopup', 'menu');
}
const headerContainer = dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.headerContainer);
// add another data link. now we'll check that the multi-link popups work.
await addDataLink('Another test link', 'https://grafana.com/foo');
// loop thru the columns, click the links, observe that the tooltip appears, and close the tooltip.
for (let colIdx = 0; colIdx < colCount; colIdx++) {
const cell = await getCell(page, 1, colIdx);
if (colIdx === 1) {
// the Info column should still have its single link.
expect(cell.locator('a')).not.toHaveAttribute('aria-haspopup', 'menu');
continue;
}
await cell.locator('a').click({ force: true });
await expect(page.getByTestId(selectors.components.DataLinksActionsTooltip.tooltipWrapper)).toBeVisible();
await headerContainer.click(); // convenient just to click the header to close the tooltip.
await expect(page.getByTestId(selectors.components.DataLinksActionsTooltip.tooltipWrapper)).not.toBeVisible();
}
// add an Action to the whole table and check that the action button is added to the tooltip.
// TODO -- saving for another day.
});
test('Empty Table panel', async ({ gotoDashboardPage, selectors }) => {
const dashboardPage = await gotoDashboardPage({
uid: 'dcb9f5e9-8066-4397-889e-864b99555dbb',
queryParams: new URLSearchParams({ editPanel: '2' }),
});
await expect(
dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.PanelDataErrorMessage)
).toBeVisible();
await expect(
dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('Table - Kitchen Sink'))
).not.toBeVisible();
});
}
);

@ -0,0 +1,29 @@
import { test, expect } from '@grafana/plugin-e2e';
test.use({
viewport: { width: 1280, height: 1080 },
featureToggles: {
tableNextGen: true,
},
});
test.describe(
'Panels test: Table - Sparkline',
{
tag: ['@panels'],
},
() => {
test('Tests sparkline tables are successfully rendered', async ({ gotoDashboardPage, selectors, page }) => {
await gotoDashboardPage({
uid: 'd6373b49-1957-4f00-9218-ee2120d3ecd9',
queryParams: new URLSearchParams({ editPanel: '2' }),
});
await expect(page.getByRole('grid')).toBeVisible();
const uplotCount = await page.locator('.uplot').count();
const rowCount = await page.getByRole('row').count();
expect(uplotCount).toBe(rowCount - 1);
});
}
);

@ -11,6 +11,12 @@ const STANDARD_OTIONS_CATEGORY = 'Standard options';
const DISPLAY_NAME_LABEL = 'Display name';
const REACT_TABLE_DASHBOARD = { uid: 'U_bZIMRMk' };
test.use({
featureToggles: {
tableNextGen: true,
},
});
test.describe(
'plugin-e2e-api-tests admin',
{
@ -53,7 +59,7 @@ test.describe(
).toHaveText(scenarios.map((s) => s.name));
});
test('mocked query data response', async ({ panelEditPage, selectors }) => {
test('mocked query data response', async ({ panelEditPage, page }) => {
await panelEditPage.mockQueryDataResponse(successfulDataQuery, 200);
await panelEditPage.datasource.set('gdev-testdata');
await panelEditPage.setVisualization(TABLE_VIZ_NAME);
@ -63,9 +69,9 @@ test.describe(
formatExpectError('Did not expect panel error to be displayed after query execution')
).toBeHidden();
await expect(
panelEditPage.getByGrafanaSelector(selectors.components.Panels.Visualization.Table.body),
page.getByRole('grid'),
formatExpectError('Expected certain select options to be displayed after clicking on the select input')
).toHaveText('val1val2val3val4');
).toHaveText(/val1val2val3val4/);
});
});

@ -15,9 +15,6 @@ fi
if [ "$BASE_URL" != "" ]; then
echo -e "BASE_URL set, skipping starting server"
else
# Start it in the background
./scripts/grafana-server/start-server $LICENSE_PATH 2>&1 > scripts/grafana-server/server.log &
./scripts/grafana-server/wait-for-grafana
./scripts/grafana-server/start-server $LICENSE_PATH > scripts/grafana-server/server.log
fi
PORT=3001 HOST=localhost yarn playwright test

@ -31,7 +31,7 @@ test.describe(
await expect(sandboxDiv).toBeHidden();
const appPage = page.getByTestId('sandbox-app-test-page-one');
await expect(appPage).toBeVisible();
await expect(appPage).toBeVisible({ timeout: 10000 });
});
test('Loads the app configuration without the sandbox div wrapper', async ({ page }) => {
@ -41,7 +41,7 @@ test.describe(
await expect(sandboxDiv).toBeHidden();
const configPage = page.getByTestId('sandbox-app-test-config-page');
await expect(configPage).toBeVisible();
await expect(configPage).toBeVisible({ timeout: 10000 });
});
});
@ -59,7 +59,7 @@ test.describe(
await expect(sandboxDiv).toBeVisible();
const appPage = page.getByTestId('sandbox-app-test-page-one');
await expect(appPage).toBeVisible();
await expect(appPage).toBeVisible({ timeout: 10000 });
});
test('Loads the app configuration with the sandbox div wrapper', async ({ page }) => {
@ -69,7 +69,7 @@ test.describe(
await expect(sandboxDiv).toBeVisible();
const configPage = page.getByTestId('sandbox-app-test-config-page');
await expect(configPage).toBeVisible();
await expect(configPage).toBeVisible({ timeout: 10000 });
});
});
});

@ -1,5 +1,11 @@
import { test, expect } from '@grafana/plugin-e2e';
test.use({
featureToggles: {
tableNextGen: true,
},
});
test.describe(
'Visualization suggestions',
{
@ -39,9 +45,7 @@ test.describe(
await panelEditPage.getByGrafanaSelector(selectors.components.VisualizationPreview.card('Table')).click();
// Verify table header is visible
await expect(
panelEditPage.getByGrafanaSelector(selectors.components.Panels.Visualization.Table.header)
).toBeVisible();
await expect(page.getByRole('grid').getByRole('row').first()).toBeVisible();
});
}
);

@ -9,7 +9,7 @@ describe.skip('Dashboard Live streaming support', () => {
});
it('Should receive streaming data', () => {
e2e.flows.openDashboard({ uid: 'live-e2e-test' });
e2e.flows.openDashboard({ uid: 'live-e2e-test', queryParams: { '__feature.tableNextGen': false } });
cy.wait(1000);
e2e.components.Panels.Panel.title('Live').should('exist');
e2e.components.Panels.Visualization.Table.body().find('[role="row"]').should('have.length.at.least', 5);

@ -8,7 +8,7 @@ describe('Dashboard Live streaming support', () => {
});
it('Should receive streaming data', () => {
e2e.flows.openDashboard({ uid: 'live-e2e-test' });
e2e.flows.openDashboard({ uid: 'live-e2e-test', queryParams: { '__feature.tableNextGen': false } });
cy.wait(1000);
e2e.components.Panels.Panel.title('Live').should('exist');
e2e.components.Panels.Visualization.Table.body().find('[role="row"]').should('have.length.at.least', 5);

@ -8,7 +8,7 @@ describe.skip('Geomap spatial operations', () => {
});
it.skip('Tests location auto option', () => {
e2e.flows.openDashboard({ uid: DASHBOARD_ID, queryParams: { editPanel: 1 } });
e2e.flows.openDashboard({ uid: DASHBOARD_ID, queryParams: { '__feature.tableNextGen': false, editPanel: 1 } });
e2e.components.Tab.title('Transform data').should('be.visible').click();
e2e.components.Transforms.addTransformationButton().scrollIntoView().should('be.visible').click();
@ -26,7 +26,7 @@ describe.skip('Geomap spatial operations', () => {
});
it('Tests location coords option', () => {
e2e.flows.openDashboard({ uid: DASHBOARD_ID, queryParams: { editPanel: 1 } });
e2e.flows.openDashboard({ uid: DASHBOARD_ID, queryParams: { '__feature.tableNextGen': false, editPanel: 1 } });
e2e.components.Tab.title('Transform data').should('be.visible').click();
e2e.components.Transforms.addTransformationButton().scrollIntoView().should('be.visible').click();
@ -50,7 +50,7 @@ describe.skip('Geomap spatial operations', () => {
});
it('Tests geoshash field column appears in table view', () => {
e2e.flows.openDashboard({ uid: DASHBOARD_ID, queryParams: { editPanel: 1 } });
e2e.flows.openDashboard({ uid: DASHBOARD_ID, queryParams: { '__feature.tableNextGen': false, editPanel: 1 } });
e2e.components.Tab.title('Transform data').should('be.visible').click();
e2e.components.Transforms.addTransformationButton().scrollIntoView().should('be.visible').click();
@ -73,7 +73,7 @@ describe.skip('Geomap spatial operations', () => {
});
it('Tests location lookup option', () => {
e2e.flows.openDashboard({ uid: DASHBOARD_ID, queryParams: { editPanel: 1 } });
e2e.flows.openDashboard({ uid: DASHBOARD_ID, queryParams: { '__feature.tableNextGen': false, editPanel: 1 } });
e2e.components.Tab.title('Transform data').should('be.visible').click();
e2e.components.Transforms.addTransformationButton().scrollIntoView().should('be.visible').click();

@ -11,7 +11,7 @@ describe('Panel edit tests', () => {
cy.intercept({
pathname: '/api/ds/query',
}).as('query');
e2e.flows.openDashboard({ uid: 'TkZXxlNG3' });
e2e.flows.openDashboard({ uid: 'TkZXxlNG3', queryParams: { '__feature.tableNextGen': false } });
cy.wait('@query');
e2e.flows.openPanelMenuItem(e2e.flows.PanelMenuItems.Edit, PANEL_UNDER_TEST);

@ -6,7 +6,7 @@ describe('Visualization suggestions', () => {
});
it('Should be shown and clickable', () => {
e2e.flows.openDashboard({ uid: 'aBXrJ0R7z', queryParams: { editPanel: 9 } });
e2e.flows.openDashboard({ uid: 'aBXrJ0R7z', queryParams: { '__feature.tableNextGen': false, editPanel: 9 } });
// Try visualization suggestions
e2e.components.PanelEditor.toggleVizPicker().click();

@ -8,7 +8,7 @@ describe.skip('Geomap spatial operations', () => {
});
it('Tests location auto option', () => {
e2e.flows.openDashboard({ uid: DASHBOARD_ID, queryParams: { editPanel: 1 } });
e2e.flows.openDashboard({ uid: DASHBOARD_ID, queryParams: { '__feature.tableNextGen': false, editPanel: 1 } });
e2e.components.Tab.title('Transformations').should('be.visible').click();
e2e.components.Transforms.addTransformationButton().scrollIntoView().should('be.visible').click();
@ -26,7 +26,7 @@ describe.skip('Geomap spatial operations', () => {
});
it('Tests location coords option', () => {
e2e.flows.openDashboard({ uid: DASHBOARD_ID, queryParams: { editPanel: 1 } });
e2e.flows.openDashboard({ uid: DASHBOARD_ID, queryParams: { '__feature.tableNextGen': false, editPanel: 1 } });
e2e.components.Tab.title('Transformations').should('be.visible').click();
e2e.components.Transforms.addTransformationButton().scrollIntoView().should('be.visible').click();
@ -50,7 +50,7 @@ describe.skip('Geomap spatial operations', () => {
});
it('Tests geoshash field column appears in table view', () => {
e2e.flows.openDashboard({ uid: DASHBOARD_ID, queryParams: { editPanel: 1 } });
e2e.flows.openDashboard({ uid: DASHBOARD_ID, queryParams: { '__feature.tableNextGen': false, editPanel: 1 } });
e2e.components.Tab.title('Transformations').should('be.visible').click();
e2e.components.Transforms.addTransformationButton().scrollIntoView().should('be.visible').click();
@ -73,7 +73,7 @@ describe.skip('Geomap spatial operations', () => {
});
it('Tests location lookup option', () => {
e2e.flows.openDashboard({ uid: DASHBOARD_ID, queryParams: { editPanel: 1 } });
e2e.flows.openDashboard({ uid: DASHBOARD_ID, queryParams: { '__feature.tableNextGen': false, editPanel: 1 } });
e2e.components.Tab.title('Transformations').should('be.visible').click();
e2e.components.Transforms.addTransformationButton().scrollIntoView().should('be.visible').click();

@ -13,7 +13,7 @@ describe('Panel edit tests', () => {
cy.intercept({
pathname: '/api/ds/query',
}).as('query');
e2e.flows.openDashboard({ uid: 'TkZXxlNG3' });
e2e.flows.openDashboard({ uid: 'TkZXxlNG3', queryParams: { '__feature.tableNextGen': false } });
cy.wait('@query');
e2e.components.Panels.Panel.title('Lines 500 data points')

@ -6,7 +6,7 @@ describe('Visualization suggestions', () => {
});
it('Should be shown and clickable', () => {
e2e.flows.openDashboard({ uid: 'aBXrJ0R7z', queryParams: { editPanel: 9 } });
e2e.flows.openDashboard({ uid: 'aBXrJ0R7z', queryParams: { '__feature.tableNextGen': false, editPanel: 9 } });
// Try visualization suggestions
e2e.components.PanelEditor.toggleVizPicker().click();

@ -104,7 +104,7 @@ require (
github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79 // @grafana/grafana-backend-group
github.com/grafana/grafana-plugin-sdk-go v0.278.0 // @grafana/plugins-platform-backend
github.com/grafana/loki/v3 v3.2.1 // @grafana/observability-logs
github.com/grafana/nanogit v0.0.0-20250709085038-55508a6a9f40 // @grafana-app-platform-squad
github.com/grafana/nanogit v0.0.0-20250717084510-7027b3f0138e // @grafana-app-platform-squad
github.com/grafana/otel-profiling-go v0.5.1 // @grafana/grafana-backend-group
github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // @grafana/observability-traces-and-profiling
github.com/grafana/pyroscope/api v1.2.1-0.20250415190842-3ff7247547ae // @grafana/observability-traces-and-profiling

@ -1641,8 +1641,8 @@ github.com/grafana/loki/pkg/push v0.0.0-20231124142027-e52380921608 h1:ZYk42718k
github.com/grafana/loki/pkg/push v0.0.0-20231124142027-e52380921608/go.mod h1:f3JSoxBTPXX5ec4FxxeC19nTBSxoTz+cBgS3cYLMcr0=
github.com/grafana/loki/v3 v3.2.1 h1:VB7u+KHfvL5aHAxgoVBvz5wVhsdGuqKC7uuOFOOe7jw=
github.com/grafana/loki/v3 v3.2.1/go.mod h1:WvdLl6wOS+yahaeQY+xhD2m2XzkHDfKr5FZaX7D/X2Y=
github.com/grafana/nanogit v0.0.0-20250709085038-55508a6a9f40 h1:wsIgOI4Ou1o/UtxtJlemLufpVBpMdcXVJxedk0wLoCM=
github.com/grafana/nanogit v0.0.0-20250709085038-55508a6a9f40/go.mod h1:ToqLjIdvV3AZQa3K6e5m9hy/nsGaUByc2dWQlctB9iA=
github.com/grafana/nanogit v0.0.0-20250717084510-7027b3f0138e h1:IcrC8SqJcNbGlNq0nqptJ4X8pyy21smMaFrhA7DrfYg=
github.com/grafana/nanogit v0.0.0-20250717084510-7027b3f0138e/go.mod h1:ToqLjIdvV3AZQa3K6e5m9hy/nsGaUByc2dWQlctB9iA=
github.com/grafana/otel-profiling-go v0.5.1 h1:stVPKAFZSa7eGiqbYuG25VcqYksR6iWvF3YH66t4qL8=
github.com/grafana/otel-profiling-go v0.5.1/go.mod h1:ftN/t5A/4gQI19/8MoWurBEtC6gFw8Dns1sJZ9W4Tls=
github.com/grafana/prometheus-alertmanager v0.25.1-0.20250620093340-be61a673dee6 h1:oJnbhG6ZNy10AjsgNeAtAKeGHogIGOMfAsBH6fYYa5M=

@ -24,6 +24,6 @@ use (
./pkg/semconv
)
replace github.com/prometheus/alertmanager => github.com/grafana/prometheus-alertmanager v0.25.1-0.20250604130045-92c8f6389b36
replace github.com/prometheus/alertmanager => github.com/grafana/prometheus-alertmanager v0.25.1-0.20250620093340-be61a673dee6
replace github.com/crewjam/saml => github.com/grafana/saml v0.4.15-0.20240917091248-ae3bbdad8a56

@ -24,7 +24,6 @@
"e2e:enterprise:dev": "./e2e/start-and-run-suite enterprise dev",
"e2e:enterprise:debug": "./e2e/start-and-run-suite enterprise debug",
"e2e:playwright": "yarn playwright test",
"e2e:playwright:server": "yarn e2e:plugin:build && ./e2e-playwright/start-and-run-suite",
"e2e:playwright:storybook": "yarn playwright test -c playwright.storybook.config.ts",
"e2e:storybook": "PORT=9001 ./e2e/run-suite storybook true",
"e2e:plugin:build": "nx run-many -t build --projects='@test-plugins/*'",
@ -47,7 +46,7 @@
"prettier:check": "prettier --check --ignore-path .prettierignore --list-different=false --log-level=warn \"**/*.{ts,tsx,scss,md,mdx,json,js,cjs}\"",
"prettier:checkDocs": "prettier --check --list-different=false --log-level=warn \"docs/**/*.md\" \"*.md\" \"packages/**/*.{ts,tsx,scss,md,mdx,json,js,cjs}\"",
"prettier:write": "prettier --ignore-path .prettierignore --list-different \"**/*.{js,ts,tsx,scss,md,mdx,json,cjs}\" --write",
"start": "yarn predev && NODE_ENV=dev nx exec -- webpack --config scripts/webpack/webpack.dev.js --watch",
"start": "yarn predev && NODE_ENV=dev nx exec -- webpack --config scripts/webpack/webpack.dev.js --watch $@",
"start:liveReload": "yarn start -- --env liveReload=1",
"start:noTsCheck": "yarn start -- --env noTsCheck=1",
"start:noLint": "yarn start -- --env noTsCheck=1 --env noLint=1",
@ -80,9 +79,9 @@
},
"devDependencies": {
"@arethetypeswrong/cli": "^0.18.2",
"@babel/core": "7.26.10",
"@babel/preset-env": "7.26.9",
"@babel/runtime": "7.27.0",
"@babel/core": "7.28.0",
"@babel/preset-env": "7.28.0",
"@babel/runtime": "7.27.6",
"@betterer/betterer": "5.4.0",
"@betterer/cli": "5.4.0",
"@crowdin/crowdin-api-client": "^1.42.0",
@ -185,7 +184,7 @@
"esbuild": "0.25.6",
"esbuild-loader": "4.3.0",
"esbuild-plugin-browserslist": "^1.0.0",
"eslint": "9.19.0",
"eslint": "9.28.0",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jest": "28.11.0",
@ -240,12 +239,12 @@
"redux-mock-store": "1.5.5",
"rimraf": "6.0.1",
"sass": "1.83.4",
"sass-loader": "16.0.4",
"sass-loader": "16.0.5",
"smtp-tester": "^2.1.0",
"style-loader": "4.0.0",
"stylelint": "16.14.1",
"stylelint-config-sass-guidelines": "12.1.0",
"terser-webpack-plugin": "5.3.11",
"terser-webpack-plugin": "5.3.14",
"testing-library-selector": "0.3.1",
"tracelib": "1.0.1",
"ts-jest": "29.2.5",
@ -254,9 +253,8 @@
"webpack": "5.97.1",
"webpack-assets-manifest": "^5.1.0",
"webpack-cli": "6.0.1",
"webpack-dev-server": "5.2.1",
"webpack-livereload-plugin": "3.0.2",
"webpack-manifest-plugin": "5.0.0",
"webpack-manifest-plugin": "5.0.1",
"webpack-merge": "6.0.1",
"webpack-subresource-integrity": "^5.2.0-rc.1",
"webpackbar": "^7.0.0",
@ -361,7 +359,7 @@
"lru-cache": "11.1.0",
"lru-memoize": "^1.1.0",
"lucene": "^2.1.1",
"marked": "16.0.0",
"marked": "16.1.1",
"memoize-one": "6.0.0",
"micro-memoize": "^4.1.2",
"ml-regression-polynomial": "^3.0.0",
@ -427,8 +425,8 @@
"type-fest": "^4.18.2",
"uplot": "1.6.32",
"uuid": "11.1.0",
"vis-data": "^7.1.10",
"vis-network": "9.1.13",
"vis-data": "^8.0.0",
"vis-network": "10.0.1",
"whatwg-fetch": "3.6.20"
},
"resolutions": {

@ -75,7 +75,7 @@
"react-redux": "^9.2.0",
"rimraf": "^6.0.1",
"rollup": "^4.22.4",
"rollup-plugin-esbuild": "6.2.0",
"rollup-plugin-esbuild": "6.2.1",
"rollup-plugin-node-externals": "^8.0.0",
"type-fest": "^4.40.0",
"typescript": "5.8.3"

@ -68,7 +68,7 @@
"fast_array_intersect": "1.1.0",
"history": "4.10.1",
"lodash": "4.17.21",
"marked": "16.0.0",
"marked": "16.1.1",
"marked-mangle": "1.1.11",
"moment": "2.30.1",
"moment-timezone": "0.5.47",
@ -97,7 +97,7 @@
"react-dom": "18.3.1",
"rimraf": "6.0.1",
"rollup": "^4.22.4",
"rollup-plugin-esbuild": "6.2.0",
"rollup-plugin-esbuild": "6.2.1",
"rollup-plugin-node-externals": "^8.0.0",
"typescript": "5.8.3"
},

@ -1055,4 +1055,8 @@ export interface FeatureToggles {
* @default false
*/
pluginAssetProvider?: boolean;
/**
* Enable dual reader for unified storage search
*/
unifiedStorageSearchDualReaderEnabled?: boolean;
}

@ -45,7 +45,7 @@
"esbuild": "0.25.6",
"rimraf": "6.0.1",
"rollup": "^4.22.4",
"rollup-plugin-esbuild": "6.2.0",
"rollup-plugin-esbuild": "6.2.1",
"rollup-plugin-node-externals": "^8.0.0"
},
"dependencies": {

@ -481,6 +481,19 @@ export const versionedComponents = {
'10.2.0': 'data-testid table body',
},
},
TableNG: {
Filters: {
HeaderButton: {
'12.1.0': 'data-testid tableng header filter',
},
Container: {
'12.1.0': 'data-testid tablenf filter container',
},
SelectAll: {
'12.1.0': 'data-testid tableng filter select-all',
},
},
},
},
},
VizLegend: {

@ -18,7 +18,7 @@
},
"devDependencies": {
"@typescript-eslint/types": "^8.9.0",
"eslint": "9.19.0",
"eslint": "9.28.0",
"tslib": "2.8.1"
},
"private": true

@ -56,9 +56,9 @@
"tslib": "2.8.1"
},
"devDependencies": {
"@babel/core": "7.26.10",
"@babel/preset-env": "7.26.9",
"@babel/preset-react": "7.26.3",
"@babel/core": "7.28.0",
"@babel/preset-env": "7.28.0",
"@babel/preset-react": "7.27.1",
"@grafana/tsconfig": "^2.0.0",
"@rollup/plugin-node-resolve": "16.0.1",
"@testing-library/dom": "10.4.0",
@ -77,7 +77,7 @@
"jest": "^29.6.4",
"jest-canvas-mock": "2.5.2",
"rollup": "^4.22.4",
"rollup-plugin-esbuild": "6.2.0",
"rollup-plugin-esbuild": "6.2.1",
"rollup-plugin-node-externals": "^8.0.0",
"ts-jest": "29.2.5",
"ts-node": "10.9.2",

@ -15,7 +15,7 @@
"@types/eslint": "9.6.1",
"@types/webpack-bundle-analyzer": "^4.7.0",
"copy-webpack-plugin": "12.0.2",
"eslint": "9.19.0",
"eslint": "9.28.0",
"eslint-webpack-plugin": "4.2.0",
"fork-ts-checker-webpack-plugin": "9.0.2",
"glob": "11.0.3",

@ -99,7 +99,7 @@
"react-select-event": "5.5.1",
"rimraf": "6.0.1",
"rollup": "^4.22.4",
"rollup-plugin-esbuild": "6.2.0",
"rollup-plugin-esbuild": "6.2.1",
"rollup-plugin-node-externals": "^8.0.0",
"testing-library-selector": "0.3.1",
"typescript": "5.8.3"

@ -2,201 +2,201 @@
"grafana-prometheus": {
"components": {
"annotation-query-editor": {
"annotation-data-load-error": "",
"aria-label-lower-limit-parameter": "",
"label-min-step": "",
"label-series-value-as-timestamp": "",
"annotation-data-load-error": "Fehler beim Laden der Anmerkungsdaten!",
"aria-label-lower-limit-parameter": "Untergrenze für den Schrittparameter festlegen",
"label-min-step": "Min. Schritt",
"label-series-value-as-timestamp": "Reihenwert als Zeitstempel",
"label-tags": "Tags",
"label-text": "",
"label-text": "Text",
"label-title": "Titel",
"placeholder-auto": "",
"tooltip-either-pattern-example-instance-replaced-label": "",
"tooltip-min-step": "",
"tooltip-timestamp-milliseconds-series-value-seconds-multiply": ""
"placeholder-auto": "Auto",
"tooltip-either-pattern-example-instance-replaced-label": "Verwenden Sie entweder den Namen oder ein Muster. Ein Beispiel: {{labelTemplate}} wird durch den Label-Wert für das Label {{labelName}} ersetzt.",
"tooltip-min-step": "Eine zusätzliche Untergrenze für den Schrittparameter der Prometheus-Abfrage und für die Variablen <2>{{intervalVar}}</2> und <4>{{rateIntervalVar}}</4>.",
"tooltip-timestamp-milliseconds-series-value-seconds-multiply": "Die Einheit des Zeitstempels ist Millisekunden. Wenn die Einheit des Reihenwerts Sekunden ist, multiplizieren Sie den Bereichsvektor mit 1000."
},
"get-query-type-options": {
"description": {
"instant-query-range": ""
"instant-query-range": "Eine Instant-Abfrage und eine Bereichsabfrage ausführen"
},
"label": {
"both": ""
"both": "Beides"
},
"range-options": {
"description": {
"query-range": ""
"query-range": "Abfrage über einen bestimmten Zeitraum ausführen"
},
"label": {
"instant": "",
"range": ""
"instant": "Instant",
"range": "Bereich"
}
}
},
"label-selector": {
"aria-label-filter-expression-for-label": "",
"description-select-labels": "",
"select-labels-to-search-in": ""
"aria-label-filter-expression-for-label": "Filterausdruck für Label",
"description-select-labels": "Sobald die Label-Werte ausgewählt sind, werden nur mögliche Label-Kombinationen angezeigt.",
"select-labels-to-search-in": "2. Wählen Sie Labels aus, in denen gesucht werden soll"
},
"metric-selector": {
"aria-label-filter-expression-for-metric": "",
"aria-label-limit-results-from-series-endpoint": "",
"description-series-limit": "",
"label-select-metric": "",
"select-a-metric": "",
"series-limit": ""
"aria-label-filter-expression-for-metric": "Filterausdruck für Metrik",
"aria-label-limit-results-from-series-endpoint": "Ergebnisse vom Reihenendpunkt begrenzen",
"description-series-limit": "Die Grenze gilt für alle Metriken, Labels und Werte. Wenn Sie das Feld leer lassen, wird die Standardgrenze verwendet. Durch eine Einstellung auf 0 wird die Grenze deaktiviert und alles abgerufen – dies kann zu Leistungsproblemen führen.",
"label-select-metric": "Sobald eine Metrik ausgewählt ist, werden nur mögliche Labels angezeigt. Labels werden durch die folgende Reihengrenze begrenzt.",
"select-a-metric": "1. Metrik auswählen",
"series-limit": "Reihengrenze"
},
"prom-cheat-sheet": {
"prom-ql-cheat-sheet": ""
"prom-ql-cheat-sheet": "PromQL Cheat Sheet"
},
"prom-exemplar-field": {
"exemplars": "",
"tooltip-disable-query": "",
"tooltip-enable-query": ""
"exemplars": "Exemplare",
"tooltip-disable-query": "Abfrage mit Exemplaren deaktivieren",
"tooltip-enable-query": "Abfrage mit Exemplaren aktivieren"
},
"prom-explore-extra-field": {
"aria-label-prometheus-extra-field": "",
"aria-label-query-type-field": "",
"aria-label-step-field": "",
"min-step": "",
"query-type": "",
"tooltip-units-builtin-variables-example-interval-rateinterval": ""
"aria-label-prometheus-extra-field": "Zusätzliches Feld in Prometheus",
"aria-label-query-type-field": "Abfragetyp-Feld",
"aria-label-step-field": "Schrittfeld",
"min-step": "Min. Schritt",
"query-type": "Abfragetyp",
"tooltip-units-builtin-variables-example-interval-rateinterval": "Hier können Zeiteinheiten und integrierte Variablen verwendet werden, zum Beispiel: {{example1}}, {{example2}}, {{example3}}, {{example4}}, {{example5}}, {{example6}}, {{example7}} (Standardwert bei fehlender Einheit: {{default}})"
},
"prom-query-field": {
"placeholder-enter-a-prom-ql-query": ""
"placeholder-enter-a-prom-ql-query": "Geben Sie eine PromQL-Abfrage ein "
},
"prom-variable-query-editor": {
"aria-label-classic-query": "",
"aria-label-metric-regex": "",
"aria-label-metric-selector": "",
"aria-label-prometheus-query": "",
"aria-label-query-type": "",
"aria-label-series-query": "",
"label-classic-query": "",
"aria-label-classic-query": "Klassische Abfrage",
"aria-label-metric-regex": "Metrik-Regex",
"aria-label-metric-selector": "Metrik-Selektor",
"aria-label-prometheus-query": "Prometheus-Abfrage",
"aria-label-query-type": "Abfragetyp",
"aria-label-series-query": "Reihenabfrage",
"label-classic-query": "Klassische Abfrage",
"label-label": "Label",
"label-metric-regex": "",
"label-metric-regex": "Metrik-RegEx",
"label-query": "Abfrage",
"label-query-type": "",
"label-series-query": "",
"placeholder-classic-query": "",
"placeholder-metric-regex": "",
"placeholder-prometheus-query": "",
"label-query-type": "Abfragetyp",
"label-series-query": "Reihenabfrage",
"placeholder-classic-query": "Klassische Abfrage",
"placeholder-metric-regex": "Metrik-Regex",
"placeholder-prometheus-query": "Prometheus-Abfrage",
"placeholder-select-query-type": "Abfragetyp auswählen",
"placeholder-series-query": "",
"returns-metrics-matching-specified-metric-regex": "",
"tooltip-classic-query": "",
"tooltip-label": "",
"tooltip-metric-regex": "",
"tooltip-query": "",
"tooltip-query-type": "",
"tooltip-series-query": ""
"placeholder-series-query": "Reihenabfrage",
"returns-metrics-matching-specified-metric-regex": "Gibt eine Liste von Metriken zurück, die mit dem angegebenen Metrik-Regex übereinstimmen.",
"tooltip-classic-query": "Die ursprüngliche Implementierung des Prometheus-Variablen-Abfrageeditors. Geben Sie eine Zeichenfolge mit dem richtigen Abfragetyp und den richtigen Parametern ein, wie in diesen Dokumenten beschrieben. Zum Beispiel: {{exampleQuery}}.",
"tooltip-label": "Gibt eine Liste von Label-Werten für den Label-Namen in allen Metriken zurück, es sei denn, die Metrik ist angegeben.",
"tooltip-metric-regex": "Gibt eine Liste von Label-Namen zurück, die optional gemäß dem angegebenen Metrik-Regex gefiltert werden.",
"tooltip-query": "Gibt eine Liste der Prometheus-Abfrageergebnisse für die Abfrage zurück. Dies kann Prometheus-Funktionen umfassen, z. B. {{exampleQuery}}.",
"tooltip-query-type": "Das Prometheus-Datenquellen-Plugin bietet die folgenden Abfragetypen für Vorlagenvariablen.",
"tooltip-series-query": "Geben Sie eine Metrik mit Labels ein, nur eine Metrik oder nur Labels, z. B. {{example1}}, {{example2}} oder {{example3}}. Gibt eine Liste der Zeitreihen zurück, die den eingegebenen Daten zugeordnet sind."
},
"selector-actions": {
"aria-label-selector": "",
"aria-label-selector-clear-button": "",
"aria-label-use-selector-as-metrics-button": "",
"aria-label-use-selector-for-query-button": "",
"aria-label-validate-submit-button": "",
"aria-label-selector": "Selektor",
"aria-label-selector-clear-button": "Löschen-Schaltfläche des Selektors",
"aria-label-use-selector-as-metrics-button": "Schaltfläche zur Verwendung des Selektors als Metrik",
"aria-label-use-selector-for-query-button": "Schaltfläche zur Verwendung des Selektors für die Abfrage",
"aria-label-validate-submit-button": "Validieren und Absenden-Schaltfläche",
"clear": "Löschen",
"resulting-selector": "",
"use-as-rate-query": "",
"use-query": "",
"validate-selector": ""
"resulting-selector": "4. Resultierender Selektor",
"use-as-rate-query": "Als Bewertungsabfrage verwenden",
"use-query": "Abfrage verwenden",
"validate-selector": "Selektor validieren"
},
"value-selector": {
"aria-label-filter-expression-for-label-values": "",
"aria-label-values-for": "",
"description-search-field-values-across-selected-labels": "",
"select-multiple-values-for-your-labels": ""
"aria-label-filter-expression-for-label-values": "Filterausdruck für Label-Werte",
"aria-label-values-for": "Werte für {{labelKey}}",
"description-search-field-values-across-selected-labels": "Verwenden Sie das Suchfeld, um Werte über mehrere ausgewählte Labels zu finden.",
"select-multiple-values-for-your-labels": "3. Wählen Sie (mehrere) Werte für Ihre Labels aus"
}
},
"configuration": {
"alerting-settings-overhaul": {
"label-allow-as-recording-rules-target": "",
"label-manage-alerts-via-alerting-ui": "",
"label-allow-as-recording-rules-target": "Als Ziel für Aufnahmeregeln zulassen",
"label-manage-alerts-via-alerting-ui": "Benachrichtigungen über Alerting-UI verwalten",
"title-alerting": "Meldungen",
"tooltip-allow-as-recording-rules-target": "",
"tooltip-allow-as-recording-rules-target": "Erlauben, dass diese Datenquelle als Ziel für das Schreiben von Aufnahmeregeln ausgewählt wird.",
"tooltip-manage-alerts-via-alerting-ui": "Verwalten Sie Warnregeln für diese Datenquelle. Fügen Sie eine Altermanager-Datenquelle hinzu, um andere Warnressourcen zu verwalten."
},
"config-editor": {
"browser-access-mode-error": "",
"description-advanced-settings": "",
"browser-access-mode-error": "Der Browserzugriffsmodus in der Prometheus-Datenquelle ist nicht mehr verfügbar. Wechseln Sie in den Serverzugriffsmodus.",
"description-advanced-settings": "Zusätzliche Einstellungen sind optionale Einstellungen, die für mehr Kontrolle über Ihre Datenquelle konfiguriert werden können.",
"title-advanced-settings": "Erweiterte Einstellungen",
"title-error": "Fehler"
},
"data-source-http-settings-overhaul": {
"tooltip-browser-access-mode": "Ihre Zugriffsmethode ist <1>Browser</1>, d. h. die URL muss über den Browser zugänglich sein.",
"tooltip-http-url": "",
"tooltip-http-url": "Geben Sie eine vollständige HTTP-URL an (z. B. {{exampleURL}})",
"tooltip-server-access-mode": "Ihre Zugriffsmethode ist <1>Server</1>, d. h. die URL muss über das Grafana-Backend/den Grafana-Server zugänglich sein."
},
"docs-tip": {
"visit-docs-for-more-details-here": ""
"visit-docs-for-more-details-here": "Weitere Details finden Sie hier in der Dokumentation."
},
"exemplar-setting": {
"label-data-source": "Datenquelle",
"label-internal-link": "",
"label-internal-link": "Interner Link",
"label-label-name": "Label-Name",
"label-remove-exemplar-link": "",
"label-remove-exemplar-link": "Exemplar-Link entfernen",
"label-url": "URL",
"label-url-label": "",
"placeholder-go-to-examplecom": "",
"placeholder-httpsexamplecomvalueraw": "",
"placeholder-trace-id": "",
"title-remove-exemplar-link": "",
"tooltip-data-source": "",
"tooltip-internal-link": "",
"tooltip-label-name": "",
"tooltip-url": "",
"tooltip-url-label": ""
"label-url-label": "URL-Label",
"placeholder-go-to-examplecom": "Zu example.com",
"placeholder-httpsexamplecomvalueraw": "https://example.com/${__value.raw}",
"placeholder-trace-id": "traceID",
"title-remove-exemplar-link": "Exemplar-Link entfernen",
"tooltip-data-source": "Die Datenquelle, zu der das Exemplar navigiert.",
"tooltip-internal-link": "Aktivieren Sie diese Option, wenn Sie einen internen Link haben. Wenn dies aktiviert ist, wird der Datenquellen-Selektor angezeigt. Wählen Sie den Backend-Tracing-Datenspeicher für Ihre Exemplar-Daten aus.",
"tooltip-label-name": "Der Name des Felds im Label-Objekt, das für den Erhalt der TraceID verwendet werden soll.",
"tooltip-url": "Die URL des Trace-Backends, die der Nutzer zur Ansicht des Trace aufrufen würde",
"tooltip-url-label": "Damit können Sie das Schaltflächen-Label im Feld der Exemplar-TraceID überschreiben."
},
"exemplars-settings": {
"add": "Hinzufügen",
"no-exemplars-configurations": "",
"title-exemplars": ""
"no-exemplars-configurations": "Keine Exemplar-Konfigurationen",
"title-exemplars": "Exemplare"
},
"prom-settings": {
"aria-label-default-editor": "",
"aria-label-prom-type-type": "",
"aria-label-prometheus-type": "",
"aria-label-select-http-method": "",
"aria-label-default-editor": "Standard-Editor (Code oder Builder)",
"aria-label-prom-type-type": "{{promType}} Typ",
"aria-label-prometheus-type": "Prometheus-Typ",
"aria-label-select-http-method": "HTTP-Methode auswählen",
"editor-options": {
"label-builder": "",
"label-code": ""
},
"label-cache-level": "",
"label-custom-query-parameters": "",
"label-default-editor": "",
"label-disable-metrics-lookup": "",
"label-disable-recording-rules-beta": "",
"label-http-method": "",
"label-incremental-querying-beta": "",
"label-metric-names-suggestion-limit": "",
"label-prom-type-version": "",
"label-prometheus-type": "",
"label-query-overlap-window": "",
"label-query-timeout": "",
"label-scrape-interval": "",
"label-series-limit": "",
"label-use-series-endpoint": "",
"more-info": "",
"placeholder-example-maxsourceresolutionmtimeout": "",
"title-interval-behaviour": "",
"title-other": "",
"label-cache-level": "Cache-Level",
"label-custom-query-parameters": "Benutzerdefinierte Abfrageparameter",
"label-default-editor": "Standard-Editor",
"label-disable-metrics-lookup": "Metrik-Suche deaktivieren",
"label-disable-recording-rules-beta": "Aufnahmeregeln deaktivieren (Beta)",
"label-http-method": "HTTP-Methode",
"label-incremental-querying-beta": "Inkrementelle Abfrage (Beta)",
"label-metric-names-suggestion-limit": "Begrenzung der Vorschläge für Metriknamen",
"label-prom-type-version": "{{promType}} Version",
"label-prometheus-type": "Prometheus-Typ",
"label-query-overlap-window": "Fenster der Abfrage-Überschneidung",
"label-query-timeout": "Abfrage-Timeout",
"label-scrape-interval": "Scrape-Intervall",
"label-series-limit": "Reihengrenze",
"label-use-series-endpoint": "Reihenendpunkt verwenden",
"more-info": "Weitere Informationen zur Konfiguration des Typs und der Version von Prometheus in Datenquellen finden Sie in der <2>Bereitstellungsdokumentation</2>.",
"placeholder-example-maxsourceresolutionmtimeout": "Beispiel: {{example}}",
"title-interval-behaviour": "Intervallverhalten",
"title-other": "Sonstiges",
"title-performance": "Leistung",
"title-query-editor": "",
"tooltip-cache-level": "",
"tooltip-custom-query-parameters": "",
"tooltip-default-editor": "",
"tooltip-disable-metrics-lookup": "",
"tooltip-disable-recording-rules-beta": "",
"tooltip-http-method": "",
"tooltip-incremental-querying-beta": "",
"tooltip-metric-names-suggestion-limit": "",
"tooltip-prom-type-version": "",
"tooltip-prometheus-type": "",
"tooltip-query-overlap-window": "",
"tooltip-query-timeout": "",
"tooltip-scrape-interval": "",
"tooltip-series-limit": "",
"tooltip-use-series-endpoint": ""
"title-query-editor": "Abfrage-Editor",
"tooltip-cache-level": "Legt die Browser-Cache-Level für Editor-Abfragen fest. Für Datenquellen mit hoher Kardinalität werden höhere Cache-Einstellungen empfohlen.",
"tooltip-custom-query-parameters": "Fügen Sie der URL der Prometheus-Abfrage benutzerdefinierte Parameter hinzu. Zum Beispiel {{example1}}, {{example2}}, {{example3}} oder {{example4}}. Mehrere Parameter sollten mit {{concatenationChar}} verknüpft werden.",
"tooltip-default-editor": "Legen Sie die Standard-Editoroption für alle Nutzer dieser Datenquelle fest.",
"tooltip-disable-metrics-lookup": "Wenn diese Option aktiviert ist, werden die Metrikauswahl und die Unterstützung für Metriken/Labels im Rahmen der Autovervollständigung des Abfragefelds deaktiviert. Dies hilft, wenn Sie Leistungsprobleme mit größeren Prometheus-Instanzen haben. ",
"tooltip-disable-recording-rules-beta": "Diese Funktion deaktiviert die Aufnahmeregeln. Wenn Sie dies aktivieren, wird die Dashboard-Leistung verbessert",
"tooltip-http-method": "Sie können entweder die HTTP-Methode POST oder GET für die Abfrage Ihrer Prometheus-Datenquelle verwenden. POST ist die empfohlene Methode, da sie größere Abfragen ermöglicht. Ändern Sie dies zu GET, wenn Ihre Prometheus-Version älter als 2.1 ist oder POST-Abfragen in Ihrem Netzwerk beschränkt sind.",
"tooltip-incremental-querying-beta": "Diese Funktion ändert das Standardverhalten von relativen Abfragen, sodass immer neue Daten von der Prometheus-Instanz abgefragt werden. Stattdessen werden Abfrageergebnisse zwischengespeichert und nur neue Datensätze abgefragt. Wenn Sie dies aktivieren, wird die Datenbank- und Netzwerklast reduziert.",
"tooltip-metric-names-suggestion-limit": "Die maximale Anzahl an Metriknamen, die im Code-Modus des Abfrage-Editors als Vorschläge im Rahmen der Autovervollständigung angezeigt werden können.",
"tooltip-prom-type-version": "Nutzen Sie diese Option, um die Version Ihrer Instanz von {{promType}} festzulegen, wenn sie nicht automatisch konfiguriert wird.",
"tooltip-prometheus-type": "Stellen Sie dies auf den Typ Ihrer Prometheus-Datenbank ein, z. B. Prometheus, Cortex, Mimir oder Thanos. Wenn Sie dieses Feld ändern, werden Ihre aktuellen Einstellungen gespeichert. Bestimmte Typen von Prometheus unterstützen entweder verschiedene APIs oder nicht. Zum Beispiel unterstützen manche Typen Regex-Matching für Label-Abfragen, um die Leistung zu verbessern. Manche Typen haben eine API für Metadaten. Wenn Sie dies falsch einstellen, kann es bei der Abfrage von Metriken und Labels zu einem ungewöhnlichen Verhalten kommen. Bitte prüfen Sie Ihre Prometheus-Dokumentation, um sicherzugehen, dass Sie den richtigen Typ eingeben.",
"tooltip-query-overlap-window": "Stellen Sie eine Dauer ein, zum Beispiel {{example1}} oder {{example2}} oder {{example3}}. Standardwert: {{default}}. Diese Dauer wird zur Dauer jeder inkrementellen Abfrage hinzugefügt.",
"tooltip-query-timeout": "Legen Sie das Prometheus-Abfrage-Timeout fest.",
"tooltip-scrape-interval": "Dieses Intervall gibt an, wie oft Prometheus ein Scraping für Ziele durchführt. Stellen Sie dies auf das typische Scrape- und Bewertungsintervall ein, das in Ihrer Prometheus-Konfigurationsdatei konfiguriert ist. Wenn Sie dies auf einen größeren Wert als das Intervall Ihrer Prometheus-Konfigurationsdatei einstellen, wertet Grafana die Daten gemäß diesem Intervall aus und Sie sehen weniger Datenpunkte. Standardmäßig {{default}}.",
"tooltip-series-limit": "Die Grenze gilt für alle Ressourcen (Metriken, Labels und Werte) für beide Endpunkte (Reihen und Labels). Wenn Sie das Feld leer lassen, wird die Standardgrenze verwendet (40.000). Durch eine Einstellung auf 0 wird die Grenze deaktiviert und alles abgerufen – dies kann zu Leistungsproblemen führen. Die Standardgrenze beträgt 40.000.",
"tooltip-use-series-endpoint": "Wenn diese Option aktiviert ist, wird der Reihenendpunkt mit dem Parameter {{exampleParameter}} gegenüber dem Endpunkt der Label-Werte mit dem Parameter {{exampleParameter}} bevorzugt. Obwohl der Endpunkt der Label-Werte als leistungsfähiger gilt, könnten manche Nutzer die Reihe bevorzugen, da sie über eine POST-Methode verfügt, während der Endpunkt der Label-Werte nur über eine GET-Methode verfügt."
}
},
"prom-query-legend-editor": {
@ -211,12 +211,12 @@
},
"querybuilder": {
"additional-settings": {
"content-filter-metric-names-regex-search-using": "",
"disable-text-wrap": ""
"content-filter-metric-names-regex-search-using": "Filtern Sie Metriknamen per Regex-Suche und nutzen Sie dabei einen zusätzlichen Aufruf der Prometheus-API.",
"disable-text-wrap": "Textumbruch deaktivieren"
},
"feedback-link": {
"give-feedback": "Feedback geben",
"title-give-feedback": ""
"title-give-feedback": "Der Metrik-Explorer ist neu. Bitte teilen Sie uns mit, wie wir ihn verbessern können."
},
"get-collapsed-info": {
"exemplars": "",
@ -250,18 +250,18 @@
},
"handle-function": {
"text": {
"query-parsing-is-ambiguous": ""
"query-parsing-is-ambiguous": "Das Abfrage-Parsing ist unklar."
}
},
"label-filter-item": {
"aria-label-remove": "",
"placeholder-select-label": "",
"aria-label-remove": "Entfernen von {{name}}",
"placeholder-select-label": "Label auswählen",
"placeholder-select-value": "Wert auswählen"
},
"label-filters": {
"label-filters": "",
"label-label-filters": "",
"tooltip-label-filters": ""
"label-filters": "Label-Filter",
"label-label-filters": "Label-Filter",
"tooltip-label-filters": "Optional: wird verwendet, um die Metrikauswahl für diesen Abfragetyp zu filtern."
},
"label-param-editor": {
"loadingMessage-loading-labels": "",
@ -269,92 +269,92 @@
},
"metric-combobox": {
"async-select": {
"aria-label-open-metrics-explorer": "",
"placeholder-select-metric": "",
"tooltip-open-metrics-explorer": ""
"aria-label-open-metrics-explorer": "Metrik-Explorer öffnen",
"placeholder-select-metric": "Metrik auswählen",
"tooltip-open-metrics-explorer": "Metrik-Explorer öffnen"
},
"label-metric": "Metrik",
"tooltip-metric": ""
"tooltip-metric": "Optional: gibt eine Liste von Label-Werten für den Label-Namen in der angegebenen Metrik zurück."
},
"metrics-modal": {
"additional-settings": "",
"additional-settings": "Zusätzliche Einstellungen",
"aria-label-additional-settings": "Zusätzliche Einstellungen",
"aria-label-browse-metrics": "",
"currently-selected": "",
"metrics-pre-filtered": "",
"placeholder-results-per-page": "",
"results-per-page": "",
"title-metrics-explorer": "",
"results-amount_one": "",
"results-amount_other": ""
"aria-label-browse-metrics": "Metriken durchsuchen",
"currently-selected": "Aktuell ausgewählt: {{selected}}",
"metrics-pre-filtered": "Diese Metriken wurden anhand der Labels, die in den Label-Filtern ausgewählt wurden, vorgefiltert.",
"placeholder-results-per-page": "Ergebnisse pro Seite",
"results-per-page": "Ergebnisse pro Seite",
"title-metrics-explorer": "Metrik-Explorer",
"results-amount_one": "{{num}} von {{count}} Ergebnissen werden angezeigt",
"results-amount_other": "{{num}} von {{count}} Ergebnissen werden angezeigt"
},
"nested-query": {
"label": {
"ignoring": "",
"ignoring": "Ignorieren",
"on": "Aktiviert"
},
"operator": "Bediener",
"tooltip-remove-match": "",
"vector-matches": ""
"tooltip-remove-match": "Übereinstimmung entfernen",
"vector-matches": "Vektorübereinstimmungen"
},
"operation-editor": {
"not-found": "",
"title-remove": ""
"not-found": "Vorgang {{id}} nicht gefunden",
"title-remove": "Entfernen von {{name}}"
},
"operation-header": {
"placeholder-replace-with": "Ersetzen mit",
"title-click-to-view-alternative-operations": "",
"title-remove-operation": ""
"title-click-to-view-alternative-operations": "Klicken Sie zur Anzeige alternativer Vorgänge",
"title-remove-operation": "Vorgang entfernen"
},
"operation-info-button": {
"title-click-to-show-description": "",
"title-remove-operation": ""
"title-click-to-show-description": "Klicken Sie zur Ansicht der Beschreibung",
"title-remove-operation": "Operation entfernen"
},
"operation-list": {
"operations": "",
"operations": "Vorgänge",
"placeholder-search": "Suche",
"title-add-operation": ""
"title-add-operation": "Vorgang hinzufügen"
},
"operation-param-editor": {
"title-add": "",
"title-remove": ""
"title-add": "{{name}} hinzufügen",
"title-remove": "{{name}} entfernen"
},
"prom-query-builder-options": {
"aria-label-lower-limit-parameter": "",
"aria-label-select-resolution": "",
"aria-label-lower-limit-parameter": "Untergrenze für den Schrittparameter festlegen",
"aria-label-select-resolution": "Auflösung auswählen",
"format-options": {
"label-heatmap": "",
"label-table": "",
"label-time-series": ""
},
"label-exemplars": "",
"label-exemplars": "Exemplare",
"label-format": "Format",
"label-min-step": "",
"label-resolution": "",
"label-min-step": "Min. Schritt",
"label-resolution": "Auflösung",
"label-type": "Typ",
"placeholder-auto": "",
"placeholder-auto": "Auto",
"title-options": "Optionen",
"tooltip-min-step": ""
"tooltip-min-step": "Eine zusätzliche Untergrenze für den Schrittparameter der Prometheus-Abfrage und für die Variablen <2>{{interval}}</2> und <4>{{rateInterval}}</4>."
},
"prom-query-code-editor-autocomplete-info": {
"autocomplete-suggestions-limited": "",
"tooltip-autocomplete-suggestions-limited": ""
"autocomplete-suggestions-limited": "Vorschläge der Autovervollständigung begrenzt",
"tooltip-autocomplete-suggestions-limited": "Die Anzahl der Metriknamen überschreitet die Grenze der Autovervollständigung. Es werden nur die für {{autocompleteLimit}} relevantesten Metriken angezeigt. Sie können die Grenze in den Datenquelleneinstellungen anpassen."
},
"prom-query-editor-selector": {
"body-syntax-error": "",
"confirmText-continue": "",
"kick-start-your-query": "Starten Sie Ihre Abfrage",
"label-explain": "",
"run-queries": "",
"title-parsing-error-switch-builder": ""
"label-explain": "Erklären",
"run-queries": "Abfragen ausführen",
"title-parsing-error-switch-builder": "Parsing-Fehler: In den Builder-Modus wechseln?"
},
"prom-query-legend-editor": {
"label-legend": "",
"placeholder-select-legend-mode": "",
"tooltip-legend": ""
"label-legend": "Legende",
"placeholder-select-legend-mode": "Legendenmodus auswählen",
"tooltip-legend": "Überschreibung des Reihennamens oder Vorlage. Beispiel: {{templateExample}} wird durch den Label-Wert für {{labelName}} ersetzt."
},
"query-builder-hints": {
"hint-details": ""
"hint-details": "Hinweis: {{hintDetails}}"
},
"query-editor-mode-toggle": {
"editor-modes": {
@ -363,30 +363,30 @@
}
},
"query-pattern": {
"apply-query": "",
"aria-label-apply-query-starter-button": "",
"aria-label-back-button": "",
"aria-label-create-new-query-button": "",
"aria-label-raw-query": "",
"aria-label-use-this-query-button": "",
"apply-query": "Abfrage anwenden",
"aria-label-apply-query-starter-button": "Schaltfläche zur Anwendung des Abfrage-Starters",
"aria-label-back-button": "Zurück-Schaltfläche",
"aria-label-create-new-query-button": "Schaltfläche zur Erstellung einer neuen Abfrage",
"aria-label-raw-query": "{{patternName}} Rohabfrage",
"aria-label-use-this-query-button": "Schaltfläche zum Nutzen dieser Abfrage",
"back": "Zurück",
"create-new-query": "",
"create-new-query": "Neue Abfrage erstellen",
"use-this-query": "Diese Abfrage nutzen"
},
"query-patterns-modal": {
"aria-label-close-kick-start-your-query-modal": "",
"aria-label-close-kick-start-your-query-modal": "Modal zum Starten Ihrer Abfrage schließen",
"aria-label-kick-start-your-query-modal": "Starten Sie Ihr Abfrage-Modal",
"aria-label-toggle-query-starter": "",
"aria-label-toggle-query-starter": "Öffnen und Schließen der {{patternType}} Abfrage-Starter-Karte",
"close": "Schließen",
"description-kick-start-your-query": "",
"label-toggle-query-starter": "",
"description-kick-start-your-query": "Starten Sie Ihre Abfrage, indem Sie eine dieser Abfragen auswählen. Sie können dann mit dem Abschluss Ihrer Abfrage fortfahren.",
"label-toggle-query-starter": "{{patternType}} Abfrage-Starter",
"title-kick-start-your-query": "Starten Sie Ihre Abfrage"
},
"raw-query": {
"aria-label-selector": ""
"aria-label-selector": "Selektor"
},
"results-table": {
"content-descriptive-type": "",
"content-descriptive-type": "Bei der Erstellung von {{descriptiveType}} zeigt Prometheus mehrere Reihen mit dem Typ Counter. ",
"description": "Beschreibung",
"message-expand-label-filters": "",
"message-expand-search": "",
@ -397,7 +397,7 @@
},
"update-function-args": {
"text": {
"query-parsing-is-ambiguous": ""
"query-parsing-is-ambiguous": "Das Abfrage-Parsing ist unklar."
}
}
}

@ -2,201 +2,201 @@
"grafana-prometheus": {
"components": {
"annotation-query-editor": {
"annotation-data-load-error": "",
"aria-label-lower-limit-parameter": "",
"label-min-step": "",
"label-series-value-as-timestamp": "",
"annotation-data-load-error": "Hiba a jegyzetadatok betöltése során.",
"aria-label-lower-limit-parameter": "Állítsa be a léptékparaméter alsó határát",
"label-min-step": "Min. lépték",
"label-series-value-as-timestamp": "Sorozatérték időbélyegként",
"label-tags": "Címkék",
"label-text": "",
"label-text": "Szöveg",
"label-title": "Cím",
"placeholder-auto": "",
"tooltip-either-pattern-example-instance-replaced-label": "",
"tooltip-min-step": "",
"tooltip-timestamp-milliseconds-series-value-seconds-multiply": ""
"placeholder-auto": "automatikus",
"tooltip-either-pattern-example-instance-replaced-label": "Használja a nevet vagy egy mintázatot. Például a(z) {{labelTemplate}} helyébe a(z) {{labelName}} címke címkeértéke lép.",
"tooltip-min-step": "További alsó határérték a Prometheus-lekérdezés lépésparaméteréhez, valamint a(z) <2>{{intervalVar}}</2> és <4>{{rateIntervalVar}}</4> változóhoz.",
"tooltip-timestamp-milliseconds-series-value-seconds-multiply": "Az időbélyeg mértékegysége az ezredmásodperc. Ha a sorozatérték mértékegysége a másodperc, szorozza meg a tartományvektorát 1000-rel."
},
"get-query-type-options": {
"description": {
"instant-query-range": ""
"instant-query-range": "Azonnali lekérdezés és tartománylekérdezés futtatása"
},
"label": {
"both": ""
"both": "Mindkettő"
},
"range-options": {
"description": {
"query-range": ""
"query-range": "Lekérdezés futtatása egy időtartományban"
},
"label": {
"instant": "",
"range": ""
"instant": "Azonnali",
"range": "Tartomány"
}
}
},
"label-selector": {
"aria-label-filter-expression-for-label": "",
"description-select-labels": "",
"select-labels-to-search-in": ""
"aria-label-filter-expression-for-label": "Szűrőkifejezés címkéhez",
"description-select-labels": "A címkeértékek kiválasztása után csak a lehetséges címkekombinációk jelennek meg.",
"select-labels-to-search-in": "2. Válassza ki a kereséshez használni kívánt címkéket"
},
"metric-selector": {
"aria-label-filter-expression-for-metric": "",
"aria-label-limit-results-from-series-endpoint": "",
"description-series-limit": "",
"label-select-metric": "",
"select-a-metric": "",
"series-limit": ""
"aria-label-filter-expression-for-metric": "Szűrőkifejezés a metrikához",
"aria-label-limit-results-from-series-endpoint": "A sorozat végpontjáról származó eredmények korlátozása",
"description-series-limit": "A korlát minden metrikára, címkére és értékre vonatkozik. Hagyja üresen a mezőt az alapértelmezett korlát használatához. Állítsa 0-ra a korlát letiltásához és az összes lekéréséhez – ez teljesítményproblémákat okozhat.",
"label-select-metric": "A metrika kiválasztása után csak a lehetséges címkék jelennek meg. A címkéket az alábbi sorozatkorlát korlátozza.",
"select-a-metric": "1. Válasszon egy metrikát",
"series-limit": "Sorozatkorlát"
},
"prom-cheat-sheet": {
"prom-ql-cheat-sheet": ""
"prom-ql-cheat-sheet": "PromQL-puska"
},
"prom-exemplar-field": {
"exemplars": "",
"tooltip-disable-query": "",
"tooltip-enable-query": ""
"exemplars": "Mintapéldányok",
"tooltip-disable-query": "Mintapéldányokkal rendelkező lekérdezések letiltása",
"tooltip-enable-query": "Mintapéldányokkal rendelkező lekérdezések engedélyezése"
},
"prom-explore-extra-field": {
"aria-label-prometheus-extra-field": "",
"aria-label-query-type-field": "",
"aria-label-step-field": "",
"min-step": "",
"query-type": "",
"tooltip-units-builtin-variables-example-interval-rateinterval": ""
"aria-label-prometheus-extra-field": "Prometheus extra mező",
"aria-label-query-type-field": "Lekérdezéstípus mező",
"aria-label-step-field": "Lépték mező",
"min-step": "Min. lépték",
"query-type": "Lekérdezés típusa",
"tooltip-units-builtin-variables-example-interval-rateinterval": "Itt időegységek és beépített változók használhatók, például: {{example1}}, {{example2}}, {{example3}}, {{example4}}, {{example5}}, {{example6}}, {{example7}} (alapértelmezett, ha nincs megadva mértékegység: {{default}})"
},
"prom-query-field": {
"placeholder-enter-a-prom-ql-query": ""
"placeholder-enter-a-prom-ql-query": "Írjon be egy PromQL-lekérdezést…"
},
"prom-variable-query-editor": {
"aria-label-classic-query": "",
"aria-label-metric-regex": "",
"aria-label-metric-selector": "",
"aria-label-prometheus-query": "",
"aria-label-query-type": "",
"aria-label-series-query": "",
"label-classic-query": "",
"aria-label-classic-query": "Klasszikus lekérdezés",
"aria-label-metric-regex": "Metrika reguláris kifejezése",
"aria-label-metric-selector": "Metrikaválasztó",
"aria-label-prometheus-query": "Prometheus-lekérdezés",
"aria-label-query-type": "Lekérdezés típusa",
"aria-label-series-query": "Sorozatlekérdezés",
"label-classic-query": "Klasszikus lekérdezés",
"label-label": "Címke",
"label-metric-regex": "",
"label-metric-regex": "Metrika reguláris kifejezése",
"label-query": "Lekérdezés",
"label-query-type": "",
"label-series-query": "",
"placeholder-classic-query": "",
"placeholder-metric-regex": "",
"placeholder-prometheus-query": "",
"label-query-type": "Lekérdezés típusa",
"label-series-query": "Sorozatlekérdezés",
"placeholder-classic-query": "Klasszikus lekérdezés",
"placeholder-metric-regex": "Metrika reguláris kifejezése",
"placeholder-prometheus-query": "Prometheus-lekérdezés",
"placeholder-select-query-type": "Lekérdezéstípus kiválasztása",
"placeholder-series-query": "",
"returns-metrics-matching-specified-metric-regex": "",
"tooltip-classic-query": "",
"tooltip-label": "",
"tooltip-metric-regex": "",
"tooltip-query": "",
"tooltip-query-type": "",
"tooltip-series-query": ""
"placeholder-series-query": "Sorozatlekérdezés",
"returns-metrics-matching-specified-metric-regex": "A megadott metrikai reguláris kifejezésnek megfelelő metrikák listáját adja vissza.",
"tooltip-classic-query": "A Prometheus változólekérdezés-szerkesztő eredeti implementációja. Adjon meg egy karakterláncot a megfelelő lekérdezéstípussal és paraméterekkel, a jelen dokumentumokban leírtak szerint. Például: {{exampleQuery}}.",
"tooltip-label": "A címke nevéhez tartozó címkeértékek listáját adja vissza az összes metrikában, kivéve, ha a metrika meg van adva.",
"tooltip-metric-regex": "A címkenevek listáját adja vissza, opcionálisan a megadott metrikai reguláris kifejezés szerint szűrve.",
"tooltip-query": "A lekérdezéshez a Prometheus-lekérdezési eredmények listáját adja vissza. Ez magában foglalhatja a Prometheus-funkciókat, azaz {{exampleQuery}}.",
"tooltip-query-type": "A Prometheus adatforrás-beépülőmodul a következő lekérdezéstípusokat biztosítja a sablonváltozókhoz.",
"tooltip-series-query": "Adjon meg egy metrikát címkékkel, csak egy metrikát vagy csak címkéket: {{example1}}, {{example2}} vagy {{example3}}. A bevitt adatokhoz társított idősorok listáját adja vissza."
},
"selector-actions": {
"aria-label-selector": "",
"aria-label-selector-clear-button": "",
"aria-label-use-selector-as-metrics-button": "",
"aria-label-use-selector-for-query-button": "",
"aria-label-validate-submit-button": "",
"aria-label-selector": "választó",
"aria-label-selector-clear-button": "Választó törlése gomb",
"aria-label-use-selector-as-metrics-button": "Választó használata metrikaként gomb",
"aria-label-use-selector-for-query-button": "Választó használata lekérdezéshez gomb",
"aria-label-validate-submit-button": "Küldés érvényesítése gomb",
"clear": "Törlés",
"resulting-selector": "",
"use-as-rate-query": "",
"use-query": "",
"validate-selector": ""
"resulting-selector": "4. Eredményként kapott választó",
"use-as-rate-query": "Használat értékeléses lekérdezésként",
"use-query": "Lekérdezés használata",
"validate-selector": "Választó érvényesítése"
},
"value-selector": {
"aria-label-filter-expression-for-label-values": "",
"aria-label-values-for": "",
"description-search-field-values-across-selected-labels": "",
"select-multiple-values-for-your-labels": ""
"aria-label-filter-expression-for-label-values": "Szűrőkifejezés címkeértékekhez",
"aria-label-values-for": "Értékek a következőhöz: {{labelKey}}",
"description-search-field-values-across-selected-labels": "A keresőmező segítségével kereshet értékeket a kiválasztott címkék között.",
"select-multiple-values-for-your-labels": "3. Válasszon (több) értéket a címkéihez"
}
},
"configuration": {
"alerting-settings-overhaul": {
"label-allow-as-recording-rules-target": "",
"label-manage-alerts-via-alerting-ui": "",
"label-allow-as-recording-rules-target": "Engedélyezés felvételkészítési szabályok céljaként",
"label-manage-alerts-via-alerting-ui": "Riasztások kezelése az Alerting kezelőfelületén keresztül",
"title-alerting": "Riasztás",
"tooltip-allow-as-recording-rules-target": "",
"tooltip-allow-as-recording-rules-target": "Engedélyezze, hogy ez az adatforrás célként legyen kiválasztva a felvételkészítési szabályok írásához.",
"tooltip-manage-alerts-via-alerting-ui": "Riasztási szabályok kezelése ehhez az adatforráshoz. Más Alerting-erőforrások kezeléséhez adjon hozzá egy Alertmanager-adatforrást."
},
"config-editor": {
"browser-access-mode-error": "",
"description-advanced-settings": "",
"browser-access-mode-error": "A Prometheus-adatforrás böngészős hozzáférési módja már nem érhető el. Váltás kiszolgáló-hozzáférési módra.",
"description-advanced-settings": "A további beállítások olyan opcionális beállítások, amelyek konfigurálhatók az adatforrás nagyobb mértékű ellenőrzése érdekében.",
"title-advanced-settings": "Speciális beállítások",
"title-error": "Hiba"
},
"data-source-http-settings-overhaul": {
"tooltip-browser-access-mode": "Az Ön hozzáférési módja <1>Böngésző</1>, ez azt jelenti, hogy az URL-címnek elérhetőnek kell lennie a böngészőből.",
"tooltip-http-url": "",
"tooltip-http-url": "Adjon meg egy teljes HTTP URL-címet (például: {{exampleURL}})",
"tooltip-server-access-mode": "Az Ön hozzáférési módja <1>Kiszolgáló</1>, ez azt jelenti, hogy az URL-címnek elérhetőnek kell lennie a Grafana-háttérrendszerből/-kiszolgálóról."
},
"docs-tip": {
"visit-docs-for-more-details-here": ""
"visit-docs-for-more-details-here": "További részletekért tekintse meg a dokumentumokat itt."
},
"exemplar-setting": {
"label-data-source": "Adatforrás",
"label-internal-link": "",
"label-internal-link": "Belső hivatkozás",
"label-label-name": "Címkenév",
"label-remove-exemplar-link": "",
"label-remove-exemplar-link": "Mintapéldány-hivatkozás eltávolítása",
"label-url": "URL-cím",
"label-url-label": "",
"placeholder-go-to-examplecom": "",
"placeholder-httpsexamplecomvalueraw": "",
"placeholder-trace-id": "",
"title-remove-exemplar-link": "",
"tooltip-data-source": "",
"tooltip-internal-link": "",
"tooltip-label-name": "",
"tooltip-url": "",
"tooltip-url-label": ""
"label-url-label": "URL-címke",
"placeholder-go-to-examplecom": "Tovább az example.com webhelyre",
"placeholder-httpsexamplecomvalueraw": "https://example.com/${__value.raw}",
"placeholder-trace-id": "traceID",
"title-remove-exemplar-link": "Mintapéldány-hivatkozás eltávolítása",
"tooltip-data-source": "A mintapéldány ehhez az adatforráshoz fog navigálni.",
"tooltip-internal-link": "Engedélyezze ezt a lehetőséget, ha van belső hivatkozása. Ha engedélyezve van, megjeleníti az adatforrás-választót. Válassza ki a háttérrendszeri követési adattárat a mintapéldány-adatokhoz.",
"tooltip-label-name": "A címkeobjektum azon mezőjének neve, amelyet a traceID lekéréséhez kell használni.",
"tooltip-url": "A nyomkövetési háttérrendszer URL-címe, ahová a felhasználó menne, hogy lássa a nyomkövetést",
"tooltip-url-label": "Használja a gombcímke felülbírálásához a mintapéldány traceID mezőjén."
},
"exemplars-settings": {
"add": "Hozzáadás",
"no-exemplars-configurations": "",
"title-exemplars": ""
"no-exemplars-configurations": "Nincsenek mintapéldány-konfigurációk",
"title-exemplars": "Mintapéldányok"
},
"prom-settings": {
"aria-label-default-editor": "",
"aria-label-prom-type-type": "",
"aria-label-prometheus-type": "",
"aria-label-select-http-method": "",
"aria-label-default-editor": "Alapértelmezett szerkesztő (kód vagy építő)",
"aria-label-prom-type-type": "{{promType}} típusa",
"aria-label-prometheus-type": "Prometheus-típus",
"aria-label-select-http-method": "HTTP-módszer kiválasztása",
"editor-options": {
"label-builder": "",
"label-code": ""
},
"label-cache-level": "",
"label-custom-query-parameters": "",
"label-default-editor": "",
"label-disable-metrics-lookup": "",
"label-disable-recording-rules-beta": "",
"label-http-method": "",
"label-incremental-querying-beta": "",
"label-metric-names-suggestion-limit": "",
"label-prom-type-version": "",
"label-prometheus-type": "",
"label-query-overlap-window": "",
"label-query-timeout": "",
"label-scrape-interval": "",
"label-series-limit": "",
"label-use-series-endpoint": "",
"more-info": "",
"placeholder-example-maxsourceresolutionmtimeout": "",
"title-interval-behaviour": "",
"title-other": "",
"label-cache-level": "Gyorsítótár szintje",
"label-custom-query-parameters": "Egyéni lekérdezési paraméterek",
"label-default-editor": "Alapértelmezett szerkesztő",
"label-disable-metrics-lookup": "Metrikák keresésének letiltása",
"label-disable-recording-rules-beta": "Felvételkészítési szabályok letiltása (béta)",
"label-http-method": "HTTP-metódus",
"label-incremental-querying-beta": "Növekményes lekérdezés (béta)",
"label-metric-names-suggestion-limit": "Metrikanevek javaslatának korlátja",
"label-prom-type-version": "{{promType}} verziója",
"label-prometheus-type": "Prometheus-típus",
"label-query-overlap-window": "Lekérdezésátfedési ablak",
"label-query-timeout": "Lekérdezési időtúllépés",
"label-scrape-interval": "Adatgyűjtési intervallum",
"label-series-limit": "Sorozatkorlát",
"label-use-series-endpoint": "Sorozat végpontjának használata",
"more-info": "A Prometheus-típus és -verzió adatforrásokban történő konfigurálásával kapcsolatos további információkért tekintse meg a <2>kiépítési dokumentációt</2>.",
"placeholder-example-maxsourceresolutionmtimeout": "Példa: {{example}}",
"title-interval-behaviour": "Intervallum viselkedése",
"title-other": "Egyéb",
"title-performance": "Teljesítmény",
"title-query-editor": "",
"tooltip-cache-level": "",
"tooltip-custom-query-parameters": "",
"tooltip-default-editor": "",
"tooltip-disable-metrics-lookup": "",
"tooltip-disable-recording-rules-beta": "",
"tooltip-http-method": "",
"tooltip-incremental-querying-beta": "",
"tooltip-metric-names-suggestion-limit": "",
"tooltip-prom-type-version": "",
"tooltip-prometheus-type": "",
"tooltip-query-overlap-window": "",
"tooltip-query-timeout": "",
"tooltip-scrape-interval": "",
"tooltip-series-limit": "",
"tooltip-use-series-endpoint": ""
"title-query-editor": "Lekérdezésszerkesztő",
"tooltip-cache-level": "Beállítja a böngésző gyorsítótárának szintjét a szerkesztői lekérdezésekhez. A magasabb számossági adatforrásokhoz magasabb gyorsítótár-beállítások ajánlottak.",
"tooltip-custom-query-parameters": "Egyéni paraméterek hozzáadása a Prometheus lekérdezési URL-jéhez. Például: {{example1}}, {{example2}}, {{example3}} vagy {{example4}}. Több paramétert a következővel kell összefűzni: {{concatenationChar}}.",
"tooltip-default-editor": "Beállítja az alapértelmezett szerkesztőopciót az adatforrás minden felhasználója számára.",
"tooltip-disable-metrics-lookup": "Ennek az opciónak a bejelölése letiltja a metrikaválasztót és a metrika-/címketámogatást a lekérdezési mező automatikus kitöltésében. Ez segít, ha a nagyobb Prometheus-példányokkal teljesítményproblémái vannak. ",
"tooltip-disable-recording-rules-beta": "Ez a funkció letiltja a felvételkészítési szabályokat. Kapcsolja be az irányítópult teljesítményének javítása érdekében",
"tooltip-http-method": "A Prometheus-adatforrás lekérdezéséhez használhatja a POST- vagy a GET HTTP-metódust. A POST az ajánlott metódus, mivel nagyobb lekérdezéseket tesz lehetővé. Módosítsa ezt GET-re, ha a Prometheus-verziója régebbi, mint a 2.1-es, vagy ha a POST-kérések korlátozva vannak a hálózatában.",
"tooltip-incremental-querying-beta": "Ez a funkció megváltoztatja a relatív lekérdezések azon alapértelmezett viselkedését, hogy mindig friss adatokat kérjenek le a Prometheus-példányból, ehelyett a lekérdezési eredményeket a rendszer gyorsítótárazza, és csak új rekordok lesznek lekérve. Kapcsolja be az adatbázis és a hálózat terhelésének csökkentése érdekében.",
"tooltip-metric-names-suggestion-limit": "Azon metrikanevek maximális száma, amelyek automatikus kitöltési javaslatként jelenhetnek meg a lekérdezésszerkesztő Kód módjában.",
"tooltip-prom-type-version": "Ezzel állíthatja be a(z) {{promType}}-példány verzióját, ha nincs automatikusan konfigurálva.",
"tooltip-prometheus-type": "Állítsa be a Prometheus-adatbázis típusára, pl.: Prometheus, Cortex, Mimir vagy Thanos. A mező módosításával menti az aktuális beállításokat. A Prometheus bizonyos típusai támogatják vagy nem támogatják a különböző API-kat. Például egyes típusok támogatják a reguláris kifejezéses egyeztetést a címkelekérdezésekhez a teljesítmény javítása érdekében. Egyes típusok rendelkeznek API-val a metaadatokhoz. Ha ezt helytelenül állítja be, furcsa viselkedést tapasztalhat a metrikák és címkék lekérdezésekor. Ellenőrizze a Prometheus dokumentációját, hogy biztosan a megfelelő típust adja meg.",
"tooltip-query-overlap-window": "Állítson be egy időtartamot, például: {{example1}}, vagy {{example2}}, vagy {{example3}}. A(z) {{default}} alapértelmezése. Ez az időtartam hozzáadódik az egyes növekményes kérések időtartamához.",
"tooltip-query-timeout": "Állítsa be a Prometheus lekérdezési időtúllépését.",
"tooltip-scrape-interval": "Ez az intervallum azt mutatja, hogy a Prometheus milyen gyakran gyűjt adatokat a célokról. Állítsa be a Prometheus konfigurációs fájljában konfigurált tipikus adatgyűjtési és értékelési intervallumra. Ha ezt nagyobb értékre állítja, mint a Prometheus konfigurációs fájljának intervalluma, a Grafana ennek az intervallumnak megfelelően értékeli az adatokat, és kevesebb adatpontot fog látni. Alapértelmezett érték: {{default}}.",
"tooltip-series-limit": "A korlát minden erőforrásra (metrikára, címkére és értékre) vonatkozik mindkét végpont (sorozatok és címkék) esetében. Hagyja üresen a mezőt az alapértelmezett korlát (40 000) használatához. Állítsa 0-ra a korlát letiltásához és az összes lekéréséhez – ez teljesítményproblémákat okozhat. Az alapértelmezett korlát 40 000.",
"tooltip-use-series-endpoint": "Ennek az opciónak a bejelölésével előnyben részesíti a sorozat végpontját {{exampleParameter}} paraméterrel a címkeértékek végpontjához képest {{exampleParameter}} paraméterrel. Bár a címkeértékek végpontja hatékonyabbnak tekinthető, egyes felhasználók előnyben részesíthetik a sorozatot, mert rendelkezik POST-metódussal, míg a címkeértékek végpontja csak GET-metódussal rendelkezik."
}
},
"prom-query-legend-editor": {
@ -211,12 +211,12 @@
},
"querybuilder": {
"additional-settings": {
"content-filter-metric-names-regex-search-using": "",
"disable-text-wrap": ""
"content-filter-metric-names-regex-search-using": "A metrikanevek szűrése reguláris kifejezéses kereséssel, a Prometheus API további hívásával.",
"disable-text-wrap": "Sortörés letiltása"
},
"feedback-link": {
"give-feedback": "Visszajelzés küldése",
"title-give-feedback": ""
"title-give-feedback": "A metrikaböngésző új, és számítunk az építő jellegű visszajelzésére"
},
"get-collapsed-info": {
"exemplars": "",
@ -250,18 +250,18 @@
},
"handle-function": {
"text": {
"query-parsing-is-ambiguous": ""
"query-parsing-is-ambiguous": "A lekérdezés elemzése nem egyértelmű."
}
},
"label-filter-item": {
"aria-label-remove": "",
"placeholder-select-label": "",
"aria-label-remove": "{{name}} eltávolítása",
"placeholder-select-label": "Címke kiválasztása",
"placeholder-select-value": "Érték kijelölése"
},
"label-filters": {
"label-filters": "",
"label-label-filters": "",
"tooltip-label-filters": ""
"label-filters": "Címkeszűrők",
"label-label-filters": "Címkeszűrők",
"tooltip-label-filters": "Opcionális: a lekérdezéstípushoz kiválasztott metrika szűrésére szolgál."
},
"label-param-editor": {
"loadingMessage-loading-labels": "",
@ -269,92 +269,92 @@
},
"metric-combobox": {
"async-select": {
"aria-label-open-metrics-explorer": "",
"placeholder-select-metric": "",
"tooltip-open-metrics-explorer": ""
"aria-label-open-metrics-explorer": "Metrikaböngésző megnyitása",
"placeholder-select-metric": "Metrika kiválasztása",
"tooltip-open-metrics-explorer": "Metrikaböngésző megnyitása"
},
"label-metric": "Metrika",
"tooltip-metric": ""
"tooltip-metric": "Opcionális: a megadott metrikában a címke nevéhez tartozó címkeértékek listáját adja vissza."
},
"metrics-modal": {
"additional-settings": "",
"additional-settings": "További beállítások",
"aria-label-additional-settings": "További beállítások",
"aria-label-browse-metrics": "",
"currently-selected": "",
"metrics-pre-filtered": "",
"placeholder-results-per-page": "",
"results-per-page": "",
"title-metrics-explorer": "",
"results-amount_one": "",
"results-amount_other": ""
"aria-label-browse-metrics": "Metrikák böngészése",
"currently-selected": "Jelenleg kiválasztott: {{selected}}",
"metrics-pre-filtered": "Ezek a metrikák előszűrtek a címkeszűrőkben kiválasztott címkék alapján.",
"placeholder-results-per-page": "találat oldalanként",
"results-per-page": "Találatok száma oldalanként",
"title-metrics-explorer": "Metrikaböngésző",
"results-amount_one": "{{count}}/{{num}} találat megjelenítése",
"results-amount_other": "{{count}}/{{num}} találat megjelenítése"
},
"nested-query": {
"label": {
"ignoring": "",
"ignoring": "Mellőzés",
"on": "Be"
},
"operator": "Műveleti jel",
"tooltip-remove-match": "",
"vector-matches": ""
"tooltip-remove-match": "Egyezés eltávolítása",
"vector-matches": "Vektoregyezések"
},
"operation-editor": {
"not-found": "",
"title-remove": ""
"not-found": "A(z) {{id}} művelet nem található",
"title-remove": "{{name}} eltávolítása"
},
"operation-header": {
"placeholder-replace-with": "Csere ezzel:",
"title-click-to-view-alternative-operations": "",
"title-remove-operation": ""
"title-click-to-view-alternative-operations": "Kattintson az alternatív műveletek megtekintéséhez",
"title-remove-operation": "Művelet eltávolítása"
},
"operation-info-button": {
"title-click-to-show-description": "",
"title-remove-operation": ""
"title-click-to-show-description": "Kattintson a leírás megjelenítéséhez",
"title-remove-operation": "Művelet eltávolítása"
},
"operation-list": {
"operations": "",
"operations": "Műveletek",
"placeholder-search": "Keresés",
"title-add-operation": ""
"title-add-operation": "Művelet hozzáadása"
},
"operation-param-editor": {
"title-add": "",
"title-remove": ""
"title-add": "{{name}} hozzáadása",
"title-remove": "{{name}} eltávolítása"
},
"prom-query-builder-options": {
"aria-label-lower-limit-parameter": "",
"aria-label-select-resolution": "",
"aria-label-lower-limit-parameter": "Állítsa be a léptékparaméter alsó határát",
"aria-label-select-resolution": "Felbontás kiválasztása",
"format-options": {
"label-heatmap": "",
"label-table": "",
"label-time-series": ""
},
"label-exemplars": "",
"label-exemplars": "Mintapéldányok",
"label-format": "Formátum",
"label-min-step": "",
"label-resolution": "",
"label-min-step": "Min. lépték",
"label-resolution": "Felbontás",
"label-type": "Típus",
"placeholder-auto": "",
"placeholder-auto": "automatikus",
"title-options": "Beállítások",
"tooltip-min-step": ""
"tooltip-min-step": "További alsó határérték a Prometheus-lekérdezés léptékparaméteréhez, valamint a(z) <2>{{interval}}</2> és <4>{{rateInterval}}</4> változóhoz."
},
"prom-query-code-editor-autocomplete-info": {
"autocomplete-suggestions-limited": "",
"tooltip-autocomplete-suggestions-limited": ""
"autocomplete-suggestions-limited": "Automatikus kitöltési javaslatok korlátozva",
"tooltip-autocomplete-suggestions-limited": "A metrikanevek száma meghaladja az automatikus kitöltés korlátját. Csak a(z) {{autocompleteLimit}} legrelevánsabb metrika jelenik meg. A küszöbértéket az adatforrás beállításai között módosíthatja."
},
"prom-query-editor-selector": {
"body-syntax-error": "",
"confirmText-continue": "",
"kick-start-your-query": "Előbeállításos lekérdezés",
"label-explain": "",
"run-queries": "",
"title-parsing-error-switch-builder": ""
"label-explain": "Magyarázat",
"run-queries": "Lekérdezések futtatása",
"title-parsing-error-switch-builder": "Elemzési hiba: Váltás építő módba?"
},
"prom-query-legend-editor": {
"label-legend": "",
"placeholder-select-legend-mode": "",
"tooltip-legend": ""
"label-legend": "Jelmagyarázat",
"placeholder-select-legend-mode": "Jelmagyarázat mód kiválasztása",
"tooltip-legend": "Sorozatnév felülbírálása vagy sablon. Például a(z) {{templateExample}} helyébe a(z) {{labelName}} címkeértéke lép."
},
"query-builder-hints": {
"hint-details": ""
"hint-details": "tipp: {{hintDetails}}"
},
"query-editor-mode-toggle": {
"editor-modes": {
@ -363,30 +363,30 @@
}
},
"query-pattern": {
"apply-query": "",
"aria-label-apply-query-starter-button": "",
"aria-label-back-button": "",
"aria-label-create-new-query-button": "",
"aria-label-raw-query": "",
"aria-label-use-this-query-button": "",
"apply-query": "Lekérdezés alkalmazása",
"aria-label-apply-query-starter-button": "lekérdezés-előbeállító alkalmazása gomb",
"aria-label-back-button": "vissza gomb",
"aria-label-create-new-query-button": "új lekérdezés létrehozása gomb",
"aria-label-raw-query": "{{patternName}} nyers lekérdezés",
"aria-label-use-this-query-button": "használja ezt a lekérdezést gomb",
"back": "Vissza",
"create-new-query": "",
"create-new-query": "Új lekérdezés létrehozása",
"use-this-query": "Használja ezt a lekérdezést"
},
"query-patterns-modal": {
"aria-label-close-kick-start-your-query-modal": "",
"aria-label-close-kick-start-your-query-modal": "előbeállításos lekérdezés modális ablakának bezárása",
"aria-label-kick-start-your-query-modal": "Előbeállításos lekérdezés modális ablak",
"aria-label-toggle-query-starter": "",
"aria-label-toggle-query-starter": "{{patternType}} lekérdezés-előbeállító kártya megnyitása és bezárása",
"close": "Bezárás",
"description-kick-start-your-query": "",
"label-toggle-query-starter": "",
"description-kick-start-your-query": "Kezdje el létrehozni a lekérdezést előbeállításokkal az alábbi lekérdezések egyikének kiválasztásával. Ezután folytathatja a lekérdezés befejezését.",
"label-toggle-query-starter": "{{patternType}} lekérdezés-előbeállítók",
"title-kick-start-your-query": "Előbeállításos lekérdezés"
},
"raw-query": {
"aria-label-selector": ""
"aria-label-selector": "választó"
},
"results-table": {
"content-descriptive-type": "",
"content-descriptive-type": "{{descriptiveType}} létrehozásakor a Prometheus több, számláló típusú sorozatot jelenít meg. ",
"description": "Leírás",
"message-expand-label-filters": "",
"message-expand-search": "",
@ -397,7 +397,7 @@
},
"update-function-args": {
"text": {
"query-parsing-is-ambiguous": ""
"query-parsing-is-ambiguous": "A lekérdezés elemzése nem egyértelmű."
}
}
}

@ -2,201 +2,201 @@
"grafana-prometheus": {
"components": {
"annotation-query-editor": {
"annotation-data-load-error": "",
"aria-label-lower-limit-parameter": "",
"label-min-step": "",
"label-series-value-as-timestamp": "",
"annotation-data-load-error": "Terjadi kesalahan pemuatan data anotasi!",
"aria-label-lower-limit-parameter": "Tetapkan batas bawah untuk parameter langkah",
"label-min-step": "Langkah minimum",
"label-series-value-as-timestamp": "Nilai data seri sebagai stempel waktu",
"label-tags": "Tag",
"label-text": "",
"label-text": "Teks",
"label-title": "Judul",
"placeholder-auto": "",
"tooltip-either-pattern-example-instance-replaced-label": "",
"tooltip-min-step": "",
"tooltip-timestamp-milliseconds-series-value-seconds-multiply": ""
"placeholder-auto": "auto",
"tooltip-either-pattern-example-instance-replaced-label": "Gunakan nama atau pola. Misalnya, {{labelTemplate}} diganti dengan nilai label untuk label {{labelName}}.",
"tooltip-min-step": "Batas bawah tambahan untuk parameter langkah kueri Prometheus dan untuk variabel <2>{{intervalVar}}</2> dan <4>{{rateIntervalVar}}</4>.",
"tooltip-timestamp-milliseconds-series-value-seconds-multiply": "Unit stempel waktu adalah milidetik. Jika satuan nilai data seri adalah detik, kalikan vektor rentangnya dengan 1000."
},
"get-query-type-options": {
"description": {
"instant-query-range": ""
"instant-query-range": "Jalankan kueri Instan dan kueri Rentang"
},
"label": {
"both": ""
"both": "Keduanya"
},
"range-options": {
"description": {
"query-range": ""
"query-range": "Jalankan kueri selama rentang waktu tertentu"
},
"label": {
"instant": "",
"range": ""
"instant": "Instan",
"range": "Rentang"
}
}
},
"label-selector": {
"aria-label-filter-expression-for-label": "",
"description-select-labels": "",
"select-labels-to-search-in": ""
"aria-label-filter-expression-for-label": "Filter persamaan berdasarkan label",
"description-select-labels": "Setelah nilai label dipilih, hanya kombinasi label yang mungkin yang ditampilkan.",
"select-labels-to-search-in": "2. Pilih label untuk pencarian"
},
"metric-selector": {
"aria-label-filter-expression-for-metric": "",
"aria-label-limit-results-from-series-endpoint": "",
"description-series-limit": "",
"label-select-metric": "",
"select-a-metric": "",
"series-limit": ""
"aria-label-filter-expression-for-metric": "Filter persamaan berdasarkan metrik",
"aria-label-limit-results-from-series-endpoint": "Batasi hasil dari titik akhir data seri",
"description-series-limit": "Batas ini berlaku untuk semua metrik, label, dan nilai. Biarkan bidang kosong untuk menggunakan batas default. Atur ke 0 untuk menonaktifkan batas dan mengambil semuanya — ini dapat menyebabkan masalah kinerja.",
"label-select-metric": "Setelah metrik dipilih, hanya label yang mungkin yang ditampilkan. Label dibatasi oleh batas data seri di bawah ini.",
"select-a-metric": "1. Pilih metrik",
"series-limit": "Batas data seri"
},
"prom-cheat-sheet": {
"prom-ql-cheat-sheet": ""
"prom-ql-cheat-sheet": "Lembar Ringkasan PromQL"
},
"prom-exemplar-field": {
"exemplars": "",
"tooltip-disable-query": "",
"tooltip-enable-query": ""
"exemplars": "Contoh",
"tooltip-disable-query": "Nonaktifkan kueri dengan contoh",
"tooltip-enable-query": "Aktifkan kueri dengan contoh"
},
"prom-explore-extra-field": {
"aria-label-prometheus-extra-field": "",
"aria-label-query-type-field": "",
"aria-label-step-field": "",
"min-step": "",
"query-type": "",
"tooltip-units-builtin-variables-example-interval-rateinterval": ""
"aria-label-prometheus-extra-field": "Bidang tambahan Prometheus",
"aria-label-query-type-field": "Bidang jenis kueri",
"aria-label-step-field": "Bidang langkah",
"min-step": "Langkah minimum",
"query-type": "Jenis kueri",
"tooltip-units-builtin-variables-example-interval-rateinterval": "Unit waktu dan variabel bawaan dapat digunakan di sini, misalnya: {{example1}}, {{example2}}, {{example3}}, {{example4}}, {{example5}}, {{example6}}, {{example7}} (Default jika tidak ada unit yang ditentukan: {{default}})"
},
"prom-query-field": {
"placeholder-enter-a-prom-ql-query": ""
"placeholder-enter-a-prom-ql-query": "Masukkan kueri PromQL…"
},
"prom-variable-query-editor": {
"aria-label-classic-query": "",
"aria-label-metric-regex": "",
"aria-label-metric-selector": "",
"aria-label-prometheus-query": "",
"aria-label-query-type": "",
"aria-label-series-query": "",
"label-classic-query": "",
"aria-label-classic-query": "Kueri Klasik",
"aria-label-metric-regex": "Ekspresi reguler metrik",
"aria-label-metric-selector": "Selektor metrik",
"aria-label-prometheus-query": "Kueri Prometheus",
"aria-label-query-type": "Jenis kueri",
"aria-label-series-query": "Kueri Data Seri",
"label-classic-query": "Kueri Klasik",
"label-label": "Label",
"label-metric-regex": "",
"label-metric-regex": "Ekspresi reguler metrik",
"label-query": "Kueri",
"label-query-type": "",
"label-series-query": "",
"placeholder-classic-query": "",
"placeholder-metric-regex": "",
"placeholder-prometheus-query": "",
"label-query-type": "Jenis kueri",
"label-series-query": "Kueri Data Seri",
"placeholder-classic-query": "Kueri Klasik",
"placeholder-metric-regex": "Ekspresi reguler metrik",
"placeholder-prometheus-query": "Kueri Prometheus",
"placeholder-select-query-type": "Pilih jenis kueri",
"placeholder-series-query": "",
"returns-metrics-matching-specified-metric-regex": "",
"tooltip-classic-query": "",
"tooltip-label": "",
"tooltip-metric-regex": "",
"tooltip-query": "",
"tooltip-query-type": "",
"tooltip-series-query": ""
"placeholder-series-query": "Kueri Data Seri",
"returns-metrics-matching-specified-metric-regex": "Mengembalikan daftar metrik yang sesuai dengan regex metrik yang ditentukan.",
"tooltip-classic-query": "Implementasi awal dari editor kueri variabel Prometheus. Masukkan string dengan jenis kueri dan parameter yang benar seperti yang dijelaskan dalam dokumen ini. Misalnya, {{exampleQuery}}.",
"tooltip-label": "Mengembalikan daftar nilai label untuk nama label di semua metrik kecuali metrik tersebut ditentukan.",
"tooltip-metric-regex": "Mengembalikan daftar nama label, secara opsional menyaring berdasarkan regex metrik yang ditentukan.",
"tooltip-query": "Mengembalikan daftar hasil kueri Prometheus untuk kueri tersebut. Ini dapat mencakup fungsi Prometheus, yaitu {{exampleQuery}}.",
"tooltip-query-type": "Plugin sumber data Prometheus menyediakan jenis kueri berikut untuk variabel templat.",
"tooltip-series-query": "Masukkan metrik dengan label, hanya metrik atau hanya label, yaitu {{example1}}, {{example2}}, atau {{example3}}. Mengembalikan daftar deret waktu yang terkait dengan data yang dimasukkan."
},
"selector-actions": {
"aria-label-selector": "",
"aria-label-selector-clear-button": "",
"aria-label-use-selector-as-metrics-button": "",
"aria-label-use-selector-for-query-button": "",
"aria-label-validate-submit-button": "",
"aria-label-selector": "selektor",
"aria-label-selector-clear-button": "Tombol hapus selektor",
"aria-label-use-selector-as-metrics-button": "Gunakan selektor sebagai tombol metrik",
"aria-label-use-selector-for-query-button": "Gunakan selektor untuk tombol kueri",
"aria-label-validate-submit-button": "Validasi tombol kirim",
"clear": "Hapus",
"resulting-selector": "",
"use-as-rate-query": "",
"use-query": "",
"validate-selector": ""
"resulting-selector": "4. Selektor yang dihasilkan",
"use-as-rate-query": "Gunakan sebagai kueri rate",
"use-query": "Gunakan kueri",
"validate-selector": "Validasi selektor"
},
"value-selector": {
"aria-label-filter-expression-for-label-values": "",
"aria-label-values-for": "",
"description-search-field-values-across-selected-labels": "",
"select-multiple-values-for-your-labels": ""
"aria-label-filter-expression-for-label-values": "Filter persamaan berdasarkan nilai label",
"aria-label-values-for": "Nilai untuk {{labelKey}}",
"description-search-field-values-across-selected-labels": "Gunakan bidang pencarian untuk menemukan nilai di seluruh label yang dipilih.",
"select-multiple-values-for-your-labels": "3. Pilih (beberapa) nilai untuk label Anda"
}
},
"configuration": {
"alerting-settings-overhaul": {
"label-allow-as-recording-rules-target": "",
"label-manage-alerts-via-alerting-ui": "",
"label-allow-as-recording-rules-target": "Izinkan sebagai target aturan perekaman",
"label-manage-alerts-via-alerting-ui": "Kelola peringatan melalui UI Peringatan",
"title-alerting": "Alerting",
"tooltip-allow-as-recording-rules-target": "",
"tooltip-allow-as-recording-rules-target": "Izinkan sumber data ini dipilih sebagai target untuk menulis aturan perekaman.",
"tooltip-manage-alerts-via-alerting-ui": "Kelola aturan peringatan untuk sumber data ini. Untuk mengelola sumber daya alerting lainnya, tambahkan sumber data Alertmanager."
},
"config-editor": {
"browser-access-mode-error": "",
"description-advanced-settings": "",
"browser-access-mode-error": "Mode akses browser di sumber data Prometheus tidak lagi tersedia. Beralih ke mode akses server.",
"description-advanced-settings": "Pengaturan tambahan adalah pengaturan opsional yang dapat dikonfigurasi agar memiliki kendali lebih besar atas sumber data Anda.",
"title-advanced-settings": "Pengaturan lanjutan",
"title-error": "Kesalahan"
},
"data-source-http-settings-overhaul": {
"tooltip-browser-access-mode": "Metode akses Anda adalah <1>Browser</1>, ini berarti URL harus dapat diakses dari browser.",
"tooltip-http-url": "",
"tooltip-http-url": "Tentukan URL HTTP lengkap (misalnya {{exampleURL}})",
"tooltip-server-access-mode": "Metode akses Anda adalah <1>Server</1>, ini berarti URL harus dapat diakses dari backend/server grafana."
},
"docs-tip": {
"visit-docs-for-more-details-here": ""
"visit-docs-for-more-details-here": "Kunjungi dokumen untuk detail selengkapnya di sini."
},
"exemplar-setting": {
"label-data-source": "Sumber data",
"label-internal-link": "",
"label-internal-link": "Tautan internal",
"label-label-name": "Nama label",
"label-remove-exemplar-link": "",
"label-remove-exemplar-link": "Hapus tautan contoh",
"label-url": "URL",
"label-url-label": "",
"placeholder-go-to-examplecom": "",
"placeholder-httpsexamplecomvalueraw": "",
"placeholder-trace-id": "",
"title-remove-exemplar-link": "",
"tooltip-data-source": "",
"tooltip-internal-link": "",
"tooltip-label-name": "",
"tooltip-url": "",
"tooltip-url-label": ""
"label-url-label": "Label URL",
"placeholder-go-to-examplecom": "Buka example.com",
"placeholder-httpsexamplecomvalueraw": "https://example.com/${__value.raw}",
"placeholder-trace-id": "traceID",
"title-remove-exemplar-link": "Hapus tautan contoh",
"tooltip-data-source": "Sumber data yang akan dinavigasi oleh contoh.",
"tooltip-internal-link": "Aktifkan opsi ini jika Anda memiliki tautan internal. Saat diaktifkan, ini akan menampilkan selektor sumber data. Pilih penyimpanan data pelacakan backend untuk data contoh Anda.",
"tooltip-label-name": "Nama bidang dalam objek label yang harus digunakan untuk mendapatkan traceID.",
"tooltip-url": "URL backend jejak yang akan digunakan pengguna untuk melihat jejaknya",
"tooltip-url-label": "Gunakan untuk mengganti label tombol pada bidang traceID contoh."
},
"exemplars-settings": {
"add": "Tambahkan",
"no-exemplars-configurations": "",
"title-exemplars": ""
"no-exemplars-configurations": "Tidak ada konfigurasi contoh",
"title-exemplars": "Contoh"
},
"prom-settings": {
"aria-label-default-editor": "",
"aria-label-prom-type-type": "",
"aria-label-prometheus-type": "",
"aria-label-select-http-method": "",
"aria-label-default-editor": "Editor Default (Kode atau Pembuat)",
"aria-label-prom-type-type": "Jenis {{promType}}",
"aria-label-prometheus-type": "Jenis Prometheus",
"aria-label-select-http-method": "Pilih metode HTTP",
"editor-options": {
"label-builder": "",
"label-code": ""
},
"label-cache-level": "",
"label-custom-query-parameters": "",
"label-default-editor": "",
"label-disable-metrics-lookup": "",
"label-disable-recording-rules-beta": "",
"label-http-method": "",
"label-incremental-querying-beta": "",
"label-metric-names-suggestion-limit": "",
"label-prom-type-version": "",
"label-prometheus-type": "",
"label-query-overlap-window": "",
"label-query-timeout": "",
"label-scrape-interval": "",
"label-series-limit": "",
"label-use-series-endpoint": "",
"more-info": "",
"placeholder-example-maxsourceresolutionmtimeout": "",
"title-interval-behaviour": "",
"title-other": "",
"label-cache-level": "Level cache",
"label-custom-query-parameters": "Parameter kueri kustom",
"label-default-editor": "Editor default",
"label-disable-metrics-lookup": "Nonaktifkan pencarian metrik",
"label-disable-recording-rules-beta": "Nonaktifkan aturan perekaman (beta)",
"label-http-method": "Metode HTTP",
"label-incremental-querying-beta": "Kueri inkremental (beta)",
"label-metric-names-suggestion-limit": "Batas saran nama metrik",
"label-prom-type-version": "Versi {{promType}}",
"label-prometheus-type": "Jenis Prometheus",
"label-query-overlap-window": "Jendela kueri tumpang tindih",
"label-query-timeout": "Batas waktu kueri habis",
"label-scrape-interval": "Interval scrape",
"label-series-limit": "Batas data seri",
"label-use-series-endpoint": "Gunakan titik akhir data seri",
"more-info": "Untuk informasi lengkap tentang mengonfigurasi jenis dan versi prometheus dalam sumber data, lihat <2>dokumentasi penyediaan</2>.",
"placeholder-example-maxsourceresolutionmtimeout": "Contoh: {{example}}",
"title-interval-behaviour": "Perilaku interval",
"title-other": "Lainnya",
"title-performance": "Kinerja",
"title-query-editor": "",
"tooltip-cache-level": "",
"tooltip-custom-query-parameters": "",
"tooltip-default-editor": "",
"tooltip-disable-metrics-lookup": "",
"tooltip-disable-recording-rules-beta": "",
"tooltip-http-method": "",
"tooltip-incremental-querying-beta": "",
"tooltip-metric-names-suggestion-limit": "",
"tooltip-prom-type-version": "",
"tooltip-prometheus-type": "",
"tooltip-query-overlap-window": "",
"tooltip-query-timeout": "",
"tooltip-scrape-interval": "",
"tooltip-series-limit": "",
"tooltip-use-series-endpoint": ""
"title-query-editor": "Editor kueri",
"tooltip-cache-level": "Mengatur level cache peramban untuk kueri editor. Pengaturan cache yang lebih tinggi disarankan untuk sumber data dengan kardinalitas tinggi.",
"tooltip-custom-query-parameters": "Tambahkan parameter kustom ke URL kueri Prometheus. Misalnya {{example1}}, {{example2}}, {{example3}}, atau {{example4}}. Beberapa parameter harus digabungkan bersama dengan {{concatenationChar}}.",
"tooltip-default-editor": "Atur opsi editor default untuk semua pengguna sumber data ini.",
"tooltip-disable-metrics-lookup": "Memeriksa opsi ini akan menonaktifkan pemilih metrik dan dukungan metrik/label dalam pelengkapan otomatis bidang kueri. Ini membantu jika Anda memiliki masalah kinerja dengan instans Prometheus yang lebih besar. ",
"tooltip-disable-recording-rules-beta": "Fitur ini akan menonaktifkan aturan perekaman. Aktifkan ini untuk meningkatkan kinerja dasbor",
"tooltip-http-method": "Anda dapat menggunakan metode HTTP POST atau GET untuk melakukan kueri sumber data Prometheus Anda. POST adalah metode yang disarankan karena memungkinkan kueri yang lebih besar. Ubah ini menjadi GET jika Anda memiliki versi Prometheus yang lebih lama dari 2.1 atau jika permintaan POST dibatasi di jaringan Anda.",
"tooltip-incremental-querying-beta": "Fitur ini akan mengubah perilaku default kueri relatif: alih-alih selalu meminta data terbaru dari instans Prometheus, hasil kueri akan disimpan sementara, dan hanya data baru yang akan diminta. Aktifkan ini untuk mengurangi beban basis data dan jaringan.",
"tooltip-metric-names-suggestion-limit": "Jumlah maksimum nama metrik yang mungkin muncul sebagai saran pelengkapan otomatis dalam mode Kode editor kueri.",
"tooltip-prom-type-version": "Gunakan ini untuk mengatur versi instans {{promType}} Anda jika tidak dikonfigurasi secara otomatis.",
"tooltip-prometheus-type": "Atur ini ke jenis basis data prometheus Anda, misalnya Prometheus, Cortex, Mimir, atau Thanos. Mengubah bidang ini akan menyimpan pengaturan Anda saat ini. Jenis Prometheus tertentu mendukung atau tidak mendukung berbagai API. Misalnya, beberapa jenis mendukung pencocokan regex bagi kueri label untuk meningkatkan kinerja. Beberapa jenis memiliki API untuk metadata. Jika Anda mengatur ini secara tidak benar, Anda mungkin mengalami perilaku tidak biasa saat melakukan kueri metrik dan label. Periksa dokumentasi Prometheus Anda untuk memastikan Anda memasukkan jenis yang benar.",
"tooltip-query-overlap-window": "Tetapkan durasi seperti {{example1}} atau {{example2}} atau {{example3}}. Default {{default}}. Durasi ini akan ditambahkan ke durasi setiap permintaan tambahan.",
"tooltip-query-timeout": "Atur batas waktu kueri Prometheus.",
"tooltip-scrape-interval": "Interval ini adalah seberapa sering Prometheus melakukan scrape pada target. Atur ini ke interval scrape dan evaluasi umum yang dikonfigurasi dalam file konfigurasi Prometheus Anda. Jika Anda mengatur ini ke nilai yang lebih besar dari interval file konfigurasi Prometheus Anda, Grafana akan mengevaluasi data sesuai dengan interval ini dan Anda akan melihat lebih sedikit titik data. Default ke {{default}}.",
"tooltip-series-limit": "Batas ini berlaku untuk semua sumber daya (metrik, label, dan nilai) untuk kedua endpoint (deret dan label). Biarkan bidang kosong untuk menggunakan batas default (40000). Atur ke 0 untuk menonaktifkan batas dan mengambil semuanya — ini dapat menyebabkan masalah kinerja. Batas default adalah 40000.",
"tooltip-use-series-endpoint": "Memeriksa opsi ini akan mengutamakan titik akhir data seri dengan {{exampleParameter}} parameter daripada titik akhir nilai label dengan {{exampleParameter}} parameter. Meskipun titik akhir nilai label dianggap memiliki kinerja yang lebih baik, beberapa pengguna mungkin lebih menyukai data seri karena memiliki metode POST, sementara titik akhir nilai label hanya memiliki metode GET."
}
},
"prom-query-legend-editor": {
@ -211,12 +211,12 @@
},
"querybuilder": {
"additional-settings": {
"content-filter-metric-names-regex-search-using": "",
"disable-text-wrap": ""
"content-filter-metric-names-regex-search-using": "Filter nama metrik dengan pencarian regex, menggunakan panggilan tambahan pada API Prometheus.",
"disable-text-wrap": "Nonaktifkan pemenggalan teks otomatis"
},
"feedback-link": {
"give-feedback": "Berikan umpan balik",
"title-give-feedback": ""
"title-give-feedback": "Penjelajah metrik ini masih baru, beri tahu kami cara untuk meningkatkannya"
},
"get-collapsed-info": {
"exemplars": "",
@ -250,18 +250,18 @@
},
"handle-function": {
"text": {
"query-parsing-is-ambiguous": ""
"query-parsing-is-ambiguous": "Penguraian kueri mengalami masalah ketidakjelasan."
}
},
"label-filter-item": {
"aria-label-remove": "",
"placeholder-select-label": "",
"aria-label-remove": "Hapus {{name}}",
"placeholder-select-label": "Pilih label",
"placeholder-select-value": "Pilih nilai"
},
"label-filters": {
"label-filters": "",
"label-label-filters": "",
"tooltip-label-filters": ""
"label-filters": "Filter label",
"label-label-filters": "Filter label",
"tooltip-label-filters": "Opsional: digunakan untuk menyaring metrik yang dipilih untuk jenis kueri ini."
},
"label-param-editor": {
"loadingMessage-loading-labels": "",
@ -269,91 +269,91 @@
},
"metric-combobox": {
"async-select": {
"aria-label-open-metrics-explorer": "",
"placeholder-select-metric": "",
"tooltip-open-metrics-explorer": ""
"aria-label-open-metrics-explorer": "Buka penjelajah metrik",
"placeholder-select-metric": "Pilih metrik",
"tooltip-open-metrics-explorer": "Buka penjelajah metrik"
},
"label-metric": "Metrik",
"tooltip-metric": ""
"tooltip-metric": "Opsional: mengembalikan daftar nilai label untuk nama label dalam metrik yang ditentukan."
},
"metrics-modal": {
"additional-settings": "",
"additional-settings": "Pengaturan Tambahan",
"aria-label-additional-settings": "Pengaturan tambahan",
"aria-label-browse-metrics": "",
"currently-selected": "",
"metrics-pre-filtered": "",
"placeholder-results-per-page": "",
"results-per-page": "",
"title-metrics-explorer": "",
"results-amount_other": ""
"aria-label-browse-metrics": "Telusuri metrik",
"currently-selected": "Sedang dipilih: {{selected}}",
"metrics-pre-filtered": "Metrik ini telah difilter sebelumnya berdasarkan label yang dipilih di filter label.",
"placeholder-results-per-page": "hasil per halaman",
"results-per-page": "Hasil per halaman",
"title-metrics-explorer": "Penjelajah metrik",
"results-amount_other": "Menampilkan {{num}} dari {{count}} hasil"
},
"nested-query": {
"label": {
"ignoring": "",
"ignoring": "Mengabaikan",
"on": "Aktif"
},
"operator": "Operator",
"tooltip-remove-match": "",
"vector-matches": ""
"tooltip-remove-match": "Hapus kecocokan",
"vector-matches": "Kecocokan vektor"
},
"operation-editor": {
"not-found": "",
"title-remove": ""
"not-found": "Operasi {{id}} tidak ditemukan",
"title-remove": "Hapus {{name}}"
},
"operation-header": {
"placeholder-replace-with": "Ganti dengan",
"title-click-to-view-alternative-operations": "",
"title-remove-operation": ""
"title-click-to-view-alternative-operations": "Klik untuk melihat operasi alternatif",
"title-remove-operation": "Hapus operasi"
},
"operation-info-button": {
"title-click-to-show-description": "",
"title-remove-operation": ""
"title-click-to-show-description": "Klik untuk menampilkan deskripsi",
"title-remove-operation": "Hapus operasi"
},
"operation-list": {
"operations": "",
"operations": "Operasi",
"placeholder-search": "Cari",
"title-add-operation": ""
"title-add-operation": "Tambah operasi"
},
"operation-param-editor": {
"title-add": "",
"title-remove": ""
"title-add": "Tambahkan {{name}}",
"title-remove": "Hapus {{name}}"
},
"prom-query-builder-options": {
"aria-label-lower-limit-parameter": "",
"aria-label-select-resolution": "",
"aria-label-lower-limit-parameter": "Tetapkan batas bawah untuk parameter langkah",
"aria-label-select-resolution": "Pilih resolusi",
"format-options": {
"label-heatmap": "",
"label-table": "",
"label-time-series": ""
},
"label-exemplars": "",
"label-exemplars": "Contoh",
"label-format": "Format",
"label-min-step": "",
"label-resolution": "",
"label-min-step": "Langkah minimum",
"label-resolution": "Resolusi",
"label-type": "Jenis",
"placeholder-auto": "",
"placeholder-auto": "auto",
"title-options": "Opsi",
"tooltip-min-step": ""
"tooltip-min-step": "Batas bawah tambahan untuk parameter langkah kueri Prometheus dan untuk variabel <2>{{interval}}</2> dan <4>{{rateInterval}}</4>."
},
"prom-query-code-editor-autocomplete-info": {
"autocomplete-suggestions-limited": "",
"tooltip-autocomplete-suggestions-limited": ""
"autocomplete-suggestions-limited": "Saran pelengkapan otomatis dibatasi",
"tooltip-autocomplete-suggestions-limited": "Jumlah nama metrik melebihi batas pelengkapan otomatis. Hanya {{autocompleteLimit}} metrik yang paling relevan yang ditampilkan. Anda dapat menyesuaikan ambang batas dalam pengaturan sumber data."
},
"prom-query-editor-selector": {
"body-syntax-error": "",
"confirmText-continue": "",
"kick-start-your-query": "Mulai kueri Anda",
"label-explain": "",
"run-queries": "",
"title-parsing-error-switch-builder": ""
"label-explain": "Penjelasan",
"run-queries": "Jalankan kueri",
"title-parsing-error-switch-builder": "Terjadi kesalahan penguraian: Beralih ke mode pembuat?"
},
"prom-query-legend-editor": {
"label-legend": "",
"placeholder-select-legend-mode": "",
"tooltip-legend": ""
"label-legend": "Legenda",
"placeholder-select-legend-mode": "Pilih mode legenda",
"tooltip-legend": "Mengganti nama seri atau templat. Misalnya, {{templateExample}} akan diganti dengan nilai label untuk {{labelName}}."
},
"query-builder-hints": {
"hint-details": ""
"hint-details": "petunjuk: {{hintDetails}}"
},
"query-editor-mode-toggle": {
"editor-modes": {
@ -362,30 +362,30 @@
}
},
"query-pattern": {
"apply-query": "",
"aria-label-apply-query-starter-button": "",
"aria-label-back-button": "",
"aria-label-create-new-query-button": "",
"aria-label-raw-query": "",
"aria-label-use-this-query-button": "",
"apply-query": "Terapkan kueri",
"aria-label-apply-query-starter-button": "tombol mulai terapkan kueri",
"aria-label-back-button": "tombol kembali",
"aria-label-create-new-query-button": "tombol buat kueri baru",
"aria-label-raw-query": "Kueri {{patternName}} mentah",
"aria-label-use-this-query-button": "tombol gunakan kueri ini",
"back": "Kembali",
"create-new-query": "",
"create-new-query": "Buat kueri baru",
"use-this-query": "Gunakan kueri ini"
},
"query-patterns-modal": {
"aria-label-close-kick-start-your-query-modal": "",
"aria-label-close-kick-start-your-query-modal": "tutup modal untuk memulai kueri Anda",
"aria-label-kick-start-your-query-modal": "Mulai modal kueri Anda",
"aria-label-toggle-query-starter": "",
"aria-label-toggle-query-starter": "buka dan tutup kartu pemula kueri {{patternType}}",
"close": "Tutup",
"description-kick-start-your-query": "",
"label-toggle-query-starter": "",
"description-kick-start-your-query": "Mulai kueri Anda dengan memilih salah satu kueri ini. Anda kemudian dapat melanjutkan untuk menyelesaikan kueri Anda.",
"label-toggle-query-starter": "kueri awal {{patternType}}",
"title-kick-start-your-query": "Mulai kueri Anda"
},
"raw-query": {
"aria-label-selector": ""
"aria-label-selector": "selektor"
},
"results-table": {
"content-descriptive-type": "",
"content-descriptive-type": "Saat membuat {{descriptiveType}}, Prometheus mengekspos beberapa data seri dengan penghitung jenis. ",
"description": "Deskripsi",
"message-expand-label-filters": "",
"message-expand-search": "",
@ -396,7 +396,7 @@
},
"update-function-args": {
"text": {
"query-parsing-is-ambiguous": ""
"query-parsing-is-ambiguous": "Penguraian kueri mengalami masalah ketidakjelasan."
}
}
}

@ -2,201 +2,201 @@
"grafana-prometheus": {
"components": {
"annotation-query-editor": {
"annotation-data-load-error": "",
"aria-label-lower-limit-parameter": "",
"label-min-step": "",
"label-series-value-as-timestamp": "",
"annotation-data-load-error": "注釈データの読み込みエラー!",
"aria-label-lower-limit-parameter": "ステップパラメーターの下限を設定",
"label-min-step": "最小ステップ",
"label-series-value-as-timestamp": "タイムスタンプとしての系列値",
"label-tags": "タグ",
"label-text": "",
"label-text": "テキスト",
"label-title": "タイトル",
"placeholder-auto": "",
"tooltip-either-pattern-example-instance-replaced-label": "",
"tooltip-min-step": "",
"tooltip-timestamp-milliseconds-series-value-seconds-multiply": ""
"placeholder-auto": "自動",
"tooltip-either-pattern-example-instance-replaced-label": "名前またはパターンのいずれかを使用します。例えば、{{labelTemplate}}はラベル{{labelName}}のラベル値に置き換えられます。",
"tooltip-min-step": "Prometheusクエリのステップパラメーターと<2>{{intervalVar}}</2>および<4>{{rateIntervalVar}}</4>変数の追加下限。",
"tooltip-timestamp-milliseconds-series-value-seconds-multiply": "タイムスタンプの単位はミリ秒です。系列値の単位が秒の場合、その範囲ベクトルに1000を掛けます。"
},
"get-query-type-options": {
"description": {
"instant-query-range": ""
"instant-query-range": "インスタントクエリと範囲クエリを実行"
},
"label": {
"both": ""
"both": "両方"
},
"range-options": {
"description": {
"query-range": ""
"query-range": "時間範囲にわたってクエリを実行"
},
"label": {
"instant": "",
"range": ""
"instant": "インスタント",
"range": "範囲"
}
}
},
"label-selector": {
"aria-label-filter-expression-for-label": "",
"description-select-labels": "",
"select-labels-to-search-in": ""
"aria-label-filter-expression-for-label": "ラベルのフィルター式",
"description-select-labels": "ラベル値を選択すると、可能なラベルの組み合わせのみが表示されます。",
"select-labels-to-search-in": "2. 検索するラベルを選択"
},
"metric-selector": {
"aria-label-filter-expression-for-metric": "",
"aria-label-limit-results-from-series-endpoint": "",
"description-series-limit": "",
"label-select-metric": "",
"select-a-metric": "",
"series-limit": ""
"aria-label-filter-expression-for-metric": "メトリックのフィルター式",
"aria-label-limit-results-from-series-endpoint": "系列エンドポイントからの結果を制限",
"description-series-limit": "制限はすべてのメトリック、ラベル、値に適用されます。デフォルトの制限を使用するには、フィールドを空のままにしてください。制限を無効にしてすべてを取得するには0に設定します。これによりパフォーマンスの問題が発生する可能性があります。",
"label-select-metric": "メトリックを選択すると、可能なラベルのみが表示されます。ラベルには以下の系列制限が適用されます。",
"select-a-metric": "メトリックを選択",
"series-limit": "系列制限"
},
"prom-cheat-sheet": {
"prom-ql-cheat-sheet": ""
"prom-ql-cheat-sheet": "PromQLチートシート"
},
"prom-exemplar-field": {
"exemplars": "",
"tooltip-disable-query": "",
"tooltip-enable-query": ""
"exemplars": "エグゼンプラー",
"tooltip-disable-query": "エグゼンプラーを使用したクエリを無効化",
"tooltip-enable-query": "エグゼンプラーを使用したクエリを有効化"
},
"prom-explore-extra-field": {
"aria-label-prometheus-extra-field": "",
"aria-label-query-type-field": "",
"aria-label-step-field": "",
"min-step": "",
"query-type": "",
"tooltip-units-builtin-variables-example-interval-rateinterval": ""
"aria-label-prometheus-extra-field": "Prometheus追加フィールド",
"aria-label-query-type-field": "クエリタイプフィールド",
"aria-label-step-field": "ステップフィールド",
"min-step": "最小ステップ",
"query-type": "クエリタイプ",
"tooltip-units-builtin-variables-example-interval-rateinterval": "ここでは時間単位と組み込み変数を使用できます。例: {{example1}}、{{example2}}、{{example3}}、{{example4}}、{{example5}}、{{example6}}、{{example7}}(単位が指定されていない場合のデフォルト: {{default}})"
},
"prom-query-field": {
"placeholder-enter-a-prom-ql-query": ""
"placeholder-enter-a-prom-ql-query": "PromQLクエリを入力…"
},
"prom-variable-query-editor": {
"aria-label-classic-query": "",
"aria-label-metric-regex": "",
"aria-label-metric-selector": "",
"aria-label-prometheus-query": "",
"aria-label-query-type": "",
"aria-label-series-query": "",
"label-classic-query": "",
"aria-label-classic-query": "クラシッククエリ",
"aria-label-metric-regex": "メトリック正規表現",
"aria-label-metric-selector": "メトリックセレクター",
"aria-label-prometheus-query": "Prometheusクエリ",
"aria-label-query-type": "クエリタイプ",
"aria-label-series-query": "系列クエリ",
"label-classic-query": "クラシッククエリ",
"label-label": "ラベル",
"label-metric-regex": "",
"label-metric-regex": "メトリック正規表現",
"label-query": "クエリ",
"label-query-type": "",
"label-series-query": "",
"placeholder-classic-query": "",
"placeholder-metric-regex": "",
"placeholder-prometheus-query": "",
"label-query-type": "クエリタイプ",
"label-series-query": "系列クエリ",
"placeholder-classic-query": "クラシッククエリ",
"placeholder-metric-regex": "メトリック正規表現",
"placeholder-prometheus-query": "Prometheusクエリ",
"placeholder-select-query-type": "クエリタイプを選択",
"placeholder-series-query": "",
"returns-metrics-matching-specified-metric-regex": "",
"tooltip-classic-query": "",
"tooltip-label": "",
"tooltip-metric-regex": "",
"tooltip-query": "",
"tooltip-query-type": "",
"tooltip-series-query": ""
"placeholder-series-query": "系列クエリ",
"returns-metrics-matching-specified-metric-regex": "指定された正規表現に一致するメトリックのリストを返します。",
"tooltip-classic-query": "Prometheus変数クエリエディターの元の実装。これらのドキュメントに記載されているように、正しいクエリタイプとパラメーターを含む文字列を入力してください。例: {{exampleQuery}}。",
"tooltip-label": "メトリックが指定されていない限り、すべてのメトリックのラベル名に対するラベル値のリストを返します。",
"tooltip-metric-regex": "ラベル名のリストを返します。オプションで、指定されたメトリック正規表現でフィルタリングすることも可能です。",
"tooltip-query": "クエリのPrometheusクエリ結果のリストを返します。これには、Prometheus関数を含めることもできます。例: {{exampleQuery}}。",
"tooltip-query-type": "Prometheusデータソースプラグインは、テンプレート変数に以下のクエリタイプを入力します。",
"tooltip-series-query": "ラベル付きメトリック、メトリックのみ、またはラベルのみを入力します。例: {{example1}}、{{example2}}、または{{example3}}。入力されたデータに関連する時系列のリストを返します。"
},
"selector-actions": {
"aria-label-selector": "",
"aria-label-selector-clear-button": "",
"aria-label-use-selector-as-metrics-button": "",
"aria-label-use-selector-for-query-button": "",
"aria-label-validate-submit-button": "",
"aria-label-selector": "セレクター",
"aria-label-selector-clear-button": "セレクタークリアボタン",
"aria-label-use-selector-as-metrics-button": "メトリックボタンにセレクターを使用",
"aria-label-use-selector-for-query-button": "クエリボタンにセレクターを使用",
"aria-label-validate-submit-button": "送信ボタンを検証",
"clear": "消去",
"resulting-selector": "",
"use-as-rate-query": "",
"use-query": "",
"validate-selector": ""
"resulting-selector": "4. 結果セレクター",
"use-as-rate-query": "レートクエリとして使用",
"use-query": "このクエリを使用",
"validate-selector": "セレクターを検証"
},
"value-selector": {
"aria-label-filter-expression-for-label-values": "",
"aria-label-values-for": "",
"description-search-field-values-across-selected-labels": "",
"select-multiple-values-for-your-labels": ""
"aria-label-filter-expression-for-label-values": "ラベル値のフィルター式",
"aria-label-values-for": "{{labelKey}}の値",
"description-search-field-values-across-selected-labels": "検索フィールドを使用して選択したラベル全体の値を検索します。",
"select-multiple-values-for-your-labels": "3. ラベルの値を(複数)選択"
}
},
"configuration": {
"alerting-settings-overhaul": {
"label-allow-as-recording-rules-target": "",
"label-manage-alerts-via-alerting-ui": "",
"label-allow-as-recording-rules-target": "記録ルールのターゲットとして許可",
"label-manage-alerts-via-alerting-ui": "アラートUIでアラートを管理",
"title-alerting": "アラート",
"tooltip-allow-as-recording-rules-target": "",
"tooltip-allow-as-recording-rules-target": "このデータソースを記録ルール書き込みのターゲットとして選択できるようにします。",
"tooltip-manage-alerts-via-alerting-ui": "このデータソースのアラートルールを管理します。他のアラートリソースを管理するには、Alertmanagerデータソースを追加します。"
},
"config-editor": {
"browser-access-mode-error": "",
"description-advanced-settings": "",
"browser-access-mode-error": "Prometheusデータソースのブラウザアクセスモードは利用できなくなりました。サーバーアクセスモードに切り替えてください。",
"description-advanced-settings": "追加設定は、データソースをより詳細に制御するために指定できるオプション設定です。",
"title-advanced-settings": "詳細設定",
"title-error": "エラー"
},
"data-source-http-settings-overhaul": {
"tooltip-browser-access-mode": "アクセス方法は<1>ブラウザ</1>です。つまり、URLにブラウザからアクセスできる必要があります。",
"tooltip-http-url": "",
"tooltip-http-url": "完全なHTTP URLを指定してください(例: {{exampleURL}})",
"tooltip-server-access-mode": "アクセス方法は<1>サーバー</1>です。つまり、URLにGrafanaバックエンド/サーバーからアクセスできる必要があります。"
},
"docs-tip": {
"visit-docs-for-more-details-here": ""
"visit-docs-for-more-details-here": "詳細についてはこちらのドキュメントをご覧ください。"
},
"exemplar-setting": {
"label-data-source": "データソース",
"label-internal-link": "",
"label-internal-link": "内部リンク",
"label-label-name": "ラベル名",
"label-remove-exemplar-link": "",
"label-remove-exemplar-link": "エグゼンプラーリンクを削除",
"label-url": "URL",
"label-url-label": "",
"placeholder-go-to-examplecom": "",
"placeholder-httpsexamplecomvalueraw": "",
"placeholder-trace-id": "",
"title-remove-exemplar-link": "",
"tooltip-data-source": "",
"tooltip-internal-link": "",
"tooltip-label-name": "",
"tooltip-url": "",
"tooltip-url-label": ""
"label-url-label": "URLラベル",
"placeholder-go-to-examplecom": "example.comに移動",
"placeholder-httpsexamplecomvalueraw": "https://example.com/${__value.raw}",
"placeholder-trace-id": "traceID",
"title-remove-exemplar-link": "エグゼンプラーリンクを削除",
"tooltip-data-source": "エグゼンプラーによる移動先のデータソース。",
"tooltip-internal-link": "内部リンクがある場合は、このオプションを有効にしてください。有効にすると、データソースセレクターが表示されます。エグゼンプラーデータのバックエンドトレーシングデータストアを選択してください。",
"tooltip-label-name": "traceIDを取得するために使用されるラベルオブジェクト内のフィールド名。",
"tooltip-url": "ユーザーがトレースを確認するためにアクセスするトレースバックエンドのURL",
"tooltip-url-label": "エグゼンプラーのtraceIDフィールドのボタンラベルを上書きするために使用します。"
},
"exemplars-settings": {
"add": "追加",
"no-exemplars-configurations": "",
"title-exemplars": ""
"no-exemplars-configurations": "エグゼンプラー設定がありません",
"title-exemplars": "エグゼンプラー"
},
"prom-settings": {
"aria-label-default-editor": "",
"aria-label-prom-type-type": "",
"aria-label-prometheus-type": "",
"aria-label-select-http-method": "",
"aria-label-default-editor": "デフォルトエディター(コードまたはビルダー)",
"aria-label-prom-type-type": "{{promType}}タイプ",
"aria-label-prometheus-type": "Prometheusタイプ",
"aria-label-select-http-method": "HTTPメソッドを選択",
"editor-options": {
"label-builder": "",
"label-code": ""
},
"label-cache-level": "",
"label-custom-query-parameters": "",
"label-default-editor": "",
"label-disable-metrics-lookup": "",
"label-disable-recording-rules-beta": "",
"label-http-method": "",
"label-incremental-querying-beta": "",
"label-metric-names-suggestion-limit": "",
"label-prom-type-version": "",
"label-prometheus-type": "",
"label-query-overlap-window": "",
"label-query-timeout": "",
"label-scrape-interval": "",
"label-series-limit": "",
"label-use-series-endpoint": "",
"more-info": "",
"placeholder-example-maxsourceresolutionmtimeout": "",
"title-interval-behaviour": "",
"title-other": "",
"label-cache-level": "キャッシュレベル",
"label-custom-query-parameters": "カスタムクエリパラメーター",
"label-default-editor": "デフォルトエディター",
"label-disable-metrics-lookup": "メトリック検索を無効化",
"label-disable-recording-rules-beta": "記録ルールを無効化(ベータ版)",
"label-http-method": "HTTPメソッド",
"label-incremental-querying-beta": "増分クエリ(ベータ版)",
"label-metric-names-suggestion-limit": "メトリック名提案制限",
"label-prom-type-version": "{{promType}}バージョン",
"label-prometheus-type": "Prometheusタイプ",
"label-query-overlap-window": "クエリ重複ウィンドウ",
"label-query-timeout": "クエリタイムアウト",
"label-scrape-interval": "スクレイプ間隔",
"label-series-limit": "系列制限",
"label-use-series-endpoint": "系列エンドポイントを使用",
"more-info": "データソースでのPrometheusタイプとバージョンの設定の詳細については、<2>プロビジョニングドキュメント</2>をご覧ください。",
"placeholder-example-maxsourceresolutionmtimeout": "例: {{example}}",
"title-interval-behaviour": "間隔の動作",
"title-other": "その他",
"title-performance": "パフォーマンス",
"title-query-editor": "",
"tooltip-cache-level": "",
"tooltip-custom-query-parameters": "",
"tooltip-default-editor": "",
"tooltip-disable-metrics-lookup": "",
"tooltip-disable-recording-rules-beta": "",
"tooltip-http-method": "",
"tooltip-incremental-querying-beta": "",
"tooltip-metric-names-suggestion-limit": "",
"tooltip-prom-type-version": "",
"tooltip-prometheus-type": "",
"tooltip-query-overlap-window": "",
"tooltip-query-timeout": "",
"tooltip-scrape-interval": "",
"tooltip-series-limit": "",
"tooltip-use-series-endpoint": ""
"title-query-editor": "クエリエディター",
"tooltip-cache-level": "エディタークエリのブラウザーキャッシュレベルを設定します。高カーディナリティデータソースには、より高いキャッシュ設定を推奨します。",
"tooltip-custom-query-parameters": "PrometheusクエリURLにカスタムパラメーターを追加します。例: {{example1}}、{{example2}}、{{example3}}、または{{example4}}。複数のパラメーターは{{concatenationChar}}で連結する必要があります。",
"tooltip-default-editor": "このデータソースのすべてのユーザーにデフォルトエディターオプションを設定します。",
"tooltip-disable-metrics-lookup": "このオプションをオンにすると、クエリフィールドのオートコンプリートでメトリック選択とメトリック/ラベルサポートが無効になります。これは、大規模なPrometheusインスタンスをご利用でパフォーマンスの問題がある場合に役立ちます。",
"tooltip-disable-recording-rules-beta": "この機能は記録ルールを無効にします。ダッシュボードのパフォーマンスを向上させるには、この機能をオンにしてください",
"tooltip-http-method": "PrometheusデータソースをクエリするにはPOSTまたはGET HTTPメソッドのいずれかを使用できます。POSTメソッドだと、より大きなクエリを実行できるため、推奨される方法です。Prometheusのバージョンが2.1より古い場合、またはネットワークでPOSTリクエストが制限されている場合は、これをGETに変更してください。",
"tooltip-incremental-querying-beta": "この機能は相対クエリのデフォルト動作が変更され、常にPrometheusインスタンスから新しいデータをリクエストする代わりに、クエリ結果をキャッシュして新しいレコードのみをリクエストするようになります。データベースとネットワークの負荷を軽減するには、これをオンにしてください。",
"tooltip-metric-names-suggestion-limit": "クエリエディターのコードモードでオートコンプリート候補として表示される可能性のあるメトリック名の最大数。",
"tooltip-prom-type-version": "自動設定されていない場合、これを使用して{{promType}}インスタンスのバージョンを設定してください。",
"tooltip-prometheus-type": "Prometheus、Cortex、Mimir、Thanosなど、Prometheusデータベースのタイプに設定してください。このフィールドを変更すると、現在の設定が保存されます。一部のPrometheusのタイプでは、さまざまなAPIがサポートされているか、またはサポートされていない場合があります。例えば、一部のタイプではパフォーマンス向上のためにラベルクエリの正規表現マッチングをサポートしています。また、タイプによってはメタデータ用のAPIがあります。これを正しく設定しないと、メトリックとラベルのクエリ時に異常な動作が発生する可能性があります。正しいタイプを入力するために、Prometheusのドキュメントを確認してください。",
"tooltip-query-overlap-window": "{{example1}}や{{example2}}または{{example3}}のような期間を設定してください。デフォルトは{{default}}です。この期間は、各増分リクエストの期間に追加されます。",
"tooltip-query-timeout": "Prometheusクエリタイムアウトを設定します。",
"tooltip-scrape-interval": "この間隔は、Prometheusがターゲットをスクレイプする頻度です。Prometheus設定ファイルで指定された一般的なスクレイプと評価間隔に設定してください。これをPrometheus設定ファイルの間隔より大きな値に設定すると、Grafanaはこの間隔に従ってデータを評価するため、データポイントが少なくなります。デフォルトは{{default}}です。",
"tooltip-series-limit": "制限は両方のエンドポイント(系列とラベル)のすべてのリソース(メトリック、ラベル、値)に適用されます。デフォルトの制限(40000)を使用するには、フィールドを空のままにしてください。制限を無効にしてすべてを取得するには0に設定します。これによりパフォーマンスの問題が発生する可能性があります。デフォルトの制限は40000です。",
"tooltip-use-series-endpoint": "このオプションをオンにすると、{{exampleParameter}}パラメーターを持つラベル値エンドポイントより、{{exampleParameter}}パラメーターを持つ系列エンドポイントが優先されます。ラベル値エンドポイントの方がパフォーマンスが高いと考えられていますが、ラベル値エンドポイントにはGETメソッドしかないのに対し、系列にはPOSTメソッドがあるため、系列を好むユーザーもいます。"
}
},
"prom-query-legend-editor": {
@ -211,12 +211,12 @@
},
"querybuilder": {
"additional-settings": {
"content-filter-metric-names-regex-search-using": "",
"disable-text-wrap": ""
"content-filter-metric-names-regex-search-using": "Prometheus APIの追加呼び出しを使用して、正規表現検索でメトリック名をフィルタリングします。",
"disable-text-wrap": "テキストの折り返しを無効化"
},
"feedback-link": {
"give-feedback": "フィードバックを送信",
"title-give-feedback": ""
"title-give-feedback": "メトリックエクスプローラーは新機能です。改善点についてお聞かせください"
},
"get-collapsed-info": {
"exemplars": "",
@ -250,18 +250,18 @@
},
"handle-function": {
"text": {
"query-parsing-is-ambiguous": ""
"query-parsing-is-ambiguous": "クエリ解析が曖昧です。"
}
},
"label-filter-item": {
"aria-label-remove": "",
"placeholder-select-label": "",
"aria-label-remove": "{{name}}を削除",
"placeholder-select-label": "ラベルを選択",
"placeholder-select-value": "値を選択"
},
"label-filters": {
"label-filters": "",
"label-label-filters": "",
"tooltip-label-filters": ""
"label-filters": "ラベルフィルター",
"label-label-filters": "ラベルフィルター",
"tooltip-label-filters": "オプション: このクエリタイプのメトリック選択をフィルタリングするために使用します。"
},
"label-param-editor": {
"loadingMessage-loading-labels": "",
@ -269,91 +269,91 @@
},
"metric-combobox": {
"async-select": {
"aria-label-open-metrics-explorer": "",
"placeholder-select-metric": "",
"tooltip-open-metrics-explorer": ""
"aria-label-open-metrics-explorer": "メトリックエクスプローラーを開く",
"placeholder-select-metric": "メトリックを選択",
"tooltip-open-metrics-explorer": "メトリックエクスプローラーを開く"
},
"label-metric": "メトリック",
"tooltip-metric": ""
"tooltip-metric": "オプション: 指定されたメトリックのラベル名に対するラベル値のリストを返します。"
},
"metrics-modal": {
"additional-settings": "",
"additional-settings": "追加設定",
"aria-label-additional-settings": "追加設定",
"aria-label-browse-metrics": "",
"currently-selected": "",
"metrics-pre-filtered": "",
"placeholder-results-per-page": "",
"results-per-page": "",
"title-metrics-explorer": "",
"results-amount_other": ""
"aria-label-browse-metrics": "メトリックを参照",
"currently-selected": "現在選択中: {{selected}}",
"metrics-pre-filtered": "これらのメトリックは、ラベルフィルターで選択されたラベルによって事前にフィルタリングされています。",
"placeholder-results-per-page": "1ページあたりの結果数",
"results-per-page": "1ページあたりの結果数",
"title-metrics-explorer": "メトリックエクスプローラー",
"results-amount_other": "{{count}}件中{{num}}件の結果を表示"
},
"nested-query": {
"label": {
"ignoring": "",
"ignoring": "無視",
"on": "オン"
},
"operator": "オペレーター",
"tooltip-remove-match": "",
"vector-matches": ""
"tooltip-remove-match": "一致を削除",
"vector-matches": "ベクトル一致"
},
"operation-editor": {
"not-found": "",
"title-remove": ""
"not-found": "操作{{id}}が見つかりません",
"title-remove": "{{name}}を削除"
},
"operation-header": {
"placeholder-replace-with": "次で置き換え",
"title-click-to-view-alternative-operations": "",
"title-remove-operation": ""
"title-click-to-view-alternative-operations": "クリックして代わりの操作を表示",
"title-remove-operation": "操作を削除"
},
"operation-info-button": {
"title-click-to-show-description": "",
"title-remove-operation": ""
"title-click-to-show-description": "クリックして説明を表示",
"title-remove-operation": "操作を削除"
},
"operation-list": {
"operations": "",
"operations": "操作",
"placeholder-search": "検索",
"title-add-operation": ""
"title-add-operation": "操作を追加"
},
"operation-param-editor": {
"title-add": "",
"title-remove": ""
"title-add": "{{name}}を追加",
"title-remove": "{{name}}を削除"
},
"prom-query-builder-options": {
"aria-label-lower-limit-parameter": "",
"aria-label-select-resolution": "",
"aria-label-lower-limit-parameter": "ステップパラメーターの下限を設定",
"aria-label-select-resolution": "解像度を選択",
"format-options": {
"label-heatmap": "",
"label-table": "",
"label-time-series": ""
},
"label-exemplars": "",
"label-exemplars": "エグゼンプラー",
"label-format": "形式",
"label-min-step": "",
"label-resolution": "",
"label-min-step": "最小ステップ",
"label-resolution": "解像度",
"label-type": "種類",
"placeholder-auto": "",
"placeholder-auto": "自動",
"title-options": "オプション",
"tooltip-min-step": ""
"tooltip-min-step": "Prometheusクエリのステップパラメーターと<2>{{interval}}</2>および<4>{{rateInterval}}</4>変数の追加下限。"
},
"prom-query-code-editor-autocomplete-info": {
"autocomplete-suggestions-limited": "",
"tooltip-autocomplete-suggestions-limited": ""
"autocomplete-suggestions-limited": "オートコンプリート候補が制限されています",
"tooltip-autocomplete-suggestions-limited": "メトリック名の数がオートコンプリート制限を超えています。最も関連性の高い{{autocompleteLimit}}個のメトリックのみが表示されます。データソース設定で閾値を調整できます。"
},
"prom-query-editor-selector": {
"body-syntax-error": "",
"confirmText-continue": "",
"kick-start-your-query": "クエリを開始",
"label-explain": "",
"run-queries": "",
"title-parsing-error-switch-builder": ""
"label-explain": "説明",
"run-queries": "クエリを実行",
"title-parsing-error-switch-builder": "解析エラー: ビルダーモードに切り替えますか?"
},
"prom-query-legend-editor": {
"label-legend": "",
"placeholder-select-legend-mode": "",
"tooltip-legend": ""
"label-legend": "凡例",
"placeholder-select-legend-mode": "凡例モードを選択",
"tooltip-legend": "系列名の上書きまたはテンプレート。例: {{templateExample}}は{{labelName}}のラベル値に置き換えられます。"
},
"query-builder-hints": {
"hint-details": ""
"hint-details": "ヒント: {{hintDetails}}"
},
"query-editor-mode-toggle": {
"editor-modes": {
@ -362,30 +362,30 @@
}
},
"query-pattern": {
"apply-query": "",
"aria-label-apply-query-starter-button": "",
"aria-label-back-button": "",
"aria-label-create-new-query-button": "",
"aria-label-raw-query": "",
"aria-label-use-this-query-button": "",
"apply-query": "クエリを適用",
"aria-label-apply-query-starter-button": "クエリ適用開始ボタン",
"aria-label-back-button": "戻るボタン",
"aria-label-create-new-query-button": "新しいクエリ作成ボタン",
"aria-label-raw-query": "{{patternName}}の生クエリ",
"aria-label-use-this-query-button": "このクエリボタンを使用",
"back": "戻る",
"create-new-query": "",
"create-new-query": "新しいクエリを作成",
"use-this-query": "このクエリを使用"
},
"query-patterns-modal": {
"aria-label-close-kick-start-your-query-modal": "",
"aria-label-close-kick-start-your-query-modal": "クエリを開始モーダルを閉じる",
"aria-label-kick-start-your-query-modal": "クエリモーダルを開始",
"aria-label-toggle-query-starter": "",
"aria-label-toggle-query-starter": "{{patternType}}クエリ開始カードを開いて閉じる",
"close": "閉じる",
"description-kick-start-your-query": "",
"label-toggle-query-starter": "",
"description-kick-start-your-query": "これらのクエリの1つを選択してクエリを開始してください。その後、クエリを完了できます。",
"label-toggle-query-starter": "{{patternType}}クエリスターター",
"title-kick-start-your-query": "クエリを開始"
},
"raw-query": {
"aria-label-selector": ""
"aria-label-selector": "セレクター"
},
"results-table": {
"content-descriptive-type": "",
"content-descriptive-type": "{{descriptiveType}}を作成する際、Prometheusはタイプカウンターで複数の系列を公開します。",
"description": "説明",
"message-expand-label-filters": "",
"message-expand-search": "",
@ -396,7 +396,7 @@
},
"update-function-args": {
"text": {
"query-parsing-is-ambiguous": ""
"query-parsing-is-ambiguous": "クエリ解析が曖昧です。"
}
}
}

@ -84,7 +84,7 @@
"react-dom": "18.3.1",
"rimraf": "6.0.1",
"rollup": "^4.22.4",
"rollup-plugin-esbuild": "6.2.0",
"rollup-plugin-esbuild": "6.2.1",
"rollup-plugin-node-externals": "^8.0.0",
"rollup-plugin-sourcemaps": "0.6.3",
"typescript": "5.8.3"

@ -42,7 +42,7 @@
"glob": "^11.0.0",
"rimraf": "6.0.1",
"rollup": "^4.22.4",
"rollup-plugin-esbuild": "6.2.0",
"rollup-plugin-esbuild": "6.2.1",
"rollup-plugin-node-externals": "^8.0.0",
"typescript": "5.8.3"
},

@ -24,6 +24,7 @@ export interface Options {
logLineMenuCustomItems?: unknown;
logRowMenuIconsAfter?: unknown;
logRowMenuIconsBefore?: unknown;
noInteractions?: boolean;
/**
* TODO: figure out how to define callbacks
*/

@ -2,26 +2,26 @@
"grafana-sql": {
"components": {
"confirm-modal": {
"builder-mode": "",
"builder-mode": "Im Builder-Modus werden keine am Code vorgenommenen Änderungen angezeigt. Der Abfrage-Builder zeigt Ihre letzten Änderungen im Builder-Modus an.",
"cancel": "Abbrechen",
"clipboard": "",
"copy-code-and-switch": "",
"discard-code-and-switch": "",
"clipboard": "Möchten Sie Ihren Code in die Zwischenablage kopieren?",
"copy-code-and-switch": "Code kopieren und wechseln",
"discard-code-and-switch": "Code verwerfen und wechseln",
"warning": "Warnung"
},
"connection-limits": {
"auto-max-idle": "",
"content-auto-max-idle": "",
"content-max-idle": "",
"content-max-lifetime": "",
"content-max-open": "",
"max-idle": "",
"max-lifetime": "",
"max-open": "",
"title-connection-limits": ""
"auto-max-idle": "Auto. max. inaktiv",
"content-auto-max-idle": "Wenn dies aktiviert ist, wird die Anzahl der <1>Maximalen inaktiven Verbindungen</1> automatisch auf den gleichen Wert der<3> Maximalen offenen Verbindungen</3> festgelegt. Wenn die Anzahl der maximalen offenen Verbindungen nicht festgelegt ist, wird sie auf den Standardwert ({{defaultMaxIdle}}) eingestellt.",
"content-max-idle": "Die maximale Anzahl der Verbindungen im Pool der inaktiven Verbindungen. Wenn <1>Maximale offene Verbindungen</1> größer ist als 0, aber kleiner als die Anzahl der <3>Maximalen inaktiven Verbindungen</3>, werden die <5>Maximalen inaktiven Verbindungen</5> verringert, um der Grenze für die Anzahl der <8>Maximalen offenen Verbindungen</8> zu entsprechen. Wenn der Wert auf 0 eingestellt ist, werden keine inaktiven Verbindungen beibehalten.",
"content-max-lifetime": "Die maximale Zeitdauer der Wiederverwendung einer Verbindung in Sekunden. Bei einer Einstellung auf 0 werden Verbindungen immer wiederverwendet.",
"content-max-open": "Die maximale Anzahl offener Verbindungen zur Datenbank. Wenn <1>Maximale inaktive Verbindungen</1> größer als 0 ist und die Anzahl der <3>Maximalen offenen Verbindungen</3> kleiner als die Anzahl der <5>Maximalen inaktiven Verbindungen</5> ist, werden die <7>Maximalen inaktiven Verbindungen</7> bis zur Grenze für <9>Maximale offene Verbindungen</9> verringert. Wenn 0 festgelegt ist, gibt es keine Begrenzung der Anzahl offener Verbindungen.",
"max-idle": "Max. inaktiv",
"max-lifetime": "Max. Lebensdauer",
"max-open": "Max. offen",
"title-connection-limits": "Verbindungsbegrenzungen"
},
"dataset-selector": {
"aria-label-dataset-selector": ""
"aria-label-dataset-selector": "Datensatz-Selektor"
},
"error-boundary": {
"fall-back": {
@ -31,21 +31,21 @@
"get-custom-operators": {
"custom-operators": {
"label": {
"macros": ""
"macros": "Macros"
}
}
},
"make-render-column": {
"render-column": {
"aria-label-group-by": "Gruppieren nach",
"title-remove-group-by-column": ""
"title-remove-group-by-column": "Nach Spalte gruppieren entfernen"
}
},
"order-by-row": {
"aria-label-order-by": "",
"aria-label-order-by": "Sortieren nach",
"label-limit": "Limit",
"label-offset": "",
"label-order-by": ""
"label-offset": "Offset",
"label-order-by": "Sortieren nach"
},
"preview": {
"label-element": {
@ -54,100 +54,100 @@
}
},
"query-header": {
"content-invalid-query": "",
"content-invalid-query": "Ihre Abfrage ist ungültig. Weitere Informationen finden Sie unten. <1></1>Sie können diese Abfrage aber trotzdem ausführen.",
"editor-modes": {
"label-builder": "",
"label-code": ""
},
"label-dataset": "",
"label-dataset": "Datensatz",
"label-filter": "Filter",
"label-format": "Format",
"label-group": "Gruppe",
"label-order": "",
"label-order": "Reihenfolge",
"label-preview": "Vorschau",
"label-table": "Tabelle",
"placeholder-select-format": "",
"placeholder-select-format": "Format auswählen",
"run-query": "Abfrage ausführen"
},
"query-toolbox": {
"content-hit-ctrlcmdreturn-to-run-query": "",
"tooltip-collapse": "",
"tooltip-expand": "",
"tooltip-format-query": ""
"content-hit-ctrlcmdreturn-to-run-query": "Drücken Sie STRG/CMD+Eingabe, um die Abfrage auszuführen",
"tooltip-collapse": "Editor einklappen",
"tooltip-expand": "Editor ausklappen",
"tooltip-format-query": "Formatabfrage"
},
"query-validator": {
"query-will-process": "",
"validating-query": ""
"query-will-process": "<0></0> Diese Abfrage verarbeitet <2>{{bytes}}</2>, wenn sie ausgeführt wird.",
"validating-query": "Abfrage wird validiert "
},
"raw-editor": {
"render-placeholder": {
"editing-in-expanded-code-editor": ""
"editing-in-expanded-code-editor": "Bearbeitung im ausgeklappten Code-Editor"
},
"title-query-num": ""
"title-query-num": "Abfrage {{queryNum}}"
},
"select-column": {
"label-column": "Spalte"
},
"select-custom-function-parameters": {
"aria-label-parameter": "",
"aria-label-parameter": "Parameter {{index}} für Spalte {{columnIndex}}",
"render-parameters": {
"params": {
"title-remove-parameter": ""
"title-remove-parameter": "Parameter entfernen"
}
},
"title-add-parameter": ""
"title-add-parameter": "Parameter hinzufügen"
},
"select-row": {
"aggregate-options": {
"options": {
"label": {
"aggregations": "",
"macros": ""
"aggregations": "Aggregationen",
"macros": "Macros"
}
}
},
"label": {
"time": "",
"time": "Zeit",
"value": "Wert"
},
"label-alias": "Alias",
"label-data-operations": "",
"title-add-column": "",
"title-remove-column": ""
"label-data-operations": "Datenoperationen",
"title-add-column": "Spalte hinzufügen",
"title-remove-column": "Spalte entfernen"
},
"settings": {
"aria-label-conjunction": "",
"aria-label-conjunction": "Konjunktion",
"aria-label-field": "Feld",
"aria-label-operator": "Bediener",
"title-button-filter": ""
"title-button-filter": "{{ buttonLabel }} Filter"
},
"sql-query-editor-lazy": {
"text-loading-editor": "Editor wird geladen"
},
"table-selector": {
"aria-label-table-selector": "",
"placeholder-loading": "",
"placeholder-select-table": ""
"aria-label-table-selector": "Tabellenselektor",
"placeholder-loading": "Tabellen werden geladen",
"placeholder-select-table": "Tabelle auswählen"
},
"tlssecrets-config": {
"content-tlsssl-client-certificate": "",
"content-tlsssl-client-key": "",
"content-tlsssl-root-certificate": "",
"tlsssl-client-certificate": "",
"tlsssl-client-key": "",
"content-tlsssl-client-certificate": "Stellen Sie zur Authentifizierung mit einem TLS/SSL-Client-Zertifikat bitte hier das Client-Zertifikat bereit.",
"content-tlsssl-client-key": "Stellen Sie zur Authentifizierung mit einem Client-TLS/SSL-Zertifikat bitte hier den Schlüssel bereit.",
"content-tlsssl-root-certificate": "Wenn der ausgewählte TLS/SSL-Modus ein Server-Root-Zertifikat erfordert, stellen Sie es bitte hier bereit",
"tlsssl-client-certificate": "TLS/SSL-Client-Zertifikat",
"tlsssl-client-key": "TLS/SSL-Clientschlüssel",
"tlsssl-root-certificate": "TLS/SSL-Root-Zertifikat"
},
"visual-editor": {
"label-filter-by-column-value": "",
"label-group-by-column": ""
"label-filter-by-column-value": "Nach Spaltenwert filtern",
"label-group-by-column": "Nach Spalte gruppieren"
},
"widgets": {
"aria-label-macros-value-selector": ""
"aria-label-macros-value-selector": "Macros-Wert-Selektor"
}
},
"utils": {
"get-columns-width-indices": {
"label-selected-columns": ""
"label-selected-columns": "Ausgewählte Spalten"
}
}
}

@ -2,26 +2,26 @@
"grafana-sql": {
"components": {
"confirm-modal": {
"builder-mode": "",
"builder-mode": "Az építő mód nem jeleníti meg a kódban végzett módosításokat. A lekérdezésépítő megjeleníti az utolsó módosításokat, amelyeket az építő módban végzett.",
"cancel": "Mégse",
"clipboard": "",
"copy-code-and-switch": "",
"discard-code-and-switch": "",
"clipboard": "Szeretné a kódot a vágólapra másolni?",
"copy-code-and-switch": "Kód másolása és váltás",
"discard-code-and-switch": "Kód elvetése és váltás",
"warning": "Figyelmeztetés"
},
"connection-limits": {
"auto-max-idle": "",
"content-auto-max-idle": "",
"content-max-idle": "",
"content-max-lifetime": "",
"content-max-open": "",
"max-idle": "",
"max-lifetime": "",
"max-open": "",
"title-connection-limits": ""
"auto-max-idle": "Inaktív automatikus maximális száma",
"content-auto-max-idle": "Ha engedélyezve van, automatikusan beállítja az <1>Inaktív kapcsolatok maximális száma</1> értéket a <3>Megnyitott kapcsolatok maximális száma</3> értékére. Ha a nyitott kapcsolatok maximális száma nincs beállítva, akkor az alapértelmezett értékre lesz beállítva ({{defaultMaxIdle}}).",
"content-max-idle": "Az inaktív kapcsolatok készletében lévő kapcsolatok maximális száma. Ha a <1>Megnyitott kapcsolatok maximális száma</1> nagyobb, mint 0, de kisebb, mint az <3>Inaktív kapcsolatok maximális száma</3>, akkor az <5>Inaktív kapcsolatok maximális száma</5> csökken, hogy megfeleljen a <8>Megnyitott kapcsolatok maximális száma</8> határértékének. Ha 0-ra van állítva, akkor egyetlen inaktív kapcsolat sem marad meg.",
"content-max-lifetime": "A csatlakozás újrafelhasználásának maximális időtartama másodpercben. Ha 0-ra van állítva, a kapcsolatok újrafelhasználása végtelen.",
"content-max-open": "Az adatbázishoz irányuló nyitott kapcsolatok maximális száma. Ha az <1>Inaktív kapcsolatok maximális száma</1> nagyobb, mint 0, és a <3>Megnyitott kapcsolatok maximális száma</3> kisebb, mint az <5>Inaktív kapcsolatok maximális száma</5>, akkor az <7>Inaktív kapcsolatok maximális száma</7> csökken, hogy megfeleljen a <9>Megnyitott kapcsolatok maximális száma</9> határértékének. Ha 0-ra van állítva, akkor nincs korlátozva a nyitott kapcsolatok száma.",
"max-idle": "Max. inaktív",
"max-lifetime": "Max. élettartam",
"max-open": "Max. nyitott",
"title-connection-limits": "Kapcsolati korlátozások"
},
"dataset-selector": {
"aria-label-dataset-selector": ""
"aria-label-dataset-selector": "Adatkészlet-választó"
},
"error-boundary": {
"fall-back": {
@ -31,21 +31,21 @@
"get-custom-operators": {
"custom-operators": {
"label": {
"macros": ""
"macros": "Makrók"
}
}
},
"make-render-column": {
"render-column": {
"aria-label-group-by": "Csoportosítási szempont",
"title-remove-group-by-column": ""
"title-remove-group-by-column": "Csoport eltávolítása oszlop szerint"
}
},
"order-by-row": {
"aria-label-order-by": "",
"aria-label-order-by": "Rendezési szempont",
"label-limit": "Korlát",
"label-offset": "",
"label-order-by": ""
"label-offset": "Eltolás",
"label-order-by": "Rendezési szempont"
},
"preview": {
"label-element": {
@ -54,100 +54,100 @@
}
},
"query-header": {
"content-invalid-query": "",
"content-invalid-query": "A lekérdezés érvénytelen. A részleteket tekintse meg alább. <1></1>Ezt a lekérdezést azonban továbbra is futtathatja.",
"editor-modes": {
"label-builder": "",
"label-code": ""
},
"label-dataset": "",
"label-dataset": "Adatkészlet",
"label-filter": "Szűrő",
"label-format": "Formátum",
"label-group": "Csoport",
"label-order": "",
"label-order": "Sorrend",
"label-preview": "Előnézet",
"label-table": "Táblázat",
"placeholder-select-format": "",
"placeholder-select-format": "Formátum kiválasztása",
"run-query": "Lekérdezés"
},
"query-toolbox": {
"content-hit-ctrlcmdreturn-to-run-query": "",
"tooltip-collapse": "",
"tooltip-expand": "",
"tooltip-format-query": ""
"content-hit-ctrlcmdreturn-to-run-query": "A lekérdezés futtatásához nyomja le a CTRL/CMD+Enter billentyűkombinációt",
"tooltip-collapse": "Szerkesztő összecsukása",
"tooltip-expand": "Szerkesztő kibontása",
"tooltip-format-query": "Lekérdezés formázása"
},
"query-validator": {
"query-will-process": "",
"validating-query": ""
"query-will-process": "<0></0> Ez a lekérdezés <2>{{bytes}}</2> feldolgozását végzi futtatáskor.",
"validating-query": "Lekérdezés érvényesítése…"
},
"raw-editor": {
"render-placeholder": {
"editing-in-expanded-code-editor": ""
"editing-in-expanded-code-editor": "Szerkesztés kibontott kódszerkesztőben"
},
"title-query-num": ""
"title-query-num": "{{queryNum}}. lekérdezés"
},
"select-column": {
"label-column": "Oszlop"
},
"select-custom-function-parameters": {
"aria-label-parameter": "",
"aria-label-parameter": "{{columnIndex}}. oszlop {{index}}. paramétere",
"render-parameters": {
"params": {
"title-remove-parameter": ""
"title-remove-parameter": "Paraméter eltávolítása"
}
},
"title-add-parameter": ""
"title-add-parameter": "Paraméter hozzáadása"
},
"select-row": {
"aggregate-options": {
"options": {
"label": {
"aggregations": "",
"macros": ""
"aggregations": "Összegzések",
"macros": "Makrók"
}
}
},
"label": {
"time": "",
"time": "idő",
"value": "érték"
},
"label-alias": "Alias",
"label-data-operations": "",
"title-add-column": "",
"title-remove-column": ""
"label-data-operations": "Adatműveletek",
"title-add-column": "Oszlop hozzáadása",
"title-remove-column": "Oszlop eltávolítása"
},
"settings": {
"aria-label-conjunction": "",
"aria-label-conjunction": "Összekötés",
"aria-label-field": "Mező",
"aria-label-operator": "Műveleti jel",
"title-button-filter": ""
"title-button-filter": "{{ buttonLabel }} szűrő"
},
"sql-query-editor-lazy": {
"text-loading-editor": "Szerkesztő betöltése"
},
"table-selector": {
"aria-label-table-selector": "",
"placeholder-loading": "",
"placeholder-select-table": ""
"aria-label-table-selector": "Táblázatválasztó",
"placeholder-loading": "Táblázatok betöltése",
"placeholder-select-table": "Táblázat kiválasztása"
},
"tlssecrets-config": {
"content-tlsssl-client-certificate": "",
"content-tlsssl-client-key": "",
"content-tlsssl-root-certificate": "",
"tlsssl-client-certificate": "",
"tlsssl-client-key": "",
"content-tlsssl-client-certificate": "A TLS-/SSL-klienstanúsítvánnyal történő hitelesítéshez adja meg itt a klienstanúsítványt.",
"content-tlsssl-client-key": "A TLS-/SSL-klienstanúsítvánnyal történő hitelesítéshez adja meg itt a kulcsot.",
"content-tlsssl-root-certificate": "Ha a kiválasztott TLS-/SSL-módhoz kiszolgáló-gyökértanúsítvány szükséges, adja meg itt",
"tlsssl-client-certificate": "TLS-/SSL-klienstanúsítvány",
"tlsssl-client-key": "TLS-/SSL-klienskulcs",
"tlsssl-root-certificate": "TLS-/SSL-gyökértanúsítvány"
},
"visual-editor": {
"label-filter-by-column-value": "",
"label-group-by-column": ""
"label-filter-by-column-value": "Szűrés oszlopérték szerint",
"label-group-by-column": "Csoportosítás oszlop szerint"
},
"widgets": {
"aria-label-macros-value-selector": ""
"aria-label-macros-value-selector": "Makróérték-választó"
}
},
"utils": {
"get-columns-width-indices": {
"label-selected-columns": ""
"label-selected-columns": "Kijelölt oszlopok"
}
}
}

@ -2,26 +2,26 @@
"grafana-sql": {
"components": {
"confirm-modal": {
"builder-mode": "",
"builder-mode": "Mode pembuat tidak menampilkan perubahan yang dibuat dalam kode. Pembuat kueri akan menampilkan perubahan terakhir yang Anda buat dalam mode pembuat.",
"cancel": "Batalkan",
"clipboard": "",
"copy-code-and-switch": "",
"discard-code-and-switch": "",
"clipboard": "Ingin menyalin kode Anda ke papan klip?",
"copy-code-and-switch": "Salin kode dan beralih",
"discard-code-and-switch": "Buang kode dan beralih",
"warning": "PERINGATAN"
},
"connection-limits": {
"auto-max-idle": "",
"content-auto-max-idle": "",
"content-max-idle": "",
"content-max-lifetime": "",
"content-max-open": "",
"max-idle": "",
"max-lifetime": "",
"max-open": "",
"title-connection-limits": ""
"auto-max-idle": "Nonaktif maksimum otomatis",
"content-auto-max-idle": "Jika diaktifkan, secara otomatis atur jumlah <1>Koneksi nonaktif maksimum</1> ke nilai yang sama dengan<3> Koneksi terbuka maksimum</3>. Jika jumlah maksimum koneksi terbuka tidak diatur, jumlah tersebut akan diatur ke default ({{defaultMaxIdle}}).",
"content-max-idle": "Jumlah maksimum koneksi dalam pool koneksi nonaktif. Jika <1>Koneksi terbuka maksimum</1> lebih besar dari 0 tetapi kurang dari <3>Koneksi nonaktif maksimum</3>, maka <5>Koneksi nonaktif maksimum</5> akan dikurangi agar sesuai dengan batas <8>Koneksi terbuka maksimum</8>. Jika diatur ke 0, tidak ada koneksi nonaktif yang dipertahankan.",
"content-max-lifetime": "Jumlah waktu maksimum dalam detik untuk menggunakan koneksi lagi. Jika diatur ke 0, koneksi digunakan kembali terus-menerus tanpa batas waktu.",
"content-max-open": "Jumlah koneksi terbuka maksimum ke basis data. Jika <1>Koneksi nonaktif maksimum</1> lebih besar dari 0 dan <3>Koneksi terbuka maksimum</3> kurang dari <5>Koneksi nonaktif maksimum</5>, maka <7>Koneksi nonaktif maksimum</7> akan dikurangi agar sesuai dengan batas <9>Koneksi terbuka maksimum</9>. Jika diatur ke 0, tidak ada batasan jumlah koneksi terbuka.",
"max-idle": "Nonaktif maks",
"max-lifetime": "Periode maks",
"max-open": "Terbuka maks",
"title-connection-limits": "Batas koneksi"
},
"dataset-selector": {
"aria-label-dataset-selector": ""
"aria-label-dataset-selector": "Selektor kumpulan data"
},
"error-boundary": {
"fall-back": {
@ -31,21 +31,21 @@
"get-custom-operators": {
"custom-operators": {
"label": {
"macros": ""
"macros": "Makro"
}
}
},
"make-render-column": {
"render-column": {
"aria-label-group-by": "Kelompokkan berdasarkan",
"title-remove-group-by-column": ""
"title-remove-group-by-column": "Hapus grup berdasarkan kolom"
}
},
"order-by-row": {
"aria-label-order-by": "",
"aria-label-order-by": "Urutkan Berdasarkan",
"label-limit": "Batas",
"label-offset": "",
"label-order-by": ""
"label-offset": "Offset",
"label-order-by": "Urutkan Berdasarkan"
},
"preview": {
"label-element": {
@ -54,100 +54,100 @@
}
},
"query-header": {
"content-invalid-query": "",
"content-invalid-query": "Kueri Anda tidak valid. Periksa di bawah ini untuk detailnya. <1></1>Namun, Anda masih dapat menjalankan kueri ini.",
"editor-modes": {
"label-builder": "",
"label-code": ""
},
"label-dataset": "",
"label-dataset": "Kumpulan data",
"label-filter": "Filter",
"label-format": "Format",
"label-group": "Grup",
"label-order": "",
"label-order": "Pesanan",
"label-preview": "Pratinjau",
"label-table": "Tabel",
"placeholder-select-format": "",
"placeholder-select-format": "Pilih format",
"run-query": "Jalankan kueri"
},
"query-toolbox": {
"content-hit-ctrlcmdreturn-to-run-query": "",
"tooltip-collapse": "",
"tooltip-expand": "",
"tooltip-format-query": ""
"content-hit-ctrlcmdreturn-to-run-query": "Tekan CTRL/CMD+Return untuk menjalankan kueri",
"tooltip-collapse": "Ciutkan editor",
"tooltip-expand": "Perluas editor",
"tooltip-format-query": "Format kueri"
},
"query-validator": {
"query-will-process": "",
"validating-query": ""
"query-will-process": "<0></0> Kueri ini akan memproses <2>{{bytes}}</2> saat dijalankan.",
"validating-query": "Memvalidasi kueri..."
},
"raw-editor": {
"render-placeholder": {
"editing-in-expanded-code-editor": ""
"editing-in-expanded-code-editor": "Mengedit di editor kode yang diperluas"
},
"title-query-num": ""
"title-query-num": "Kueri {{queryNum}}"
},
"select-column": {
"label-column": "Kolom"
},
"select-custom-function-parameters": {
"aria-label-parameter": "",
"aria-label-parameter": "Parameter {{index}} untuk kolom {{columnIndex}}",
"render-parameters": {
"params": {
"title-remove-parameter": ""
"title-remove-parameter": "Hapus parameter"
}
},
"title-add-parameter": ""
"title-add-parameter": "Tambahkan parameter"
},
"select-row": {
"aggregate-options": {
"options": {
"label": {
"aggregations": "",
"macros": ""
"aggregations": "Agregasi",
"macros": "Makro"
}
}
},
"label": {
"time": "",
"time": "waktu",
"value": "nilai"
},
"label-alias": "Alias",
"label-data-operations": "",
"title-add-column": "",
"title-remove-column": ""
"label-data-operations": "Operasi data",
"title-add-column": "Tambah kolom",
"title-remove-column": "Hapus kolom"
},
"settings": {
"aria-label-conjunction": "",
"aria-label-conjunction": "Kata Penghubung",
"aria-label-field": "Bidang",
"aria-label-operator": "Operator",
"title-button-filter": ""
"title-button-filter": "Filter {{ buttonLabel }}"
},
"sql-query-editor-lazy": {
"text-loading-editor": "Memuat editor"
},
"table-selector": {
"aria-label-table-selector": "",
"placeholder-loading": "",
"placeholder-select-table": ""
"aria-label-table-selector": "Selektor tabel",
"placeholder-loading": "Memuat tabel",
"placeholder-select-table": "Pilih tabel"
},
"tlssecrets-config": {
"content-tlsssl-client-certificate": "",
"content-tlsssl-client-key": "",
"content-tlsssl-root-certificate": "",
"tlsssl-client-certificate": "",
"tlsssl-client-key": "",
"content-tlsssl-client-certificate": "Untuk mengautentikasi dengan sertifikat klien TLS/SSL, berikan sertifikat klien di sini.",
"content-tlsssl-client-key": "Untuk mengautentikasi dengan sertifikat TLS/SSL klien, berikan kunci di sini.",
"content-tlsssl-root-certificate": "Jika mode TLS/SSL yang dipilih memerlukan sertifikat root server, berikan di sini",
"tlsssl-client-certificate": "Sertifikat Klien TLS/SSL",
"tlsssl-client-key": "Kunci Klien TLS",
"tlsssl-root-certificate": "Sertifikat Root TLS/SSL"
},
"visual-editor": {
"label-filter-by-column-value": "",
"label-group-by-column": ""
"label-filter-by-column-value": "Filter berdasarkan nilai kolom",
"label-group-by-column": "Kelompokkan berdasarkan kolom"
},
"widgets": {
"aria-label-macros-value-selector": ""
"aria-label-macros-value-selector": "Selektor nilai makro"
}
},
"utils": {
"get-columns-width-indices": {
"label-selected-columns": ""
"label-selected-columns": "Kolom yang dipilih"
}
}
}

@ -2,26 +2,26 @@
"grafana-sql": {
"components": {
"confirm-modal": {
"builder-mode": "",
"builder-mode": "ビルダーモードではコードに加えられた変更は反映されません。クエリビルダーはビルダーモードで加えられた最後の変更を表示します。",
"cancel": "キャンセル",
"clipboard": "",
"copy-code-and-switch": "",
"discard-code-and-switch": "",
"clipboard": "コードをクリップボードにコピーしますか?",
"copy-code-and-switch": "コードをコピーして切り替え",
"discard-code-and-switch": "コードを破棄して切り替え",
"warning": "警告"
},
"connection-limits": {
"auto-max-idle": "",
"content-auto-max-idle": "",
"content-max-idle": "",
"content-max-lifetime": "",
"content-max-open": "",
"max-idle": "",
"max-lifetime": "",
"max-open": "",
"title-connection-limits": ""
"auto-max-idle": "自動最大アイドル",
"content-auto-max-idle": "有効にすると、<1>最大アイドル接続数</1>が<3>最大オープン接続数</3>と同じ値に自動設定されます。最大オープン接続数が設定されていない場合、デフォルト({{defaultMaxIdle}})に設定されます。",
"content-max-idle": "アイドル接続プールの最大接続数。<1>最大オープン接続数</1>が0より大きく<3>最大アイドル接続数</3>より小さい場合、<5>最大アイドル接続数</5>は<8>最大オープン接続数</8>の制限に合わせて削減されます。0に設定すると、アイドル接続は保持されません。",
"content-max-lifetime": "接続を再利用できる最大時間(秒)。0に設定すると、接続は永続的に再利用されます。",
"content-max-open": "データベースへの最大オープン接続数。<1>最大アイドル接続数</1>が0より大きく<3>最大オープン接続数</3>が<5>最大アイドル接続数</5>より小さい場合、<7>最大アイドル接続数</7>は<9>最大オープン接続数</9>の制限に合わせて削減されます。0に設定すると、オープン接続数に制限はありません。",
"max-idle": "最大アイドル",
"max-lifetime": "最大有効期間",
"max-open": "最大オープン",
"title-connection-limits": "接続制限"
},
"dataset-selector": {
"aria-label-dataset-selector": ""
"aria-label-dataset-selector": "データセットセレクター"
},
"error-boundary": {
"fall-back": {
@ -31,21 +31,21 @@
"get-custom-operators": {
"custom-operators": {
"label": {
"macros": ""
"macros": "マクロ"
}
}
},
"make-render-column": {
"render-column": {
"aria-label-group-by": "グループ化",
"title-remove-group-by-column": ""
"title-remove-group-by-column": "グループ化列を削除"
}
},
"order-by-row": {
"aria-label-order-by": "",
"aria-label-order-by": "並び順",
"label-limit": "制限",
"label-offset": "",
"label-order-by": ""
"label-offset": "オフセット",
"label-order-by": "並び順"
},
"preview": {
"label-element": {
@ -54,100 +54,100 @@
}
},
"query-header": {
"content-invalid-query": "",
"content-invalid-query": "クエリが無効です。詳細は下記をご確認ください。<1></1>ただし、このクエリは引き続き実行できます。",
"editor-modes": {
"label-builder": "",
"label-code": ""
},
"label-dataset": "",
"label-dataset": "データセット",
"label-filter": "フィルタリング",
"label-format": "形式",
"label-group": "グループ",
"label-order": "",
"label-order": "順番",
"label-preview": "プレビュー",
"label-table": "テーブル",
"placeholder-select-format": "",
"placeholder-select-format": "フォーマットを選択",
"run-query": "クエリの実行"
},
"query-toolbox": {
"content-hit-ctrlcmdreturn-to-run-query": "",
"tooltip-collapse": "",
"tooltip-expand": "",
"tooltip-format-query": ""
"content-hit-ctrlcmdreturn-to-run-query": "CTRL/CMD+Returnでクエリを実行",
"tooltip-collapse": "エディターを折りたたむ",
"tooltip-expand": "エディターを展開",
"tooltip-format-query": "クエリをフォーマット"
},
"query-validator": {
"query-will-process": "",
"validating-query": ""
"query-will-process": "<0></0>このクエリは実行時に<2>{{bytes}}</2>を処理します。",
"validating-query": "クエリを検証中..."
},
"raw-editor": {
"render-placeholder": {
"editing-in-expanded-code-editor": ""
"editing-in-expanded-code-editor": "展開されたコードエディターで編集中"
},
"title-query-num": ""
"title-query-num": "{{queryNum}}個のクエリ"
},
"select-column": {
"label-column": "列"
},
"select-custom-function-parameters": {
"aria-label-parameter": "",
"aria-label-parameter": "列{{columnIndex}}のパラメーター{{index}}",
"render-parameters": {
"params": {
"title-remove-parameter": ""
"title-remove-parameter": "パラメーターを削除"
}
},
"title-add-parameter": ""
"title-add-parameter": "パラメーターを追加"
},
"select-row": {
"aggregate-options": {
"options": {
"label": {
"aggregations": "",
"macros": ""
"aggregations": "集計",
"macros": "マクロ"
}
}
},
"label": {
"time": "",
"time": "時間",
"value": "値"
},
"label-alias": "エイリアス",
"label-data-operations": "",
"title-add-column": "",
"title-remove-column": ""
"label-data-operations": "データ操作",
"title-add-column": "列を追加",
"title-remove-column": "列を削除"
},
"settings": {
"aria-label-conjunction": "",
"aria-label-conjunction": "結合",
"aria-label-field": "フィールド",
"aria-label-operator": "オペレーター",
"title-button-filter": ""
"title-button-filter": "{{ buttonLabel }}フィルター"
},
"sql-query-editor-lazy": {
"text-loading-editor": "エディタを読み込んでいます"
},
"table-selector": {
"aria-label-table-selector": "",
"placeholder-loading": "",
"placeholder-select-table": ""
"aria-label-table-selector": "テーブルセレクター",
"placeholder-loading": "テーブルを読み込み中...",
"placeholder-select-table": "テーブルを選択"
},
"tlssecrets-config": {
"content-tlsssl-client-certificate": "",
"content-tlsssl-client-key": "",
"content-tlsssl-root-certificate": "",
"tlsssl-client-certificate": "",
"tlsssl-client-key": "",
"content-tlsssl-client-certificate": "TLS/SSLクライアント証明書で認証するには、ここにクライアント証明書を入力します。",
"content-tlsssl-client-key": "クライアントTLS/SSL証明書で認証するには、ここにキーを入力します。",
"content-tlsssl-root-certificate": "選択したTLS/SSLモードでサーバールート証明書が必要な場合は、ここに入力します",
"tlsssl-client-certificate": "TLS/SSLクライアント証明書",
"tlsssl-client-key": "TLS/SSLクライアントキー",
"tlsssl-root-certificate": "TLS/SSLルート証明書"
},
"visual-editor": {
"label-filter-by-column-value": "",
"label-group-by-column": ""
"label-filter-by-column-value": "列の値でフィルタリング",
"label-group-by-column": "列でグループ化"
},
"widgets": {
"aria-label-macros-value-selector": ""
"aria-label-macros-value-selector": "マクロ値セレクター"
}
},
"utils": {
"get-columns-width-indices": {
"label-selected-columns": ""
"label-selected-columns": "選択された列"
}
}
}

@ -133,7 +133,7 @@
"uwrap": "0.1.1"
},
"devDependencies": {
"@babel/core": "7.26.10",
"@babel/core": "7.28.0",
"@faker-js/faker": "^9.0.0",
"@grafana/tsconfig": "^2.0.0",
"@rollup/plugin-node-resolve": "16.0.1",
@ -195,10 +195,10 @@
"rimraf": "6.0.1",
"rollup": "^4.22.4",
"rollup-plugin-copy": "3.5.0",
"rollup-plugin-esbuild": "6.2.0",
"rollup-plugin-esbuild": "6.2.1",
"rollup-plugin-node-externals": "^8.0.0",
"rollup-plugin-svg-import": "3.0.0",
"sass-loader": "16.0.4",
"sass-loader": "16.0.5",
"storybook": "^8.6.2",
"style-loader": "4.0.0",
"typescript": "5.8.3",

@ -16,7 +16,7 @@ import { getInputStyles, Input } from '../../Input/Input';
import { ScrollContainer } from '../../ScrollContainer/ScrollContainer';
import { TimePickerTitle } from '../TimeRangePicker/TimePickerTitle';
import { TimeRangeList } from '../TimeRangePicker/TimeRangeList';
import { quickOptions } from '../options';
import { getQuickOptions } from '../options';
import {
isRangeValid,
@ -39,8 +39,6 @@ type InputState = {
validation: RangeValidation;
};
const validOptions = quickOptions.filter((o) => isRelativeFormat(o.from));
/**
* @internal
*/
@ -57,6 +55,7 @@ export function RelativeTimeRangePicker(props: RelativeTimeRangePickerProps) {
ref
);
const { dialogProps } = useDialog({}, ref);
const validOptions = getQuickOptions().filter((o) => isRelativeFormat(o.from));
// the order of middleware is important!
// see https://floating-ui.com/docs/arrow#order

@ -13,7 +13,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 { getQuickOptions } from './options';
import { isValidTimeRange } from './utils';
export interface TimeRangeInputProps {
@ -123,7 +123,7 @@ export const TimeRangeInput = ({
timeZone={timeZone}
value={isValidTimeRange(value) ? value : getDefaultTimeRange()}
onChange={onRangeChange}
quickOptions={quickOptions}
quickOptions={getQuickOptions()}
onChangeTimeZone={onChangeTimeZone}
className={styles.content}
hideTimeZone={hideTimeZone}

@ -28,7 +28,7 @@ import { Tooltip } from '../Tooltip/Tooltip';
import { TimePickerContent } from './TimeRangePicker/TimePickerContent';
import { TimeZoneDescription } from './TimeZonePicker/TimeZoneDescription';
import { WeekStart } from './WeekStartPicker';
import { quickOptions } from './options';
import { getQuickOptions } from './options';
import { useTimeSync } from './utils/useTimeSync';
/** @public */
@ -189,7 +189,7 @@ export function TimeRangePicker(props: TimeRangePickerProps) {
fiscalYearStartMonth={fiscalYearStartMonth}
value={value}
onChange={onChange}
quickOptions={quickRanges || quickOptions}
quickOptions={quickRanges || getQuickOptions()}
history={history}
showHistory
widthOverride={widthOverride}

@ -18,7 +18,7 @@ import { TimeZonePicker } from '../TimeZonePicker';
import { TimeZoneDescription } from '../TimeZonePicker/TimeZoneDescription';
import { TimeZoneOffset } from '../TimeZonePicker/TimeZoneOffset';
import { TimeZoneTitle } from '../TimeZonePicker/TimeZoneTitle';
import { monthOptions } from '../options';
import { getMonthOptions } from '../options';
interface Props {
timeZone?: TimeZone;
@ -146,7 +146,7 @@ export const TimePickerFooter = (props: Props) => {
>
<Combobox
value={fiscalYearStartMonth ?? null}
options={monthOptions}
options={getMonthOptions()}
onChange={(value) => {
if (onChangeFiscalYearStartMonth) {
onChangeFiscalYearStartMonth(value?.value ?? 0);

@ -1,57 +1,134 @@
import { TimeOption } from '@grafana/data';
import { t } from '@grafana/i18n';
import { ComboboxOption } from '../Combobox/types';
export const quickOptions: TimeOption[] = [
{ from: 'now-5m', to: 'now', display: 'Last 5 minutes' },
{ from: 'now-15m', to: 'now', display: 'Last 15 minutes' },
{ from: 'now-30m', to: 'now', display: 'Last 30 minutes' },
{ from: 'now-1h', to: 'now', display: 'Last 1 hour' },
{ from: 'now-3h', to: 'now', display: 'Last 3 hours' },
{ from: 'now-6h', to: 'now', display: 'Last 6 hours' },
{ from: 'now-12h', to: 'now', display: 'Last 12 hours' },
{ from: 'now-24h', to: 'now', display: 'Last 24 hours' },
{ from: 'now-2d', to: 'now', display: 'Last 2 days' },
{ from: 'now-7d', to: 'now', display: 'Last 7 days' },
{ from: 'now-30d', to: 'now', display: 'Last 30 days' },
{ from: 'now-90d', to: 'now', display: 'Last 90 days' },
{ from: 'now-6M', to: 'now', display: 'Last 6 months' },
{ from: 'now-1y', to: 'now', display: 'Last 1 year' },
{ from: 'now-2y', to: 'now', display: 'Last 2 years' },
{ from: 'now-5y', to: 'now', display: 'Last 5 years' },
{ from: 'now-1d/d', to: 'now-1d/d', display: 'Yesterday' },
{ from: 'now-2d/d', to: 'now-2d/d', display: 'Day before yesterday' },
{ from: 'now-7d/d', to: 'now-7d/d', display: 'This day last week' },
{ from: 'now-1w/w', to: 'now-1w/w', display: 'Previous week' },
{ from: 'now-1M/M', to: 'now-1M/M', display: 'Previous month' },
{ from: 'now-1Q/fQ', to: 'now-1Q/fQ', display: 'Previous fiscal quarter' },
{ from: 'now-1y/y', to: 'now-1y/y', display: 'Previous year' },
{ from: 'now-1y/fy', to: 'now-1y/fy', display: 'Previous fiscal year' },
{ from: 'now/d', to: 'now/d', display: 'Today' },
{ from: 'now/d', to: 'now', display: 'Today so far' },
{ from: 'now/w', to: 'now/w', display: 'This week' },
{ from: 'now/w', to: 'now', display: 'This week so far' },
{ from: 'now/M', to: 'now/M', display: 'This month' },
{ from: 'now/M', to: 'now', display: 'This month so far' },
{ from: 'now/y', to: 'now/y', display: 'This year' },
{ from: 'now/y', to: 'now', display: 'This year so far' },
{ from: 'now/fQ', to: 'now', display: 'This fiscal quarter so far' },
{ from: 'now/fQ', to: 'now/fQ', display: 'This fiscal quarter' },
{ from: 'now/fy', to: 'now', display: 'This fiscal year so far' },
{ from: 'now/fy', to: 'now/fy', display: 'This fiscal year' },
export const getQuickOptions: () => TimeOption[] = () => [
{ from: 'now-5m', to: 'now', display: t('grafana-ui.date-time-pickers.quick-options.last-5-mins', 'Last 5 minutes') },
{
from: 'now-15m',
to: 'now',
display: t('grafana-ui.date-time-pickers.quick-options.last-15-mins', 'Last 15 minutes'),
},
{
from: 'now-30m',
to: 'now',
display: t('grafana-ui.date-time-pickers.quick-options.last-30-mins', 'Last 30 minutes'),
},
{ from: 'now-1h', to: 'now', display: t('grafana-ui.date-time-pickers.quick-options.last-1-hour', 'Last 1 hour') },
{ from: 'now-3h', to: 'now', display: t('grafana-ui.date-time-pickers.quick-options.last-3-hours', 'Last 3 hours') },
{ from: 'now-6h', to: 'now', display: t('grafana-ui.date-time-pickers.quick-options.last-6-hours', 'Last 6 hours') },
{
from: 'now-12h',
to: 'now',
display: t('grafana-ui.date-time-pickers.quick-options.last-12-hours', 'Last 12 hours'),
},
{
from: 'now-24h',
to: 'now',
display: t('grafana-ui.date-time-pickers.quick-options.last-24-hours', 'Last 24 hours'),
},
{ from: 'now-2d', to: 'now', display: t('grafana-ui.date-time-pickers.quick-options.last-2-days', 'Last 2 days') },
{ from: 'now-7d', to: 'now', display: t('grafana-ui.date-time-pickers.quick-options.last-7-days', 'Last 7 days') },
{ from: 'now-30d', to: 'now', display: t('grafana-ui.date-time-pickers.quick-options.last-30-days', 'Last 30 days') },
{ from: 'now-90d', to: 'now', display: t('grafana-ui.date-time-pickers.quick-options.last-90-days', 'Last 90 days') },
{
from: 'now-6M',
to: 'now',
display: t('grafana-ui.date-time-pickers.quick-options.last-6-months', 'Last 6 months'),
},
{ from: 'now-1y', to: 'now', display: t('grafana-ui.date-time-pickers.quick-options.last-1-year', 'Last 1 year') },
{ from: 'now-2y', to: 'now', display: t('grafana-ui.date-time-pickers.quick-options.last-2-years', 'Last 2 years') },
{ from: 'now-5y', to: 'now', display: t('grafana-ui.date-time-pickers.quick-options.last-5-years', 'Last 5 years') },
{ from: 'now-1d/d', to: 'now-1d/d', display: t('grafana-ui.date-time-pickers.quick-options.yesterday', 'Yesterday') },
{
from: 'now-2d/d',
to: 'now-2d/d',
display: t('grafana-ui.date-time-pickers.quick-options.day-before-yesterday', 'Day before yesterday'),
},
{
from: 'now-7d/d',
to: 'now-7d/d',
display: t('grafana-ui.date-time-pickers.quick-options.this-day-last-week', 'This day last week'),
},
{
from: 'now-1w/w',
to: 'now-1w/w',
display: t('grafana-ui.date-time-pickers.quick-options.previous-week', 'Previous week'),
},
{
from: 'now-1M/M',
to: 'now-1M/M',
display: t('grafana-ui.date-time-pickers.quick-options.previous-month', 'Previous month'),
},
{
from: 'now-1Q/fQ',
to: 'now-1Q/fQ',
display: t('grafana-ui.date-time-pickers.quick-options.previous-fiscal-quarter', 'Previous fiscal quarter'),
},
{
from: 'now-1y/y',
to: 'now-1y/y',
display: t('grafana-ui.date-time-pickers.quick-options.previous-year', 'Previous year'),
},
{
from: 'now-1y/fy',
to: 'now-1y/fy',
display: t('grafana-ui.date-time-pickers.quick-options.previous-fiscal-year', 'Previous fiscal year'),
},
{ from: 'now/d', to: 'now/d', display: t('grafana-ui.date-time-pickers.quick-options.today', 'Today') },
{ from: 'now/d', to: 'now', display: t('grafana-ui.date-time-pickers.quick-options.today-so-far', 'Today so far') },
{ from: 'now/w', to: 'now/w', display: t('grafana-ui.date-time-pickers.quick-options.this-week', 'This week') },
{
from: 'now/w',
to: 'now',
display: t('grafana-ui.date-time-pickers.quick-options.this-week-so-far', 'This week so far'),
},
{ from: 'now/M', to: 'now/M', display: t('grafana-ui.date-time-pickers.quick-options.this-month', 'This month') },
{
from: 'now/M',
to: 'now',
display: t('grafana-ui.date-time-pickers.quick-options.this-month-so-far', 'This month so far'),
},
{ from: 'now/y', to: 'now/y', display: t('grafana-ui.date-time-pickers.quick-options.this-year', 'This year') },
{
from: 'now/y',
to: 'now',
display: t('grafana-ui.date-time-pickers.quick-options.this-year-so-far', 'This year so far'),
},
{
from: 'now/fQ',
to: 'now',
display: t('grafana-ui.date-time-pickers.quick-options.this-fiscal-quarter-so-far', 'This fiscal quarter so far'),
},
{
from: 'now/fQ',
to: 'now/fQ',
display: t('grafana-ui.date-time-pickers.quick-options.this-fiscal-quarter', 'This fiscal quarter'),
},
{
from: 'now/fy',
to: 'now',
display: t('grafana-ui.date-time-pickers.quick-options.this-fiscal-year-so-far', 'This fiscal year so far'),
},
{
from: 'now/fy',
to: 'now/fy',
display: t('grafana-ui.date-time-pickers.quick-options.this-fiscal-year', 'This fiscal year'),
},
];
export const monthOptions: Array<ComboboxOption<number>> = [
{ label: 'January', value: 0 },
{ label: 'February', value: 1 },
{ label: 'March', value: 2 },
{ label: 'April', value: 3 },
{ label: 'May', value: 4 },
{ label: 'June', value: 5 },
{ label: 'July', value: 6 },
{ label: 'August', value: 7 },
{ label: 'September', value: 8 },
{ label: 'October', value: 9 },
{ label: 'November', value: 10 },
{ label: 'December', value: 11 },
export const getMonthOptions: () => Array<ComboboxOption<number>> = () => [
{ label: t('grafana-ui.date-time-pickers.month-options.label-january', 'January'), value: 0 },
{ label: t('grafana-ui.date-time-pickers.month-options.label-february', 'February'), value: 1 },
{ label: t('grafana-ui.date-time-pickers.month-options.label-march', 'March'), value: 2 },
{ label: t('grafana-ui.date-time-pickers.month-options.label-april', 'April'), value: 3 },
{ label: t('grafana-ui.date-time-pickers.month-options.label-may', 'May'), value: 4 },
{ label: t('grafana-ui.date-time-pickers.month-options.label-june', 'June'), value: 5 },
{ label: t('grafana-ui.date-time-pickers.month-options.label-july', 'July'), value: 6 },
{ label: t('grafana-ui.date-time-pickers.month-options.label-august', 'August'), value: 7 },
{ label: t('grafana-ui.date-time-pickers.month-options.label-september', 'September'), value: 8 },
{ label: t('grafana-ui.date-time-pickers.month-options.label-october', 'October'), value: 9 },
{ label: t('grafana-ui.date-time-pickers.month-options.label-november', 'November'), value: 10 },
{ label: t('grafana-ui.date-time-pickers.month-options.label-december', 'December'), value: 11 },
];

@ -27,20 +27,48 @@ FieldTypeMatcherEditor.displayName = 'FieldTypeMatcherEditor';
// Select options for all field types.
// This is not eported to the published package, but used internally
export const allFieldTypeIconOptions: Array<SelectableValue<FieldType>> = [
{ value: FieldType.number, label: 'Number', icon: getFieldTypeIconName(FieldType.number) },
{ value: FieldType.string, label: 'String', icon: getFieldTypeIconName(FieldType.string) },
{ value: FieldType.time, label: 'Time', icon: getFieldTypeIconName(FieldType.time) },
{ value: FieldType.boolean, label: 'Boolean', icon: getFieldTypeIconName(FieldType.boolean) },
{ value: FieldType.trace, label: 'Traces', icon: getFieldTypeIconName(FieldType.trace) },
{ value: FieldType.enum, label: 'Enum', icon: getFieldTypeIconName(FieldType.enum) },
{ value: FieldType.other, label: 'Other', icon: getFieldTypeIconName(FieldType.other) },
export const getAllFieldTypeIconOptions: () => Array<SelectableValue<FieldType>> = () => [
{
value: FieldType.number,
label: t('grafana-ui.matchers-ui.get-all-field-type-icon-options.label-number', 'Number'),
icon: getFieldTypeIconName(FieldType.number),
},
{
value: FieldType.string,
label: t('grafana-ui.matchers-ui.get-all-field-type-icon-options.label-string', 'String'),
icon: getFieldTypeIconName(FieldType.string),
},
{
value: FieldType.time,
label: t('grafana-ui.matchers-ui.get-all-field-type-icon-options.label-time', 'Time'),
icon: getFieldTypeIconName(FieldType.time),
},
{
value: FieldType.boolean,
label: t('grafana-ui.matchers-ui.get-all-field-type-icon-options.label-boolean', 'Boolean'),
icon: getFieldTypeIconName(FieldType.boolean),
},
{
value: FieldType.trace,
label: t('grafana-ui.matchers-ui.get-all-field-type-icon-options.label-traces', 'Traces'),
icon: getFieldTypeIconName(FieldType.trace),
},
{
value: FieldType.enum,
label: t('grafana-ui.matchers-ui.get-all-field-type-icon-options.label-enum', 'Enum'),
icon: getFieldTypeIconName(FieldType.enum),
},
{
value: FieldType.other,
label: t('grafana-ui.matchers-ui.get-all-field-type-icon-options.label-other', 'Other'),
icon: getFieldTypeIconName(FieldType.other),
},
];
const useFieldCounts = (data: DataFrame[]): Map<FieldType, number> => {
return useMemo(() => {
const counts: Map<FieldType, number> = new Map();
for (const t of allFieldTypeIconOptions) {
for (const t of getAllFieldTypeIconOptions()) {
counts.set(t.value!, 0);
}
for (const frame of data) {
@ -61,7 +89,7 @@ const useSelectOptions = (counts: Map<string, number>, opt?: string): Array<Sele
return useMemo(() => {
let found = false;
const options: Array<SelectableValue<string>> = [];
for (const t of allFieldTypeIconOptions) {
for (const t of getAllFieldTypeIconOptions()) {
const count = counts.get(t.value!);
const match = opt === t.value;
if (count || match) {

@ -199,7 +199,9 @@ function getListOfQueryRefIds(data: DataFrame[]): Array<SelectableValue<string>>
for (const [refId, frames] of queries.entries()) {
values.push({
value: refId,
label: `Query: ${refId ?? '(missing refId)'}`,
label: refId
? t('grafana-ui.matchers-ui.get-list-of-query-ref-ids.label', 'Query: {{refId}}', { refId })
: t('grafana-ui.matchers-ui.get-list-of-query-ref-ids.label-missing-ref-id', 'Query: (missing refId)'),
description: getFramesDescription(frames),
});
}
@ -208,11 +210,17 @@ function getListOfQueryRefIds(data: DataFrame[]): Array<SelectableValue<string>>
}
function getFramesDescription(frames: DataFrame[]): string {
return `Frames (${frames.length}):
${frames
return t(
'grafana-ui.matchers-ui.get-list-of-query-ref-ids.description',
'Frames ({{framesCount}}): {{framesNames}}',
{
framesCount: frames.length,
framesNames: `${frames
.slice(0, Math.min(3, frames.length))
.map((x) => getFrameDisplayName(x))
.join(', ')} ${frames.length > 3 ? '...' : ''}`;
.join(', ')} ${frames.length > 3 ? '...' : ''}`,
}
);
}
/**

@ -2,6 +2,7 @@ import { css, cx } from '@emotion/css';
import { useRef, useState } from 'react';
import { Field, GrafanaTheme2, SelectableValue } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { useStyles2 } from '../../../../themes/ThemeContext';
import { Icon } from '../../../Icon/Icon';
@ -61,6 +62,7 @@ export const Filter = ({
className={styles.headerFilter}
ref={ref}
type="button"
data-testid={selectors.components.Panels.Visualization.TableNG.Filters.HeaderButton}
onClick={(ev) => {
setPopoverVisible(true);
ev.stopPropagation();

@ -4,6 +4,7 @@ import * as React from 'react';
import { FixedSizeList as List, ListChildComponentProps } from 'react-window';
import { GrafanaTheme2, formattedValueToString, getValueFormat, SelectableValue } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { Trans } from '@grafana/i18n';
import { useStyles2, useTheme2 } from '../../../../themes/ThemeContext';
@ -160,7 +161,10 @@ export const FilterList = ({ options, values, caseSensitive, onChange, searchFil
>
{ItemRenderer}
</List>
<div className={styles.filterListRow}>
<div
className={styles.filterListRow}
data-testid={selectors.components.Panels.Visualization.TableNG.Filters.SelectAll}
>
<Checkbox
value={selectCheckValue}
indeterminate={selectCheckIndeterminate}

@ -2,6 +2,7 @@ import { css } from '@emotion/css';
import React, { useCallback, useMemo, useState } from 'react';
import { Field, GrafanaTheme2, SelectableValue } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { t, Trans } from '@grafana/i18n';
import { useStyles2, useTheme2 } from '../../../../themes/ThemeContext';
@ -108,7 +109,11 @@ export const FilterPopup = ({
<ClickOutsideWrapper onClick={onCancel} useCapture={true}>
{/* This is just blocking click events from bubbeling and should not have a keyboard interaction. */}
{/* eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */}
<div className={styles.filterContainer} onClick={stopPropagation}>
<div
className={styles.filterContainer}
onClick={stopPropagation}
data-testid={selectors.components.Panels.Visualization.TableNG.Filters.Container}
>
<Stack direction="column">
<Stack alignItems="center">
{field && <Label className={styles.label}>{getDisplayName(field)}</Label>}

@ -45,7 +45,7 @@ export {
} from '../components/MatchersUI/utils';
export type { FieldMatcherUIRegistryItem } from '../components/MatchersUI/types';
export { RefIDMultiPicker, RefIDPicker, stringsToRegexp } from '../components/MatchersUI/FieldsByFrameRefIdMatcher';
export { allFieldTypeIconOptions } from '../components/MatchersUI/FieldTypeMatcherEditor';
export { getAllFieldTypeIconOptions } from '../components/MatchersUI/FieldTypeMatcherEditor';
export { getStyles as getSliderStyles } from '../components/Slider/styles';
export { getSelectStyles } from '../components/Select/getSelectStyles';

@ -7,6 +7,8 @@ import (
"fmt"
"net/http"
"net/url"
"path"
"regexp"
"strings"
"github.com/grafana/grafana/pkg/api/response"
@ -39,6 +41,9 @@ var getViewIndex = func() string {
return viewIndex
}
// Only allow redirects that start with an alphanumerical character, a dash or an underscore.
var redirectRe = regexp.MustCompile(`^/[a-zA-Z0-9-_].*`)
var (
errAbsoluteRedirectTo = errors.New("absolute URLs are not allowed for redirect_to cookie value")
errInvalidRedirectTo = errors.New("invalid redirect_to cookie value")
@ -68,6 +73,15 @@ func (hs *HTTPServer) ValidateRedirectTo(redirectTo string) error {
return errForbiddenRedirectTo
}
cleanPath := path.Clean(to.Path)
// "." is what path.Clean returns for empty paths
if cleanPath == "." {
return errForbiddenRedirectTo
}
if to.Path != "/" && !redirectRe.MatchString(cleanPath) {
return errForbiddenRedirectTo
}
// when using a subUrl, the redirect_to should start with the subUrl (which contains the leading slash), otherwise the redirect
// will send the user to the wrong location
if hs.Cfg.AppSubURL != "" && !strings.HasPrefix(to.Path, hs.Cfg.AppSubURL+"/") {

@ -4,6 +4,7 @@ import (
"context"
"fmt"
"net/http"
"net/url"
"testing"
"time"
@ -20,6 +21,7 @@ import (
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/services/user/usertest"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web/webtest"
)
func TestUserTokenAPIEndpoint(t *testing.T) {
@ -150,6 +152,95 @@ func TestUserTokenAPIEndpoint(t *testing.T) {
})
}
func TestHTTPServer_RotateUserAuthTokenRedirect(t *testing.T) {
redirectTestCases := []struct {
name string
redirectUrl string
expectedUrl string
}{
// Valid redirects should be preserved
{"valid root path", "/", "/"},
{"valid simple path", "/hello", "/hello"},
{"valid single char path", "/a", "/a"},
{"valid nested path", "/asd/hello", "/asd/hello"},
// Invalid redirects should be converted to root
{"backslash domain", `/\grafana.com`, "/"},
{"traversal backslash domain", `/a/../\grafana.com`, "/"},
{"double slash", "//grafana", "/"},
{"missing initial slash", "missingInitialSlash", "/"},
{"parent directory", "/../", "/"},
}
sessionTestCases := []struct {
name string
useSessionStorageRedirect bool
}{
{"when useSessionStorageRedirect is enabled", true},
{"when useSessionStorageRedirect is disabled", false},
}
for _, sessionCase := range sessionTestCases {
t.Run(sessionCase.name, func(t *testing.T) {
for _, redirectCase := range redirectTestCases {
t.Run(redirectCase.name, func(t *testing.T) {
server := SetupAPITestServer(t, func(hs *HTTPServer) {
cfg := setting.NewCfg()
cfg.LoginCookieName = "grafana_session"
cfg.LoginMaxLifetime = 10 * time.Hour
hs.Cfg = cfg
hs.log = log.New()
hs.AuthTokenService = &authtest.FakeUserAuthTokenService{
RotateTokenProvider: func(ctx context.Context, cmd auth.RotateCommand) (*auth.UserToken, error) {
return &auth.UserToken{UnhashedToken: "new"}, nil
},
}
})
redirectToQuery := url.QueryEscape(redirectCase.redirectUrl)
urlString := "/user/auth-tokens/rotate"
if sessionCase.useSessionStorageRedirect {
urlString = urlString + "?redirectTo=" + redirectToQuery
}
req := server.NewGetRequest(urlString)
req.AddCookie(&http.Cookie{Name: "grafana_session", Value: "123", Path: "/"})
if sessionCase.useSessionStorageRedirect {
req = webtest.RequestWithWebContext(req, &contextmodel.ReqContext{UseSessionStorageRedirect: true})
} else {
req.AddCookie(&http.Cookie{Name: "redirect_to", Value: redirectToQuery, Path: "/"})
}
var redirectStatusCode int
var redirectLocation string
server.HttpClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
if len(via) > 1 {
// Stop after first redirect
return http.ErrUseLastResponse
}
if req.Response == nil {
return nil
}
redirectStatusCode = req.Response.StatusCode
redirectLocation = req.Response.Header.Get("Location")
return nil
}
res, err := server.Send(req)
require.NoError(t, err)
assert.Equal(t, 302, redirectStatusCode)
assert.Equal(t, redirectCase.expectedUrl, redirectLocation)
require.NoError(t, res.Body.Close())
})
}
})
}
}
func TestHTTPServer_RotateUserAuthToken(t *testing.T) {
type testCase struct {
desc string

@ -32,12 +32,17 @@ func RunTest(
) (*dagger.Container, error) {
playwrightCommand := buildPlaywrightCommand(opts)
grafanaHost, err := opts.GrafanaService.Hostname(ctx)
if err != nil {
return nil, err
}
e2eContainer := opts.FrontendContainer.
WithWorkdir("/src").
WithDirectory("/src", opts.HostSrc).
WithMountedCache(".nx", d.CacheVolume("nx-cache")).
WithEnvVariable("HOST", grafanaHost).
WithEnvVariable("PORT", fmt.Sprint(grafanaPort)).
WithEnvVariable("CI", "true").
WithEnvVariable("GRAFANA_URL", fmt.Sprintf("http://%s:%d", grafanaHost, grafanaPort)).
WithServiceBinding(grafanaHost, opts.GrafanaService).
WithEnvVariable("bustcache", "1").
WithEnvVariable("PLAYWRIGHT_HTML_OPEN", "never").

@ -12,7 +12,6 @@ import (
)
var (
grafanaHost = "grafana"
grafanaPort = 3001
)

@ -408,7 +408,12 @@ func (dn *DSNode) Execute(ctx context.Context, now time.Time, _ mathexp.Vars, s
}
} else {
// transform request from backend.QueryDataRequest to k8s request
k8sReq := &data.QueryDataRequest{}
k8sReq := &data.QueryDataRequest{
TimeRange: data.TimeRange{
From: req.Queries[0].TimeRange.From.Format(time.RFC3339),
To: req.Queries[0].TimeRange.To.Format(time.RFC3339),
},
}
for _, q := range req.Queries {
var dataQuery data.DataQuery
err := json.Unmarshal(q.JSON, &dataQuery)

@ -3,6 +3,8 @@ package middleware
import (
"fmt"
"net/http"
"path"
"regexp"
"strconv"
"github.com/grafana/grafana/pkg/services/contexthandler"
@ -11,6 +13,9 @@ import (
"github.com/grafana/grafana/pkg/web"
)
// Only allow redirects that start with an alphanumerical character, a dash or an underscore.
var redirectRe = regexp.MustCompile(`^/?[a-zA-Z0-9-_].*`)
// OrgRedirect changes org and redirects users if the
// querystring `orgId` doesn't match the active org.
func OrgRedirect(cfg *setting.Cfg, userSvc user.Service) web.Handler {
@ -31,6 +36,11 @@ func OrgRedirect(cfg *setting.Cfg, userSvc user.Service) web.Handler {
return
}
if !validRedirectPath(c.Req.URL.Path) {
// Do not switch orgs or perform the redirect because the new path is not valid
return
}
if err := userSvc.Update(ctx.Req.Context(), &user.UpdateUserCommand{UserID: ctx.UserID, OrgID: &orgId}); err != nil {
if ctx.IsApiRequest() {
ctx.JsonApiErr(404, "Not found", nil)
@ -54,3 +64,8 @@ func OrgRedirect(cfg *setting.Cfg, userSvc user.Service) web.Handler {
c.Redirect(newURL, 302)
}
}
func validRedirectPath(p string) bool {
cleanPath := path.Clean(p)
return cleanPath == "." || cleanPath == "/" || redirectRe.MatchString(cleanPath)
}

@ -2,6 +2,7 @@ package middleware
import (
"fmt"
"net/url"
"testing"
"github.com/stretchr/testify/require"
@ -23,6 +24,12 @@ func TestOrgRedirectMiddleware(t *testing.T) {
expStatus: 302,
expLocation: "/?orgId=3",
},
{
desc: "when setting a correct org for the user with an empty path",
input: "?orgId=3",
expStatus: 302,
expLocation: "/?orgId=3",
},
{
desc: "when setting a correct org for the user with '&kiosk'",
input: "/?orgId=3&kiosk",
@ -64,6 +71,16 @@ func TestOrgRedirectMiddleware(t *testing.T) {
require.Equal(t, 404, sc.resp.Code)
})
middlewareScenario(t, "when redirecting to an invalid path", func(t *testing.T, sc *scenarioContext) {
sc.withIdentity(&authn.Identity{})
path := url.QueryEscape(`/\example.com`)
sc.m.Get(url.QueryEscape(path), sc.defaultHandler)
sc.fakeReq("GET", fmt.Sprintf("%s?orgId=3", path)).exec()
require.Equal(t, 404, sc.resp.Code)
})
middlewareScenario(t, "works correctly when grafana is served under a subpath", func(t *testing.T, sc *scenarioContext) {
sc.withIdentity(&authn.Identity{})

@ -122,7 +122,7 @@ func RegisterAPIService(
dbp := legacysql.NewDatabaseProvider(sql)
namespacer := request.GetNamespaceMapper(cfg)
legacyDashboardSearcher := legacysearcher.NewDashboardSearchClient(dashStore, sorter)
folderClient := client.NewK8sHandler(dual, request.GetNamespaceMapper(cfg), folders.FolderResourceInfo.GroupVersionResource(), restConfigProvider.GetRestConfig, dashStore, userService, unified, sorter)
folderClient := client.NewK8sHandler(dual, request.GetNamespaceMapper(cfg), folders.FolderResourceInfo.GroupVersionResource(), restConfigProvider.GetRestConfig, dashStore, userService, unified, sorter, features)
builder := &DashboardsAPIBuilder{
log: log.New("grafana-apiserver.dashboards"),

@ -43,7 +43,7 @@ type SearchHandler struct {
}
func NewSearchHandler(tracer trace.Tracer, dual dualwrite.Service, legacyDashboardSearcher resourcepb.ResourceIndexClient, resourceClient resource.ResourceClient, features featuremgmt.FeatureToggles) *SearchHandler {
searchClient := resource.NewSearchClient(dualwrite.NewSearchAdapter(dual), dashboardv0alpha1.DashboardResourceInfo.GroupResource(), resourceClient, legacyDashboardSearcher)
searchClient := resource.NewSearchClient(dualwrite.NewSearchAdapter(dual), dashboardv0alpha1.DashboardResourceInfo.GroupResource(), resourceClient, legacyDashboardSearcher, features)
return &SearchHandler{
client: searchClient,
log: log.New("grafana-apiserver.dashboards.search"),

@ -126,19 +126,22 @@ func (b *IdentityAccessManagementAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *ge
storage[teamBindingResource.StoragePath()] = team.NewLegacyBindingStore(b.store)
userResource := legacyiamv0.UserResourceInfo
store, err := grafanaregistry.NewRegistryStore(opts.Scheme, userResource, opts.OptsGetter)
if err != nil {
return err
}
legacyStore := user.NewLegacyStore(b.store, b.legacyAccessClient)
dw, err := opts.DualWriteBuilder(userResource.GroupResource(), legacyStore, store)
if err != nil {
return err
}
// TODO: Figure out what's missing for the DualWriter setup in a MT setup
// MT app is unable to start if DW is configured
// store, err := grafanaregistry.NewRegistryStore(opts.Scheme, userResource, opts.OptsGetter)
// if err != nil {
// return err
// }
// dw, err := opts.DualWriteBuilder(userResource.GroupResource(), legacyStore, store)
// if err != nil {
// return err
// }
storage[userResource.StoragePath()] = dw
// storage[userResource.StoragePath()] = dw
storage[userResource.StoragePath()] = legacyStore
storage[userResource.StoragePath("teams")] = user.NewLegacyTeamMemberREST(b.store)
serviceAccountResource := legacyiamv0.ServiceAccountResourceInfo

@ -54,6 +54,7 @@ import (
"github.com/grafana/grafana/pkg/registry/apis/provisioning/resources/signature"
"github.com/grafana/grafana/pkg/registry/apis/provisioning/safepath"
"github.com/grafana/grafana/pkg/registry/apis/provisioning/secrets"
"github.com/grafana/grafana/pkg/registry/apis/provisioning/usage"
"github.com/grafana/grafana/pkg/services/apiserver"
"github.com/grafana/grafana/pkg/services/apiserver/builder"
"github.com/grafana/grafana/pkg/services/featuremgmt"
@ -75,6 +76,7 @@ var (
type APIBuilder struct {
features featuremgmt.FeatureToggles
usageStats usagestats.Service
tracer tracing.Tracer
getter rest.Getter
@ -117,6 +119,7 @@ func NewAPIBuilder(
ghFactory *github.Factory,
legacyMigrator legacy.LegacyMigrator,
storageStatus dualwrite.Service,
usageStats usagestats.Service,
repositorySecrets secrets.RepositorySecrets,
access authlib.AccessChecker,
tracer tracing.Tracer,
@ -134,6 +137,7 @@ func NewAPIBuilder(
b := &APIBuilder{
mutators: mutators,
tracer: tracer,
usageStats: usageStats,
localFileResolver: local,
features: features,
ghFactory: ghFactory,
@ -184,7 +188,7 @@ func RegisterAPIService(
access authlib.AccessClient,
legacyMigrator legacy.LegacyMigrator,
storageStatus dualwrite.Service,
usageStatsService usagestats.Service,
usageStats usagestats.Service,
repositorySecrets secrets.RepositorySecrets,
tracer tracing.Tracer,
extraBuilders []ExtraBuilder,
@ -202,13 +206,13 @@ func RegisterAPIService(
filepath.Join(cfg.DataPath, "clone"), // where repositories are cloned (temporarialy for now)
configProvider, ghFactory,
legacyMigrator, storageStatus,
usageStats,
repositorySecrets,
access,
tracer,
extraBuilders,
)
apiregistration.RegisterAPI(builder)
usageStatsService.RegisterMetricsFunc(builder.collectProvisioningStats)
return builder, nil
}
@ -434,41 +438,6 @@ func (b *APIBuilder) Mutate(ctx context.Context, a admission.Attributes, o admis
r.Spec.Sync.IntervalSeconds = 60
}
// TODO: move this logic into github repository concrete implementation.
if r.Spec.Type == provisioning.GitHubRepositoryType {
if r.Spec.GitHub == nil {
return fmt.Errorf("github configuration is required")
}
// Trim trailing slash or .git
if len(r.Spec.GitHub.URL) > 5 {
r.Spec.GitHub.URL = strings.TrimSuffix(r.Spec.GitHub.URL, ".git")
r.Spec.GitHub.URL = strings.TrimSuffix(r.Spec.GitHub.URL, "/")
}
}
if r.Spec.Type == provisioning.GitRepositoryType {
if r.Spec.Git == nil {
return fmt.Errorf("git configuration is required")
}
if r.Spec.GitHub != nil {
return fmt.Errorf("git and github cannot be used together")
}
if r.Spec.Local != nil {
return fmt.Errorf("git and local cannot be used together")
}
// Trim trailing slash and ensure .git is present
if len(r.Spec.Git.URL) > 5 {
r.Spec.Git.URL = strings.TrimSuffix(r.Spec.Git.URL, "/")
if !strings.HasSuffix(r.Spec.Git.URL, ".git") {
r.Spec.Git.URL = r.Spec.Git.URL + ".git"
}
}
}
if r.Spec.Workflows == nil {
r.Spec.Workflows = []provisioning.Workflow{}
}
@ -596,6 +565,10 @@ func (b *APIBuilder) GetPostStartHooks() (map[string]genericapiserver.PostStartH
b.repositoryLister = repoInformer.Lister()
// Create the repository resources factory
usageMetricCollector := usage.MetricCollector(b.tracer, b.repositoryLister, b.unified)
b.usageStats.RegisterMetricsFunc(usageMetricCollector)
stageIfPossible := repository.WrapWithStageAndPushIfPossible
exportWorker := export.NewExportWorker(
b.clients,

@ -2,6 +2,8 @@ package git
import (
"context"
"fmt"
"strings"
"k8s.io/apimachinery/pkg/runtime"
@ -17,10 +19,27 @@ func Mutator(secrets secrets.RepositorySecrets) controller.Mutator {
return nil
}
if repo.Spec.Git == nil {
if repo.Spec.Type != provisioning.GitRepositoryType {
return nil
}
if repo.Spec.Git == nil {
return fmt.Errorf("git configuration is required for git repository type")
}
if repo.Spec.Git.URL != "" {
url := strings.TrimSpace(repo.Spec.Git.URL)
if url != "" {
// Remove any trailing slashes
url = strings.TrimRight(url, "/")
// Only add .git if it's not already present
if !strings.HasSuffix(url, ".git") {
url = url + ".git"
}
repo.Spec.Git.URL = url
}
}
if repo.Spec.Git.Token != "" {
secretName := repo.Name + gitTokenSecretSuffix
nameOrValue, err := secrets.Encrypt(ctx, repo, secretName, repo.Spec.Git.Token)

@ -21,6 +21,7 @@ func TestMutator(t *testing.T) {
expectedToken string
expectedEncryptedToken string
expectedError string
expectedURL string
}{
{
name: "successful token encryption",
@ -30,6 +31,7 @@ func TestMutator(t *testing.T) {
Namespace: "default",
},
Spec: provisioning.RepositorySpec{
Type: provisioning.GitRepositoryType,
Git: &provisioning.GitRepositoryConfig{
Token: "secret-token",
},
@ -44,6 +46,7 @@ func TestMutator(t *testing.T) {
Namespace: "default",
},
Spec: provisioning.RepositorySpec{
Type: provisioning.GitRepositoryType,
Git: &provisioning.GitRepositoryConfig{
Token: "secret-token",
},
@ -64,6 +67,7 @@ func TestMutator(t *testing.T) {
Namespace: "default",
},
Spec: provisioning.RepositorySpec{
Type: provisioning.GitRepositoryType,
Git: &provisioning.GitRepositoryConfig{
Token: "secret-token",
},
@ -78,6 +82,7 @@ func TestMutator(t *testing.T) {
Namespace: "default",
},
Spec: provisioning.RepositorySpec{
Type: provisioning.GitRepositoryType,
Git: &provisioning.GitRepositoryConfig{
Token: "secret-token",
},
@ -97,6 +102,7 @@ func TestMutator(t *testing.T) {
Namespace: "default",
},
Spec: provisioning.RepositorySpec{
Type: provisioning.LocalRepositoryType,
Git: nil,
},
},
@ -104,6 +110,24 @@ func TestMutator(t *testing.T) {
// No expectations
},
},
{
name: "no git spec for git repository type",
obj: &provisioning.Repository{
ObjectMeta: metav1.ObjectMeta{
Name: "test-repo",
Namespace: "default",
},
Spec: provisioning.RepositorySpec{
Type: provisioning.GitRepositoryType,
Git: nil,
},
},
setupMocks: func(mockSecrets *secrets.MockRepositorySecrets) {
// No expectations
},
expectedError: "git configuration is required for git repository type",
},
{
name: "empty token",
obj: &provisioning.Repository{
@ -112,6 +136,7 @@ func TestMutator(t *testing.T) {
Namespace: "default",
},
Spec: provisioning.RepositorySpec{
Type: provisioning.GitRepositoryType,
Git: &provisioning.GitRepositoryConfig{
Token: "",
},
@ -128,6 +153,101 @@ func TestMutator(t *testing.T) {
// No expectations
},
},
{
name: "URL normalization - add .git suffix",
obj: &provisioning.Repository{
ObjectMeta: metav1.ObjectMeta{
Name: "test-repo",
Namespace: "default",
},
Spec: provisioning.RepositorySpec{
Type: provisioning.GitRepositoryType,
Git: &provisioning.GitRepositoryConfig{
URL: "https://github.com/grafana/grafana",
},
},
},
setupMocks: func(mockSecrets *secrets.MockRepositorySecrets) {
// No expectations
},
expectedURL: "https://github.com/grafana/grafana.git",
},
{
name: "URL normalization - keep existing .git suffix",
obj: &provisioning.Repository{
ObjectMeta: metav1.ObjectMeta{
Name: "test-repo",
Namespace: "default",
},
Spec: provisioning.RepositorySpec{
Type: provisioning.GitRepositoryType,
Git: &provisioning.GitRepositoryConfig{
URL: "https://github.com/grafana/grafana.git",
},
},
},
setupMocks: func(mockSecrets *secrets.MockRepositorySecrets) {
// No expectations
},
expectedURL: "https://github.com/grafana/grafana.git",
},
{
name: "URL normalization - remove trailing slash and add .git",
obj: &provisioning.Repository{
ObjectMeta: metav1.ObjectMeta{
Name: "test-repo",
Namespace: "default",
},
Spec: provisioning.RepositorySpec{
Type: provisioning.GitRepositoryType,
Git: &provisioning.GitRepositoryConfig{
URL: "https://github.com/grafana/grafana/",
},
},
},
setupMocks: func(mockSecrets *secrets.MockRepositorySecrets) {
// No expectations
},
expectedURL: "https://github.com/grafana/grafana.git",
},
{
name: "URL normalization - trim whitespace and add .git",
obj: &provisioning.Repository{
ObjectMeta: metav1.ObjectMeta{
Name: "test-repo",
Namespace: "default",
},
Spec: provisioning.RepositorySpec{
Type: provisioning.GitRepositoryType,
Git: &provisioning.GitRepositoryConfig{
URL: " https://github.com/grafana/grafana ",
},
},
},
setupMocks: func(mockSecrets *secrets.MockRepositorySecrets) {
// No expectations
},
expectedURL: "https://github.com/grafana/grafana.git",
},
{
name: "URL normalization - empty URL after trim",
obj: &provisioning.Repository{
ObjectMeta: metav1.ObjectMeta{
Name: "test-repo",
Namespace: "default",
},
Spec: provisioning.RepositorySpec{
Type: provisioning.GitRepositoryType,
Git: &provisioning.GitRepositoryConfig{
URL: " ",
},
},
},
setupMocks: func(mockSecrets *secrets.MockRepositorySecrets) {
// No expectations
},
expectedURL: "",
},
}
for _, tt := range tests {
@ -152,6 +272,11 @@ func TestMutator(t *testing.T) {
// EncryptedToken should be set to the expected value
assert.Equal(t, tt.expectedEncryptedToken, string(repo.Spec.Git.EncryptedToken), "EncryptedToken should match expected value")
}
// Check URL normalization
if tt.expectedURL != "" {
assert.Equal(t, tt.expectedURL, repo.Spec.Git.URL, "URL should be normalized correctly")
}
}
}
})

@ -12,6 +12,7 @@ import (
// It exists only for the ability to test the code easily.
type Factory struct {
// Client allows overriding the client to use in the GH client returned. It exists primarily for testing.
// FIXME: we should replace in this way. We should add some options pattern for the factory.
Client *http.Client
}
@ -28,7 +29,7 @@ func (r *Factory) New(ctx context.Context, ghToken string) Client {
&oauth2.Token{AccessToken: ghToken},
)
if len(ghToken) == 0 {
if len(ghToken) > 0 {
tokenClient := oauth2.NewClient(ctx, tokenSrc)
return NewClient(github.NewClient(tokenClient))
}

@ -2,6 +2,7 @@ package github
import (
"context"
"strings"
"k8s.io/apimachinery/pkg/runtime"
@ -21,6 +22,15 @@ func Mutator(secrets secrets.RepositorySecrets) controller.Mutator {
return nil
}
// Trim trailing ".git" and any trailing slash from the GitHub URL, if present, using the strings package.
if repo.Spec.GitHub.URL != "" {
url := repo.Spec.GitHub.URL
url = strings.TrimRight(url, "/")
url = strings.TrimSuffix(url, ".git")
url = strings.TrimRight(url, "/")
repo.Spec.GitHub.URL = url
}
if repo.Spec.GitHub.Token != "" {
secretName := repo.Name + githubTokenSecretSuffix
nameOrValue, err := secrets.Encrypt(ctx, repo, secretName, repo.Spec.GitHub.Token)

@ -22,6 +22,74 @@ func TestMutator(t *testing.T) {
expectedEncryptedToken string
expectedError string
}{
{
name: "trims trailing .git and slash from GitHub URL",
obj: &provisioning.Repository{
ObjectMeta: metav1.ObjectMeta{
Name: "repo1",
Namespace: "default",
},
Spec: provisioning.RepositorySpec{
GitHub: &provisioning.GitHubRepositoryConfig{
URL: "https://github.com/org/repo.git/",
},
},
},
setupMocks: func(mockSecrets *secrets.MockRepositorySecrets) {},
expectedToken: "",
expectedEncryptedToken: "",
},
{
name: "trims only trailing slash from GitHub URL",
obj: &provisioning.Repository{
ObjectMeta: metav1.ObjectMeta{
Name: "repo2",
Namespace: "default",
},
Spec: provisioning.RepositorySpec{
GitHub: &provisioning.GitHubRepositoryConfig{
URL: "https://github.com/org/repo/",
},
},
},
setupMocks: func(mockSecrets *secrets.MockRepositorySecrets) {},
expectedToken: "",
expectedEncryptedToken: "",
},
{
name: "trims only trailing .git from GitHub URL",
obj: &provisioning.Repository{
ObjectMeta: metav1.ObjectMeta{
Name: "repo3",
Namespace: "default",
},
Spec: provisioning.RepositorySpec{
GitHub: &provisioning.GitHubRepositoryConfig{
URL: "https://github.com/org/repo.git",
},
},
},
setupMocks: func(mockSecrets *secrets.MockRepositorySecrets) {},
expectedToken: "",
expectedEncryptedToken: "",
},
{
name: "does not trim if no .git or slash",
obj: &provisioning.Repository{
ObjectMeta: metav1.ObjectMeta{
Name: "repo4",
Namespace: "default",
},
Spec: provisioning.RepositorySpec{
GitHub: &provisioning.GitHubRepositoryConfig{
URL: "https://github.com/org/repo",
},
},
},
setupMocks: func(mockSecrets *secrets.MockRepositorySecrets) {},
expectedToken: "",
expectedEncryptedToken: "",
},
{
name: "successful token encryption",
obj: &provisioning.Repository{

@ -114,7 +114,10 @@ func (r *githubRepository) Validate() (list field.ErrorList) {
}
func ParseOwnerRepoGithub(giturl string) (owner string, repo string, err error) {
parsed, e := url.Parse(strings.TrimSuffix(giturl, ".git"))
giturl = strings.TrimSuffix(giturl, ".git")
giturl = strings.TrimSuffix(giturl, "/")
parsed, e := url.Parse(giturl)
if e != nil {
err = e
return

@ -56,7 +56,9 @@ func NewRepositorySecrets(features featuremgmt.FeatureToggles, secretsSvc Servic
// If the feature flag is disabled, it uses the legacy secrets service
// If the feature flag is enabled, it uses the secrets service
func (s *repositorySecrets) Encrypt(ctx context.Context, r *provisioning.Repository, name string, data string) (nameOrValue []byte, err error) {
logger := logging.FromContext(ctx).With("name", name, "namespace", r.GetNamespace())
if s.features.IsEnabled(ctx, featuremgmt.FlagProvisioningSecretsService) {
logger.Info("Encrypting secret with new secrets service")
encrypted, err := s.secretsSvc.Encrypt(ctx, r.GetNamespace(), name, data)
if err != nil {
return nil, err
@ -64,6 +66,7 @@ func (s *repositorySecrets) Encrypt(ctx context.Context, r *provisioning.Reposit
return []byte(encrypted), err
}
logger.Info("Encrypting secret with legacy secrets service")
encrypted, err := s.legacySecrets.Encrypt(ctx, []byte(data))
if err != nil {
return nil, err
@ -87,10 +90,10 @@ func (s *repositorySecrets) Decrypt(ctx context.Context, r *provisioning.Reposit
logger := logging.FromContext(ctx)
// HACK: this is a hack to identify if the name is a potential Kubernetes name for a secret.
if strings.HasPrefix(nameOrValue, r.GetName()) {
logger.Info("Decrypting secret with new secrets service", "name", nameOrValue)
logger.Info("Decrypting secret with new secrets service")
return s.secretsSvc.Decrypt(ctx, r.GetNamespace(), nameOrValue)
} else {
logger.Info("Decrypting secret with legacy secrets service", "name", nameOrValue)
logger.Info("Decrypting secret with legacy secrets service")
return s.legacySecrets.Decrypt(ctx, []byte(nameOrValue))
}
}

@ -3,12 +3,14 @@ package provisioning
import (
"context"
"encoding/json"
"fmt"
"net/http"
"reflect"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/rest"
provisioning "github.com/grafana/grafana/pkg/apis/provisioning/v0alpha1"
@ -43,6 +45,11 @@ func (*testConnector) NewConnectOptions() (runtime.Object, bool, string) {
}
func (s *testConnector) Connect(ctx context.Context, name string, opts runtime.Object, responder rest.Responder) (http.Handler, error) {
ns, ok := request.NamespaceFrom(ctx)
if !ok {
return nil, fmt.Errorf("missing namespace")
}
return WithTimeout(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
body, err := readBody(r, defaultMaxBodySize)
if err != nil {
@ -60,6 +67,23 @@ func (s *testConnector) Connect(ctx context.Context, name string, opts runtime.O
// In case the body is an empty object
if !reflect.ValueOf(cfg).IsZero() {
// HACK: Set the name and namespace if not set so that the temporary repository can be created
// This can be removed once we deprecate legacy secrets is deprecated or we use InLineSecureValues as we
// use the same field and repository name to detect which one to use.
if cfg.GetName() == "" {
if name == "new" {
// HACK: frontend is passing a "new" we need to remove the hack there as well
// Otherwise creation will fail as `new` is a reserved word. Not relevant here as we only "test"
name = "hack-on-hack-for-new"
}
cfg.SetName(name)
}
if cfg.GetNamespace() == "" {
cfg.SetNamespace(ns)
}
// Create a temporary repository
tmp, err := s.getter.AsRepository(ctx, &cfg)
if err != nil {

@ -1,78 +0,0 @@
package provisioning
import (
"context"
"fmt"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apiserver/pkg/endpoints/request"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/storage/unified/resourcepb"
)
func (b *APIBuilder) collectProvisioningStats(ctx context.Context) (metrics map[string]any, err error) {
ctx, span := b.tracer.Start(ctx, "Provisioning.Usage.collectProvisioningStats")
defer func() {
span.SetStatus(codes.Error, fmt.Sprintf("failed to fetch provisioning usage stats: %v", err))
span.End()
}()
m := map[string]any{}
if b.unified == nil {
span.SetStatus(codes.Ok, "unified storage is not available")
return m, nil
}
// FIXME: hardcoded to "default" for now -- it works for single tenant deployments
// we could discover the set of valid namespaces, but that would count everything for
// each instance in cloud.
ns := "default"
ctx, _, err = identity.WithProvisioningIdentity(ctx, ns)
if err != nil {
return nil, err
}
ctx = request.WithNamespace(ctx, ns)
// FIXME: hardcoded to "default" for now -- it works for single tenant deployments
// we could discover the set of valid namespaces, but that would count everything for
// each instance in cloud.
//
// We could get namespaces from the list of repos below, but that could be zero
// while we still have resources managed by terraform, etc
count, err := b.unified.CountManagedObjects(ctx, &resourcepb.CountManagedObjectsRequest{
Namespace: ns,
})
if err != nil {
return m, fmt.Errorf("count managed objects: %w", err)
}
counts := make(map[string]int, 10)
for _, v := range count.Items {
counts[v.Kind] = counts[v.Kind] + int(v.Count)
}
span.SetAttributes(attribute.Int("totalManagedObjectsCount", len(count.Items)))
for k, v := range counts {
m[fmt.Sprintf("stats.managed_by.%s.count", k)] = v
}
// Inspect all configs
repos, err := b.repositoryLister.List(labels.Everything())
if err != nil {
return m, fmt.Errorf("list repositories: %w", err)
}
clear(counts)
for _, repo := range repos {
counts[string(repo.Spec.Type)] = counts[string(repo.Spec.Type)] + 1
}
span.SetAttributes(attribute.Int("repositoryCount", len(repos)))
// Count how many items of each repository type
for k, v := range counts {
m[fmt.Sprintf("stats.repository.%s.count", k)] = v
}
return m, nil
}

@ -0,0 +1,85 @@
package usage
import (
"context"
"fmt"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apiserver/pkg/endpoints/request"
"github.com/grafana/grafana/pkg/apimachinery/identity"
listers "github.com/grafana/grafana/pkg/generated/listers/provisioning/v0alpha1"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/infra/usagestats"
"github.com/grafana/grafana/pkg/storage/unified/resource"
"github.com/grafana/grafana/pkg/storage/unified/resourcepb"
)
func MetricCollector(tracer tracing.Tracer, repositoryLister listers.RepositoryLister, unified resource.ResourceClient) usagestats.MetricsFunc {
return func(ctx context.Context) (metrics map[string]any, err error) {
ctx, span := tracer.Start(ctx, "Provisioning.Usage.collectProvisioningStats")
defer func() {
span.SetStatus(codes.Error, fmt.Sprintf("failed to fetch provisioning usage stats: %v", err))
span.End()
}()
m := map[string]any{}
if unified == nil {
// FIXME: does this case make any sense? no unified storage -> no game
span.SetStatus(codes.Ok, "unified storage is not available")
return m, nil
}
// FIXME: hardcoded to "default" for now -- it works for single tenant deployments
// we could discover the set of valid namespaces, but that would count everything for
// each instance in cloud.
ns := "default"
ctx, _, err = identity.WithProvisioningIdentity(ctx, ns)
if err != nil {
return nil, err
}
ctx = request.WithNamespace(ctx, ns)
// FIXME: hardcoded to "default" for now -- it works for single tenant deployments
// we could discover the set of valid namespaces, but that would count everything for
// each instance in cloud.
//
// We could get namespaces from the list of repos below, but that could be zero
// while we still have resources managed by terraform, etc
count, err := unified.CountManagedObjects(ctx, &resourcepb.CountManagedObjectsRequest{
Namespace: ns,
})
if err != nil {
return m, fmt.Errorf("count managed objects: %w", err)
}
counts := make(map[string]int, 10)
for _, v := range count.Items {
counts[v.Kind] = counts[v.Kind] + int(v.Count)
}
span.SetAttributes(attribute.Int("totalManagedObjectsCount", len(count.Items)))
for k, v := range counts {
m[fmt.Sprintf("stats.managed_by.%s.count", k)] = v
}
// Inspect all configs
repos, err := repositoryLister.List(labels.Everything())
if err != nil {
return m, fmt.Errorf("list repositories: %w", err)
}
clear(counts)
for _, repo := range repos {
counts[string(repo.Spec.Type)] = counts[string(repo.Spec.Type)] + 1
}
span.SetAttributes(attribute.Int("repositoryCount", len(repos)))
// Count how many items of each repository type
for k, v := range counts {
m[fmt.Sprintf("stats.repository.%s.count", k)] = v
}
return m, nil
}
}

@ -18,7 +18,8 @@ type GrafanaAuthorizer struct {
auth authorizer.Authorizer
}
// NewGrafanaAuthorizer returns an authorizer configured for a grafana instance.
// NewGrafanaBuiltInSTAuthorizer returns an authorizer configured for a grafana instance.
// should not be used anywhere except for ST builtin Grafana
// This authorizer is a chain of smaller authorizers that together form the decision if
// access should be granted.
// 1. We deny all impersonate request.
@ -28,7 +29,7 @@ type GrafanaAuthorizer struct {
// 4. We check authorizer that is configured speficially for an api.
// 5. As a last fallback we check Role, this will only happen if an api have not configured
// an authorizer or return authorizer.DecisionNoOpinion
func NewGrafanaAuthorizer(cfg *setting.Cfg) *GrafanaAuthorizer {
func NewGrafanaBuiltInSTAuthorizer(cfg *setting.Cfg) *GrafanaAuthorizer {
authorizers := []authorizer.Authorizer{
newImpersonationAuthorizer(),
authorizerfactory.NewPrivilegedGroups(k8suser.SystemPrivilegedGroup),

@ -15,6 +15,7 @@ import (
"github.com/grafana/grafana/pkg/registry/apis/dashboard/legacysearcher"
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/search/sort"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/storage/legacysql/dualwrite"
@ -46,9 +47,9 @@ type k8sHandler struct {
}
func NewK8sHandler(dual dualwrite.Service, namespacer request.NamespaceMapper, gvr schema.GroupVersionResource,
restConfig func(context.Context) (*rest.Config, error), dashStore dashboards.Store, userSvc user.Service, resourceClient resource.ResourceClient, sorter sort.Service) K8sHandler {
restConfig func(context.Context) (*rest.Config, error), dashStore dashboards.Store, userSvc user.Service, resourceClient resource.ResourceClient, sorter sort.Service, features featuremgmt.FeatureToggles) K8sHandler {
legacySearcher := legacysearcher.NewDashboardSearchClient(dashStore, sorter)
searchClient := resource.NewSearchClient(dualwrite.NewSearchAdapter(dual), gvr.GroupResource(), resourceClient, legacySearcher)
searchClient := resource.NewSearchClient(dualwrite.NewSearchAdapter(dual), gvr.GroupResource(), resourceClient, legacySearcher, features)
return &k8sHandler{
namespacer: namespacer,

@ -138,7 +138,7 @@ func ProvideService(
rr: rr,
stopCh: make(chan struct{}),
builders: []builder.APIGroupBuilder{},
authorizer: authorizer.NewGrafanaAuthorizer(cfg),
authorizer: authorizer.NewGrafanaBuiltInSTAuthorizer(cfg),
tracing: tracing,
db: db, // For Unified storage
metrics: reg,

@ -5,7 +5,6 @@ import (
"fmt"
"sync"
"github.com/prometheus/client_golang/prometheus"
"go.opentelemetry.io/otel/attribute"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@ -18,11 +17,13 @@ import (
"github.com/grafana/grafana/pkg/services/apiserver/client"
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/search/sort"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/storage/legacysql/dualwrite"
"github.com/grafana/grafana/pkg/storage/unified/resource"
"github.com/prometheus/client_golang/prometheus"
)
type K8sClientFactory func(ctx context.Context, version string) client.K8sHandler
@ -44,8 +45,9 @@ func NewK8sClientWithFallback(
sorter sort.Service,
dual dualwrite.Service,
reg prometheus.Registerer,
features featuremgmt.FeatureToggles,
) *K8sClientWithFallback {
newClientFunc := newK8sClientFactory(cfg, restConfigProvider, dashboardStore, userService, resourceClient, sorter, dual)
newClientFunc := newK8sClientFactory(cfg, restConfigProvider, dashboardStore, userService, resourceClient, sorter, dual, features)
return &K8sClientWithFallback{
K8sHandler: newClientFunc(context.Background(), dashboardv0.VERSION),
newClientFunc: newClientFunc,
@ -112,6 +114,7 @@ func newK8sClientFactory(
resourceClient resource.ResourceClient,
sorter sort.Service,
dual dualwrite.Service,
features featuremgmt.FeatureToggles,
) K8sClientFactory {
clientCache := make(map[string]client.K8sHandler)
cacheMutex := &sync.RWMutex{}
@ -149,7 +152,7 @@ func newK8sClientFactory(
}
span.AddEvent("Creating new client")
newClient := client.NewK8sHandler(dual, request.GetNamespaceMapper(cfg), gvr, restConfigProvider.GetRestConfig, dashboardStore, userService, resourceClient, sorter)
newClient := client.NewK8sHandler(dual, request.GetNamespaceMapper(cfg), gvr, restConfigProvider.GetRestConfig, dashboardStore, userService, resourceClient, sorter, features)
clientCache[version] = newClient
return newClient

@ -387,7 +387,7 @@ func ProvideDashboardServiceImpl(
serverLockService *serverlock.ServerLockService,
kvstore kvstore.KVStore,
) (*DashboardServiceImpl, error) {
k8sclient := dashboardclient.NewK8sClientWithFallback(cfg, restConfigProvider, dashboardStore, userService, resourceClient, sorter, dual, r)
k8sclient := dashboardclient.NewK8sClientWithFallback(cfg, restConfigProvider, dashboardStore, userService, resourceClient, sorter, dual, r, features)
dashSvc := &DashboardServiceImpl{
cfg: cfg,
log: log.New("dashboard-service"),

@ -61,6 +61,7 @@ func ProvideService(cfg *setting.Cfg, db db.DB, dashboardService dashboards.Dash
userService,
unified,
sorter,
features,
),
dashSvc: dashboardService,
log: log.New("dashboard-version"),

@ -1819,6 +1819,14 @@ var (
Expression: "false",
RequiresRestart: true,
},
{
Name: "unifiedStorageSearchDualReaderEnabled",
Description: "Enable dual reader for unified storage search",
Stage: FeatureStageExperimental,
Owner: grafanaSearchAndStorageSquad,
HideFromAdminPage: true,
HideFromDocs: true,
},
}
)

@ -235,3 +235,4 @@ enablePluginImporter,experimental,@grafana/plugins-platform-backend,false,false,
otelLogsFormatting,experimental,@grafana/observability-logs,false,false,true
alertingNotificationHistory,experimental,@grafana/alerting-squad,false,false,false
pluginAssetProvider,experimental,@grafana/plugins-platform-backend,false,true,false
unifiedStorageSearchDualReaderEnabled,experimental,@grafana/search-and-storage,false,false,false

1 Name Stage Owner requiresDevMode RequiresRestart FrontendOnly
235 otelLogsFormatting experimental @grafana/observability-logs false false true
236 alertingNotificationHistory experimental @grafana/alerting-squad false false false
237 pluginAssetProvider experimental @grafana/plugins-platform-backend false true false
238 unifiedStorageSearchDualReaderEnabled experimental @grafana/search-and-storage false false false

@ -950,4 +950,8 @@ const (
// FlagPluginAssetProvider
// Allows decoupled core plugins to load from the Grafana CDN
FlagPluginAssetProvider = "pluginAssetProvider"
// FlagUnifiedStorageSearchDualReaderEnabled
// Enable dual reader for unified storage search
FlagUnifiedStorageSearchDualReaderEnabled = "unifiedStorageSearchDualReaderEnabled"
)

@ -2452,16 +2452,15 @@
},
{
"metadata": {
"name": "pluginLoadingRefactor",
"resourceVersion": "1752218524617",
"creationTimestamp": "2025-07-11T07:22:04Z",
"deletionTimestamp": "2025-07-11T07:23:34Z"
"name": "pluginAssetProvider",
"resourceVersion": "1752486584712",
"creationTimestamp": "2025-07-14T09:49:44Z"
},
"spec": {
"description": "Set this to true to use the new plugin loading functionality",
"description": "Allows decoupled core plugins to load from the Grafana CDN",
"stage": "experimental",
"codeowner": "@grafana/plugins-platform-backend",
"frontend": true,
"requiresRestart": true,
"hideFromAdminPage": true,
"hideFromDocs": true,
"expression": "false"
@ -2469,15 +2468,16 @@
},
{
"metadata": {
"name": "pluginAssetProvider",
"resourceVersion": "1752486584712",
"creationTimestamp": "2025-07-14T09:49:44Z"
"name": "pluginLoadingRefactor",
"resourceVersion": "1752218524617",
"creationTimestamp": "2025-07-11T07:22:04Z",
"deletionTimestamp": "2025-07-11T07:23:34Z"
},
"spec": {
"description": "Allows decoupled core plugins to load from the Grafana CDN",
"description": "Set this to true to use the new plugin loading functionality",
"stage": "experimental",
"codeowner": "@grafana/plugins-platform-backend",
"requiresRestart": true,
"frontend": true,
"hideFromAdminPage": true,
"hideFromDocs": true,
"expression": "false"
@ -3350,6 +3350,20 @@
"hideFromDocs": true
}
},
{
"metadata": {
"name": "unifiedStorageSearchDualReaderEnabled",
"resourceVersion": "1752500336818",
"creationTimestamp": "2025-07-14T13:38:56Z"
},
"spec": {
"description": "Enable dual reader for unified storage search",
"stage": "experimental",
"codeowner": "@grafana/search-and-storage",
"hideFromAdminPage": true,
"hideFromDocs": true
}
},
{
"metadata": {
"name": "unifiedStorageSearchPermissionFiltering",

@ -122,6 +122,7 @@ func ProvideService(
userService,
resourceClient,
sorter,
features,
)
unifiedStore := ProvideUnifiedStore(k8sHandler, userService, tracer)
@ -140,6 +141,7 @@ func ProvideService(
userService,
resourceClient,
sorter,
features,
)
srv.dashboardK8sClient = dashHandler
}

@ -199,7 +199,7 @@ func TestIntegrationFolderServiceViaUnifiedStorage(t *testing.T) {
tracer := noop.NewTracerProvider().Tracer("TestIntegrationFolderServiceViaUnifiedStorage")
dashboardStore := dashboards.NewFakeDashboardStore(t)
k8sCli := client.NewK8sHandler(dualwrite.ProvideTestService(), request.GetNamespaceMapper(cfg), folderv1.FolderResourceInfo.GroupVersionResource(), restCfgProvider.GetRestConfig, dashboardStore, userService, nil, sort.ProvideService())
k8sCli := client.NewK8sHandler(dualwrite.ProvideTestService(), request.GetNamespaceMapper(cfg), folderv1.FolderResourceInfo.GroupVersionResource(), restCfgProvider.GetRestConfig, dashboardStore, userService, nil, sort.ProvideService(), nil)
unifiedStore := ProvideUnifiedStore(k8sCli, userService, tracer)
ctx := context.Background()

@ -64,3 +64,23 @@ func NewMtDatasourceClientBuilderWithClientSupplier(
logger: logger,
}
}
func NewTestMTDSClientBuilder(isMultiTenant bool, mockClient clientapi.QueryDataClient) MTDatasourceClientBuilder {
return &testBuilder{
mockClient: mockClient,
isMultitenant: isMultiTenant,
}
}
type testBuilder struct {
mockClient clientapi.QueryDataClient
isMultitenant bool
}
func (b *testBuilder) BuildClient(pluginId string, uid string) (clientapi.QueryDataClient, bool) {
if !b.isMultitenant {
return nil, false
}
return b.mockClient, true
}

@ -5,10 +5,10 @@ import (
"encoding/json"
"errors"
"fmt"
"strings"
"time"
"github.com/go-openapi/strfmt"
alertingTemplates "github.com/grafana/alerting/templates"
amv2 "github.com/prometheus/alertmanager/api/v2/models"
"github.com/prometheus/alertmanager/config"
"github.com/prometheus/alertmanager/pkg/labels"
@ -17,6 +17,7 @@ import (
"github.com/grafana/alerting/definition"
alertingmodels "github.com/grafana/alerting/models"
"github.com/grafana/grafana/pkg/apimachinery/errutil"
)
@ -267,9 +268,32 @@ type (
PostableApiReceiver = definition.PostableApiReceiver
PostableGrafanaReceivers = definition.PostableGrafanaReceivers
ReceiverType = definition.ReceiverType
MergeResult = definition.MergeResult
)
type MergeResult definition.MergeResult
func (m MergeResult) LogContext() []any {
if len(m.RenamedReceivers) == 0 && len(m.RenamedTimeIntervals) == 0 {
return nil
}
logCtx := make([]any, 0, 4)
if len(m.RenamedTimeIntervals) > 0 {
rcvBuilder := strings.Builder{}
for from, to := range m.RenamedReceivers {
rcvBuilder.WriteString(fmt.Sprintf("'%s'->'%s',", from, to))
}
logCtx = append(logCtx, "renamedReceivers", fmt.Sprintf("[%s]", rcvBuilder.String()[0:rcvBuilder.Len()-1]))
}
if len(m.RenamedTimeIntervals) > 0 {
rcvBuilder := strings.Builder{}
for from, to := range m.RenamedTimeIntervals {
rcvBuilder.WriteString(fmt.Sprintf("'%s'->'%s',", from, to))
}
logCtx = append(logCtx, "renamedTimeIntervals", fmt.Sprintf("[%s]", rcvBuilder.String()[0:rcvBuilder.Len()-1]))
}
return logCtx
}
const (
GrafanaReceiverType = definition.GrafanaReceiverType
AlertmanagerReceiverType = definition.AlertmanagerReceiverType
@ -779,31 +803,20 @@ func (c *PostableUserConfig) GetMergedAlertmanagerConfig() (MergeResult, error)
return MergeResult{}, fmt.Errorf("failed to get mimir alertmanager config: %w", err)
}
return definition.Merge(c.AlertmanagerConfig, mcfg, opts)
m, err := definition.Merge(c.AlertmanagerConfig, mcfg, opts)
if err != nil {
return MergeResult{}, fmt.Errorf("failed to merge alertmanager config: %w", err)
}
return MergeResult(m), nil
}
// GetMergedTemplateDefinitions converts the given PostableUserConfig's TemplateFiles to a slice of TemplateDefinitions.
func (c *PostableUserConfig) GetMergedTemplateDefinitions() []alertingTemplates.TemplateDefinition {
out := make([]alertingTemplates.TemplateDefinition, 0, len(c.TemplateFiles))
for name, tmpl := range c.TemplateFiles {
out = append(out, alertingTemplates.TemplateDefinition{
Name: name,
Template: tmpl,
Kind: alertingTemplates.GrafanaKind,
})
}
if len(c.ExtraConfigs) == 0 {
// GetMergedTemplateDefinitions converts the given PostableUserConfig's TemplateFiles to a slice of Templates.
func (c *PostableUserConfig) GetMergedTemplateDefinitions() []definition.PostableApiTemplate {
out := definition.TemplatesMapToPostableAPITemplates(c.TemplateFiles, definition.GrafanaTemplateKind)
if len(c.ExtraConfigs) == 0 || len(c.ExtraConfigs[0].TemplateFiles) == 0 {
return out
}
// support only one config for now
for name, tmpl := range c.ExtraConfigs[0].TemplateFiles {
out = append(out, alertingTemplates.TemplateDefinition{
Name: name,
Template: tmpl,
Kind: alertingTemplates.MimirKind,
})
}
return out
return append(out, definition.TemplatesMapToPostableAPITemplates(c.ExtraConfigs[0].TemplateFiles, definition.MimirTemplateKind)...)
}
func (c *PostableUserConfig) UnmarshalJSON(b []byte) error {

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

Loading…
Cancel
Save