From 12005d197c0ef5714236e923d7c953d8a5df280b Mon Sep 17 00:00:00 2001 From: Tibo De Peuter Date: Thu, 17 Apr 2025 09:53:03 +0200 Subject: [PATCH] style(frontend): Linting --- frontend/eslint.config.ts | 30 +++++------ frontend/src/queries/assignments.ts | 41 ++++++++++---- frontend/src/queries/classes.ts | 41 ++++++++++---- frontend/src/queries/groups.ts | 84 +++++++++++++++++------------ frontend/src/queries/submissions.ts | 66 ++++++++++++++--------- frontend/src/router/index.ts | 1 - 6 files changed, 168 insertions(+), 95 deletions(-) diff --git a/frontend/eslint.config.ts b/frontend/eslint.config.ts index 9ca1a08b..3e012904 100644 --- a/frontend/eslint.config.ts +++ b/frontend/eslint.config.ts @@ -1,9 +1,9 @@ -import pluginVue from "eslint-plugin-vue"; -import { defineConfigWithVueTs, vueTsConfigs } from "@vue/eslint-config-typescript"; -import pluginVitest from "@vitest/eslint-plugin"; -import pluginPlaywright from "eslint-plugin-playwright"; -import skipFormatting from "@vue/eslint-config-prettier/skip-formatting"; -import rootConfig from "../eslint.config"; +import pluginVue from 'eslint-plugin-vue'; +import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript'; +import pluginVitest from '@vitest/eslint-plugin'; +import pluginPlaywright from 'eslint-plugin-playwright'; +import skipFormatting from '@vue/eslint-config-prettier/skip-formatting'; +import rootConfig from '../eslint.config'; // To allow more languages other than `ts` in `.vue` files, uncomment the following lines: // Import { configureVueProject } from '@vue/eslint-config-typescript' @@ -12,29 +12,29 @@ import rootConfig from "../eslint.config"; const vueConfig = defineConfigWithVueTs( { - name: "app/files-to-lint", - files: ["**/*.{ts,mts,tsx,vue}"], + name: 'app/files-to-lint', + files: ['**/*.{ts,mts,tsx,vue}'], rules: { - "no-useless-assignment": "off", // Depend on `no-unused-vars` to catch this + 'no-useless-assignment': 'off', // Depend on `no-unused-vars` to catch this }, }, { - name: "app/files-to-ignore", - ignores: ["**/dist/**", "**/dist-ssr/**", "**/coverage/**", "prettier.config.js"], + name: 'app/files-to-ignore', + ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**', 'prettier.config.js', '**/test-results/**', '**/playwright-report/**'], }, - pluginVue.configs["flat/essential"], + pluginVue.configs['flat/essential'], vueTsConfigs.recommended, { ...pluginVitest.configs.recommended, - files: ["src/**/__tests__/*"], + files: ['src/**/__tests__/*'], }, { - ...pluginPlaywright.configs["flat/recommended"], - files: ["e2e/**/*.{test,spec}.{js,ts,jsx,tsx}"], + ...pluginPlaywright.configs['flat/recommended'], + files: ['e2e/**/*.{test,spec}.{js,ts,jsx,tsx}'], }, skipFormatting, ); diff --git a/frontend/src/queries/assignments.ts b/frontend/src/queries/assignments.ts index 3251836a..fadfa1f7 100644 --- a/frontend/src/queries/assignments.ts +++ b/frontend/src/queries/assignments.ts @@ -15,16 +15,27 @@ import type { AssignmentDTO } from "@dwengo-1/common/interfaces/assignment"; import type { QueryClient } from "@tanstack/react-query"; import { invalidateAllSubmissionKeys } from "./submissions"; -function assignmentsQueryKey(classid: string, full: boolean) { +type AssignmentsQueryKey = ["assignments", string, boolean]; + +function assignmentsQueryKey(classid: string, full: boolean): AssignmentsQueryKey { return ["assignments", classid, full]; } -function assignmentQueryKey(classid: string, assignmentNumber: number) { + +type AssignmentQueryKey = ["assignment", string, number]; + +function assignmentQueryKey(classid: string, assignmentNumber: number): AssignmentQueryKey { return ["assignment", classid, assignmentNumber]; } -function assignmentSubmissionsQueryKey(classid: string, assignmentNumber: number, full: boolean) { + +type AssignmentSubmissionsQueryKey = ["assignment-submissions", string, number, boolean]; + +function assignmentSubmissionsQueryKey(classid: string, assignmentNumber: number, full: boolean): AssignmentSubmissionsQueryKey { return ["assignment-submissions", classid, assignmentNumber, full]; } -function assignmentQuestionsQueryKey(classid: string, assignmentNumber: number, full: boolean) { + +type AssignmentQuestionsQueryKey = ["assignment-questions", string, number, boolean]; + +function assignmentQuestionsQueryKey(classid: string, assignmentNumber: number, full: boolean): AssignmentQuestionsQueryKey { return ["assignment-questions", classid, assignmentNumber, full]; } @@ -32,13 +43,15 @@ export async function invalidateAllAssignmentKeys( queryClient: QueryClient, classid?: string, assignmentNumber?: number, -) { +): Promise { const keys = ["assignment", "assignment-submissions", "assignment-questions"]; - for (const key of keys) { - const queryKey = [key, classid, assignmentNumber].filter((arg) => arg !== undefined); - await queryClient.invalidateQueries({ queryKey: queryKey }); - } + await Promise.all( + keys.map(async (key) => { + const queryKey = [key, classid, assignmentNumber].filter((arg) => arg !== undefined); + return queryClient.invalidateQueries({ queryKey: queryKey }); + }) + ); await queryClient.invalidateQueries({ queryKey: ["assignments", classid].filter((arg) => arg !== undefined) }); } @@ -50,12 +63,20 @@ function checkEnabled( ): boolean { return Boolean(classid) && !isNaN(Number(groupNumber)) && !isNaN(Number(assignmentNumber)); } + +interface Values { + cid: string | undefined; + an: number | undefined; + gn: number | undefined; + f: boolean; +} + function toValues( classid: MaybeRefOrGetter, assignmentNumber: MaybeRefOrGetter, groupNumber: MaybeRefOrGetter, full: MaybeRefOrGetter, -) { +): Values { return { cid: toValue(classid), an: toValue(assignmentNumber), gn: toValue(groupNumber), f: toValue(full) }; } diff --git a/frontend/src/queries/classes.ts b/frontend/src/queries/classes.ts index 68ba0127..aeb647a0 100644 --- a/frontend/src/queries/classes.ts +++ b/frontend/src/queries/classes.ts @@ -17,32 +17,51 @@ import { invalidateAllSubmissionKeys } from "./submissions"; const classController = new ClassController(); /* Query cache keys */ -function classesQueryKey(full: boolean) { +type ClassesQueryKey = ["classes", boolean]; + +function classesQueryKey(full: boolean): ClassesQueryKey { return ["classes", full]; } -function classQueryKey(classid: string) { + +type ClassQueryKey = ["class", string]; + +function classQueryKey(classid: string): ClassQueryKey { return ["class", classid]; } -function classStudentsKey(classid: string, full: boolean) { + +type ClassStudentsKey = ["class-students", string, boolean]; + +function classStudentsKey(classid: string, full: boolean): ClassStudentsKey { return ["class-students", classid, full]; } -function classTeachersKey(classid: string, full: boolean) { + +type ClassTeachersKey = ["class-teachers", string, boolean]; + +function classTeachersKey(classid: string, full: boolean): ClassTeachersKey { return ["class-teachers", classid, full]; } -function classTeacherInvitationsKey(classid: string, full: boolean) { + +type ClassTeacherInvitationsKey = ["class-teacher-invitations", string, boolean]; + +function classTeacherInvitationsKey(classid: string, full: boolean): ClassTeacherInvitationsKey { return ["class-teacher-invitations", classid, full]; } -function classAssignmentsKey(classid: string, full: boolean) { + +type ClassAssignmentsKey = ["class-assignments", string, boolean]; + +function classAssignmentsKey(classid: string, full: boolean): ClassAssignmentsKey { return ["class-assignments", classid, full]; } -export async function invalidateAllClassKeys(queryClient: QueryClient, classid?: string) { +export async function invalidateAllClassKeys(queryClient: QueryClient, classid?: string): Promise { const keys = ["class", "class-students", "class-teachers", "class-teacher-invitations", "class-assignments"]; - for (const key of keys) { - const queryKey = [key, classid].filter((arg) => arg !== undefined); - await queryClient.invalidateQueries({ queryKey: queryKey }); - } + await Promise.all( + keys.map(async (key) => { + const queryKey = [key, classid].filter((arg) => arg !== undefined); + return queryClient.invalidateQueries({ queryKey: queryKey }); + }) + ); await queryClient.invalidateQueries({ queryKey: ["classes"] }); } diff --git a/frontend/src/queries/groups.ts b/frontend/src/queries/groups.ts index cdef2899..bfa5ad32 100644 --- a/frontend/src/queries/groups.ts +++ b/frontend/src/queries/groups.ts @@ -1,31 +1,40 @@ -import type { ClassesResponse } from "@/controllers/classes"; -import { GroupController, type GroupResponse, type GroupsResponse } from "@/controllers/groups"; -import type { QuestionsResponse } from "@/controllers/questions"; -import type { SubmissionsResponse } from "@/controllers/submissions"; -import type { GroupDTO } from "@dwengo-1/common/interfaces/group"; +import { GroupController, type GroupResponse, type GroupsResponse } from '@/controllers/groups'; +import type { QuestionsResponse } from '@/controllers/questions'; +import type { SubmissionsResponse } from '@/controllers/submissions'; +import type { GroupDTO } from '@dwengo-1/common/interfaces/group'; import { QueryClient, useMutation, + type UseMutationReturnType, useQuery, useQueryClient, - type UseMutationReturnType, type UseQueryReturnType, -} from "@tanstack/vue-query"; -import { computed, toValue, type MaybeRefOrGetter } from "vue"; -import { invalidateAllAssignmentKeys } from "./assignments"; -import { invalidateAllSubmissionKeys } from "./submissions"; +} from '@tanstack/vue-query'; +import { computed, type MaybeRefOrGetter, toValue } from 'vue'; +import { invalidateAllSubmissionKeys } from './submissions'; -export function groupsQueryKey(classid: string, assignmentNumber: number, full: boolean) { - return ["groups", classid, assignmentNumber, full]; +type GroupsQueryKey = ['groups', string, number, boolean]; + +export function groupsQueryKey(classid: string, assignmentNumber: number, full: boolean): GroupsQueryKey { + return ['groups', classid, assignmentNumber, full]; } -function groupQueryKey(classid: string, assignmentNumber: number, groupNumber: number) { - return ["group", classid, assignmentNumber, groupNumber]; + +type GroupQueryKey = ['group', string, number, number]; + +function groupQueryKey(classid: string, assignmentNumber: number, groupNumber: number): GroupQueryKey { + return ['group', classid, assignmentNumber, groupNumber]; } -function groupSubmissionsQueryKey(classid: string, assignmentNumber: number, groupNumber: number, full: boolean) { - return ["group-submissions", classid, assignmentNumber, groupNumber, full]; + +type GroupSubmissionsQueryKey = ['group-submissions', string, number, number, boolean]; + +function groupSubmissionsQueryKey(classid: string, assignmentNumber: number, groupNumber: number, full: boolean): GroupSubmissionsQueryKey { + return ['group-submissions', classid, assignmentNumber, groupNumber, full]; } -function groupQuestionsQueryKey(classid: string, assignmentNumber: number, groupNumber: number, full: boolean) { - return ["group-questions", classid, assignmentNumber, groupNumber, full]; + +type GroupQuestionsQueryKey = ['group-questions', string, number, number, boolean]; + +function groupQuestionsQueryKey(classid: string, assignmentNumber: number, groupNumber: number, full: boolean): GroupQuestionsQueryKey { + return ['group-questions', classid, assignmentNumber, groupNumber, full]; } export async function invalidateAllGroupKeys( @@ -33,16 +42,17 @@ export async function invalidateAllGroupKeys( classid?: string, assignmentNumber?: number, groupNumber?: number, -) { - const keys = ["group", "group-submissions", "group-questions"]; - - for (const key of keys) { - const queryKey = [key, classid, assignmentNumber, groupNumber].filter((arg) => arg !== undefined); - await queryClient.invalidateQueries({ queryKey: queryKey }); - } +): Promise { + const keys = ['group', 'group-submissions', 'group-questions']; + await Promise.all( + keys.map(async (key) => { + const queryKey = [key, classid, assignmentNumber, groupNumber].filter((arg) => arg !== undefined); + return queryClient.invalidateQueries({ queryKey: queryKey }); + }), + ); await queryClient.invalidateQueries({ - queryKey: ["groups", classid, assignmentNumber].filter((arg) => arg !== undefined), + queryKey: ['groups', classid, assignmentNumber].filter((arg) => arg !== undefined), }); } @@ -53,12 +63,20 @@ function checkEnabled( ): boolean { return Boolean(classid) && !isNaN(Number(groupNumber)) && !isNaN(Number(assignmentNumber)); } + +interface Values { + cid: string | undefined; + an: number | undefined; + gn: number | undefined; + f: boolean; +} + function toValues( classid: MaybeRefOrGetter, assignmentNumber: MaybeRefOrGetter, groupNumber: MaybeRefOrGetter, full: MaybeRefOrGetter, -) { +): Values { return { cid: toValue(classid), an: toValue(assignmentNumber), gn: toValue(groupNumber), f: toValue(full) }; } @@ -101,9 +119,9 @@ export function useCreateGroupMutation(): UseMutationReturnType< return useMutation({ mutationFn: async ({ cid, an, data }) => new GroupController(cid, an).createGroup(data), onSuccess: async (response) => { - const cid = typeof response.group.class === "string" ? response.group.class : response.group.class.id; + const cid = typeof response.group.class === 'string' ? response.group.class : response.group.class.id; const an = - typeof response.group.assignment === "number" + typeof response.group.assignment === 'number' ? response.group.assignment : response.group.assignment.id; @@ -124,9 +142,9 @@ export function useDeleteGroupMutation(): UseMutationReturnType< return useMutation({ mutationFn: async ({ cid, an, gn }) => new GroupController(cid, an).deleteGroup(gn), onSuccess: async (response) => { - const cid = typeof response.group.class === "string" ? response.group.class : response.group.class.id; + const cid = typeof response.group.class === 'string' ? response.group.class : response.group.class.id; const an = - typeof response.group.assignment === "number" + typeof response.group.assignment === 'number' ? response.group.assignment : response.group.assignment.id; const gn = response.group.groupNumber; @@ -148,9 +166,9 @@ export function useUpdateGroupMutation(): UseMutationReturnType< return useMutation({ mutationFn: async ({ cid, an, gn, data }) => new GroupController(cid, an).updateGroup(gn, data), onSuccess: async (response) => { - const cid = typeof response.group.class === "string" ? response.group.class : response.group.class.id; + const cid = typeof response.group.class === 'string' ? response.group.class : response.group.class.id; const an = - typeof response.group.assignment === "number" + typeof response.group.assignment === 'number' ? response.group.assignment : response.group.assignment.id; const gn = response.group.groupNumber; diff --git a/frontend/src/queries/submissions.ts b/frontend/src/queries/submissions.ts index 97effd15..eef3fec2 100644 --- a/frontend/src/queries/submissions.ts +++ b/frontend/src/queries/submissions.ts @@ -1,5 +1,5 @@ -import { SubmissionController, type SubmissionResponse, type SubmissionsResponse } from "@/controllers/submissions"; -import type { SubmissionDTO } from "@dwengo-1/common/interfaces/submission"; +import { SubmissionController, type SubmissionResponse, type SubmissionsResponse } from '@/controllers/submissions'; +import type { SubmissionDTO } from '@dwengo-1/common/interfaces/submission'; import { QueryClient, useMutation, @@ -7,14 +7,19 @@ import { useQueryClient, type UseMutationReturnType, type UseQueryReturnType, -} from "@tanstack/vue-query"; -import { computed, toValue, type MaybeRefOrGetter } from "vue"; +} from '@tanstack/vue-query'; +import { computed, toValue, type MaybeRefOrGetter } from 'vue'; -function submissionsQueryKey(classid: string, assignmentNumber: number, groupNumber: number, full: boolean) { - return ["submissions", classid, assignmentNumber, groupNumber, full]; +type SubmissionsQueryKey = ['submissions', string, number, number, boolean]; + +function submissionsQueryKey(classid: string, assignmentNumber: number, groupNumber: number, full: boolean): SubmissionsQueryKey { + return ['submissions', classid, assignmentNumber, groupNumber, full]; } -function submissionQueryKey(classid: string, assignmentNumber: number, groupNumber: number, submissionNumber: number) { - return ["submission", classid, assignmentNumber, groupNumber, submissionNumber]; + +type SubmissionQueryKey = ['submission', string, number, number, number]; + +function submissionQueryKey(classid: string, assignmentNumber: number, groupNumber: number, submissionNumber: number): SubmissionQueryKey { + return ['submission', classid, assignmentNumber, groupNumber, submissionNumber]; } export async function invalidateAllSubmissionKeys( @@ -23,24 +28,26 @@ export async function invalidateAllSubmissionKeys( assignmentNumber?: number, groupNumber?: number, submissionNumber?: number, -) { - const keys = ["submission"]; +): Promise { + const keys = ['submission']; - for (const key of keys) { - const queryKey = [key, classid, assignmentNumber, groupNumber, submissionNumber].filter( - (arg) => arg !== undefined, - ); - await queryClient.invalidateQueries({ queryKey: queryKey }); - } + await Promise.all( + keys.map(async (key) => { + const queryKey = [key, classid, assignmentNumber, groupNumber, submissionNumber].filter( + (arg) => arg !== undefined, + ); + return queryClient.invalidateQueries({ queryKey: queryKey }); + }) + ); await queryClient.invalidateQueries({ - queryKey: ["submissions", classid, assignmentNumber, groupNumber].filter((arg) => arg !== undefined), + queryKey: ['submissions', classid, assignmentNumber, groupNumber].filter((arg) => arg !== undefined), }); await queryClient.invalidateQueries({ - queryKey: ["group-submissions", classid, assignmentNumber, groupNumber].filter((arg) => arg !== undefined), + queryKey: ['group-submissions', classid, assignmentNumber, groupNumber].filter((arg) => arg !== undefined), }); await queryClient.invalidateQueries({ - queryKey: ["assignment-submissions", classid, assignmentNumber].filter((arg) => arg !== undefined), + queryKey: ['assignment-submissions', classid, assignmentNumber].filter((arg) => arg !== undefined), }); } @@ -57,13 +64,22 @@ function checkEnabled( !isNaN(Number(submissionNumber)) ); } + +interface Values { + cid: string | undefined; + an: number | undefined; + gn: number | undefined; + sn: number | undefined; + f: boolean; +} + function toValues( classid: MaybeRefOrGetter, assignmentNumber: MaybeRefOrGetter, groupNumber: MaybeRefOrGetter, submissionNumber: MaybeRefOrGetter, full: MaybeRefOrGetter, -) { +): Values { return { cid: toValue(classid), an: toValue(assignmentNumber), @@ -93,7 +109,7 @@ export function useSubmissionQuery( assignmentNumber: MaybeRefOrGetter, groupNumber: MaybeRefOrGetter, ): UseQueryReturnType { - const { cid, an, gn, sn, f } = toValues(classid, assignmentNumber, groupNumber, 1, true); + const { cid, an, gn, sn } = toValues(classid, assignmentNumber, groupNumber, 1, true); return useQuery({ queryKey: computed(() => submissionQueryKey(cid!, an!, gn!, sn!)), @@ -119,8 +135,8 @@ export function useCreateSubmissionMutation(): UseMutationReturnType< const cls = response.submission.group.class; const assignment = response.submission.group.assignment; - const cid = typeof cls === "string" ? cls : cls.id; - const an = typeof assignment === "number" ? assignment : assignment.id; + const cid = typeof cls === 'string' ? cls : cls.id; + const an = typeof assignment === 'number' ? assignment : assignment.id; const gn = response.submission.group.groupNumber; await invalidateAllSubmissionKeys(queryClient, cid, an, gn); @@ -146,8 +162,8 @@ export function useDeleteSubmissionMutation(): UseMutationReturnType< const cls = response.submission.group.class; const assignment = response.submission.group.assignment; - const cid = typeof cls === "string" ? cls : cls.id; - const an = typeof assignment === "number" ? assignment : assignment.id; + const cid = typeof cls === 'string' ? cls : cls.id; + const an = typeof assignment === 'number' ? assignment : assignment.id; const gn = response.submission.group.groupNumber; await invalidateAllSubmissionKeys(queryClient, cid, an, gn); diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index 90bc1f2c..e7aa8d24 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -7,7 +7,6 @@ import CreateClass from "@/views/classes/CreateClass.vue"; import CreateAssignment from "@/views/assignments/CreateAssignment.vue"; import CreateDiscussion from "@/views/discussions/CreateDiscussion.vue"; import CallbackPage from "@/views/CallbackPage.vue"; -import UserDiscussions from "@/views/discussions/UserDiscussions.vue"; import UserClasses from "@/views/classes/UserClasses.vue"; import UserAssignments from "@/views/classes/UserAssignments.vue"; import authState from "@/services/auth/auth-service.ts";