From d8d3c4800e88d98e5705f81717b73f02eae0d621 Mon Sep 17 00:00:00 2001 From: Marco polo Date: Tue, 3 Sep 2024 15:16:00 -0400 Subject: [PATCH] Add lint rule to disallow importing Route from react-router-dom (#24176) ## Summary & Motivation Adds a lint rule to disallow importing Route directly from react-router-dom. Instead it should be imported from our custom Route component that wraps the one from react-router-dom ## How I Tested These Changes jest test + ran `yarn lint --fix` which created the updated imports in this PR ## Changelog [New | Bug | Docs] NOCHANGELOG --- .../packages/eslint-config/.eslintrc.js | 5 + .../missing-graphql-variables-type.test.js | 2 +- .../rules/__tests__/no-apollo-client.js | 32 +++ .../__tests__/no-react-router-route.test.js | 35 ++++ .../packages/eslint-config/rules/index.js | 4 +- .../rules/missing-graphql-variables-type.js | 192 +++++++++--------- .../eslint-config/rules/no-apollo-client.js | 63 +++--- .../eslint-config/rules/no-oss-imports.js | 12 +- .../rules/no-react-router-route.js | 98 +++++++++ .../util/findRelativeImportPath.js | 23 +++ .../ui-core/src/apollo-client/index.tsx | 1 - .../src/app/__tests__/analytics.test.tsx | 3 +- .../assets/__tests__/AssetPartitions.test.tsx | 3 +- ...ueryAndLocalStoragePersistedState.test.tsx | 3 +- .../__tests__/useQueryPersistedState.test.tsx | 3 +- .../__stories__/BackfillPage.stories.tsx | 3 +- .../__tests__/BackfillLogsTab.test.tsx | 3 +- .../backfill/__tests__/BackfillPage.test.tsx | 3 +- 18 files changed, 338 insertions(+), 150 deletions(-) create mode 100644 js_modules/dagster-ui/packages/eslint-config/rules/__tests__/no-apollo-client.js create mode 100644 js_modules/dagster-ui/packages/eslint-config/rules/__tests__/no-react-router-route.test.js create mode 100644 js_modules/dagster-ui/packages/eslint-config/rules/no-react-router-route.js create mode 100644 js_modules/dagster-ui/packages/eslint-config/util/findRelativeImportPath.js diff --git a/js_modules/dagster-ui/packages/eslint-config/.eslintrc.js b/js_modules/dagster-ui/packages/eslint-config/.eslintrc.js index 1e12e02212f5d..6845ecbd80a5f 100644 --- a/js_modules/dagster-ui/packages/eslint-config/.eslintrc.js +++ b/js_modules/dagster-ui/packages/eslint-config/.eslintrc.js @@ -1,3 +1,8 @@ module.exports = { extends: './index.js', + overrides: { + rules: { + '@typescript-eslint/no-var-requires': 'off', + }, + }, }; diff --git a/js_modules/dagster-ui/packages/eslint-config/rules/__tests__/missing-graphql-variables-type.test.js b/js_modules/dagster-ui/packages/eslint-config/rules/__tests__/missing-graphql-variables-type.test.js index 543168d2eecd8..fec653450ee5d 100644 --- a/js_modules/dagster-ui/packages/eslint-config/rules/__tests__/missing-graphql-variables-type.test.js +++ b/js_modules/dagster-ui/packages/eslint-config/rules/__tests__/missing-graphql-variables-type.test.js @@ -10,7 +10,7 @@ jest.mock('fs'); const fs = require('fs'); // @ts-expect-error - using require because this package isn't setup for import declarations -const {rule} = require('../missing-graphql-variables-type'); +const rule = require('../missing-graphql-variables-type'); fs.readFileSync = (path) => { const api = path.includes('Query') diff --git a/js_modules/dagster-ui/packages/eslint-config/rules/__tests__/no-apollo-client.js b/js_modules/dagster-ui/packages/eslint-config/rules/__tests__/no-apollo-client.js new file mode 100644 index 0000000000000..f570a2ec035a5 --- /dev/null +++ b/js_modules/dagster-ui/packages/eslint-config/rules/__tests__/no-apollo-client.js @@ -0,0 +1,32 @@ +/* eslint-disable */ +const {ESLintUtils, AST_NODE_TYPES} = require('@typescript-eslint/utils'); + +const ruleTester = new ESLintUtils.RuleTester({ + parser: '@typescript-eslint/parser', +}); + +const rule = require('../no-apollo-client'); + +ruleTester.run('rule', rule, { + valid: [ + ` + import {useQuery} from '../../apollo-client'; + `, + ], + invalid: [ + { + code: ` + import {useQuery} from '@apollo/client'; + `, + output: ` + import {useQuery} from '@dagster-io/ui-core/apollo-client'; + `, + errors: [ + { + type: AST_NODE_TYPES.ImportDeclaration, + messageId: 'useWrappedApolloClient', + }, + ], + }, + ], +}); diff --git a/js_modules/dagster-ui/packages/eslint-config/rules/__tests__/no-react-router-route.test.js b/js_modules/dagster-ui/packages/eslint-config/rules/__tests__/no-react-router-route.test.js new file mode 100644 index 0000000000000..0dd1c078f2217 --- /dev/null +++ b/js_modules/dagster-ui/packages/eslint-config/rules/__tests__/no-react-router-route.test.js @@ -0,0 +1,35 @@ +/* eslint-disable */ +const {ESLintUtils, AST_NODE_TYPES} = require('@typescript-eslint/utils'); + +const ruleTester = new ESLintUtils.RuleTester({ + parser: '@typescript-eslint/parser', +}); + +const rule = require('../no-react-router-route'); + +ruleTester.run('rule', rule, { + valid: [ + ` + import {Redirect, Switch} from 'react-router-dom'; + + import {Route} from './Route'; + `, + ], + invalid: [ + { + code: ` +import {Redirect, Route, Switch} from 'react-router-dom'; + `, + output: ` +import { Route } from '@dagster-io/ui-core/app/Route'; +import {Redirect, Switch} from 'react-router-dom'; + `, + errors: [ + { + type: AST_NODE_TYPES.ImportDeclaration, + messageId: 'useDagsterRoute', + }, + ], + }, + ], +}); diff --git a/js_modules/dagster-ui/packages/eslint-config/rules/index.js b/js_modules/dagster-ui/packages/eslint-config/rules/index.js index 6ad2643f0d846..c5f4bac408b74 100644 --- a/js_modules/dagster-ui/packages/eslint-config/rules/index.js +++ b/js_modules/dagster-ui/packages/eslint-config/rules/index.js @@ -2,9 +2,10 @@ const projectName = 'dagster-rules'; const rules = { - 'missing-graphql-variables-type': require('./missing-graphql-variables-type').rule, + 'missing-graphql-variables-type': require('./missing-graphql-variables-type'), 'no-oss-imports': require('./no-oss-imports'), 'no-apollo-client': require('./no-apollo-client'), + 'no-react-router-route': require('./no-react-router-route'), }; module.exports = { @@ -16,6 +17,7 @@ module.exports = { [`${projectName}/missing-graphql-variables-type`]: 'error', [`${projectName}/no-oss-imports`]: 'error', [`${projectName}/no-apollo-client`]: 'error', + [`${projectName}/no-react-router-route`]: 'error', }, }, }, diff --git a/js_modules/dagster-ui/packages/eslint-config/rules/missing-graphql-variables-type.js b/js_modules/dagster-ui/packages/eslint-config/rules/missing-graphql-variables-type.js index ad49c7aff32fe..af9e3f0d34579 100644 --- a/js_modules/dagster-ui/packages/eslint-config/rules/missing-graphql-variables-type.js +++ b/js_modules/dagster-ui/packages/eslint-config/rules/missing-graphql-variables-type.js @@ -25,104 +25,102 @@ const APIToEnding = { useLazyQuery: 'LazyQuery', }; -module.exports = { - rule: createRule({ - create(context) { - return { - [AST_NODE_TYPES.CallExpression](node) { - const callee = node.callee; - if (callee.type !== 'Identifier') { - return; - } - // if it's not a useQuery call then ignore - if (!APIS.has(callee.name)) { - return; - } - const API = callee.name; - const queryType = - node.typeParameters && node.typeParameters.params && node.typeParameters.params[0]; - if (!queryType || queryType.type !== 'TSTypeReference') { - return; - } - if (queryType.typeName.type !== 'Identifier') { - return; - } - const queryName = queryType.typeName.name; - // if the type doesn't end with Query then ignore - if (!queryName.endsWith(APIToEnding[API])) { - return; - } - const variablesName = queryName + 'Variables'; - let queryImportSpecifier = null; - const importDeclaration = context.getSourceCode().ast.body.find( - (node) => - node.type === 'ImportDeclaration' && - node.specifiers.find((node) => { - if (node.type === 'ImportSpecifier' && node.local.name === queryName) { - queryImportSpecifier = node; - return true; - } - }), - ); - const importPath = importDeclaration.source.value; - const currentPath = context.getFilename().split('/').slice(0, -1).join('/'); - const fullPath = path.join(currentPath, importPath + '.ts'); +module.exports = createRule({ + create(context) { + return { + [AST_NODE_TYPES.CallExpression](node) { + const callee = node.callee; + if (callee.type !== 'Identifier') { + return; + } + // if it's not a useQuery call then ignore + if (!APIS.has(callee.name)) { + return; + } + const API = callee.name; + const queryType = + node.typeParameters && node.typeParameters.params && node.typeParameters.params[0]; + if (!queryType || queryType.type !== 'TSTypeReference') { + return; + } + if (queryType.typeName.type !== 'Identifier') { + return; + } + const queryName = queryType.typeName.name; + // if the type doesn't end with Query then ignore + if (!queryName.endsWith(APIToEnding[API])) { + return; + } + const variablesName = queryName + 'Variables'; + let queryImportSpecifier = null; + const importDeclaration = context.getSourceCode().ast.body.find( + (node) => + node.type === 'ImportDeclaration' && + node.specifiers.find((node) => { + if (node.type === 'ImportSpecifier' && node.local.name === queryName) { + queryImportSpecifier = node; + return true; + } + }), + ); + const importPath = importDeclaration.source.value; + const currentPath = context.getFilename().split('/').slice(0, -1).join('/'); + const fullPath = path.join(currentPath, importPath + '.ts'); - const graphqlTypeFile = fs.readFileSync(fullPath, {encoding: 'utf8'}); + const graphqlTypeFile = fs.readFileSync(fullPath, {encoding: 'utf8'}); - // This part is kind of hacky. I should use the parser service to find the identifier - // but this is faster then tokenizing the whole file - if ( - !graphqlTypeFile.includes('export type ' + variablesName) && - !graphqlTypeFile.includes('export interface ' + variablesName) - ) { - return; - } - // This is a Query type with a generated QueryVariables type. Make sure we're using it - const secondType = node.typeParameters.params[1]; - if ( - !secondType || - (secondType.type === 'TSTypeReference' && - secondType.typeName.type === 'Identifier' && - secondType.typeName.name !== variablesName) - ) { - context.report({ - messageId: 'missing-graphql-variables-type', - node, - data: { - queryType: queryName, - variablesType: variablesName, - api: API, - }, - *fix(fixer) { - if ( - !importDeclaration.specifiers.find( - (node) => node.type === 'ImportSpecifier' && node.local.name === variablesName, - ) - ) { - yield fixer.insertTextAfter(queryImportSpecifier, `, ${variablesName}`); - } - yield fixer.insertTextAfter(queryType, `, ${variablesName}`); - }, - }); - } - }, - }; - }, - name: 'missing-graphql-variables-type', - meta: { - fixable: true, - docs: { - description: 'useQuery is missing QueryVariables parameter.', - recommended: 'error', - }, - messages: { - 'missing-graphql-variables-type': - '`{{api}}<{{queryType}}>(...)` should be `{{api}}<{{queryType}},{{variablesType}}>(...)`.', + // This part is kind of hacky. I should use the parser service to find the identifier + // but this is faster then tokenizing the whole file + if ( + !graphqlTypeFile.includes('export type ' + variablesName) && + !graphqlTypeFile.includes('export interface ' + variablesName) + ) { + return; + } + // This is a Query type with a generated QueryVariables type. Make sure we're using it + const secondType = node.typeParameters.params[1]; + if ( + !secondType || + (secondType.type === 'TSTypeReference' && + secondType.typeName.type === 'Identifier' && + secondType.typeName.name !== variablesName) + ) { + context.report({ + messageId: 'missing-graphql-variables-type', + node, + data: { + queryType: queryName, + variablesType: variablesName, + api: API, + }, + *fix(fixer) { + if ( + !importDeclaration.specifiers.find( + (node) => node.type === 'ImportSpecifier' && node.local.name === variablesName, + ) + ) { + yield fixer.insertTextAfter(queryImportSpecifier, `, ${variablesName}`); + } + yield fixer.insertTextAfter(queryType, `, ${variablesName}`); + }, + }); + } }, - type: 'problem', - schema: [], + }; + }, + name: 'missing-graphql-variables-type', + meta: { + fixable: true, + docs: { + description: 'useQuery is missing QueryVariables parameter.', + recommended: 'error', }, - defaultOptions: [], - }), -}; + messages: { + 'missing-graphql-variables-type': + '`{{api}}<{{queryType}}>(...)` should be `{{api}}<{{queryType}},{{variablesType}}>(...)`.', + }, + type: 'problem', + schema: [], + }, + defaultOptions: [], +}); diff --git a/js_modules/dagster-ui/packages/eslint-config/rules/no-apollo-client.js b/js_modules/dagster-ui/packages/eslint-config/rules/no-apollo-client.js index 236b600ef4faf..dab89899203d2 100644 --- a/js_modules/dagster-ui/packages/eslint-config/rules/no-apollo-client.js +++ b/js_modules/dagster-ui/packages/eslint-config/rules/no-apollo-client.js @@ -1,21 +1,12 @@ -/* eslint-disable */ +const {findRelativeImportPath} = require('../util/findRelativeImportPath'); +const {ESLintUtils, AST_NODE_TYPES} = require('@typescript-eslint/utils'); +const createRule = ESLintUtils.RuleCreator((name) => name); -const fs = require('fs'); -const path = require('path'); - -module.exports = { - meta: { - type: 'suggestion', - fixable: 'code', - messages: { - useWrappedApolloClient: - 'Please use our wrapped apollo-client module which includes performance instrumentation.', - }, - }, +module.exports = createRule({ create(context) { return { - ImportDeclaration(node) { - if (context.getFilename().endsWith('/apollo-client')) { + [AST_NODE_TYPES.ImportDeclaration](node) { + if (context.getFilename().endsWith('/apollo-client/index.tsx')) { return; } if (node.source.value === '@apollo/client') { @@ -26,35 +17,29 @@ module.exports = { const currentFilePath = context.getFilename(); const relativeImportPath = findRelativeImportPath( currentFilePath, - 'src/apollo-client', - 'index.tsx', + 'src/apollo-client/index.tsx', ); - return fixer.replaceText(node.source, `'${relativeImportPath}'`); + // If we can't find the file then it means we're not in the ui-core package (we might be in cloud) so + // grab the import from @dagster-io/ui-core. + return fixer.replaceText( + node.source, + `'${relativeImportPath ?? '@dagster-io/ui-core/apollo-client'}'`, + ); }, }); } }, }; }, -}; - -function findRelativeImportPath(currentFilePath, targetDirName, targetFileName) { - let currentDir = path.dirname(currentFilePath); - - while (currentDir !== path.parse(currentDir).root) { - const srcPath = path.join(currentDir, targetDirName); - const targetFilePath = path.join(srcPath, targetFileName); - - if (fs.existsSync(targetFilePath)) { - return path.relative(path.dirname(currentFilePath), srcPath); - } - - currentDir = path.dirname(currentDir); - } - - // If we can't find the file then it means we're not in the ui-core package (we might be in cloud) so - // grab the import from @dagster-io/ui-core. - - return '@dagster-io/ui-core/apollo-client'; -} + name: 'no-apollo-client', + meta: { + type: 'suggestion', + fixable: 'code', + messages: { + useWrappedApolloClient: + 'Please use our wrapped apollo-client module which includes performance instrumentation.', + }, + }, + defaultOptions: [], +}); diff --git a/js_modules/dagster-ui/packages/eslint-config/rules/no-oss-imports.js b/js_modules/dagster-ui/packages/eslint-config/rules/no-oss-imports.js index 912a35e148746..bb89e8595af96 100644 --- a/js_modules/dagster-ui/packages/eslint-config/rules/no-oss-imports.js +++ b/js_modules/dagster-ui/packages/eslint-config/rules/no-oss-imports.js @@ -1,8 +1,11 @@ /* eslint-disable */ const path = require('path'); +const {ESLintUtils, AST_NODE_TYPES} = require('@typescript-eslint/utils'); -module.exports = { +const createRule = ESLintUtils.RuleCreator((name) => name); + +module.exports = createRule({ meta: { type: 'problem', docs: { @@ -14,9 +17,10 @@ module.exports = { fixable: 'code', schema: [], // no options }, + defaultOptions: [], create(context) { return { - ImportDeclaration(node) { + [AST_NODE_TYPES.ImportDeclaration](node) { if (node.source.value.endsWith('.oss') && node.source.value.startsWith('.')) { context.report({ node, @@ -33,7 +37,7 @@ module.exports = { }); } }, - ImportExpression(node) { + [AST_NODE_TYPES.ImportExpression](node) { if (node.source.value.endsWith('.oss') && node.source.value.startsWith('.')) { context.report({ node, @@ -52,4 +56,4 @@ module.exports = { }, }; }, -}; +}); diff --git a/js_modules/dagster-ui/packages/eslint-config/rules/no-react-router-route.js b/js_modules/dagster-ui/packages/eslint-config/rules/no-react-router-route.js new file mode 100644 index 0000000000000..3de4f7c41624b --- /dev/null +++ b/js_modules/dagster-ui/packages/eslint-config/rules/no-react-router-route.js @@ -0,0 +1,98 @@ +const {findRelativeImportPath} = require('../util/findRelativeImportPath'); + +const {ESLintUtils, AST_NODE_TYPES} = require('@typescript-eslint/utils'); + +const createRule = ESLintUtils.RuleCreator((name) => name); + +module.exports = createRule({ + create(context) { + return { + [AST_NODE_TYPES.ImportDeclaration](node) { + console.log(context.getFilename()); + if (context.getFilename().endsWith('/ui-core/src/app/Route.tsx')) { + return; + } + if ( + node.source.value === 'react-router-dom' && + node.specifiers.some((specifier) => specifier.imported.name === 'Route') + ) { + context.report({ + node, + messageId: 'useDagsterRoute', + fix(fixer) { + const routeSpecifier = node.specifiers.find( + (specifier) => specifier.imported.name === 'Route', + ); + const importRange = [node.range[0], node.range[1]]; + const routeRange = [routeSpecifier.range[0], routeSpecifier.range[1]]; + + const currentFilePath = context.getFilename(); + let relativeImportPath = findRelativeImportPath(currentFilePath, 'src/app/Route.tsx'); + + if (!relativeImportPath) { + relativeImportPath = '@dagster-io/ui-core/app/Route'; + } else if (!relativeImportPath.endsWith('Route')) { + relativeImportPath = `${relativeImportPath}/Route`; + } + + const newImport = `import { Route } from '${relativeImportPath}';\n`; + + const newImportRange = + routeSpecifier === node.specifiers[0] ? importRange : routeRange; + + const fixes = []; + + if (node.specifiers.length === 1) { + // Remove the entire import statement if it only imports `Route` + fixes.push(fixer.remove(node)); + } else { + // Check if the specifier to remove is at the start or end + if (routeSpecifier === node.specifiers[0]) { + // Remove the specifier and the following comma + fixes.push(fixer.removeRange([routeRange[0], node.specifiers[1].range[0]])); + } else if (routeSpecifier === node.specifiers[node.specifiers.length - 1]) { + // Remove the preceding comma and the specifier + fixes.push( + fixer.removeRange([ + node.specifiers[node.specifiers.length - 2].range[1], + routeRange[1], + ]), + ); + } else { + // Remove the specifier and the comma before it + fixes.push( + fixer.removeRange([ + node.specifiers[node.specifiers.indexOf(routeSpecifier) - 1].range[1], + routeRange[1], + ]), + ); + } + } + + // Insert the new import statement + fixes.push(fixer.insertTextBeforeRange(node.range, newImport)); + + return fixes; + }, + }); + } + }, + }; + }, + meta: { + type: 'suggestion', + docs: { + description: + 'Disallow importing "Route" from "react-router-dom" and autofix to import from "@dagster-io/ui-core/Route"', + category: 'Best Practices', + recommended: true, + }, + fixable: 'code', + messages: { + useDagsterRoute: + 'Import "Route" from "@dagster-io/ui-core/Route" instead of "react-router-dom".', + }, + schema: [], // no options + }, + defaultOptions: [], +}); diff --git a/js_modules/dagster-ui/packages/eslint-config/util/findRelativeImportPath.js b/js_modules/dagster-ui/packages/eslint-config/util/findRelativeImportPath.js new file mode 100644 index 0000000000000..b4ac957dd2706 --- /dev/null +++ b/js_modules/dagster-ui/packages/eslint-config/util/findRelativeImportPath.js @@ -0,0 +1,23 @@ +const fs = require('fs'); +const path = require('path'); + +function findRelativeImportPath(currentFilePath, targetPath) { + let currentDir = path.dirname(currentFilePath); + + while (currentDir !== path.parse(currentDir).root) { + if (currentDir === '.') { + break; + } + const targetFilePath = path.join(currentDir, targetPath); + + if (fs.existsSync(targetFilePath)) { + return path.relative(path.dirname(currentFilePath), path.dirname(targetFilePath)); + } + + currentDir = path.dirname(currentDir); + } + + return null; +} + +module.exports = {findRelativeImportPath}; diff --git a/js_modules/dagster-ui/packages/ui-core/src/apollo-client/index.tsx b/js_modules/dagster-ui/packages/ui-core/src/apollo-client/index.tsx index aaa595f224f9c..270575aa635ce 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/apollo-client/index.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/apollo-client/index.tsx @@ -1,4 +1,3 @@ -/* eslint-disable no-restricted-imports, dagster-rules/no-apollo-client */ import { LazyQueryHookOptions, OperationVariables, diff --git a/js_modules/dagster-ui/packages/ui-core/src/app/__tests__/analytics.test.tsx b/js_modules/dagster-ui/packages/ui-core/src/app/__tests__/analytics.test.tsx index ae559965aeb15..ff934a6149e74 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/app/__tests__/analytics.test.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/app/__tests__/analytics.test.tsx @@ -1,9 +1,10 @@ import {render, screen, waitFor} from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import * as React from 'react'; -import {MemoryRouter, Route, Switch} from 'react-router-dom'; +import {MemoryRouter, Switch} from 'react-router-dom'; import {RecoilRoot} from 'recoil'; +import {Route} from '../Route'; import {AnalyticsContext, GenericAnalytics, useTrackEvent, useTrackPageView} from '../analytics'; describe('Analytics', () => { diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/AssetPartitions.test.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/AssetPartitions.test.tsx index 544a5bff90580..840bd07b01109 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/AssetPartitions.test.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/AssetPartitions.test.tsx @@ -2,8 +2,9 @@ import {MockedProvider, MockedResponse} from '@apollo/client/testing'; import {getByTestId, render, screen, waitFor} from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import {useState} from 'react'; -import {MemoryRouter, Route} from 'react-router-dom'; +import {MemoryRouter} from 'react-router-dom'; +import {Route} from '../../app/Route'; import {AssetKeyInput} from '../../graphql/types'; import {AssetPartitionListProps} from '../AssetPartitionList'; import {AssetPartitionStatus} from '../AssetPartitionStatus'; diff --git a/js_modules/dagster-ui/packages/ui-core/src/hooks/__tests__/useQueryAndLocalStoragePersistedState.test.tsx b/js_modules/dagster-ui/packages/ui-core/src/hooks/__tests__/useQueryAndLocalStoragePersistedState.test.tsx index 18eb2df6c2e26..29eceaf2bf6b1 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/hooks/__tests__/useQueryAndLocalStoragePersistedState.test.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/hooks/__tests__/useQueryAndLocalStoragePersistedState.test.tsx @@ -1,7 +1,8 @@ import {act, renderHook, waitFor} from '@testing-library/react'; import * as React from 'react'; -import {MemoryRouter, Route} from 'react-router-dom'; +import {MemoryRouter} from 'react-router-dom'; +import {Route} from '../../app/Route'; import {useQueryAndLocalStoragePersistedState} from '../useQueryAndLocalStoragePersistedState'; // Mock local storage diff --git a/js_modules/dagster-ui/packages/ui-core/src/hooks/__tests__/useQueryPersistedState.test.tsx b/js_modules/dagster-ui/packages/ui-core/src/hooks/__tests__/useQueryPersistedState.test.tsx index 748807e55930e..890991cced98a 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/hooks/__tests__/useQueryPersistedState.test.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/hooks/__tests__/useQueryPersistedState.test.tsx @@ -1,8 +1,9 @@ import {render, screen, waitFor} from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import {useCallback, useMemo} from 'react'; -import {MemoryRouter, Route} from 'react-router-dom'; +import {MemoryRouter} from 'react-router-dom'; +import {Route} from '../../app/Route'; import {useQueryPersistedState} from '../useQueryPersistedState'; const Test = ({options}: {options: Parameters[0]}) => { diff --git a/js_modules/dagster-ui/packages/ui-core/src/instance/backfill/__stories__/BackfillPage.stories.tsx b/js_modules/dagster-ui/packages/ui-core/src/instance/backfill/__stories__/BackfillPage.stories.tsx index 4cc9facebc416..07fdad7c15cda 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/instance/backfill/__stories__/BackfillPage.stories.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/instance/backfill/__stories__/BackfillPage.stories.tsx @@ -1,7 +1,8 @@ import {MockedProvider} from '@apollo/client/testing'; import {Meta, StoryFn} from '@storybook/react'; -import {MemoryRouter, Route} from 'react-router-dom'; +import {MemoryRouter} from 'react-router-dom'; +import {Route} from '../../../app/Route'; import {AnalyticsContext} from '../../../app/analytics'; import { BulkActionStatus, diff --git a/js_modules/dagster-ui/packages/ui-core/src/instance/backfill/__tests__/BackfillLogsTab.test.tsx b/js_modules/dagster-ui/packages/ui-core/src/instance/backfill/__tests__/BackfillLogsTab.test.tsx index d2c3c55c156f2..77858dc2c5665 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/instance/backfill/__tests__/BackfillLogsTab.test.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/instance/backfill/__tests__/BackfillLogsTab.test.tsx @@ -1,8 +1,9 @@ import {MockedProvider} from '@apollo/client/testing'; import {render, screen, waitFor} from '@testing-library/react'; -import {MemoryRouter, Route} from 'react-router-dom'; +import {MemoryRouter} from 'react-router-dom'; import {RecoilRoot} from 'recoil'; +import {Route} from '../../../app/Route'; import {AnalyticsContext} from '../../../app/analytics'; import { buildInstigationEvent, diff --git a/js_modules/dagster-ui/packages/ui-core/src/instance/backfill/__tests__/BackfillPage.test.tsx b/js_modules/dagster-ui/packages/ui-core/src/instance/backfill/__tests__/BackfillPage.test.tsx index 3a5c8da36e542..ba1f860148b31 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/instance/backfill/__tests__/BackfillPage.test.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/instance/backfill/__tests__/BackfillPage.test.tsx @@ -1,8 +1,9 @@ import {MockedProvider} from '@apollo/client/testing'; import {getAllByText, getByText, getByTitle, render, screen, waitFor} from '@testing-library/react'; -import {MemoryRouter, Route} from 'react-router-dom'; +import {MemoryRouter} from 'react-router-dom'; import {RecoilRoot} from 'recoil'; +import {Route} from '../../../app/Route'; import {AnalyticsContext} from '../../../app/analytics'; import { BulkActionStatus,