Skip to content

Commit

Permalink
Update to ESLint v9
Browse files Browse the repository at this point in the history
As per https://eslint.org/docs/latest/use/migrate-to-9.0.0. The main
change is that the config format has changed.

We also update some configuration files to match the latest version of
the relevant Vite template:
https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts

As part of this, we enable type checking when running "yarn build" (it
was disabled until now, and "vite build" only performs transpilation),
and address type checking errors as necessary.

Signed-off-by: Antonin Bas <[email protected]>
  • Loading branch information
antoninbas committed Nov 25, 2024
1 parent ffd0562 commit d7ecc7d
Show file tree
Hide file tree
Showing 19 changed files with 476 additions and 510 deletions.
6 changes: 0 additions & 6 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,3 @@ updates:
schedule:
interval: "weekly"
open-pull-requests-limit: 10
ignore:
# Starting with v0.5, only the new eslint flat config is supported.
# We cannot upgrade to flat config (eslint v9) until more of the ecosystem supports it, so we
# pin the version of eslint-plugin-vitest to v0.4.
- dependency-name: "eslint-plugin-vitest"
update-types: ["version-update:semver-major", "version-update:semver-minor"] # ignore all except for patch updates
89 changes: 0 additions & 89 deletions client/web/antrea-ui/.eslintrc.cjs

This file was deleted.

69 changes: 69 additions & 0 deletions client/web/antrea-ui/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/**
* Copyright 2024 Antrea 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 js from '@eslint/js'
import globals from 'globals'
import react from 'eslint-plugin-react'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'
import vitest from "eslint-plugin-vitest";

export default tseslint.config(
{ ignores: ['dist'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
languageOptions: {
ecmaVersion: 'latest',
globals: globals.browser,
},
settings: { react: { version: 'detect' } },
plugins: {
'react': react,
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
'vitest': vitest,
},
rules: {
...react.configs.recommended.rules,
...react.configs['jsx-runtime'].rules,
...reactHooks.configs.recommended.rules,
...vitest.configs.recommended.rules,
// for Clarity (cds properties)
'react/no-unknown-property': ['off'],
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
'@typescript-eslint/no-unused-vars': [
'error',
{ 'argsIgnorePattern': '^_' },
],
'@typescript-eslint/no-explicit-any': [
'error',
{ 'ignoreRestArgs': true },
],
semi: ['warn', 'always'],
},
},
// file-pattern specific overrides
{
files: ["**/*.test.tsx"],
rules: {
"@typescript-eslint/no-explicit-any": ["off"],
},
},
)
10 changes: 5 additions & 5 deletions client/web/antrea-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
},
"scripts": {
"start": "vite",
"build": "vite build",
"build": "tsc -b --noEmit && vite build",
"test": "vitest",
"lint": "eslint 'src/**/*.ts{,x}' --max-warnings=0"
},
Expand All @@ -60,15 +60,15 @@
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@types/uuid": "^10.0.0",
"@typescript-eslint/eslint-plugin": "^7.0.0",
"@typescript-eslint/parser": "^6.21.0",
"eslint": "^8.57.1",
"eslint": "^9.15.0",
"eslint-plugin-react": "^7.37.2",
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-refresh": "^0.4.14",
"eslint-plugin-vitest": "^0.4.1",
"eslint-plugin-vitest": "^0.5.4",
"jsdom": "^25.0.1",
"nock": "^13.5.6",
"rollup-plugin-visualizer": "^5.12.0",
"typescript-eslint": "^8.16.0",
"uuid": "^11.0.3"
}
}
12 changes: 6 additions & 6 deletions client/web/antrea-ui/src/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const consoleErrorMock = vi.spyOn(console, 'error');
let testStore: AppStore;

