Chore: Fix no-restricted-imports config not applying correctly (#110232)

* fix types

* get useSelector from the correct place

* use declare module instead
This commit is contained in:
Josh Hunt
2025-08-28 10:19:36 +01:00
committed by GitHub
parent 9b24e7eac8
commit 87fe2f4258
5 changed files with 105 additions and 102 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ const grafanaI18nPlugin = require('@grafana/i18n/eslint-plugin');
// as we just want to pull in all of the necessary configuration but not run the rules
// (this should only be concerned with checking rules that we want to improve,
// so there's no need to try and run the rules that will be linted properly anyway)
const mappedBaseConfigs = grafanaConfig.map((config) => {
const mappedBaseConfigs = grafanaConfig.map((/** @type {import('eslint').Linter.Config} */ config) => {
const { rules, ...baseConfig } = config;
return baseConfig;
});
+99 -100
View File
@@ -26,6 +26,48 @@ const pluginsToTranslate = [
'public/app/plugins/datasource/mssql',
];
// [FIXME] add comment about this applying everywhere
const baseImportConfig = {
patterns: [
{
group: ['react-i18next', 'i18next'],
importNames: ['t'],
message: 'Please import from @grafana/i18n instead',
},
{
group: ['react-i18next'],
importNames: ['Trans'],
message: 'Please import from @grafana/i18n instead',
},
{
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/store instead.',
},
],
};
/**
*
* @param {{ patterns?: Array<object>, paths?: Array<object> }} config
* @returns
*/
function withBaseRestrictedImportsConfig(config = {}) {
const finalConfig = {
patterns: [...baseImportConfig.patterns, ...(config?.patterns ?? [])],
paths: [...baseImportConfig.paths, ...(config?.paths ?? [])],
};
return finalConfig;
}
/**
* @type {Array<import('eslint').Linter.Config>}
*/
@@ -118,35 +160,7 @@ module.exports = [
pathGroupsExcludedImportTypes: ['builtin'],
},
],
'no-restricted-imports': [
'error',
{
patterns: [
{
group: ['react-i18next', 'i18next'],
importNames: ['t'],
message: 'Please import from @grafana/i18n instead',
},
{
group: ['react-i18next'],
importNames: ['Trans'],
message: 'Please import from @grafana/i18n instead',
},
{
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.',
},
],
},
],
'no-restricted-imports': ['error', baseImportConfig],
'no-restricted-globals': ['error'].concat(restrictedGlobals),
// Use typescript's no-redeclare for compatibility with overrides
@@ -168,6 +182,26 @@ module.exports = [
'react-hooks/rules-of-hooks': 'off',
},
},
{
name: 'grafana/no-extensions-imports',
files: ['public/**/*.{ts,tsx,js}'],
ignores: ['public/app/extensions/**/*'],
rules: {
'no-restricted-imports': [
'error',
withBaseRestrictedImportsConfig({
patterns: [
{
group: ['app/extensions', 'app/extensions/*'],
message: 'Importing from app/extensions is not allowed',
},
],
}),
],
},
},
{
name: 'grafana/uplot-overrides',
files: ['packages/grafana-ui/src/components/uPlot/**/*.{ts,tsx}'],
@@ -221,76 +255,58 @@ module.exports = [
],
},
},
{
name: 'grafana/data-overrides',
files: ['packages/grafana-data/**/*.{ts,tsx}'],
ignores: ['packages/grafana-data/src/**/*.{spec,test}.{ts,tsx}'],
// No NPM package should import from @grafana/*/internal because it does not exist
// outside of this repo - they're not published to NPM.
name: 'grafana/packages-overrides',
files: ['packages/**/*.{ts,tsx}'],
ignores: [],
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: [
withBaseRestrictedImportsConfig({
patterns: [
{
name: 'react-i18next',
importNames: ['Trans', 't'],
message: 'Please import from grafana-ui/src/utils/i18n instead',
group: ['@grafana/*/internal'],
message: "'internal' exports are not available in NPM packages because they are not published to NPM",
},
],
},
}),
],
},
},
{
name: 'grafana/schema-overrides',
files: ['packages/grafana-schema/**/*.{ts,tsx}'],
ignores: ['packages/grafana-schema/**/*.test.{ts,tsx}'],
// @grafana/runtime shouldn't be imported from our 'library' NPM packages
name: 'grafana/packages-that-cant-import-runtime',
files: [
'packages/grafana-ui/**/*.{ts,tsx}',
'packages/grafana-data/**/*.{ts,tsx}',
'packages/grafana-schema/**/*.{ts,tsx}',
'packages/grafana-e2e-selectors/**/*.{ts,tsx}',
],
ignores: [],
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/*'],
},
withBaseRestrictedImportsConfig({
patterns: [
{
// Duplicated because these rules override the previous grafana/packages-overrides
group: ['@grafana/*/internal'],
message: "'internal' exports are not available in NPM packages because they are not published to NPM",
},
{
group: ['@grafana/runtime'],
message: "'@grafana/runtime' should not be imported from library packages",
},
],
}),
],
},
},
{
name: 'grafana/alerting-overrides',
plugins: {
@@ -427,24 +443,7 @@ module.exports = [
],
},
},
{
name: 'grafana/no-extensions-imports',
files: ['**/*.{ts,tsx,js}'],
ignores: ['public/app/extensions/**/*'],
rules: {
'no-restricted-imports': [
'error',
{
patterns: [
{
group: ['app/extensions', 'app/extensions/*'],
message: 'Importing from app/extensions is not allowed',
},
],
},
],
},
},
// Conditionally run the betterer rules if enabled in dev's config
// Should be last in the config so it can override any temporary disables in here
...(enableBettererRules ? bettererConfig : []),
@@ -1,10 +1,10 @@
import { useMemo } from 'react';
import { useSelector } from 'react-redux';
import { ManagerKind } from 'app/features/apiserver/types';
import { rootItemsSelector, useChildrenByParentUIDState } from 'app/features/browse-dashboards/state/hooks';
import { findItem } from 'app/features/browse-dashboards/state/utils';
import { DashboardTreeSelection } from 'app/features/browse-dashboards/types';
import { useSelector } from 'app/types/store';
// This hook retrieves the folder UID from the selection state. Because search endpoint currently does not return resource metadata
// NOTE: This is a temporary workaround until the search endpoint is updated
+3
View File
@@ -0,0 +1,3 @@
declare module 'eslint-plugin-jsx-a11y';
declare module 'eslint-plugin-lodash';
declare module '@grafana/eslint-config/flat';
+1
View File
@@ -24,6 +24,7 @@
}
},
"include": [
"eslint.config.js",
"public/app/**/*.ts*",
"public/swagger/**/*.ts*",
"public/e2e-test/**/*.ts",