mirror of
https://github.com/hay-kot/homebox.git
synced 2025-08-04 08:40:28 +00:00
ts errors
This commit is contained in:
parent
af3b34a4ba
commit
13d3c727ba
17 changed files with 68 additions and 59 deletions
|
@ -38,12 +38,10 @@
|
||||||
default: "",
|
default: "",
|
||||||
},
|
},
|
||||||
modelValue: {
|
modelValue: {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
type: Array as () => any[],
|
type: Array as () => any[],
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
items: {
|
items: {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
type: Array as () => any[],
|
type: Array as () => any[],
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
|
|
@ -24,12 +24,10 @@
|
||||||
default: "",
|
default: "",
|
||||||
},
|
},
|
||||||
modelValue: {
|
modelValue: {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
type: [Object, String] as any,
|
type: [Object, String] as any,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
items: {
|
items: {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
type: Array as () => any[],
|
type: Array as () => any[],
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
@ -86,7 +84,6 @@
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
function compare(a: any, b: any): boolean {
|
function compare(a: any, b: any): boolean {
|
||||||
if (a === b) {
|
if (a === b) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { UseConfirmDialogRevealResult, UseConfirmDialogReturn } from "@vueuse/core";
|
import { UseConfirmDialogRevealResult, UseConfirmDialogReturn } from "@vueuse/core";
|
||||||
import { Ref } from "vue";
|
import { Ref } from "vue";
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
type Store = UseConfirmDialogReturn<any, boolean, boolean> & {
|
type Store = UseConfirmDialogReturn<any, boolean, boolean> & {
|
||||||
text: Ref<string>;
|
text: Ref<string>;
|
||||||
setup: boolean;
|
setup: boolean;
|
||||||
|
@ -23,7 +22,7 @@ const store: Partial<Store> = {
|
||||||
export function useConfirm(): Store {
|
export function useConfirm(): Store {
|
||||||
if (!store.setup) {
|
if (!store.setup) {
|
||||||
store.setup = true;
|
store.setup = true;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const { isRevealed, reveal, confirm, cancel } = useConfirmDialog<any, boolean, boolean>();
|
const { isRevealed, reveal, confirm, cancel } = useConfirmDialog<any, boolean, boolean>();
|
||||||
store.isRevealed = isRevealed;
|
store.isRevealed = isRevealed;
|
||||||
store.reveal = reveal;
|
store.reveal = reveal;
|
||||||
|
|
|
@ -7,7 +7,7 @@ export function useRouteQuery(q: string, def: string[]): WritableComputedRef<str
|
||||||
export function useRouteQuery(q: string, def: string): WritableComputedRef<string>;
|
export function useRouteQuery(q: string, def: string): WritableComputedRef<string>;
|
||||||
export function useRouteQuery(q: string, def: boolean): WritableComputedRef<boolean>;
|
export function useRouteQuery(q: string, def: boolean): WritableComputedRef<boolean>;
|
||||||
export function useRouteQuery(q: string, def: number): WritableComputedRef<number>;
|
export function useRouteQuery(q: string, def: number): WritableComputedRef<number>;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
export function useRouteQuery(q: string, def: any): WritableComputedRef<any> {
|
export function useRouteQuery(q: string, def: any): WritableComputedRef<any> {
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
|
@ -16,13 +16,13 @@ export function useTheme(): UseTheme {
|
||||||
preferences.value.theme = newTheme;
|
preferences.value.theme = newTheme;
|
||||||
|
|
||||||
if (htmlEl) {
|
if (htmlEl) {
|
||||||
htmlEl.value.setAttribute("data-theme", newTheme);
|
htmlEl.value?.setAttribute("data-theme", newTheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
themeRef.value = newTheme;
|
themeRef.value = newTheme;
|
||||||
};
|
};
|
||||||
|
|
||||||
const htmlEl = ref<HTMLElement>(null);
|
const htmlEl = ref<HTMLElement | null>();
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (htmlEl.value) {
|
if (htmlEl.value) {
|
||||||
|
|
|
@ -9,13 +9,13 @@ import { Requests } from "../../../requests";
|
||||||
|
|
||||||
function itemField(id = null): ItemField {
|
function itemField(id = null): ItemField {
|
||||||
return {
|
return {
|
||||||
id,
|
id: id ?? "",
|
||||||
name: faker.lorem.word(),
|
name: faker.lorem.word(),
|
||||||
type: "text",
|
type: "text",
|
||||||
textValue: faker.lorem.sentence(),
|
textValue: faker.lorem.sentence(),
|
||||||
booleanValue: false,
|
booleanValue: false,
|
||||||
numberValue: faker.datatype.number(),
|
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 {
|
return {
|
||||||
|
parentId,
|
||||||
name: faker.address.city(),
|
name: faker.address.city(),
|
||||||
description: faker.lorem.sentence(),
|
description: faker.lorem.sentence(),
|
||||||
};
|
};
|
||||||
|
@ -56,7 +57,7 @@ function publicClient(): PublicApi {
|
||||||
function userClient(token: string): UserClient {
|
function userClient(token: string): UserClient {
|
||||||
overrideParts(config.BASE_URL, "/api/v1");
|
overrideParts(config.BASE_URL, "/api/v1");
|
||||||
const requests = new Requests("", token);
|
const requests = new Requests("", token);
|
||||||
return new UserClient(requests);
|
return new UserClient(requests, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
type TestUser = {
|
type TestUser = {
|
||||||
|
@ -75,7 +76,7 @@ async function userSingleUse(): Promise<TestUser> {
|
||||||
expect(result.status).toBe(200);
|
expect(result.status).toBe(200);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
client: new UserClient(new Requests("", result.data.token)),
|
client: new UserClient(new Requests("", result.data.token), result.data.attachmentToken),
|
||||||
user: usr,
|
user: usr,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { faker } from "@faker-js/faker";
|
import { faker } from "@faker-js/faker";
|
||||||
import { describe, test, expect } from "vitest";
|
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 { AttachmentTypes } from "../../types/non-generated";
|
||||||
import { UserClient } from "../../user";
|
import { UserClient } from "../../user";
|
||||||
import { factories } from "../factories";
|
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<void>]> {
|
async function useLocation(api: UserClient): Promise<[LocationOut, () => Promise<void>]> {
|
||||||
const { response, data } = await api.locations.create({
|
const { response, data } = await api.locations.create({
|
||||||
|
parentId: null,
|
||||||
name: `__test__.location.name_${increment}`,
|
name: `__test__.location.name_${increment}`,
|
||||||
description: `__test__.location.description_${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 = {
|
const itemUpdate = {
|
||||||
parentId: null,
|
parentId: null,
|
||||||
...item,
|
...item,
|
||||||
locationId: item.location.id,
|
locationId: item.location?.id || null,
|
||||||
labelIds: item.labels.map(l => l.id),
|
labelIds: item.labels.map(l => l.id),
|
||||||
fields,
|
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(updateResponse.status).toBe(200);
|
||||||
|
|
||||||
expect(item2.fields).toHaveLength(fields.length);
|
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]];
|
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(updateResponse2.status).toBe(200);
|
||||||
|
|
||||||
expect(item3.fields).toHaveLength(2);
|
expect(item3.fields).toHaveLength(2);
|
||||||
|
|
|
@ -49,6 +49,8 @@ describe("locations lifecycle (create, update, delete)", () => {
|
||||||
const [location, cleanup] = await useLocation(api);
|
const [location, cleanup] = await useLocation(api);
|
||||||
|
|
||||||
const updateData = {
|
const updateData = {
|
||||||
|
id: location.id,
|
||||||
|
parentId: location.parent?.id,
|
||||||
name: "test-location-updated",
|
name: "test-location-updated",
|
||||||
description: "test-description-updated",
|
description: "test-description-updated",
|
||||||
};
|
};
|
||||||
|
|
|
@ -77,13 +77,13 @@ function importFileGenerator(entries: number): ImportObj[] {
|
||||||
describe("group related statistics tests", () => {
|
describe("group related statistics tests", () => {
|
||||||
const TOTAL_ITEMS = 30;
|
const TOTAL_ITEMS = 30;
|
||||||
|
|
||||||
let api: UserClient | undefined;
|
let tAPI: UserClient | undefined;
|
||||||
const imports = importFileGenerator(TOTAL_ITEMS);
|
const imports = importFileGenerator(TOTAL_ITEMS);
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
// -- Setup --
|
// -- Setup --
|
||||||
const { client } = await factories.client.singleUse();
|
const { client } = await factories.client.singleUse();
|
||||||
api = client;
|
tAPI = client;
|
||||||
|
|
||||||
const csv = toCsv(imports);
|
const csv = toCsv(imports);
|
||||||
|
|
||||||
|
@ -92,6 +92,13 @@ describe("group related statistics tests", () => {
|
||||||
expect(setupResp.status).toBe(204);
|
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
|
// Write to file system for debugging
|
||||||
// fs.writeFileSync("test.csv", csv);
|
// fs.writeFileSync("test.csv", csv);
|
||||||
test("Validate Group Statistics", async () => {
|
test("Validate Group Statistics", async () => {
|
||||||
|
|
|
@ -9,8 +9,8 @@ type BaseApiType = {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function hasKey(obj: object, key: string): obj is Required<BaseApiType> {
|
export function hasKey(obj: Record<string, any>, key: string): obj is Required<BaseApiType> {
|
||||||
return typeof obj[key] === "string";
|
return key in obj ? typeof obj[key] === "string" : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseDate<T>(obj: T, keys: Array<keyof T> = []): T {
|
export function parseDate<T>(obj: T, keys: Array<keyof T> = []): T {
|
||||||
|
|
|
@ -141,4 +141,8 @@ export class ItemsApi extends BaseAPI {
|
||||||
data: formData,
|
data: formData,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exportURL() {
|
||||||
|
return route("/items/export");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +1,7 @@
|
||||||
import { BaseAPI, route } from "../base";
|
import { BaseAPI, route } from "../base";
|
||||||
|
|
||||||
export class ReportsAPI extends BaseAPI {
|
export class ReportsAPI extends BaseAPI {
|
||||||
async billOfMaterials(): Promise<void> {
|
billOfMaterialsURL(): string {
|
||||||
const { data: stream, error } = await this.http.get<ReadableStream>({ url: route("/reporting/bill-of-materials") });
|
return 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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,6 +76,7 @@ export class Requests {
|
||||||
|
|
||||||
const token = this.token();
|
const token = this.token();
|
||||||
if (token !== "" && payload.headers !== undefined) {
|
if (token !== "" && payload.headers !== undefined) {
|
||||||
|
// @ts-expect-error - we know that the header is there
|
||||||
payload.headers["Authorization"] = token; // eslint-disable-line dot-notation
|
payload.headers["Authorization"] = token; // eslint-disable-line dot-notation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,6 +84,7 @@ export class Requests {
|
||||||
if (rargs.data) {
|
if (rargs.data) {
|
||||||
payload.body = rargs.data;
|
payload.body = rargs.data;
|
||||||
} else {
|
} else {
|
||||||
|
// @ts-expect-error - we know that the header is there
|
||||||
payload.headers["Content-Type"] = "application/json";
|
payload.headers["Content-Type"] = "application/json";
|
||||||
payload.body = JSON.stringify(rargs.body);
|
payload.body = JSON.stringify(rargs.body);
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,16 +50,16 @@
|
||||||
name: "Created",
|
name: "Created",
|
||||||
text: location.value?.createdAt,
|
text: location.value?.createdAt,
|
||||||
type: "date",
|
type: "date",
|
||||||
},
|
} as AnyDetail,
|
||||||
{
|
{
|
||||||
name: "Updated",
|
name: "Updated",
|
||||||
text: location.value?.updatedAt,
|
text: location.value?.updatedAt,
|
||||||
type: "date",
|
type: "date",
|
||||||
},
|
} as AnyDetail,
|
||||||
{
|
{
|
||||||
name: "Database ID",
|
name: "Database ID",
|
||||||
text: location.value?.id,
|
text: location.value?.id,
|
||||||
},
|
} as AnyDetail,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +120,6 @@
|
||||||
const locationStore = useLocationStore();
|
const locationStore = useLocationStore();
|
||||||
const locations = computed(() => locationStore.allLocations);
|
const locations = computed(() => locationStore.allLocations);
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const parent = ref<LocationSummary | any>({});
|
const parent = ref<LocationSummary | any>({});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -14,13 +14,17 @@ export const useLabelStore = defineStore("labels", {
|
||||||
*/
|
*/
|
||||||
labels(state): LabelOut[] {
|
labels(state): LabelOut[] {
|
||||||
if (state.allLabels === null) {
|
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: {
|
actions: {
|
||||||
async refresh(): Promise<LabelOut[]> {
|
async refresh() {
|
||||||
const result = await this.client.labels.getAll();
|
const result = await this.client.labels.getAll();
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
|
import { LocationsApi } from "~~/lib/api/classes/locations";
|
||||||
import { LocationOutCount } from "~~/lib/api/types/data-contracts";
|
import { LocationOutCount } from "~~/lib/api/types/data-contracts";
|
||||||
|
|
||||||
export const useLocationStore = defineStore("locations", {
|
export const useLocationStore = defineStore("locations", {
|
||||||
|
@ -15,19 +16,33 @@ export const useLocationStore = defineStore("locations", {
|
||||||
*/
|
*/
|
||||||
parentLocations(state): LocationOutCount[] {
|
parentLocations(state): LocationOutCount[] {
|
||||||
if (state.parents === null) {
|
if (state.parents === null) {
|
||||||
Promise.resolve(this.refreshParents());
|
this.client.locations.getAll({ filterChildren: true }).then(result => {
|
||||||
|
if (result.error) {
|
||||||
|
console.error(result.error);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return state.parents;
|
|
||||||
|
this.parents = result.data.items;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return state.parents ?? [];
|
||||||
},
|
},
|
||||||
allLocations(state): LocationOutCount[] {
|
allLocations(state): LocationOutCount[] {
|
||||||
if (state.Locations === null) {
|
if (state.Locations === null) {
|
||||||
Promise.resolve(this.refreshChildren());
|
this.client.locations.getAll({ filterChildren: false }).then(result => {
|
||||||
|
if (result.error) {
|
||||||
|
console.error(result.error);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return state.Locations;
|
|
||||||
|
this.Locations = result.data.items;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return state.Locations ?? [];
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
async refreshParents(): Promise<LocationOutCount[]> {
|
async refreshParents(): ReturnType<LocationsApi["getAll"]> {
|
||||||
const result = await this.client.locations.getAll({ filterChildren: true });
|
const result = await this.client.locations.getAll({ filterChildren: true });
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
return result;
|
return result;
|
||||||
|
@ -36,7 +51,7 @@ export const useLocationStore = defineStore("locations", {
|
||||||
this.parents = result.data.items;
|
this.parents = result.data.items;
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
async refreshChildren(): Promise<LocationOutCount[]> {
|
async refreshChildren(): ReturnType<LocationsApi["getAll"]> {
|
||||||
const result = await this.client.locations.getAll({ filterChildren: false });
|
const result = await this.client.locations.getAll({ filterChildren: false });
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -13,7 +13,7 @@ export const setup = () => {
|
||||||
export const teardown = () => {
|
export const teardown = () => {
|
||||||
if (process.env.TEST_SHUTDOWN_API_SERVER) {
|
if (process.env.TEST_SHUTDOWN_API_SERVER) {
|
||||||
const pc = exec("pkill -SIGTERM api"); // Kill background API process
|
const pc = exec("pkill -SIGTERM api"); // Kill background API process
|
||||||
pc.stdout.on("data", data => {
|
pc.stdout?.on("data", data => {
|
||||||
console.log(`stdout: ${data}`);
|
console.log(`stdout: ${data}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue