diff --git a/.changeset/warm-maps-scream.md b/.changeset/warm-maps-scream.md new file mode 100644 index 0000000000..3ea5d93b03 --- /dev/null +++ b/.changeset/warm-maps-scream.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-azure-devops': patch +'@backstage/plugin-devtools': patch +'@backstage/plugin-linguist': patch +--- + +Updated imports from named to default imports to help with the Material UI v4 to v5 migration diff --git a/.changeset/young-rules-repeat.md b/.changeset/young-rules-repeat.md new file mode 100644 index 0000000000..5c9d790214 --- /dev/null +++ b/.changeset/young-rules-repeat.md @@ -0,0 +1,5 @@ +--- +'@backstage/eslint-plugin': patch +--- + +Added new `@backstage/no-top-level-mui4-imports` rule that forbids top level imports from Material UI v4 packages diff --git a/docs/tutorials/migrate-to-mui5.md b/docs/tutorials/migrate-to-mui5.md index 96129ceb8a..1b21c8b419 100644 --- a/docs/tutorials/migrate-to-mui5.md +++ b/docs/tutorials/migrate-to-mui5.md @@ -56,7 +56,7 @@ For current known issues with the Material UI v5 migration, follow our [Mileston To migrate your plugin to Material UI v5, you can build on the resources available. -1. Manually fix the imports from named to default imports to match the new [linting rules for minimizing bundle size](https://mui.com/material-ui/guides/minimizing-bundle-size). +1. Manually fix the imports from named to default imports to match the new [linting rules for minimizing bundle size](https://mui.com/material-ui/guides/minimizing-bundle-size). Note: you can use the [new `@backstage/no-top-level-mui4-imports` ESLint](https://github.com/backstage/backstage/blob/master/packages/eslint-plugin/docs/rules/no-top-level-mui4-imports.md) rule to help with this. 2. Run the migration `codemod` for the path of the specific plugin: `npx @mui/codemod v5.0.0/preset-safe plugins/`. 3. Take a look at possible `TODO:` items the `codemod` could not fix. 4. Remove types & methods from `@backstage/theme` which are marked as `@deprecated`. diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md index c311670603..1304239caf 100644 --- a/packages/eslint-plugin/README.md +++ b/packages/eslint-plugin/README.md @@ -40,3 +40,4 @@ The following rules are provided by this plugin: | [@backstage/no-forbidden-package-imports](./docs/rules/no-forbidden-package-imports.md) | Disallow internal monorepo imports from package subpaths that are not exported. | | [@backstage/no-relative-monorepo-imports](./docs/rules/no-relative-monorepo-imports.md) | Forbid relative imports that reach outside of the package in a monorepo. | | [@backstage/no-undeclared-imports](./docs/rules/no-undeclared-imports.md) | Forbid imports of external packages that have not been declared in the appropriate dependencies field in `package.json`. | +| [@backstage/no-top-level-mui4-imports](./docs/rules/no-top-level-mui4-imports.md) | Forbid top level import from Material UI v4 packages. | diff --git a/packages/eslint-plugin/docs/rules/no-top-level-mui4-imports.md b/packages/eslint-plugin/docs/rules/no-top-level-mui4-imports.md new file mode 100644 index 0000000000..85f5821b01 --- /dev/null +++ b/packages/eslint-plugin/docs/rules/no-top-level-mui4-imports.md @@ -0,0 +1,43 @@ +# @backstage/no-top-level-mui4-imports + +Forbid top level import from Material UI v4 packages. + +## Usage + +Add the rules as follows, it has no options: + +```js +"@backstage/no-top-level-mui4-imports": ["error"] +``` + +## Rule Details + +TBD - Not sure what should go here + +### Fail + +```tsx +import { Box, Typography } from '@material-ui/core'; +``` + +```tsx +import Box from '@material-ui/core'; +``` + +```tsx +import { + Box, + DialogActions, + DialogContent, + DialogTitle, + Grid, + makeStyles, +} from '@material-ui/core'; +``` + +### Pass + +```tsx +import Typography from '@material-ui/core/Typography'; +import Box from '@material-ui/core/Box'; +``` diff --git a/packages/eslint-plugin/index.js b/packages/eslint-plugin/index.js index 20a0ff2d18..6fdc4f89fb 100644 --- a/packages/eslint-plugin/index.js +++ b/packages/eslint-plugin/index.js @@ -29,5 +29,6 @@ module.exports = { 'no-forbidden-package-imports': require('./rules/no-forbidden-package-imports'), 'no-relative-monorepo-imports': require('./rules/no-relative-monorepo-imports'), 'no-undeclared-imports': require('./rules/no-undeclared-imports'), + 'no-top-level-mui4-imports': require('./rules/no-top-level-mui4-imports'), }, }; diff --git a/packages/eslint-plugin/rules/no-top-level-mui4-imports.js b/packages/eslint-plugin/rules/no-top-level-mui4-imports.js new file mode 100644 index 0000000000..c3367a2346 --- /dev/null +++ b/packages/eslint-plugin/rules/no-top-level-mui4-imports.js @@ -0,0 +1,129 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// @ts-check + +const KNOWN_STYLES = [ + 'makeStyles', + 'withStyles', + 'createStyles', + 'styled', + 'useTheme', + 'Theme', +]; + +/** @type {import('eslint').Rule.RuleModule} */ +module.exports = { + meta: { + type: 'problem', + fixable: 'code', + messages: { + topLevelImport: 'Top level imports for Material UI are not allowed', + thirdLevelImport: + 'Third level or deeper imports for Material UI are not allowed', + }, + docs: { + description: 'Forbid top level import from Material UI v4 packages.', + url: 'https://github.com/backstage/backstage/blob/master/packages/eslint-plugin/docs/rules/no-top-level-mui4-imports.md', + }, + }, + create: context => ({ + ImportDeclaration: node => { + // Return if empty import + if (node.specifiers.length === 0) return; + // Return if empty source value + if (!node.source.value) return; + // Return if source value not a string + if (typeof node.source.value !== 'string') return; + // Return if import does not start with '@material-ui/' + if (!node.source.value.startsWith('@material-ui/')) return; + // Return if import is from '@material-ui/core/styles', as it's valid already + if (node.source.value === '@material-ui/core/styles') return; + // Return if import is from '@material-ui/core/SvgIcon', as it's valid already + if (node.source.value === '@material-ui/core/SvgIcon') return; + // Return if proper import eg. `import Box from '@material-ui/core/Box'` + if ( + node.specifiers.length === 1 && + node.source.value?.split('/').length === 3 + ) + return; + + // Report third level or deeper imports + if ( + node.specifiers.length === 1 && + node.source.value.split('/').length > 3 + ) { + context.report({ + node, + messageId: 'thirdLevelImport', + }); + return; + } + + // Report all other imports + context.report({ + node, + messageId: 'topLevelImport', + fix: fixer => { + const replacements = []; + const styles = []; + const svgIcon = []; + + const specifiers = node.specifiers.filter( + s => s.type === 'ImportSpecifier', + ); + + for (const specifier of specifiers) { + if (specifier.local.name === 'TabProps') { + replacements.push( + `import { TabProps } from '@material-ui/core/Tab';`, + ); + } else if ( + specifier.local.name === 'SvgIcon' || + specifier.local.name === 'SvgIconProps' + ) { + svgIcon.push(specifier.local.name); + } else if (KNOWN_STYLES.includes(specifier.local.name)) { + styles.push(specifier.local.name); + } else { + const replacement = `import ${specifier.local.name} from '${node.source.value}/${specifier.local.name}';`; + replacements.push(replacement); + } + } + + if (svgIcon.length > 0) { + if (svgIcon.every(s => ['SvgIcon', 'SvgIconProps'].includes(s))) { + replacements.push( + `import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon';`, + ); + } + } + + if (styles.length > 0) { + const stylesReplacement = `import { ${styles.join( + ', ', + )} } from '@material-ui/core/styles';`; + replacements.push(stylesReplacement); + } + + const result = fixer.replaceText(node, replacements.join('\n')); + + return result; + }, + }); + }, + }), +}; diff --git a/packages/eslint-plugin/src/no-top-level-mui4-imports.test.ts b/packages/eslint-plugin/src/no-top-level-mui4-imports.test.ts new file mode 100644 index 0000000000..16605aa46f --- /dev/null +++ b/packages/eslint-plugin/src/no-top-level-mui4-imports.test.ts @@ -0,0 +1,100 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { RuleTester } from 'eslint'; +import rule from '../rules/no-top-level-mui4-imports'; + +const ruleTester = new RuleTester({ + parserOptions: { + sourceType: 'module', + ecmaVersion: 2021, + }, +}); + +ruleTester.run('path-imports-rule', rule, { + valid: [ + { + code: `import Typography from '@material-ui/core/Typography';`, + }, + { + code: `import Box from '@material-ui/core/Box'`, + }, + { + code: `import { styled, withStyles } from '@material-ui/core/styles';`, + }, + { + code: `import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon';`, + }, + ], + invalid: [ + { + code: `import { Box, Typography } from '@material-ui/core';`, + errors: [{ messageId: 'topLevelImport' }], + output: `import Box from '@material-ui/core/Box'; +import Typography from '@material-ui/core/Typography';`, + }, + { + code: `import { Box } from '@material-ui/core';`, + errors: [{ messageId: 'topLevelImport' }], + output: `import Box from '@material-ui/core/Box';`, + }, + { + code: `import { + Box, + DialogActions, + DialogContent, + DialogTitle, + Grid, + makeStyles, + } from '@material-ui/core';`, + errors: [{ messageId: 'topLevelImport' }], + output: `import Box from '@material-ui/core/Box'; +import DialogActions from '@material-ui/core/DialogActions'; +import DialogContent from '@material-ui/core/DialogContent'; +import DialogTitle from '@material-ui/core/DialogTitle'; +import Grid from '@material-ui/core/Grid'; +import { makeStyles } from '@material-ui/core/styles';`, + }, + { + code: `import { TabIndicator } from '@material-ui/core/Tabs/TabIndicator';`, + errors: [{ messageId: 'thirdLevelImport' }], + }, + { + code: `import { Box, Button, makeStyles } from '@material-ui/core';`, + errors: [{ messageId: 'topLevelImport' }], + output: `import Box from '@material-ui/core/Box'; +import Button from '@material-ui/core/Button'; +import { makeStyles } from '@material-ui/core/styles';`, + }, + { + code: `import { Paper, Typography, styled, withStyles } from '@material-ui/core';`, + errors: [{ messageId: 'topLevelImport' }], + output: `import Paper from '@material-ui/core/Paper'; +import Typography from '@material-ui/core/Typography'; +import { styled, withStyles } from '@material-ui/core/styles';`, + }, + { + code: `import { styled } from '@material-ui/core';`, + errors: [{ messageId: 'topLevelImport' }], + output: `import { styled } from '@material-ui/core/styles';`, + }, + { + code: `import { TabProps } from '@material-ui/core';`, + errors: [{ messageId: 'topLevelImport' }], + output: `import { TabProps } from '@material-ui/core/Tab';`, + }, + ], +}); diff --git a/plugins/azure-devops/.eslintrc.js b/plugins/azure-devops/.eslintrc.js index e2a53a6ad2..9932358b45 100644 --- a/plugins/azure-devops/.eslintrc.js +++ b/plugins/azure-devops/.eslintrc.js @@ -1 +1,5 @@ -module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, { + rules: { + '@backstage/no-top-level-mui4-imports': 'error', + }, +}); diff --git a/plugins/azure-devops/src/components/AzureGitTagsIcon/AzureGitTagsIcon.tsx b/plugins/azure-devops/src/components/AzureGitTagsIcon/AzureGitTagsIcon.tsx index c8b63e3259..0d317e3ce1 100644 --- a/plugins/azure-devops/src/components/AzureGitTagsIcon/AzureGitTagsIcon.tsx +++ b/plugins/azure-devops/src/components/AzureGitTagsIcon/AzureGitTagsIcon.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { SvgIcon, SvgIconProps } from '@material-ui/core'; +import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon'; import React from 'react'; diff --git a/plugins/azure-devops/src/components/AzurePipelinesIcon/AzurePipelinesIcon.tsx b/plugins/azure-devops/src/components/AzurePipelinesIcon/AzurePipelinesIcon.tsx index bd19331f6e..10cdb3a905 100644 --- a/plugins/azure-devops/src/components/AzurePipelinesIcon/AzurePipelinesIcon.tsx +++ b/plugins/azure-devops/src/components/AzurePipelinesIcon/AzurePipelinesIcon.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { SvgIcon, SvgIconProps } from '@material-ui/core'; +import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon'; import React from 'react'; diff --git a/plugins/azure-devops/src/components/AzurePullRequestsIcon/AzurePullRequestsIcon.tsx b/plugins/azure-devops/src/components/AzurePullRequestsIcon/AzurePullRequestsIcon.tsx index 99e3f74e90..e298f8bc25 100644 --- a/plugins/azure-devops/src/components/AzurePullRequestsIcon/AzurePullRequestsIcon.tsx +++ b/plugins/azure-devops/src/components/AzurePullRequestsIcon/AzurePullRequestsIcon.tsx @@ -15,7 +15,7 @@ */ import React from 'react'; -import { SvgIcon, SvgIconProps } from '@material-ui/core'; +import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon'; /** @public */ export const AzurePullRequestsIcon = (props: SvgIconProps) => ( diff --git a/plugins/azure-devops/src/components/BuildTable/BuildTable.tsx b/plugins/azure-devops/src/components/BuildTable/BuildTable.tsx index 6707929a6c..09eba5f5a2 100644 --- a/plugins/azure-devops/src/components/BuildTable/BuildTable.tsx +++ b/plugins/azure-devops/src/components/BuildTable/BuildTable.tsx @@ -14,7 +14,8 @@ * limitations under the License. */ -import { Box, Typography } from '@material-ui/core'; +import Box from '@material-ui/core/Box'; +import Typography from '@material-ui/core/Typography'; import { BuildResult, BuildRun, diff --git a/plugins/azure-devops/src/components/GitTagTable/GitTagTable.tsx b/plugins/azure-devops/src/components/GitTagTable/GitTagTable.tsx index c6abba55e1..f34a1929fe 100644 --- a/plugins/azure-devops/src/components/GitTagTable/GitTagTable.tsx +++ b/plugins/azure-devops/src/components/GitTagTable/GitTagTable.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Box } from '@material-ui/core'; +import Box from '@material-ui/core/Box'; import { Link, ResponseErrorPanel, diff --git a/plugins/azure-devops/src/components/PullRequestStatusButtonGroup/PullRequestStatusButtonGroup.tsx b/plugins/azure-devops/src/components/PullRequestStatusButtonGroup/PullRequestStatusButtonGroup.tsx index f516bfb0e5..1b0b9a8afe 100644 --- a/plugins/azure-devops/src/components/PullRequestStatusButtonGroup/PullRequestStatusButtonGroup.tsx +++ b/plugins/azure-devops/src/components/PullRequestStatusButtonGroup/PullRequestStatusButtonGroup.tsx @@ -14,7 +14,8 @@ * limitations under the License. */ -import { Button, ButtonGroup } from '@material-ui/core'; +import Button from '@material-ui/core/Button'; +import ButtonGroup from '@material-ui/core/ButtonGroup'; import { PullRequestStatus } from '@backstage/plugin-azure-devops-common'; import React from 'react'; diff --git a/plugins/azure-devops/src/components/PullRequestTable/PullRequestTable.tsx b/plugins/azure-devops/src/components/PullRequestTable/PullRequestTable.tsx index b37ba6e73c..d672102945 100644 --- a/plugins/azure-devops/src/components/PullRequestTable/PullRequestTable.tsx +++ b/plugins/azure-devops/src/components/PullRequestTable/PullRequestTable.tsx @@ -14,7 +14,8 @@ * limitations under the License. */ -import { Box, Chip } from '@material-ui/core'; +import Box from '@material-ui/core/Box'; +import Chip from '@material-ui/core/Chip'; import { Link, ResponseErrorPanel, diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestCard/PullRequestCard.tsx b/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestCard/PullRequestCard.tsx index 98237cb2a3..dd9fff86b5 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestCard/PullRequestCard.tsx +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestCard/PullRequestCard.tsx @@ -15,7 +15,9 @@ */ import { Avatar, Link } from '@backstage/core-components'; -import { Card, CardContent, CardHeader } from '@material-ui/core'; +import Card from '@material-ui/core/Card'; +import CardContent from '@material-ui/core/CardContent'; +import CardHeader from '@material-ui/core/CardHeader'; import Typography from '@material-ui/core/Typography'; import { AutoCompleteIcon } from '../AutoCompleteIcon'; diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestGrid/PullRequestGrid.tsx b/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestGrid/PullRequestGrid.tsx index 8b9c49beb4..0244ea3bb1 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestGrid/PullRequestGrid.tsx +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestGrid/PullRequestGrid.tsx @@ -17,7 +17,7 @@ import { PullRequestGridColumn } from '../PullRequestGridColumn'; import { PullRequestGroup } from '../types'; import React from 'react'; -import { styled } from '@material-ui/core'; +import { styled } from '@material-ui/core/styles'; const GridDiv = styled('div')(({ theme }) => ({ display: 'flex', diff --git a/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestGridColumn/PullRequestGridColumn.tsx b/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestGridColumn/PullRequestGridColumn.tsx index 94a648188d..f06216ac76 100644 --- a/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestGridColumn/PullRequestGridColumn.tsx +++ b/plugins/azure-devops/src/components/PullRequestsPage/lib/PullRequestGridColumn/PullRequestGridColumn.tsx @@ -14,7 +14,9 @@ * limitations under the License. */ -import { Paper, Typography, styled, withStyles } from '@material-ui/core'; +import Paper from '@material-ui/core/Paper'; +import Typography from '@material-ui/core/Typography'; +import { styled, withStyles } from '@material-ui/core/styles'; import { PullRequestCard } from '../PullRequestCard'; import { PullRequestGroup } from '../types'; diff --git a/plugins/azure-devops/src/components/ReadmeCard/ReadmeCard.tsx b/plugins/azure-devops/src/components/ReadmeCard/ReadmeCard.tsx index 420fe6ecf4..300c9e0d7c 100644 --- a/plugins/azure-devops/src/components/ReadmeCard/ReadmeCard.tsx +++ b/plugins/azure-devops/src/components/ReadmeCard/ReadmeCard.tsx @@ -14,7 +14,9 @@ * limitations under the License. */ -import { Box, Button, makeStyles } from '@material-ui/core'; +import Box from '@material-ui/core/Box'; +import Button from '@material-ui/core/Button'; +import { makeStyles } from '@material-ui/core/styles'; import { InfoCard, Progress, diff --git a/plugins/devtools/.eslintrc.js b/plugins/devtools/.eslintrc.js index e2a53a6ad2..9932358b45 100644 --- a/plugins/devtools/.eslintrc.js +++ b/plugins/devtools/.eslintrc.js @@ -1 +1,5 @@ -module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, { + rules: { + '@backstage/no-top-level-mui4-imports': 'error', + }, +}); diff --git a/plugins/devtools/src/components/Content/ConfigContent/ConfigContent.tsx b/plugins/devtools/src/components/Content/ConfigContent/ConfigContent.tsx index 66129b5dae..aba46f85b7 100644 --- a/plugins/devtools/src/components/Content/ConfigContent/ConfigContent.tsx +++ b/plugins/devtools/src/components/Content/ConfigContent/ConfigContent.tsx @@ -15,16 +15,16 @@ */ import { Progress, WarningPanel } from '@backstage/core-components'; +import Box from '@material-ui/core/Box'; +import Paper from '@material-ui/core/Paper'; +import Typography from '@material-ui/core/Typography'; import { - Box, createStyles, makeStyles, - Paper, Theme, - Typography, useTheme, -} from '@material-ui/core'; -import { Alert } from '@material-ui/lab'; +} from '@material-ui/core/styles'; +import Alert from '@material-ui/lab/Alert'; import React from 'react'; import ReactJson from 'react-json-view'; import { useConfig } from '../../../hooks'; diff --git a/plugins/devtools/src/components/Content/ExternalDependenciesContent/ExternalDependenciesContent.tsx b/plugins/devtools/src/components/Content/ExternalDependenciesContent/ExternalDependenciesContent.tsx index a5dd825fe5..c6a46ea8fb 100644 --- a/plugins/devtools/src/components/Content/ExternalDependenciesContent/ExternalDependenciesContent.tsx +++ b/plugins/devtools/src/components/Content/ExternalDependenciesContent/ExternalDependenciesContent.tsx @@ -23,16 +23,12 @@ import { TableColumn, } from '@backstage/core-components'; import { ExternalDependency } from '@backstage/plugin-devtools-common'; -import { - Box, - createStyles, - Grid, - makeStyles, - Paper, - Theme, - Typography, -} from '@material-ui/core'; -import { Alert } from '@material-ui/lab'; +import Box from '@material-ui/core/Box'; +import Grid from '@material-ui/core/Grid'; +import Paper from '@material-ui/core/Paper'; +import Typography from '@material-ui/core/Typography'; +import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'; +import Alert from '@material-ui/lab/Alert'; import React from 'react'; import { useExternalDependencies } from '../../../hooks'; diff --git a/plugins/devtools/src/components/Content/InfoContent/BackstageLogoIcon.tsx b/plugins/devtools/src/components/Content/InfoContent/BackstageLogoIcon.tsx index 32f35600f2..8a9df77546 100644 --- a/plugins/devtools/src/components/Content/InfoContent/BackstageLogoIcon.tsx +++ b/plugins/devtools/src/components/Content/InfoContent/BackstageLogoIcon.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { SvgIcon, SvgIconProps } from '@material-ui/core'; +import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon'; import React from 'react'; diff --git a/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx b/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx index 0ed43d2fee..fcbea53603 100644 --- a/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx +++ b/plugins/devtools/src/components/Content/InfoContent/InfoContent.tsx @@ -15,20 +15,16 @@ */ import { Progress } from '@backstage/core-components'; -import { - Avatar, - Box, - createStyles, - Divider, - List, - ListItem, - ListItemAvatar, - ListItemText, - makeStyles, - Paper, - Theme, -} from '@material-ui/core'; -import { Alert } from '@material-ui/lab'; +import Avatar from '@material-ui/core/Avatar'; +import Box from '@material-ui/core/Box'; +import Divider from '@material-ui/core/Divider'; +import List from '@material-ui/core/List'; +import ListItem from '@material-ui/core/ListItem'; +import ListItemAvatar from '@material-ui/core/ListItemAvatar'; +import ListItemText from '@material-ui/core/ListItemText'; +import Paper from '@material-ui/core/Paper'; +import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'; +import Alert from '@material-ui/lab/Alert'; import React from 'react'; import { useInfo } from '../../../hooks'; import { InfoDependenciesTable } from './InfoDependenciesTable'; diff --git a/plugins/devtools/src/components/DevToolsLayout/DevToolsLayout.tsx b/plugins/devtools/src/components/DevToolsLayout/DevToolsLayout.tsx index ae9a337ced..bce0837ef1 100644 --- a/plugins/devtools/src/components/DevToolsLayout/DevToolsLayout.tsx +++ b/plugins/devtools/src/components/DevToolsLayout/DevToolsLayout.tsx @@ -19,7 +19,7 @@ import { attachComponentData, useElementFilter, } from '@backstage/core-plugin-api'; -import { TabProps } from '@material-ui/core'; +import { TabProps } from '@material-ui/core/Tab'; import { default as React } from 'react'; /** @public */ diff --git a/plugins/linguist/.eslintrc.js b/plugins/linguist/.eslintrc.js index e2a53a6ad2..9932358b45 100644 --- a/plugins/linguist/.eslintrc.js +++ b/plugins/linguist/.eslintrc.js @@ -1 +1,5 @@ -module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, { + rules: { + '@backstage/no-top-level-mui4-imports': 'error', + }, +}); diff --git a/plugins/linguist/src/components/LinguistCard/LinguistCard.tsx b/plugins/linguist/src/components/LinguistCard/LinguistCard.tsx index 6014487d30..6a07a958c2 100644 --- a/plugins/linguist/src/components/LinguistCard/LinguistCard.tsx +++ b/plugins/linguist/src/components/LinguistCard/LinguistCard.tsx @@ -14,15 +14,12 @@ * limitations under the License. */ -import { - Box, - Chip, - Tooltip, - Typography, - makeStyles, - Grid, - useTheme, -} from '@material-ui/core'; +import Box from '@material-ui/core/Box'; +import Chip from '@material-ui/core/Chip'; +import Tooltip from '@material-ui/core/Tooltip'; +import Typography from '@material-ui/core/Typography'; +import Grid from '@material-ui/core/Grid'; +import { makeStyles, useTheme } from '@material-ui/core/styles'; import { InfoCard, Progress } from '@backstage/core-components'; import Alert from '@material-ui/lab/Alert'; import { DateTime } from 'luxon';