The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
grafana/eslint.config.js

413 lines
13 KiB

9 months ago
// @ts-check
const emotionPlugin = require('@emotion/eslint-plugin');
const restrictedGlobals = require('confusing-browser-globals');
9 months ago
const importPlugin = require('eslint-plugin-import');
const jestPlugin = require('eslint-plugin-jest');
const jestDomPlugin = require('eslint-plugin-jest-dom');
const jsxA11yPlugin = require('eslint-plugin-jsx-a11y');
const lodashPlugin = require('eslint-plugin-lodash');
const barrelPlugin = require('eslint-plugin-no-barrel-files');
const reactPlugin = require('eslint-plugin-react');
const testingLibraryPlugin = require('eslint-plugin-testing-library');
const unicornPlugin = require('eslint-plugin-unicorn');
9 months ago
const grafanaConfig = require('@grafana/eslint-config/flat');
const grafanaPlugin = require('@grafana/eslint-plugin');
const grafanaI18nPlugin = require('@grafana/i18n/eslint-plugin');
9 months ago
const bettererConfig = require('./.betterer.eslint.config');
const getEnvConfig = require('./scripts/webpack/env-util');
const envConfig = getEnvConfig();
const enableBettererRules = envConfig.frontend_dev_betterer_eslint_rules;
const pluginsToTranslate = [
'public/app/plugins/panel',
'public/app/plugins/datasource/azuremonitor',
'public/app/plugins/datasource/mssql',
];
9 months ago
/**
* @type {Array<import('eslint').Linter.Config>}
*/
module.exports = [
{
name: 'grafana/ignores',
ignores: [
'.github',
'.yarn',
'**/.*', // dotfiles aren't ignored by default in FlatConfig
'**/*.gen.ts',
'**/build/',
'**/compiled/',
'**/dist/',
'data/',
'deployment_tools_config.json',
'devenv',
E2E: migrate to playwright (#107241) * separate playwright into its own folder * better separation * add login scenario, add tags * remove ui option * update CODEOWNERS * add a panels suite test * migrate queries test to playwright * rename + add dashlist test * add panelEdit_base * add geomap map controls test * add geomap-layer-types * add geomap-spatial-operations tests * add frontend-sandbox-panel tests * add smoke-tests-suite * add comment about adding datasource * add dashboard-browse-nested * add dashboard-browse * add dashboard-export-json * add dashboard-keybindings test * remove @wip tag * turn on screenshots and add comment for why this test fails * add dashboard-links-without-slug test * try adding permissions in the test as well * add dashboard-live-streaming * context in the test doesn't work - sad * create dashboard-public-templating * add dashboard-public-create and make live streaming more resilient * add share externally test * add dashboard-share-internally * add share-snapshot-create test * add dashboard-templating * add timepicker tests * add embedded-dashboard test * add general_dashboards test * add import-dashboard test * add load-options-from-url test * add new-constant-variable test * add custom-variable test * add new-datasource-variable test * add new-interval-variable test * add text-box-variable test * add new-query-variable test * add horizontal repeat test * add panel-vertical-repeat test * add empty-row-repeat test * add set-options-from-ui test * add snapshot-create test * add templating test * add textbox-variables test * add cloud-plugins-suite * add storybook verification tests * add playwright storybook verification workflow * add playwright browsers * update CODEOWNERS * test change to trigger storybook verification workflows * try container instead * get the version right... * go back to installing - less chance of forgetting to update * Basic Github Actions Squashed commit of the following: commit f84c650a71bba339da7f96303292717569d4caa6 Author: joshhunt <josh.hunt@grafana.com> Date: Tue Jul 1 13:23:46 2025 +0100 add arg for sharding, but not using it yet commit 7bcf0512c6652e079757e7f892d1802eb255a6a7 Author: joshhunt <josh.hunt@grafana.com> Date: Tue Jul 1 12:30:30 2025 +0100 less newline commit b6439118829a09a4c8c49d7692d38df0dff7e7ae Author: joshhunt <josh.hunt@grafana.com> Date: Tue Jul 1 12:24:31 2025 +0100 less logs commit 38f871e9c235344f12ef31121fdfced549c5323c Author: joshhunt <josh.hunt@grafana.com> Date: Tue Jul 1 10:00:26 2025 +0100 fix yaml commit db9a773136eff40a82beb3b2f55f73ab0d07a717 Author: joshhunt <josh.hunt@grafana.com> Date: Tue Jul 1 09:57:47 2025 +0100 clean up files commit c0525f41fa8b498f2fdf71b5047301b0e2945498 Author: joshhunt <josh.hunt@grafana.com> Date: Tue Jul 1 09:44:56 2025 +0100 gha workflow commit 895bea7c527bfbb148a421b9283fa0805f6ab11d Author: joshhunt <josh.hunt@grafana.com> Date: Mon Jun 30 19:33:08 2025 +0100 working dagger commit cea1f8443738e9e4b375c065dd4a1e466036bb74 Author: joshhunt <josh.hunt@grafana.com> Date: Mon Jun 30 16:17:46 2025 +0100 wip * shard gha * some tidy up * add flags for exporting results, and a gha step to merge runs * fix shard gha * add dashboard-duplicate-panel test * add dashboard-outline test * add dashboards-add-panel * remove some commented out code * add dashboards-title-description test * add dashboards-remove-panel * don't install cypress * gha: check playwright results * add dashboards-edit-adhoc-variables test * fix check-jobs * add dagger cloud token * add dagger cloud token * add edit-datasource-variable test * update CODEOWNERS * add dashboards-edit-group-by-variables (skipped for now) * add dashboards-edit-panel-title-description test * add dashboards-edit-transparent-bg test * add dashboards-edit-query-variables test * run with 8 shards * add dashboards-edit-variables * tidy up gha * add dashboard-group-panels * fix action * try to cache the grafana build * fix missing action becuase no checkout, use builtin continue-on-error instead * fix missing id * cat out.txt * debug build cache * fix debug build cache * add dashboards-panel-layouts test * tidy up * no more debug * fix grafana dir * add dashboards-move-panel test * skip some failing tests * mark up plugins tests with @plugins tag, only run @plugins tests in drone * Hackathon/Playwright Conversion - Various Suite (#107516) * Playwright Migration: Various Suite tests * skipping bad tests * fix some tests that can fail * fix uid * separate user for the verify-i18n test * build test plugins for grafana server * properly blur input fields * login manually * get dashboardPage from goto * ignore a couple of type assertions * remove a couple of timeouts * remove timeouts on dashboard-share-internally * use toBeHidden * make dashboard-share-internally more stable * remove TEMP_DAGGER_TOKEN * clean up visaulization-suggestions * unskip gauge test * unskip trace-view-scrolling * attempt to make create variable utils stable * unskip loki tests * make go linter happy * unskip edit-group-by-variables test * unskip move panel tests * isolate dashboard-timepicker tests with separate user * create data source as part of smoke test * make sure we're awaiting in dashboard-edit-adhoc-variables * make dashboards-edit-variables test more robust * Hackathon Playwright: Dashboards Search (#107580) * Hackathon Playwright: Dashboards Search * Feedback changes * make trace-view-scrolling more stable * add json report and bench step * fix bench version * move fail step to after the playwright report so we can report test failures * fix output file name * fix typo * try wrap in expect.poll * stability * bit more tidy up * fix dashboard-new-layouts tests * move test-plugins to e2e-playwright * fix go code for drone e2e run * move loki plugin-e2e test * make v2 dashboards work again --------- Co-authored-by: joshhunt <josh.hunt@grafana.com> Co-authored-by: Josh Hunt <joshhunt@users.noreply.github.com> Co-authored-by: Collin Fingar <collin.fingar@grafana.com> Co-authored-by: Jeff Levin <jeff@levinology.com>
1 week ago
'e2e-playwright/test-plugins',
9 months ago
'e2e/tmp',
'packages/grafana-ui/src/components/Icon/iconBundle.ts',
'pkg',
'playwright-report',
'public/lib/monaco/', // this path is no longer required but local dev environments may still have it
'public/locales/_build',
'public/locales/**/*.js',
'public/vendor/',
'scripts/grafana-server/tmp',
'!.betterer.eslint.config.js',
'packages/grafana-ui/src/graveyard', // deprecated UI components slated for removal
'public/build-swagger', // swagger build output
9 months ago
],
},
// Conditionally run the betterer rules if enabled in dev's config
...(enableBettererRules ? bettererConfig : []),
9 months ago
grafanaConfig,
{
name: 'react/jsx-runtime',
// @ts-ignore - not sure why but flat config is typed as a maybe?
...reactPlugin.configs.flat['jsx-runtime'],
},
{
name: 'grafana/defaults',
linterOptions: {
// This reports unused disable directives that we can clean up but
// it also conflicts with the betterer eslint rules so disabled
reportUnusedDisableDirectives: false,
},
files: ['**/*.{ts,tsx,js}'],
plugins: {
'@emotion': emotionPlugin,
lodash: lodashPlugin,
jest: jestPlugin,
import: importPlugin,
'jsx-a11y': jsxA11yPlugin,
'no-barrel-files': barrelPlugin,
'@grafana': grafanaPlugin,
unicorn: unicornPlugin,
9 months ago
},
settings: {
'import/internal-regex': '^(app/)|(@grafana)',
'import/external-module-folders': ['node_modules', '.yarn'],
// Silences a warning when linting enterprise code
react: {
version: 'detect',
},
9 months ago
},
rules: {
'no-duplicate-case': 'error',
9 months ago
'@grafana/no-border-radius-literal': 'error',
'@grafana/no-unreduced-motion': 'error',
'@grafana/no-restricted-img-srcs': 'error',
9 months ago
'react/prop-types': 'off',
// need to ignore emotion's `css` prop, see https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-unknown-property.md#rule-options
'react/no-unknown-property': ['error', { ignore: ['css'] }],
'@emotion/jsx-import': 'error',
'@emotion/syntax-preference': [2, 'object'],
'lodash/import-scope': [2, 'member'],
'jest/no-focused-tests': 'error',
'import/order': [
'error',
{
pathGroups: [
{
pattern: 'img/**',
group: 'internal',
},
],
9 months ago
groups: [['builtin', 'external'], 'internal', 'parent', 'sibling', 'index'],
'newlines-between': 'always',
alphabetize: { order: 'asc' },
pathGroupsExcludedImportTypes: ['builtin'],
9 months ago
},
],
'no-restricted-imports': [
'error',
{
patterns: [
9 months ago
{
group: ['react-i18next', 'i18next'],
importNames: ['t'],
message: 'Please import from @grafana/i18n instead',
9 months ago
},
{
group: ['react-i18next'],
importNames: ['Trans'],
message: 'Please import from @grafana/i18n instead',
9 months ago
},
{
regex: '\\.test$',
message:
'Do not import test files. If you require reuse of constants/mocks across files, create a separate file with no tests',
},
],
paths: [
{
name: 'react-redux',
importNames: ['useDispatch', 'useSelector'],
message: 'Please import from app/types instead.',
},
9 months ago
],
},
],
'no-restricted-globals': ['error'].concat(restrictedGlobals),
9 months ago
// Use typescript's no-redeclare for compatibility with overrides
'no-redeclare': 'off',
'@typescript-eslint/no-redeclare': ['error'],
'unicorn/no-empty-file': 'error',
'no-constant-condition': 'error',
9 months ago
},
},
{
name: 'grafana/uplot-overrides',
files: ['packages/grafana-ui/src/components/uPlot/**/*.{ts,tsx}'],
rules: {
'react-hooks/rules-of-hooks': 'off',
'react-hooks/exhaustive-deps': 'off',
},
},
{
name: 'grafana/theme-demo-overrides',
files: ['packages/grafana-ui/src/components/ThemeDemos/**/*.{ts,tsx}'],
rules: {
'@emotion/jsx-import': 'off',
'react/jsx-uses-react': 'off',
'react/react-in-jsx-scope': 'off',
},
},
{
name: 'grafana/story-rules',
files: ['packages/grafana-ui/src/**/*.story.tsx'],
rules: {
'@grafana/consistent-story-titles': 'error',
},
},
9 months ago
{
name: 'grafana/public-dashboards-overrides',
files: ['public/dashboards/scripted*.js'],
rules: {
'no-redeclare': 'error',
'@typescript-eslint/no-redeclare': 'off',
},
},
{
name: 'grafana/jsx-a11y-overrides',
files: ['**/*.tsx'],
ignores: ['**/*.{spec,test}.tsx'],
rules: {
...jsxA11yPlugin.configs.recommended.rules,
9 months ago
'jsx-a11y/no-autofocus': [
'error',
{
ignoreNonDOM: true,
},
],
'jsx-a11y/label-has-associated-control': [
'error',
{
controlComponents: ['NumberInput'],
depth: 2,
},
],
},
},
{
name: 'grafana/data-overrides',
files: ['packages/grafana-data/**/*.{ts,tsx}'],
ignores: ['packages/grafana-data/src/**/*.{spec,test}.{ts,tsx}'],
rules: {
'no-restricted-imports': [
'error',
{
patterns: ['@grafana/runtime', '@grafana/ui', '@grafana/data'],
},
],
},
},
{
name: 'grafana/ui-overrides',
files: ['packages/grafana-ui/**/*.{ts,tsx}'],
rules: {
'no-restricted-imports': [
'error',
{
patterns: ['@grafana/runtime', '@grafana/data/*', '@grafana/ui', '@grafana/e2e-selectors/*'],
paths: [
{
name: 'react-i18next',
importNames: ['Trans', 't'],
message: 'Please import from grafana-ui/src/utils/i18n instead',
},
],
},
],
},
},
{
name: 'grafana/schema-overrides',
files: ['packages/grafana-schema/**/*.{ts,tsx}'],
ignores: ['packages/grafana-schema/**/*.test.{ts,tsx}'],
rules: {
'no-restricted-imports': [
'error',
{
patterns: ['@grafana/*'],
},
],
},
},
{
name: 'grafana/runtime-overrides',
files: ['packages/grafana-runtime/**/*.{ts,tsx}'],
rules: {
'no-restricted-imports': [
'error',
{
patterns: ['@grafana/runtime', '@grafana/data/*', '@grafana/ui/*', '@grafana/e2e/*'],
},
],
},
},
{
name: 'grafana/flamegraph-overrides',
files: ['packages/grafana-flamegraph/**/*.{ts,tsx}'],
ignores: ['packages/grafana-flamegraph/**/*.{test,story}.{ts,tsx}'],
rules: {
'no-restricted-imports': [
'error',
{
patterns: ['@grafana/runtime', '@grafana/e2e', '@grafana/e2e-selectors/*'],
},
],
},
},
{
name: 'grafana/alerting-overrides',
plugins: {
unicorn: unicornPlugin,
react: reactPlugin,
'@grafana': grafanaPlugin,
},
files: ['public/app/features/alerting/**/*.{ts,tsx,js,jsx}', 'packages/grafana-alerting/**/*.{ts,tsx,js,jsx}'],
9 months ago
rules: {
'sort-imports': ['error', { ignoreDeclarationSort: true }],
9 months ago
'dot-notation': 'error',
'prefer-const': 'error',
'react/no-unused-prop-types': 'error',
'react/self-closing-comp': 'error',
'react/jsx-no-useless-fragment': ['error', { allowExpressions: true }],
'unicorn/no-unused-properties': 'error',
'no-nested-ternary': 'error',
9 months ago
},
},
{
// Sections of codebase that have all translation markup issues fixed
name: 'grafana/i18n-overrides',
plugins: {
'@grafana': grafanaPlugin,
'@grafana/i18n': grafanaI18nPlugin,
},
files: [
'public/app/!(plugins)/**/*.{ts,tsx,js,jsx}',
'packages/grafana-ui/**/*.{ts,tsx,js,jsx}',
'packages/grafana-sql/**/*.{ts,tsx,js,jsx}',
'packages/grafana-prometheus/**/*.{ts,tsx,js,jsx}',
...pluginsToTranslate.map((plugin) => `${plugin}/**/*.{ts,tsx,js,jsx}`),
],
ignores: [
'public/test/**',
'**/*.{test,spec,story}.{ts,tsx}',
'**/{tests,__mocks__,__tests__,fixtures,spec,mocks}/**',
'**/{test-utils,testHelpers,mocks}.{ts,tsx}',
'**/mock*.{ts,tsx}',
],
rules: {
'@grafana/i18n/no-untranslated-strings': ['error', { calleesToIgnore: ['^css$', 'use[A-Z].*'] }],
'@grafana/i18n/no-translation-top-level': 'error',
},
},
9 months ago
{
name: 'grafana/tests',
9 months ago
plugins: {
'testing-library': testingLibraryPlugin,
9 months ago
'jest-dom': jestDomPlugin,
},
files: [
'public/app/features/alerting/**/__tests__/**/*.[jt]s?(x)',
'public/app/features/alerting/**/?(*.)+(spec|test).[jt]s?(x)',
'packages/{grafana-ui,grafana-alerting}/**/*.{spec,test}.{ts,tsx}',
9 months ago
],
rules: {
...testingLibraryPlugin.configs['flat/react'].rules,
...jestDomPlugin.configs['flat/recommended'].rules,
'testing-library/prefer-user-event': 'error',
'jest/expect-expect': ['error', { assertFunctionNames: ['expect*', 'assert*', 'reducerTester'] }],
},
},
{
name: 'grafana/test-overrides-to-fix',
plugins: {
'testing-library': testingLibraryPlugin,
},
files: ['packages/grafana-ui/**/*.{spec,test}.{ts,tsx}'],
rules: {
// grafana-ui has lots of violations of direct node access and container methods, so disabling for now
'testing-library/no-node-access': 'off',
'testing-library/no-container': 'off',
9 months ago
},
},
{
name: 'grafana/explore-traceview-overrides',
files: ['public/app/features/explore/TraceView/components/demo/**/*.{ts,tsx,js,jsx}'],
rules: {
'import/no-extraneous-dependencies': 'off',
},
},
{
name: 'grafana/decoupled-plugins-overrides',
files: [
'public/app/plugins/datasource/azuremonitor/**/*.{ts,tsx}',
'public/app/plugins/datasource/cloud-monitoring/**/*.{ts,tsx}',
'public/app/plugins/datasource/cloudwatch/**/*.{ts,tsx}',
'public/app/plugins/datasource/elasticsearch/**/*.{ts,tsx}',
'public/app/plugins/datasource/elasticsearch/**/*.{ts,tsx}',
'public/app/plugins/datasource/grafana-postgresql-datasource/**/*.{ts,tsx}',
'public/app/plugins/datasource/grafana-pyroscope-datasource/**/*.{ts,tsx}',
'public/app/plugins/datasource/grafana-testdata-datasource/**/*.{ts,tsx}',
'public/app/plugins/datasource/jaeger/**/*.{ts,tsx}',
'public/app/plugins/datasource/loki/**/*.{ts,tsx}',
'public/app/plugins/datasource/loki/**/*.{ts,tsx}',
'public/app/plugins/datasource/mysql/**/*.{ts,tsx}',
'public/app/plugins/datasource/parca/**/*.{ts,tsx}',
'public/app/plugins/datasource/tempo/**/*.{ts,tsx}',
'public/app/plugins/datasource/zipkin/**/*.{ts,tsx}',
],
plugins: {
import: importPlugin,
},
settings: {
'import/resolver': {
node: {
extensions: ['.ts', '.tsx'],
},
},
},
rules: {
'import/no-restricted-paths': [
'error',
{
zones: [
{
target: './public/app/plugins',
from: './public',
except: ['./app/plugins'],
message: 'Core plugins are not allowed to depend on Grafana core packages',
},
],
},
],
},
},
];