beforeEach(() => {
consoleErrorMock.mockImplementation();
consoleErrorMock.mockImplementation(() => {});
});
afterAll(() => {
vi.restoreAllMocks();
Expand Down Expand Up @@ -90,7 +90,7 @@ describe('LoginWall', () => {
customRender(<LoginWall />, defaultSettings);
expect(await screen.findByText('Please log in')).toBeInTheDocument();
expect(mockedAuthAPI.refreshToken).toHaveBeenCalledTimes(1);
expect(console.error).not.toHaveBeenCalled();
expect(consoleErrorMock).not.toHaveBeenCalled();
});

test('refresh error - other API error', async () => {
Expand All @@ -99,7 +99,7 @@ describe('LoginWall', () => {
expect(await screen.findByText('Please log in')).toBeInTheDocument();
expect(await screen.findByText(/Not Found/)).toBeInTheDocument();
expect(mockedAuthAPI.refreshToken).toHaveBeenCalledTimes(1);
expect(console.error).toHaveBeenCalled();
expect(consoleErrorMock).toHaveBeenCalled();
});

test('refresh error - other error', async () => {
Expand All @@ -108,7 +108,7 @@ describe('LoginWall', () => {
expect(await screen.findByText('Please log in')).toBeInTheDocument();
expect(await screen.findByText(/some error/)).toBeInTheDocument();
expect(mockedAuthAPI.refreshToken).toHaveBeenCalledTimes(1);
expect(console.error).toHaveBeenCalled();
expect(consoleErrorMock).toHaveBeenCalled();
});

test('refresh success', async () => {
Expand All @@ -132,7 +132,7 @@ describe('LoginWall', () => {

test('no log in screen during refresh', async () => {
mockedAuthAPI.refreshToken.mockImplementation(async () => {
return new Promise((resolve, reject) => setTimeout(() => reject(new APIError(401, 'Unauthenticated', 'cookie expired')), 200));
return new Promise((_, reject) => setTimeout(() => reject(new APIError(401, 'Unauthenticated', 'cookie expired')), 200));
});

customRender(<LoginWall />, defaultSettings);
Expand Down Expand Up @@ -217,7 +217,7 @@ describe('WaitForSettings', () => {

expect(await screen.findByText(/Not Found/)).toBeInTheDocument();
expect(mockedSettingsAPI.fetch).toHaveBeenCalledTimes(1);
expect(console.error).toHaveBeenCalled();
expect(consoleErrorMock).toHaveBeenCalled();
});
});

Expand Down
4 changes: 2 additions & 2 deletions client/web/antrea-ui/src/api/info.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export interface Condition {
message: string
}

export interface ControllerCondition extends Condition { }
export type ControllerCondition = Condition;

export interface ControllerInfo {
metadata: {
Expand All @@ -58,7 +58,7 @@ interface OVSInfo {
flowTable?: Map<string,number>
}

export interface AgentCondition extends Condition { }
export type AgentCondition = Condition;

export interface AgentInfo {
metadata: {
Expand Down
2 changes: 1 addition & 1 deletion client/web/antrea-ui/src/api/traceflow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ export const traceflowAPI = {
return tf.status;
}
}
// eslint-disable-next-line no-unreachable
// @ts-expect-error keep this for now even though the only way to exit the loop is through a return
throw new APIError(0, "", "Timeout when waiting for traceflow request to complete");
} catch(err) {
console.error("Unable to run traceflow");
Expand Down
3 changes: 1 addition & 2 deletions client/web/antrea-ui/src/components/login.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,8 @@ const setToken = (t: string) => {
};

beforeEach(() => {
consoleErrorMock.mockImplementation();
consoleErrorMock.mockImplementation(() => {});
});

afterAll(() => {
vi.restoreAllMocks();
});
Expand Down
16 changes: 8 additions & 8 deletions client/web/antrea-ui/src/reportWebVitals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@
* limitations under the License.
*/

import { ReportHandler } from 'web-vitals';
import { MetricType } from "web-vitals";

const reportWebVitals = (onPerfEntry?: ReportHandler) => {
const reportWebVitals = (onPerfEntry?: (metric: MetricType) => void) => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
import("web-vitals").then(({ onCLS, onINP, onFCP, onLCP, onTTFB }) => {
onCLS(onPerfEntry);
onINP(onPerfEntry);
onFCP(onPerfEntry);
onLCP(onPerfEntry);
onTTFB(onPerfEntry);
});
}
};
Expand Down
2 changes: 1 addition & 1 deletion client/web/antrea-ui/src/routes/summary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ export default function Summary() {
<ComponentSummary title="Agents" data={agentInfos!} propertyNames={agentProperties} getProperties={agentPropertyValues} />
</WaitForAPIResource>
<WaitForAPIResource ready={controllerFeatureGates !== undefined} text="Loading Controller Feature Gates">
<ComponentSummary title="Controller Feature Gates" data={controllerFeatureGates} propertyNames={featureGateProperties} getProperties={featureGatePropertyValues} />
<ComponentSummary title="Controller Feature Gates" data={controllerFeatureGates!} propertyNames={featureGateProperties} getProperties={featureGatePropertyValues} />
</WaitForAPIResource>
<WaitForAPIResource ready={agentFeatureGates !== undefined} text="Loading Agent Feature Gates">
<ComponentSummary title="Agent Feature Gates" data={agentFeatureGates!} propertyNames={featureGateProperties} getProperties={featureGatePropertyValues} />
Expand Down
5 changes: 3 additions & 2 deletions client/web/antrea-ui/src/routes/traceflow.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@
* limitations under the License.
*/

import { useLayoutEffect, useRef} from 'react';
import { useLayoutEffect, useRef, ComponentProps, PropsWithChildren } from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { MemoryRouter } from 'react-router';
import { CdsSelect } from '@cds/react/select';
import Traceflow from './traceflow';
import { traceflowAPI, TraceflowSpec, TraceflowStatus } from '../api/traceflow';

Expand All @@ -33,7 +34,7 @@ vi.mock('@cds/react/select', () => ({
ref.current?.querySelector('label')?.setAttribute('for', id);
}, []);

return <div ref={ref} {...(props as unknown)} />;
return <div ref={ref} {...(props as Record<string, unknown>)} />;
},
}));

Expand Down
1 change: 1 addition & 0 deletions client/web/antrea-ui/src/routes/traceflowresult.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import { useEffect, useRef} from 'react';
import { useLocation } from "react-router";
import { TraceflowSpec, TraceflowStatus, TraceflowNodeResult, TraceflowObservation } from '../api/traceflow';
// @ts-expect-error ignore unused reference to d3
// eslint-disable-next-line
import * as d3 from 'd3';
import { graphviz } from "d3-graphviz";
Expand Down
4 changes: 2 additions & 2 deletions client/web/antrea-ui/src/store.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

import { configureStore, createSlice, PayloadAction, PreloadedState } from '@reduxjs/toolkit';
import { configureStore, createSlice, PayloadAction } from '@reduxjs/toolkit';

interface state {
// if token is undefined: we do not have a token in memory but we may have a
Expand All @@ -40,7 +40,7 @@ const authSlice = createSlice({
}
});

export const setupStore = (preloadedState?: PreloadedState<RootState>) => {
export const setupStore = (preloadedState?: RootState) => {
return configureStore({
reducer: authSlice.reducer,
preloadedState,
Expand Down
Loading

0 comments on commit d7ecc7d

Please sign in to comment.