From 13d3c727ba109e193e03fe390835886a162fd87e Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Fri, 17 Feb 2023 18:56:29 -0900 Subject: [PATCH] ts errors --- frontend/components/Form/Multiselect.vue | 2 -- frontend/components/Form/Select.vue | 3 --- frontend/composables/use-confirm.ts | 3 +-- frontend/composables/use-route-params.ts | 2 +- frontend/composables/use-theme.ts | 4 +-- frontend/lib/api/__test__/factories/index.ts | 11 ++++---- frontend/lib/api/__test__/user/items.test.ts | 9 ++++--- .../lib/api/__test__/user/locations.test.ts | 2 ++ frontend/lib/api/__test__/user/stats.test.ts | 11 ++++++-- frontend/lib/api/base/base-api.ts | 4 +-- frontend/lib/api/classes/items.ts | 4 +++ frontend/lib/api/classes/reports.ts | 24 ++--------------- frontend/lib/requests/requests.ts | 2 ++ frontend/pages/location/[id].vue | 7 +++-- frontend/stores/labels.ts | 10 ++++--- frontend/stores/locations.ts | 27 ++++++++++++++----- frontend/test/setup.ts | 2 +- 17 files changed, 68 insertions(+), 59 deletions(-) diff --git a/frontend/components/Form/Multiselect.vue b/frontend/components/Form/Multiselect.vue index 52cf2c5..e961f7f 100644 --- a/frontend/components/Form/Multiselect.vue +++ b/frontend/components/Form/Multiselect.vue @@ -38,12 +38,10 @@ default: "", }, modelValue: { - // eslint-disable-next-line @typescript-eslint/no-explicit-any type: Array as () => any[], default: null, }, items: { - // eslint-disable-next-line @typescript-eslint/no-explicit-any type: Array as () => any[], required: true, }, diff --git a/frontend/components/Form/Select.vue b/frontend/components/Form/Select.vue index 09faed9..919720f 100644 --- a/frontend/components/Form/Select.vue +++ b/frontend/components/Form/Select.vue @@ -24,12 +24,10 @@ default: "", }, modelValue: { - // eslint-disable-next-line @typescript-eslint/no-explicit-any type: [Object, String] as any, default: null, }, items: { - // eslint-disable-next-line @typescript-eslint/no-explicit-any type: Array as () => any[], required: true, }, @@ -86,7 +84,6 @@ { immediate: true } ); - // eslint-disable-next-line @typescript-eslint/no-explicit-any function compare(a: any, b: any): boolean { if (a === b) { return true; diff --git a/frontend/composables/use-confirm.ts b/frontend/composables/use-confirm.ts index 1ae1067..ddf9924 100644 --- a/frontend/composables/use-confirm.ts +++ b/frontend/composables/use-confirm.ts @@ -1,7 +1,6 @@ import { UseConfirmDialogRevealResult, UseConfirmDialogReturn } from "@vueuse/core"; import { Ref } from "vue"; -// eslint-disable-next-line @typescript-eslint/no-explicit-any type Store = UseConfirmDialogReturn & { text: Ref; setup: boolean; @@ -23,7 +22,7 @@ const store: Partial = { export function useConfirm(): Store { if (!store.setup) { store.setup = true; - // eslint-disable-next-line @typescript-eslint/no-explicit-any + const { isRevealed, reveal, confirm, cancel } = useConfirmDialog(); store.isRevealed = isRevealed; store.reveal = reveal; diff --git a/frontend/composables/use-route-params.ts b/frontend/composables/use-route-params.ts index 6708c38..4687695 100644 --- a/frontend/composables/use-route-params.ts +++ b/frontend/composables/use-route-params.ts @@ -7,7 +7,7 @@ export function useRouteQuery(q: string, def: string[]): WritableComputedRef; export function useRouteQuery(q: string, def: boolean): WritableComputedRef; export function useRouteQuery(q: string, def: number): WritableComputedRef; -// eslint-disable-next-line @typescript-eslint/no-explicit-any + export function useRouteQuery(q: string, def: any): WritableComputedRef { const route = useRoute(); const router = useRouter(); diff --git a/frontend/composables/use-theme.ts b/frontend/composables/use-theme.ts index fb3641f..cbd26d3 100644 --- a/frontend/composables/use-theme.ts +++ b/frontend/composables/use-theme.ts @@ -16,13 +16,13 @@ export function useTheme(): UseTheme { preferences.value.theme = newTheme; if (htmlEl) { - htmlEl.value.setAttribute("data-theme", newTheme); + htmlEl.value?.setAttribute("data-theme", newTheme); } themeRef.value = newTheme; }; - const htmlEl = ref(null); + const htmlEl = ref(); onMounted(() => { if (htmlEl.value) { diff --git a/frontend/lib/api/__test__/factories/index.ts b/frontend/lib/api/__test__/factories/index.ts index cebfb5f..e9c014f 100644 --- a/frontend/lib/api/__test__/factories/index.ts +++ b/frontend/lib/api/__test__/factories/index.ts @@ -9,13 +9,13 @@ import { Requests } from "../../../requests"; function itemField(id = null): ItemField { return { - id, + id: id ?? "", name: faker.lorem.word(), type: "text", textValue: faker.lorem.sentence(), booleanValue: false, numberValue: faker.datatype.number(), - timeValue: null, + timeValue: "", }; } @@ -32,8 +32,9 @@ function user(): UserRegistration { }; } -function location(): LocationCreate { +function location(parentId: string | null = null): LocationCreate { return { + parentId, name: faker.address.city(), description: faker.lorem.sentence(), }; @@ -56,7 +57,7 @@ function publicClient(): PublicApi { function userClient(token: string): UserClient { overrideParts(config.BASE_URL, "/api/v1"); const requests = new Requests("", token); - return new UserClient(requests); + return new UserClient(requests, ""); } type TestUser = { @@ -75,7 +76,7 @@ async function userSingleUse(): Promise { expect(result.status).toBe(200); return { - client: new UserClient(new Requests("", result.data.token)), + client: new UserClient(new Requests("", result.data.token), result.data.attachmentToken), user: usr, }; } diff --git a/frontend/lib/api/__test__/user/items.test.ts b/frontend/lib/api/__test__/user/items.test.ts index 1a5f94e..79c7f79 100644 --- a/frontend/lib/api/__test__/user/items.test.ts +++ b/frontend/lib/api/__test__/user/items.test.ts @@ -1,6 +1,6 @@ import { faker } from "@faker-js/faker"; import { describe, test, expect } from "vitest"; -import { ItemField, LocationOut } from "../../types/data-contracts"; +import { ItemField, ItemUpdate, LocationOut } from "../../types/data-contracts"; import { AttachmentTypes } from "../../types/non-generated"; import { UserClient } from "../../user"; import { factories } from "../factories"; @@ -14,6 +14,7 @@ describe("user should be able to create an item and add an attachment", () => { */ async function useLocation(api: UserClient): Promise<[LocationOut, () => Promise]> { const { response, data } = await api.locations.create({ + parentId: null, name: `__test__.location.name_${increment}`, description: `__test__.location.description_${increment}`, }); @@ -86,12 +87,12 @@ describe("user should be able to create an item and add an attachment", () => { const itemUpdate = { parentId: null, ...item, - locationId: item.location.id, + locationId: item.location?.id || null, labelIds: item.labels.map(l => l.id), fields, }; - const { response: updateResponse, data: item2 } = await api.items.update(item.id, itemUpdate); + const { response: updateResponse, data: item2 } = await api.items.update(item.id, itemUpdate as ItemUpdate); expect(updateResponse.status).toBe(200); expect(item2.fields).toHaveLength(fields.length); @@ -104,7 +105,7 @@ describe("user should be able to create an item and add an attachment", () => { itemUpdate.fields = [fields[0], fields[1]]; - const { response: updateResponse2, data: item3 } = await api.items.update(item.id, itemUpdate); + const { response: updateResponse2, data: item3 } = await api.items.update(item.id, itemUpdate as ItemUpdate); expect(updateResponse2.status).toBe(200); expect(item3.fields).toHaveLength(2); diff --git a/frontend/lib/api/__test__/user/locations.test.ts b/frontend/lib/api/__test__/user/locations.test.ts index eb7765e..3012faf 100644 --- a/frontend/lib/api/__test__/user/locations.test.ts +++ b/frontend/lib/api/__test__/user/locations.test.ts @@ -49,6 +49,8 @@ describe("locations lifecycle (create, update, delete)", () => { const [location, cleanup] = await useLocation(api); const updateData = { + id: location.id, + parentId: location.parent?.id, name: "test-location-updated", description: "test-description-updated", }; diff --git a/frontend/lib/api/__test__/user/stats.test.ts b/frontend/lib/api/__test__/user/stats.test.ts index 247b024..67a7b00 100644 --- a/frontend/lib/api/__test__/user/stats.test.ts +++ b/frontend/lib/api/__test__/user/stats.test.ts @@ -77,13 +77,13 @@ function importFileGenerator(entries: number): ImportObj[] { describe("group related statistics tests", () => { const TOTAL_ITEMS = 30; - let api: UserClient | undefined; + let tAPI: UserClient | undefined; const imports = importFileGenerator(TOTAL_ITEMS); beforeAll(async () => { // -- Setup -- const { client } = await factories.client.singleUse(); - api = client; + tAPI = client; const csv = toCsv(imports); @@ -92,6 +92,13 @@ describe("group related statistics tests", () => { expect(setupResp.status).toBe(204); }); + if (!tAPI) { + throw new Error("API is not defined"); + } + + // cast api to concrete type + const api = tAPI; + // Write to file system for debugging // fs.writeFileSync("test.csv", csv); test("Validate Group Statistics", async () => { diff --git a/frontend/lib/api/base/base-api.ts b/frontend/lib/api/base/base-api.ts index cc6dd1e..3847a4b 100644 --- a/frontend/lib/api/base/base-api.ts +++ b/frontend/lib/api/base/base-api.ts @@ -9,8 +9,8 @@ type BaseApiType = { [key: string]: any; }; -export function hasKey(obj: object, key: string): obj is Required { - return typeof obj[key] === "string"; +export function hasKey(obj: Record, key: string): obj is Required { + return key in obj ? typeof obj[key] === "string" : false; } export function parseDate(obj: T, keys: Array = []): T { diff --git a/frontend/lib/api/classes/items.ts b/frontend/lib/api/classes/items.ts index 0a45e62..88df5ab 100644 --- a/frontend/lib/api/classes/items.ts +++ b/frontend/lib/api/classes/items.ts @@ -141,4 +141,8 @@ export class ItemsApi extends BaseAPI { data: formData, }); } + + exportURL() { + return route("/items/export"); + } } diff --git a/frontend/lib/api/classes/reports.ts b/frontend/lib/api/classes/reports.ts index 03890cb..eeae22b 100644 --- a/frontend/lib/api/classes/reports.ts +++ b/frontend/lib/api/classes/reports.ts @@ -1,27 +1,7 @@ import { BaseAPI, route } from "../base"; export class ReportsAPI extends BaseAPI { - async billOfMaterials(): Promise { - const { data: stream, error } = await this.http.get({ url: route("/reporting/bill-of-materials") }); - - if (error) { - return; - } - - const reader = stream.getReader(); - let data = ""; - while (true) { - const { done, value } = await reader.read(); - if (done) { - break; - } - data += new TextDecoder("utf-8").decode(value); - } - - const blob = new Blob([data], { type: "text/tsv" }); - const link = document.createElement("a"); - link.href = window.URL.createObjectURL(blob); - link.download = "bill-of-materials.tsv"; - link.click(); + billOfMaterialsURL(): string { + return route("/reporting/bill-of-materials"); } } diff --git a/frontend/lib/requests/requests.ts b/frontend/lib/requests/requests.ts index f8ed355..32b79bc 100644 --- a/frontend/lib/requests/requests.ts +++ b/frontend/lib/requests/requests.ts @@ -76,6 +76,7 @@ export class Requests { const token = this.token(); if (token !== "" && payload.headers !== undefined) { + // @ts-expect-error - we know that the header is there payload.headers["Authorization"] = token; // eslint-disable-line dot-notation } @@ -83,6 +84,7 @@ export class Requests { if (rargs.data) { payload.body = rargs.data; } else { + // @ts-expect-error - we know that the header is there payload.headers["Content-Type"] = "application/json"; payload.body = JSON.stringify(rargs.body); } diff --git a/frontend/pages/location/[id].vue b/frontend/pages/location/[id].vue index cafac66..5a1b389 100644 --- a/frontend/pages/location/[id].vue +++ b/frontend/pages/location/[id].vue @@ -50,16 +50,16 @@ name: "Created", text: location.value?.createdAt, type: "date", - }, + } as AnyDetail, { name: "Updated", text: location.value?.updatedAt, type: "date", - }, + } as AnyDetail, { name: "Database ID", text: location.value?.id, - }, + } as AnyDetail, ]; } @@ -120,7 +120,6 @@ const locationStore = useLocationStore(); const locations = computed(() => locationStore.allLocations); - // eslint-disable-next-line @typescript-eslint/no-explicit-any const parent = ref({}); diff --git a/frontend/stores/labels.ts b/frontend/stores/labels.ts index 651bb49..acddf2c 100644 --- a/frontend/stores/labels.ts +++ b/frontend/stores/labels.ts @@ -14,13 +14,17 @@ export const useLabelStore = defineStore("labels", { */ labels(state): LabelOut[] { if (state.allLabels === null) { - Promise.resolve(this.refresh()); + this.client.labels.getAll().then(result => { + if (result.error) { + console.error(result.error); + } + }); } - return state.allLabels; + return state.allLabels ?? []; }, }, actions: { - async refresh(): Promise { + async refresh() { const result = await this.client.labels.getAll(); if (result.error) { return result; diff --git a/frontend/stores/locations.ts b/frontend/stores/locations.ts index 68295f6..c313040 100644 --- a/frontend/stores/locations.ts +++ b/frontend/stores/locations.ts @@ -1,4 +1,5 @@ import { defineStore } from "pinia"; +import { LocationsApi } from "~~/lib/api/classes/locations"; import { LocationOutCount } from "~~/lib/api/types/data-contracts"; export const useLocationStore = defineStore("locations", { @@ -15,19 +16,33 @@ export const useLocationStore = defineStore("locations", { */ parentLocations(state): LocationOutCount[] { if (state.parents === null) { - Promise.resolve(this.refreshParents()); + this.client.locations.getAll({ filterChildren: true }).then(result => { + if (result.error) { + console.error(result.error); + return; + } + + this.parents = result.data.items; + }); } - return state.parents; + return state.parents ?? []; }, allLocations(state): LocationOutCount[] { if (state.Locations === null) { - Promise.resolve(this.refreshChildren()); + this.client.locations.getAll({ filterChildren: false }).then(result => { + if (result.error) { + console.error(result.error); + return; + } + + this.Locations = result.data.items; + }); } - return state.Locations; + return state.Locations ?? []; }, }, actions: { - async refreshParents(): Promise { + async refreshParents(): ReturnType { const result = await this.client.locations.getAll({ filterChildren: true }); if (result.error) { return result; @@ -36,7 +51,7 @@ export const useLocationStore = defineStore("locations", { this.parents = result.data.items; return result; }, - async refreshChildren(): Promise { + async refreshChildren(): ReturnType { const result = await this.client.locations.getAll({ filterChildren: false }); if (result.error) { return result; diff --git a/frontend/test/setup.ts b/frontend/test/setup.ts index 7ad8bc0..d77dafa 100644 --- a/frontend/test/setup.ts +++ b/frontend/test/setup.ts @@ -13,7 +13,7 @@ export const setup = () => { export const teardown = () => { if (process.env.TEST_SHUTDOWN_API_SERVER) { const pc = exec("pkill -SIGTERM api"); // Kill background API process - pc.stdout.on("data", data => { + pc.stdout?.on("data", data => { console.log(`stdout: ${data}`); }); }