From 45f2fe674487ef0209c81b28461bf673c577cb2a Mon Sep 17 00:00:00 2001 From: Danny Rorabaugh Date: Tue, 29 Jul 2025 16:16:04 -0400 Subject: [PATCH 1/3] Turn off @typescript-eslint/no-redundant-type-constituents --- frontend/eslint.config.js | 5 +++-- frontend/src/lib/components/FilterBar/FilterBar.svelte | 1 - .../Projects/ProjectConfidentialityFilterSelect.svelte | 1 - frontend/src/lib/components/modals/ConfirmDeleteModal.svelte | 1 - frontend/src/lib/components/modals/FormModal.svelte | 4 ++-- frontend/src/routes/(authenticated)/admin/+page.svelte | 1 - .../src/routes/(authenticated)/admin/EditUserAccount.svelte | 1 - .../org/[org_id]/AddMyProjectsToOrgModal.svelte | 1 - .../(authenticated)/org/[org_id]/AddOrgMemberModal.svelte | 1 - .../(authenticated)/org/[org_id]/BulkAddOrgMembers.svelte | 1 - .../org/[org_id]/ChangeOrgMemberRoleModal.svelte | 1 - .../project/[project_code]/AddOrganization.svelte | 1 - .../project/[project_code]/AddProjectMember.svelte | 1 - .../(authenticated)/project/[project_code]/AddPurpose.svelte | 1 - .../project/[project_code]/BulkAddProjectMembers.svelte | 1 - .../project/[project_code]/ChangeMemberRoleModal.svelte | 1 - .../[project_code]/ProjectConfidentialityModal.svelte | 1 - .../project/[project_code]/ResetProjectModal.svelte | 1 - frontend/viewer/eslint.config.js | 5 +++-- frontend/viewer/src/lib/OpenInFieldWorksButton.svelte | 1 - .../src/lib/components/field-editors/multi-select.svelte | 3 --- .../viewer/src/lib/components/field-editors/select.svelte | 2 -- .../viewer/src/lib/components/ui/icon/pinging-icon.svelte | 1 - 23 files changed, 8 insertions(+), 29 deletions(-) diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js index 20decc3ca4..191d02e74a 100644 --- a/frontend/eslint.config.js +++ b/frontend/eslint.config.js @@ -38,11 +38,12 @@ export default [ files: ['**/*.svelte'], rules: { // The Svelte plugin doesn't seem to have typing quite figured out + '@typescript-eslint/no-redundant-type-constituents': 'off', + '@typescript-eslint/no-unsafe-argument': 'off', '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', '@typescript-eslint/no-unsafe-return': 'off', - '@typescript-eslint/no-unsafe-argument': 'off', }, }, ...svelte.configs.recommended, diff --git a/frontend/src/lib/components/FilterBar/FilterBar.svelte b/frontend/src/lib/components/FilterBar/FilterBar.svelte index b0bc2c1f04..2df0c2c440 100644 --- a/frontend/src/lib/components/FilterBar/FilterBar.svelte +++ b/frontend/src/lib/components/FilterBar/FilterBar.svelte @@ -22,7 +22,6 @@ import { DEFAULT_DEBOUNCE_TIME } from '$lib/util/time'; type DumbFilters = $$Generic>; - // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents type Filters = DumbFilters & Record; let searchInput: PlainInput | undefined = $state(); diff --git a/frontend/src/lib/components/Projects/ProjectConfidentialityFilterSelect.svelte b/frontend/src/lib/components/Projects/ProjectConfidentialityFilterSelect.svelte index 4b3f55c7a5..acdb736137 100644 --- a/frontend/src/lib/components/Projects/ProjectConfidentialityFilterSelect.svelte +++ b/frontend/src/lib/components/Projects/ProjectConfidentialityFilterSelect.svelte @@ -6,7 +6,6 @@ import type { Confidentiality } from './ProjectFilter.svelte'; interface Props extends Omit { - // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents -- false positive value: Confidentiality | undefined; } diff --git a/frontend/src/lib/components/modals/ConfirmDeleteModal.svelte b/frontend/src/lib/components/modals/ConfirmDeleteModal.svelte index ff85c4b1d1..a178b81af8 100644 --- a/frontend/src/lib/components/modals/ConfirmDeleteModal.svelte +++ b/frontend/src/lib/components/modals/ConfirmDeleteModal.svelte @@ -41,7 +41,6 @@ type Schema = typeof verify; - // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents let deletionFormModal: FormModal | undefined = $state(); let deletionForm = $derived(deletionFormModal?.form()); diff --git a/frontend/src/lib/components/modals/FormModal.svelte b/frontend/src/lib/components/modals/FormModal.svelte index b850c369bd..8a71faa080 100644 --- a/frontend/src/lib/components/modals/FormModal.svelte +++ b/frontend/src/lib/components/modals/FormModal.svelte @@ -58,12 +58,12 @@ let done = $state(false); export async function open( - value: Partial | undefined, //eslint-disable-line @typescript-eslint/no-redundant-type-constituents + value: Partial | undefined, onSubmit: SubmitCallback, ): Promise>; export async function open(onSubmit: SubmitCallback): Promise>; export async function open( - valueOrOnSubmit: Partial | SubmitCallback | undefined, //eslint-disable-line @typescript-eslint/no-redundant-type-constituents + valueOrOnSubmit: Partial | SubmitCallback | undefined, _onSubmit?: SubmitCallback, ): Promise> { done = false; diff --git a/frontend/src/routes/(authenticated)/admin/+page.svelte b/frontend/src/routes/(authenticated)/admin/+page.svelte index 7fd6332352..6fa0e1126f 100644 --- a/frontend/src/routes/(authenticated)/admin/+page.svelte +++ b/frontend/src/routes/(authenticated)/admin/+page.svelte @@ -41,7 +41,6 @@ showDeletedProjects: queryParam.boolean(false), hideDraftProjects: queryParam.boolean(false), emptyProjects: queryParam.boolean(false), - // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents -- false positive? confidential: queryParam.string(undefined), projectType: queryParam.string(undefined), memberSearch: queryParam.string(undefined), diff --git a/frontend/src/routes/(authenticated)/admin/EditUserAccount.svelte b/frontend/src/routes/(authenticated)/admin/EditUserAccount.svelte index f221a64480..cc37e134c6 100644 --- a/frontend/src/routes/(authenticated)/admin/EditUserAccount.svelte +++ b/frontend/src/routes/(authenticated)/admin/EditUserAccount.svelte @@ -39,7 +39,6 @@ type Schema = typeof schema; type RefinedSchema = typeof refinedSchema; - // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents let formModal: FormModal | undefined = $state(); export function close(): void { diff --git a/frontend/src/routes/(authenticated)/org/[org_id]/AddMyProjectsToOrgModal.svelte b/frontend/src/routes/(authenticated)/org/[org_id]/AddMyProjectsToOrgModal.svelte index a8e572902d..584f709065 100644 --- a/frontend/src/routes/(authenticated)/org/[org_id]/AddMyProjectsToOrgModal.svelte +++ b/frontend/src/routes/(authenticated)/org/[org_id]/AddMyProjectsToOrgModal.svelte @@ -21,7 +21,6 @@ const schema = z.object({}); - // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents let formModal: FormModal | undefined = $state(); let newProjects: Project[] = $state([]); let alreadyAddedProjects: number = $state(0); diff --git a/frontend/src/routes/(authenticated)/org/[org_id]/AddOrgMemberModal.svelte b/frontend/src/routes/(authenticated)/org/[org_id]/AddOrgMemberModal.svelte index fad6b4fce2..87aabfba14 100644 --- a/frontend/src/routes/(authenticated)/org/[org_id]/AddOrgMemberModal.svelte +++ b/frontend/src/routes/(authenticated)/org/[org_id]/AddOrgMemberModal.svelte @@ -28,7 +28,6 @@ role: z.enum([OrgRole.User, OrgRole.Admin]).default(OrgRole.User), canInvite: z.boolean().default(false), }); - // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents let formModal: FormModal | undefined = $state(); let form = $derived(formModal?.form()); diff --git a/frontend/src/routes/(authenticated)/org/[org_id]/BulkAddOrgMembers.svelte b/frontend/src/routes/(authenticated)/org/[org_id]/BulkAddOrgMembers.svelte index 2c2fe7f7e4..7a31a6a940 100644 --- a/frontend/src/routes/(authenticated)/org/[org_id]/BulkAddOrgMembers.svelte +++ b/frontend/src/routes/(authenticated)/org/[org_id]/BulkAddOrgMembers.svelte @@ -31,7 +31,6 @@ usernamesText: z.string().trim().min(1, $t('org_page.bulk_add_members.empty_user_field')), }); - // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents let formModal: FormModal | undefined = $state(); let form = $derived(formModal?.form()); diff --git a/frontend/src/routes/(authenticated)/org/[org_id]/ChangeOrgMemberRoleModal.svelte b/frontend/src/routes/(authenticated)/org/[org_id]/ChangeOrgMemberRoleModal.svelte index 4653f097bf..601d2f1c27 100644 --- a/frontend/src/routes/(authenticated)/org/[org_id]/ChangeOrgMemberRoleModal.svelte +++ b/frontend/src/routes/(authenticated)/org/[org_id]/ChangeOrgMemberRoleModal.svelte @@ -16,7 +16,6 @@ role: z.enum([OrgRole.User, OrgRole.Admin]), }); type Schema = typeof schema; - // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents let formModal: FormModal | undefined = $state(); let form = $derived(formModal?.form()); diff --git a/frontend/src/routes/(authenticated)/project/[project_code]/AddOrganization.svelte b/frontend/src/routes/(authenticated)/project/[project_code]/AddOrganization.svelte index d0d242d0e0..ab801fe8b9 100644 --- a/frontend/src/routes/(authenticated)/project/[project_code]/AddOrganization.svelte +++ b/frontend/src/routes/(authenticated)/project/[project_code]/AddOrganization.svelte @@ -21,7 +21,6 @@ }); type Schema = typeof schema; - // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents let formModal: FormModal | undefined = $state(); let form = $derived(formModal?.form()); diff --git a/frontend/src/routes/(authenticated)/project/[project_code]/AddProjectMember.svelte b/frontend/src/routes/(authenticated)/project/[project_code]/AddProjectMember.svelte index fb09919da3..67e3bbf6a9 100644 --- a/frontend/src/routes/(authenticated)/project/[project_code]/AddProjectMember.svelte +++ b/frontend/src/routes/(authenticated)/project/[project_code]/AddProjectMember.svelte @@ -25,7 +25,6 @@ role: z.enum([ProjectRole.Editor, ProjectRole.Manager, ProjectRole.Observer]).default(ProjectRole.Editor), canInvite: z.boolean().default(false), }); - // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents let formModal: FormModal | undefined = $state(); let form = $derived(formModal?.form()); let selectedUserId: string | undefined = $state(undefined); diff --git a/frontend/src/routes/(authenticated)/project/[project_code]/AddPurpose.svelte b/frontend/src/routes/(authenticated)/project/[project_code]/AddPurpose.svelte index f92b922f26..e9ff7f4694 100644 --- a/frontend/src/routes/(authenticated)/project/[project_code]/AddPurpose.svelte +++ b/frontend/src/routes/(authenticated)/project/[project_code]/AddPurpose.svelte @@ -20,7 +20,6 @@ }); type Schema = typeof schema; - // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents let formModal: FormModal | undefined = $state(); let form = $derived(formModal?.form()); diff --git a/frontend/src/routes/(authenticated)/project/[project_code]/BulkAddProjectMembers.svelte b/frontend/src/routes/(authenticated)/project/[project_code]/BulkAddProjectMembers.svelte index 0c8e35e431..7b89c74ce7 100644 --- a/frontend/src/routes/(authenticated)/project/[project_code]/BulkAddProjectMembers.svelte +++ b/frontend/src/routes/(authenticated)/project/[project_code]/BulkAddProjectMembers.svelte @@ -33,7 +33,6 @@ password: passwordFormRules($t), }); - // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents let formModal: FormModal | undefined = $state(); let form = $derived(formModal?.form()); diff --git a/frontend/src/routes/(authenticated)/project/[project_code]/ChangeMemberRoleModal.svelte b/frontend/src/routes/(authenticated)/project/[project_code]/ChangeMemberRoleModal.svelte index 21d777ae8a..af9eeb3c64 100644 --- a/frontend/src/routes/(authenticated)/project/[project_code]/ChangeMemberRoleModal.svelte +++ b/frontend/src/routes/(authenticated)/project/[project_code]/ChangeMemberRoleModal.svelte @@ -18,7 +18,6 @@ role: z.enum([ProjectRole.Editor, ProjectRole.Manager, ProjectRole.Observer]), }); type Schema = typeof schema; - // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents let formModal: FormModal | undefined = $state(); let form = $derived(formModal?.form()); diff --git a/frontend/src/routes/(authenticated)/project/[project_code]/ProjectConfidentialityModal.svelte b/frontend/src/routes/(authenticated)/project/[project_code]/ProjectConfidentialityModal.svelte index 0fad643068..97c4d15b73 100644 --- a/frontend/src/routes/(authenticated)/project/[project_code]/ProjectConfidentialityModal.svelte +++ b/frontend/src/routes/(authenticated)/project/[project_code]/ProjectConfidentialityModal.svelte @@ -16,7 +16,6 @@ const schema = z.object({ isConfidential: z.boolean(), }); - // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents let formModal: FormModal | undefined = $state(); let form = $derived(formModal?.form()); diff --git a/frontend/src/routes/(authenticated)/project/[project_code]/ResetProjectModal.svelte b/frontend/src/routes/(authenticated)/project/[project_code]/ResetProjectModal.svelte index d43e8a3d4d..80f5544839 100644 --- a/frontend/src/routes/(authenticated)/project/[project_code]/ResetProjectModal.svelte +++ b/frontend/src/routes/(authenticated)/project/[project_code]/ResetProjectModal.svelte @@ -109,7 +109,6 @@ } let tusUpload: TusUpload | undefined = $state(); - // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents let uploadStatus: UploadStatus | undefined = $state(); diff --git a/frontend/viewer/eslint.config.js b/frontend/viewer/eslint.config.js index 9db20ea3fe..9982c613e7 100644 --- a/frontend/viewer/eslint.config.js +++ b/frontend/viewer/eslint.config.js @@ -37,11 +37,12 @@ export default [ files: ['**/*.svelte'], rules: { // The Svelte plugin doesn't seem to have typing quite figured out + '@typescript-eslint/no-redundant-type-constituents': 'off', + '@typescript-eslint/no-unsafe-argument': 'off', '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', '@typescript-eslint/no-unsafe-return': 'off', - '@typescript-eslint/no-unsafe-argument': 'off', }, }, ...svelte.configs.recommended, diff --git a/frontend/viewer/src/lib/OpenInFieldWorksButton.svelte b/frontend/viewer/src/lib/OpenInFieldWorksButton.svelte index b37b405793..b38089fbd6 100644 --- a/frontend/viewer/src/lib/OpenInFieldWorksButton.svelte +++ b/frontend/viewer/src/lib/OpenInFieldWorksButton.svelte @@ -12,7 +12,6 @@ type Props = { entry: IEntry - // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents } & ButtonProps; const { diff --git a/frontend/viewer/src/lib/components/field-editors/multi-select.svelte b/frontend/viewer/src/lib/components/field-editors/multi-select.svelte index ac7a16f83e..b8f245233e 100644 --- a/frontend/viewer/src/lib/components/field-editors/multi-select.svelte +++ b/frontend/viewer/src/lib/components/field-editors/multi-select.svelte @@ -25,10 +25,8 @@ values: Value[]; options: ReadonlyArray; readonly?: boolean; - /* eslint-disable @typescript-eslint/no-redundant-type-constituents */ idSelector: ConditionalKeys | ((value: Value) => Primitive); labelSelector: ConditionalKeys | ((value: Value) => string); - /* eslint-enable @typescript-eslint/no-redundant-type-constituents */ placeholder?: string; filterPlaceholder?: string; emptyResultsPlaceholder?: string; @@ -157,7 +155,6 @@ } } - // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents function getHighlightedValue(): Value | undefined { const selectedItem = commandRef?.querySelector('[data-command-item][data-selected]'); const index = selectedItem?.getAttribute('data-value-index'); diff --git a/frontend/viewer/src/lib/components/field-editors/select.svelte b/frontend/viewer/src/lib/components/field-editors/select.svelte index 408dac8ab1..5a39aedeb6 100644 --- a/frontend/viewer/src/lib/components/field-editors/select.svelte +++ b/frontend/viewer/src/lib/components/field-editors/select.svelte @@ -20,10 +20,8 @@ value?: Value; options: ReadonlyArray; readonly?: boolean; - /* eslint-disable @typescript-eslint/no-redundant-type-constituents */ idSelector: ConditionalKeys | ((value: Value) => Primitive); labelSelector: ConditionalKeys | ((value: Value) => string); - /* eslint-enable @typescript-eslint/no-redundant-type-constituents */ placeholder?: string; filterPlaceholder?: string; emptyResultsPlaceholder?: string; diff --git a/frontend/viewer/src/lib/components/ui/icon/pinging-icon.svelte b/frontend/viewer/src/lib/components/ui/icon/pinging-icon.svelte index cb719ee012..fbd0dba549 100644 --- a/frontend/viewer/src/lib/components/ui/icon/pinging-icon.svelte +++ b/frontend/viewer/src/lib/components/ui/icon/pinging-icon.svelte @@ -5,7 +5,6 @@ import {cn} from '$lib/utils'; import type {IconClass} from '$lib/icon-class'; - // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents type Props = IconProps & { ping?: boolean; icon: IconClass; From 8e832979c09a84076151079dd2dc9f08443eca59 Mon Sep 17 00:00:00 2001 From: Danny Rorabaugh Date: Mon, 4 Aug 2025 08:46:52 -0400 Subject: [PATCH 2/3] Add eslint-diable-next-line for a false positive --- .../src/routes/(authenticated)/project/[project_code]/+page.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/routes/(authenticated)/project/[project_code]/+page.ts b/frontend/src/routes/(authenticated)/project/[project_code]/+page.ts index a111f48c36..b92fafb4fe 100644 --- a/frontend/src/routes/(authenticated)/project/[project_code]/+page.ts +++ b/frontend/src/routes/(authenticated)/project/[project_code]/+page.ts @@ -136,6 +136,7 @@ export async function load(event: PageLoadEvent) { { projectCode } ); + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument const nonNullableProject = tryMakeNonNullable(projectResult.projectByCode); if (!nonNullableProject) { error(404); From daa6ce61a4b9cec14bbdc1880f6a25247afeea37 Mon Sep 17 00:00:00 2001 From: Tim Haasdyk Date: Mon, 4 Aug 2025 17:57:49 +0200 Subject: [PATCH 3/3] Extend frontend readme with linting hint and remove rule comment --- frontend/README.md | 13 +++++++++++++ .../(authenticated)/project/[project_code]/+page.ts | 1 - 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/frontend/README.md b/frontend/README.md index 2d8f0d8e2e..b8b02fb960 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -38,3 +38,16 @@ To run an end-to-end test in the frontend folder: ```bash pnpm test ``` + +#### Linting + +Linting depends partially on generated code, so first: + +```bash +pnpm run -r build +``` + +And then: +```bash +pnpm run -r lint +``` diff --git a/frontend/src/routes/(authenticated)/project/[project_code]/+page.ts b/frontend/src/routes/(authenticated)/project/[project_code]/+page.ts index b92fafb4fe..a111f48c36 100644 --- a/frontend/src/routes/(authenticated)/project/[project_code]/+page.ts +++ b/frontend/src/routes/(authenticated)/project/[project_code]/+page.ts @@ -136,7 +136,6 @@ export async function load(event: PageLoadEvent) { { projectCode } ); - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument const nonNullableProject = tryMakeNonNullable(projectResult.projectByCode); if (!nonNullableProject) { error(404);