diff --git a/.eslintrc.cjs b/.eslintrc.cjs
index dc12fdcd89..6cd782607c 100644
--- a/.eslintrc.cjs
+++ b/.eslintrc.cjs
@@ -6,9 +6,13 @@ module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
warnOnUnsupportedTypeScriptVersion: false,
+ // this config is needed for type aware lint rules
+ project: true,
+ tsconfigRootDir: __dirname,
},
extends: [
'eslint:recommended',
+ 'plugin:@typescript-eslint/recommended-type-checked',
'plugin:@typescript-eslint/strict',
'plugin:@typescript-eslint/stylistic',
'plugin:jsx-a11y/recommended',
@@ -45,6 +49,18 @@ module.exports = {
'error',
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
],
+
+ // disabling the type-aware rules we don't like
+ // https://typescript-eslint.io/getting-started/typed-linting/
+ '@typescript-eslint/no-floating-promises': 'off',
+ '@typescript-eslint/no-misused-promises': 'off',
+ '@typescript-eslint/unbound-method': 'off',
+ '@typescript-eslint/no-unsafe-argument': 'off',
+ '@typescript-eslint/no-unsafe-assignment': 'off',
+ '@typescript-eslint/no-unsafe-call': 'off',
+ '@typescript-eslint/no-unsafe-member-access': 'off',
+ '@typescript-eslint/no-unsafe-return': 'off',
+
eqeqeq: ['error', 'always', { null: 'ignore' }],
'import/no-default-export': 'error',
'import/no-unresolved': 'off', // plugin doesn't know anything
diff --git a/app/components/form/SideModalForm.tsx b/app/components/form/SideModalForm.tsx
index e066f1bd3f..e0e02b7cbe 100644
--- a/app/components/form/SideModalForm.tsx
+++ b/app/components/form/SideModalForm.tsx
@@ -7,7 +7,7 @@
*/
import { useEffect, useId, type ReactNode } from 'react'
import type { FieldValues, UseFormReturn } from 'react-hook-form'
-import { useNavigationType } from 'react-router-dom'
+import { NavigationType, useNavigationType } from 'react-router-dom'
import type { ApiError } from '@oxide/api'
@@ -57,7 +57,7 @@ type SideModalFormProps = {
* any way to distinguish between fresh pageload and back/forward.
*/
export function useShouldAnimateModal() {
- return useNavigationType() === 'PUSH'
+ return useNavigationType() === NavigationType.Push
}
export function SideModalForm({
diff --git a/app/components/form/fields/DateTimeRangePicker.spec.tsx b/app/components/form/fields/DateTimeRangePicker.spec.tsx
index 0d9e37ec27..12c7274754 100644
--- a/app/components/form/fields/DateTimeRangePicker.spec.tsx
+++ b/app/components/form/fields/DateTimeRangePicker.spec.tsx
@@ -97,7 +97,7 @@ describe.skip('custom mode', () => {
expect(screen.getByRole('button', { name: 'Load' })).toHaveClass('visually-disabled')
})
- it('clicking load after changing date changes range', async () => {
+ it('clicking load after changing date changes range', () => {
const { setRange } = renderLastDay()
// expect(screen.getByLabelText('Start time')).toHaveValue(dateForInput(subDays(now, 1)))
@@ -125,7 +125,7 @@ describe.skip('custom mode', () => {
})
})
- it('clicking reset after changing inputs resets inputs', async () => {
+ it('clicking reset after changing inputs resets inputs', () => {
const { setRange } = renderLastDay()
// expect(screen.getByLabelText('Start time')).toHaveValue(dateForInput(subDays(now, 1)))
diff --git a/app/components/form/fields/ListboxField.tsx b/app/components/form/fields/ListboxField.tsx
index 09241ffc09..20f3da2b5d 100644
--- a/app/components/form/fields/ListboxField.tsx
+++ b/app/components/form/fields/ListboxField.tsx
@@ -27,7 +27,7 @@ export type ListboxFieldProps<
className?: string
label?: string
required?: boolean
- description?: string | React.ReactNode | React.ReactNode
+ description?: string | React.ReactNode
tooltipText?: string
control: Control
disabled?: boolean
diff --git a/app/forms/image-upload.tsx b/app/forms/image-upload.tsx
index b3be957b9c..6d7f5edaf8 100644
--- a/app/forms/image-upload.tsx
+++ b/app/forms/image-upload.tsx
@@ -273,7 +273,7 @@ export function CreateImageSideModalForm() {
// coordinating when to cleanup, we make cleanup idempotent by having it check
// whether it has already been run, or more concretely before each action,
// check whether it needs to be done
- async function closeModal() {
+ function closeModal() {
if (allDone) {
backToImages()
return
diff --git a/app/forms/vpc-edit.tsx b/app/forms/vpc-edit.tsx
index 87859b5521..b50a73ab40 100644
--- a/app/forms/vpc-edit.tsx
+++ b/app/forms/vpc-edit.tsx
@@ -40,7 +40,7 @@ export function EditVpcSideModalForm() {
const onDismiss = () => navigate(pb.vpcs({ project }))
const editVpc = useApiMutation('vpcUpdate', {
- async onSuccess(vpc) {
+ onSuccess(vpc) {
queryClient.invalidateQueries('vpcList')
queryClient.setQueryData(
'vpcView',
diff --git a/app/pages/SiloAccessPage.tsx b/app/pages/SiloAccessPage.tsx
index c83cf198d4..51fc141373 100644
--- a/app/pages/SiloAccessPage.tsx
+++ b/app/pages/SiloAccessPage.tsx
@@ -139,7 +139,7 @@ export function SiloAccessPage() {
doDelete: () =>
updatePolicy.mutateAsync({
// we know policy is there, otherwise there's no row to display
- body: deleteRole(row.id, siloPolicy!),
+ body: deleteRole(row.id, siloPolicy),
}),
label: (
diff --git a/app/pages/project/access/ProjectAccessPage.tsx b/app/pages/project/access/ProjectAccessPage.tsx
index 1e20984980..b93de0fe2b 100644
--- a/app/pages/project/access/ProjectAccessPage.tsx
+++ b/app/pages/project/access/ProjectAccessPage.tsx
@@ -169,7 +169,7 @@ export function ProjectAccessPage() {
updatePolicy.mutateAsync({
path: { project },
// we know policy is there, otherwise there's no row to display
- body: deleteRole(row.id, projectPolicy!),
+ body: deleteRole(row.id, projectPolicy),
}),
// TODO: explain that this will not affect the role inherited from
// the silo or roles inherited from group membership. Ideally we'd
diff --git a/app/pages/project/instances/actions.tsx b/app/pages/project/instances/actions.tsx
index 5a1650aa69..f0c91316fd 100644
--- a/app/pages/project/instances/actions.tsx
+++ b/app/pages/project/instances/actions.tsx
@@ -70,16 +70,10 @@ export const useMakeInstanceActions = (
onActivate() {
confirmAction({
actionType: 'danger',
- doAction: async () =>
- stopInstance.mutate(instanceParams, {
+ doAction: () =>
+ stopInstance.mutateAsync(instanceParams, {
onSuccess: () =>
addToast({ title: `Stopping instance '${instance.name}'` }),
- onError: (error) =>
- addToast({
- variant: 'error',
- title: `Error stopping instance '${instance.name}'`,
- content: error.message,
- }),
}),
modalTitle: 'Confirm stop instance',
modalContent: (
@@ -89,7 +83,7 @@ export const useMakeInstanceActions = (
freed.
),
- errorTitle: `Could not stop ${instance.name}`,
+ errorTitle: `Error stopping ${instance.name}`,
})
},
disabled: !instanceCan.stop(instance) && (
diff --git a/app/pages/project/vpcs/VpcPage/tabs/VpcFirewallRulesTab.tsx b/app/pages/project/vpcs/VpcPage/tabs/VpcFirewallRulesTab.tsx
index c70a6b0e7d..854cf36f57 100644
--- a/app/pages/project/vpcs/VpcPage/tabs/VpcFirewallRulesTab.tsx
+++ b/app/pages/project/vpcs/VpcPage/tabs/VpcFirewallRulesTab.tsx
@@ -72,7 +72,9 @@ const staticColumns = [
cell: (info) => {
const { hosts, ports, protocols } = info.getValue()
const children = [
- ...(hosts || []).map((tv, i) => ),
+ ...(hosts || []).map((tv, i) => (
+
+ )),
...(protocols || []).map((p, i) => {p}),
...(ports || []).map((p, i) => (
diff --git a/app/ui/lib/Button.tsx b/app/ui/lib/Button.tsx
index ae972219b0..cc43d4c99e 100644
--- a/app/ui/lib/Button.tsx
+++ b/app/ui/lib/Button.tsx
@@ -87,7 +87,7 @@ export const Button = forwardRef(
return (
}
+ with={}
>