Get front end tests passing (#299)

* chore: get front end tests passing

* chore: add @vue/runtime-core to fix types for $t

* chore: sort lockfile

* Discard changes to frontend/pnpm-lock.yaml

* chore: sort lockfile

* chore: fix some type errors

* chore: switch from nuxi typecheck to vue-tsc to force a known good version

* chore: linting

* chore: update pnpm version in frontend test

* feat: add proper pagination type (need to sort why it still doesn't work)

* chore: format imports and initialize totalPrice in label page to null when no label is present

* chore: update pnpm to v9.12.2, merge ItemSummaryPaginationResult with PaginationResult, and handle error in label generator more gracefully

* chore: lint

---------

Co-authored-by: Matt Kilgore <matthew@kilgore.dev>
This commit is contained in:
Tonya
2024-10-28 19:47:00 +00:00
committed by GitHub
parent c0860fc9ca
commit ec5b6bb8ff
31 changed files with 237 additions and 160 deletions

View File

@@ -15,7 +15,7 @@ jobs:
- uses: pnpm/action-setup@v3.0.0 - uses: pnpm/action-setup@v3.0.0
with: with:
version: 6.0.2 version: 9.12.2
- name: Install dependencies - name: Install dependencies
run: pnpm install --shamefully-hoist run: pnpm install --shamefully-hoist
@@ -54,7 +54,7 @@ jobs:
- uses: pnpm/action-setup@v3.0.0 - uses: pnpm/action-setup@v3.0.0
with: with:
version: 6.0.2 version: 9.12.2
- name: Install dependencies - name: Install dependencies
run: pnpm install run: pnpm install

View File

@@ -28,3 +28,61 @@
::-webkit-scrollbar-thumb:hover { ::-webkit-scrollbar-thumb:hover {
background-color: #9B9B9B; background-color: #9B9B9B;
} }
.scroll-bg::-webkit-scrollbar {
width: 0.5rem;
}
.scroll-bg::-webkit-scrollbar-thumb {
border-radius: 0.25rem;
@apply bg-base-300;
}
.markdown > :first-child {
margin-top: 0px !important;
}
.markdown :where(p, ul, ol, dl, blockquote, h1, h2, h3, h4, h5, h6) {
margin-top: var(--y-gap);
margin-bottom: var(--y-gap);
}
.markdown :where(ul) {
list-style: disc;
margin-left: 2rem;
}
.markdown :where(ol) {
list-style: decimal;
margin-left: 2rem;
}
/* Heading Styles */
.markdown :where(h1) {
font-size: 2rem;
font-weight: 700;
}
.markdown :where(h2) {
font-size: 1.5rem;
font-weight: 700;
}
.markdown :where(h3) {
font-size: 1.25rem;
font-weight: 700;
}
.markdown :where(h4) {
font-size: 1rem;
font-weight: 700;
}
.markdown :where(h5) {
font-size: 0.875rem;
font-weight: 700;
}
.markdown :where(h6) {
font-size: 0.75rem;
font-weight: 700;
}

View File

@@ -4,7 +4,6 @@
class="flex items-center text-3xl font-bold tracking-tight" class="flex items-center text-3xl font-bold tracking-tight"
:class="{ :class="{
'text-neutral-content': dark, 'text-neutral-content': dark,
'text-content': !dark,
}" }"
> >
<slot /> <slot />

View File

@@ -85,7 +85,10 @@
type Props = { type Props = {
label: string; label: string;
modelValue: SupportValues | null | undefined; modelValue: SupportValues | null | undefined;
items: string[] | object[]; items: {
id: string;
treeString: string;
}[];
display?: string; display?: string;
multiple?: boolean; multiple?: boolean;
}; };
@@ -156,7 +159,7 @@
const matches = index.value.search("*" + search.value + "*"); const matches = index.value.search("*" + search.value + "*");
let resultIDs = [] const resultIDs = [];
for (let i = 0; i < matches.length; i++) { for (let i = 0; i < matches.length; i++) {
const match = matches[i]; const match = matches[i];
const item = props.items[parseInt(match.ref)]; const item = props.items[parseInt(match.ref)];
@@ -170,9 +173,11 @@
* Resolve the issue of language not being supported * Resolve the issue of language not being supported
*/ */
for (let i = 0; i < props.items.length; i++) { for (let i = 0; i < props.items.length; i++) {
const item = props.items[i] const item = props.items[i];
if(resultIDs.find(item_ => item_ === item.id) != undefined){continue} if (resultIDs.find(item_ => item_ === item.id) !== undefined) {
if(item.treeString.indexOf(search.value) > -1){ continue;
}
if (item.treeString.includes(search.value)) {
const display = extractDisplay(item); const display = extractDisplay(item);
list.push({ id: i, display, value: item }); list.push({ id: i, display, value: item });
} }

View File

@@ -6,10 +6,10 @@
:class="{ :class="{
'text-red-600': 'text-red-600':
typeof value === 'string' && typeof value === 'string' &&
((maxLength && value.length > maxLength) || (minLength && value.length < minLength)), ((maxLength !== -1 && value.length > maxLength) || (minLength !== -1 && value.length < minLength)),
}" }"
> >
{{ typeof value === "string" && (maxLength || minLength) ? `${value.length}/${maxLength}` : "" }} {{ typeof value === "string" && (maxLength !== -1 || minLength !== -1) ? `${value.length}/${maxLength}` : "" }}
</span> </span>
</label> </label>
<textarea ref="el" v-model="value" class="textarea textarea-bordered h-28 w-full" :placeholder="placeholder" /> <textarea ref="el" v-model="value" class="textarea textarea-bordered h-28 w-full" :placeholder="placeholder" />
@@ -21,10 +21,10 @@
:class="{ :class="{
'text-red-600': 'text-red-600':
typeof value === 'string' && typeof value === 'string' &&
((maxLength && value.length > maxLength) || (minLength && value.length < minLength)), ((maxLength !== -1 && value.length > maxLength) || (minLength !== -1 && value.length < minLength)),
}" }"
> >
{{ typeof value === "string" && (maxLength || minLength) ? `${value.length}/${maxLength}` : "" }} {{ typeof value === "string" && (maxLength !== -1 || minLength !== -1) ? `${value.length}/${maxLength}` : "" }}
</span> </span>
</label> </label>
<textarea <textarea
@@ -63,10 +63,12 @@
}, },
maxLength: { maxLength: {
type: Number, type: Number,
default: -1,
required: false, required: false,
}, },
minLength: { minLength: {
type: Number, type: Number,
default: -1,
required: false, required: false,
}, },
}); });
@@ -84,7 +86,4 @@
}); });
const value = useVModel(props, "modelValue", emit); const value = useVModel(props, "modelValue", emit);
const valueLen = computed(() => {
return value.value ? value.value.length : 0;
});
</script> </script>

View File

@@ -6,10 +6,10 @@
:class="{ :class="{
'text-red-600': 'text-red-600':
typeof value === 'string' && typeof value === 'string' &&
((maxLength && value.length > maxLength) || (minLength && value.length < minLength)), ((maxLength !== -1 && value.length > maxLength) || (minLength !== -1 && value.length < minLength)),
}" }"
> >
{{ typeof value === "string" && (maxLength || minLength) ? `${value.length}/${maxLength}` : "" }} {{ typeof value === "string" && (maxLength !== -1 || minLength !== -1) ? `${value.length}/${maxLength}` : "" }}
</span> </span>
</label> </label>
<input <input
@@ -28,10 +28,10 @@
:class="{ :class="{
'text-red-600': 'text-red-600':
typeof value === 'string' && typeof value === 'string' &&
((maxLength && value.length > maxLength) || (minLength && value.length < minLength)), ((maxLength !== -1 && value.length > maxLength) || (minLength !== -1 && value.length < minLength)),
}" }"
> >
{{ typeof value === "string" && (maxLength || minLength) ? `${value.length}/${maxLength}` : "" }} {{ typeof value === "string" && (maxLength !== -1 || minLength !== -1) ? `${value.length}/${maxLength}` : "" }}
</span> </span>
</label> </label>
<input <input
@@ -76,10 +76,12 @@
}, },
maxLength: { maxLength: {
type: Number, type: Number,
default: -1,
required: false, required: false,
}, },
minLength: { minLength: {
type: Number, type: Number,
default: -1,
required: false, required: false,
}, },
}); });

View File

@@ -19,7 +19,7 @@
</div> </div>
</div> </div>
<div class="col-span-4 flex grow flex-col gap-y-1 rounded-b bg-base-100 p-4 pt-2"> <div class="col-span-4 flex grow flex-col gap-y-1 rounded-b bg-base-100 p-4 pt-2">
<h2 class="line-clamp-2 text-ellipsis text-lg font-bold text-wrap">{{ item.name }}</h2> <h2 class="line-clamp-2 text-ellipsis text-wrap text-lg font-bold">{{ item.name }}</h2>
<div class="divider my-0"></div> <div class="divider my-0"></div>
<div class="flex gap-2"> <div class="flex gap-2">
<div v-if="item.insured" class="tooltip z-10" data-tip="Insured"> <div v-if="item.insured" class="tooltip z-10" data-tip="Insured">

View File

@@ -12,7 +12,11 @@
:max-length="255" :max-length="255"
:min-length="1" :min-length="1"
/> />
<FormTextArea v-model="form.description" :label="$t('components.item.create_modal.item_description')" :max-length="1000" /> <FormTextArea
v-model="form.description"
:label="$t('components.item.create_modal.item_description')"
:max-length="1000"
/>
<FormMultiselect v-model="form.labels" :label="$t('global.labels')" :items="labels ?? []" /> <FormMultiselect v-model="form.labels" :label="$t('global.labels')" :items="labels ?? []" />
<div class="modal-action mb-6"> <div class="modal-action mb-6">
@@ -39,7 +43,7 @@
<label tabindex="0" class="btn rounded-l-none rounded-r-xl"> <label tabindex="0" class="btn rounded-l-none rounded-r-xl">
<MdiChevronDown class="size-5" name="mdi-chevron-down" /> <MdiChevronDown class="size-5" name="mdi-chevron-down" />
</label> </label>
<ul tabindex="0" class="dropdown-content menu rounded-box bg-base-100 right-0 w-64 p-2 shadow"> <ul tabindex="0" class="dropdown-content menu rounded-box right-0 w-64 bg-base-100 p-2 shadow">
<li> <li>
<button type="button" @click="create(false)">{{ $t("global.create_and_add") }}</button> <button type="button" @click="create(false)">{{ $t("global.create_and_add") }}</button>
</li> </li>

View File

@@ -83,7 +83,7 @@
</label> </label>
<ul tabindex="0" class="dropdown-content rounded-box flex w-64 flex-col gap-2 bg-base-100 p-2 pl-3 shadow"> <ul tabindex="0" class="dropdown-content rounded-box flex w-64 flex-col gap-2 bg-base-100 p-2 pl-3 shadow">
<li>Headers:</li> <li>Headers:</li>
<li v-for="(h, i) in headers" class="flex flex-row items-center gap-1"> <li v-for="(h, i) in headers" :key="h.value" class="flex flex-row items-center gap-1">
<button <button
class="btn btn-square btn-ghost btn-xs" class="btn btn-square btn-ghost btn-xs"
:class="{ :class="{
@@ -150,7 +150,10 @@
const defaultHeaders = [ const defaultHeaders = [
{ {
text: "items.name", value: "name", enabled: true, type: "name" text: "items.name",
value: "name",
enabled: true,
type: "name",
}, },
{ text: "items.quantity", value: "quantity", align: "center", enabled: true }, { text: "items.quantity", value: "quantity", align: "center", enabled: true },
{ text: "items.insured", value: "insured", align: "center", enabled: true, type: "boolean" }, { text: "items.insured", value: "insured", align: "center", enabled: true, type: "boolean" },
@@ -162,16 +165,13 @@
] satisfies TableHeader[]; ] satisfies TableHeader[];
const headers = ref<TableHeader[]>( const headers = ref<TableHeader[]>(
(preferences.value.tableHeaders ?? []).concat( (preferences.value.tableHeaders ?? [])
defaultHeaders.filter(h => !preferences.value.tableHeaders?.find(h2 => h2.value === h.value)) .concat(defaultHeaders.filter(h => !preferences.value.tableHeaders?.find(h2 => h2.value === h.value)))
)
// this is a hack to make sure that any changes to the defaultHeaders are reflected in the preferences // this is a hack to make sure that any changes to the defaultHeaders are reflected in the preferences
.map(h => ( .map(h => ({
{ ...(defaultHeaders.find(h2 => h2.value === h.value) as TableHeader),
...defaultHeaders.find(h2 => h2.value === h.value) as TableHeader, enabled: h.enabled,
enabled: h.enabled }))
}
))
); );
console.log(headers.value); console.log(headers.value);

View File

@@ -11,7 +11,11 @@
:max-length="255" :max-length="255"
:min-length="1" :min-length="1"
/> />
<FormTextArea v-model="form.description" :label="$t('components.label.create_modal.label_description')" :max-length="255" /> <FormTextArea
v-model="form.description"
:label="$t('components.label.create_modal.label_description')"
:max-length="255"
/>
<div class="modal-action"> <div class="modal-action">
<div class="flex justify-center"> <div class="flex justify-center">
<BaseButton class="rounded-r-none" :loading="loading" type="submit"> {{ $t("global.create") }} </BaseButton> <BaseButton class="rounded-r-none" :loading="loading" type="submit"> {{ $t("global.create") }} </BaseButton>

View File

@@ -12,7 +12,11 @@
:max-length="255" :max-length="255"
:min-length="1" :min-length="1"
/> />
<FormTextArea v-model="form.description" :label="$t('components.location.create_modal.location_description')" :max-length="1000" /> <FormTextArea
v-model="form.description"
:label="$t('components.location.create_modal.location_description')"
:max-length="1000"
/>
<LocationSelector v-model="form.parent" /> <LocationSelector v-model="form.parent" />
<div class="modal-action"> <div class="modal-action">
<div class="flex justify-center"> <div class="flex justify-center">
@@ -21,7 +25,7 @@
<label tabindex="0" class="btn rounded-l-none rounded-r-xl"> <label tabindex="0" class="btn rounded-l-none rounded-r-xl">
<MdiChevronDown class="size-5" /> <MdiChevronDown class="size-5" />
</label> </label>
<ul tabindex="0" class="dropdown-content menu rounded-box bg-base-100 right-0 w-64 p-2 shadow"> <ul tabindex="0" class="dropdown-content menu rounded-box right-0 w-64 bg-base-100 p-2 shadow">
<li> <li>
<button type="button" @click="create(false)">{{ $t("global.create_and_add") }}</button> <button type="button" @click="create(false)">{{ $t("global.create_and_add") }}</button>
</li> </li>

View File

@@ -1,5 +1,11 @@
<template> <template>
<FormAutocomplete2 v-if="locations" v-model="value" :items="locations" display="name" :label="$t('components.location.selector.parent_location')"> <FormAutocomplete2
v-if="locations"
v-model="value"
:items="locations"
display="name"
:label="$t('components.location.selector.parent_location')"
>
<template #display="{ item, selected, active }"> <template #display="{ item, selected, active }">
<div> <div>
<div class="flex w-full"> <div class="flex w-full">

View File

@@ -10,6 +10,7 @@
</script> </script>
<template> <template>
<!-- eslint-disable-next-line tailwindcss/no-custom-classname -->
<div class="root border-2 p-4"> <div class="root border-2 p-4">
<p v-if="locs.length === 0" class="text-center text-sm"> <p v-if="locs.length === 0" class="text-center text-sm">
{{ $t("location.tree.no_locations") }} {{ $t("location.tree.no_locations") }}

View File

@@ -25,17 +25,17 @@
}, },
}); });
const { data: maintenanceDataList, refresh: refreshList } = useAsyncData<MaintenanceEntryWithDetails[]>( const { data: maintenanceDataList, refresh: refreshList } = useAsyncData(
async () => { async () => {
const { data } = const { data } =
props.currentItemId !== undefined props.currentItemId !== undefined
? await api.items.maintenance.getLog(props.currentItemId, { status: maintenanceFilterStatus.value }) ? await api.items.maintenance.getLog(props.currentItemId, { status: maintenanceFilterStatus.value })
: await api.maintenance.getAll({ status: maintenanceFilterStatus.value }); : await api.maintenance.getAll({ status: maintenanceFilterStatus.value });
console.log(data); console.log(data);
return data as MaintenanceEntryWithDetails[]; return data;
}, },
{ {
watch: maintenanceFilterStatus, watch: [maintenanceFilterStatus],
} }
); );
@@ -80,7 +80,7 @@
<StatCard <StatCard
v-for="stat in stats" v-for="stat in stats"
:key="stat.id" :key="stat.id"
class="stats border-l-primary block shadow-xl" class="stats block border-l-primary shadow-xl"
:title="stat.title" :title="stat.title"
:value="stat.value" :value="stat.value"
:type="stat.type" :type="stat.type"
@@ -189,7 +189,7 @@
<div v-if="props.currentItemId" class="hidden first:block"> <div v-if="props.currentItemId" class="hidden first:block">
<button <button
type="button" type="button"
class="border-base-content relative block w-full rounded-lg border-2 border-dashed p-12 text-center" class="relative block w-full rounded-lg border-2 border-dashed border-base-content p-12 text-center"
@click="maintenanceEditModal?.openCreateModal(props.currentItemId)" @click="maintenanceEditModal?.openCreateModal(props.currentItemId)"
> >
<MdiWrenchClock class="inline size-16" /> <MdiWrenchClock class="inline size-16" />

View File

@@ -24,6 +24,7 @@
</script> </script>
<template> <template>
<!-- eslint-disable-next-line vue/no-v-html -->
<div class="markdown text-wrap" v-html="raw"></div> <div class="markdown text-wrap" v-html="raw"></div>
</template> </template>
@@ -31,53 +32,4 @@
* { * {
--y-gap: 0.65rem; --y-gap: 0.65rem;
} }
.markdown > :first-child {
margin-top: 0px !important;
}
.markdown :where(p, ul, ol, dl, blockquote, h1, h2, h3, h4, h5, h6) {
margin-top: var(--y-gap);
margin-bottom: var(--y-gap);
}
.markdown :where(ul) {
list-style: disc;
margin-left: 2rem;
}
.markdown :where(ol) {
list-style: decimal;
margin-left: 2rem;
}
/* Heading Styles */
.markdown :where(h1) {
font-size: 2rem;
font-weight: 700;
}
.markdown :where(h2) {
font-size: 1.5rem;
font-weight: 700;
}
.markdown :where(h3) {
font-size: 1.25rem;
font-weight: 700;
}
.markdown :where(h4) {
font-size: 1rem;
font-weight: 700;
}
.markdown :where(h5) {
font-size: 0.875rem;
font-weight: 700;
}
.markdown :where(h6) {
font-size: 0.75rem;
font-weight: 700;
}
</style> </style>

View File

@@ -45,8 +45,8 @@ export function useLocaleTimeAgo(date: Date) {
const I18N_MESSAGES: UseTimeAgoMessages<UseTimeAgoUnitNamesDefault> = { const I18N_MESSAGES: UseTimeAgoMessages<UseTimeAgoUnitNamesDefault> = {
justNow: t("components.global.date_time.just-now"), justNow: t("components.global.date_time.just-now"),
past: (n) => (n.match(/\d/) ? t("components.global.date_time.ago", [n]) : n), past: n => (n.match(/\d/) ? t("components.global.date_time.ago", [n]) : n),
future: (n) => (n.match(/\d/) ? t("components.global.date_time.in", [n]) : n), future: n => (n.match(/\d/) ? t("components.global.date_time.in", [n]) : n),
month: (n, past) => month: (n, past) =>
n === 1 n === 1
? past ? past
@@ -71,17 +71,9 @@ export function useLocaleTimeAgo(date: Date) {
? t("components.global.date_time.last-week") ? t("components.global.date_time.last-week")
: t("components.global.date_time.next-week") : t("components.global.date_time.next-week")
: `${n} ${t(`components.global.date_time.weeks`)}`, : `${n} ${t(`components.global.date_time.weeks`)}`,
hour: (n) => `${n} ${ hour: n => `${n} ${n === 1 ? t("components.global.date_time.hour") : t("components.global.date_time.hours")}`,
n === 1 ? t("components.global.date_time.hour") : t("components.global.date_time.hours") minute: n => `${n} ${n === 1 ? t("components.global.date_time.minute") : t("components.global.date_time.minutes")}`,
}`, second: n => `${n} ${n === 1 ? t("components.global.date_time.second") : t("components.global.date_time.seconds")}`,
minute: (n) => `${n} ${
n === 1 ? t("components.global.date_time.minute") : t("components.global.date_time.minutes")
}`,
second: (n) => `${n} ${
n === 1
? t("components.global.date_time.second")
: t("components.global.date_time.seconds")
}`,
invalid: "", invalid: "",
}; };
@@ -91,10 +83,7 @@ export function useLocaleTimeAgo(date: Date) {
}); });
} }
export function fmtDate( export function fmtDate(value: string | Date, fmt: DateTimeFormat = "human"): string {
value: string | Date,
fmt: DateTimeFormat = "human"
): string {
const months = [ const months = [
"January", "January",
"February", "February",

View File

@@ -1,5 +1,5 @@
import type { Ref } from "vue"; import type { Ref } from "vue";
import type { TableHeader } from "components/Item/View/Table.types"; import type { TableHeader } from "~/components/Item/View/Table.types";
import type { DaisyTheme } from "~~/lib/data/themes"; import type { DaisyTheme } from "~~/lib/data/themes";
export type ViewType = "table" | "card" | "tree"; export type ViewType = "table" | "card" | "tree";

View File

@@ -12,15 +12,15 @@
<AppToast /> <AppToast />
<div class="drawer drawer-mobile"> <div class="drawer drawer-mobile">
<input id="my-drawer-2" v-model="drawerToggle" type="checkbox" class="drawer-toggle" /> <input id="my-drawer-2" v-model="drawerToggle" type="checkbox" class="drawer-toggle" />
<div class="drawer-content bg-base-300 justify-center pt-20 lg:pt-0"> <div class="drawer-content justify-center bg-base-300 pt-20 lg:pt-0">
<AppHeaderDecor v-if="preferences.displayHeaderDecor" class="-mt-10 hidden lg:block" /> <AppHeaderDecor v-if="preferences.displayHeaderDecor" class="-mt-10 hidden lg:block" />
<!-- Button --> <!-- Button -->
<div class="navbar drawer-button bg-primary fixed top-0 z-[99] shadow-md lg:hidden"> <div class="navbar drawer-button fixed top-0 z-[99] bg-primary shadow-md lg:hidden">
<label for="my-drawer-2" class="btn btn-square btn-ghost drawer-button text-base-100 lg:hidden"> <label for="my-drawer-2" class="btn btn-square btn-ghost drawer-button text-base-100 lg:hidden">
<MdiMenu class="size-6" /> <MdiMenu class="size-6" />
</label> </label>
<NuxtLink to="/home"> <NuxtLink to="/home">
<h2 class="text-base-100 flex text-3xl font-bold tracking-tight"> <h2 class="flex text-3xl font-bold tracking-tight text-base-100">
HomeB HomeB
<AppLogo class="-mb-3 w-8" /> <AppLogo class="-mb-3 w-8" />
x x
@@ -29,7 +29,7 @@
</div> </div>
<slot></slot> <slot></slot>
<footer v-if="status" class="bg-base-300 text-secondary-content bottom-0 w-full pb-4 text-center"> <footer v-if="status" class="bottom-0 w-full bg-base-300 pb-4 text-center text-secondary-content">
<p class="text-center text-sm"> <p class="text-center text-sm">
{{ $t("global.version", { version: status.build.version }) }} ~ {{ $t("global.version", { version: status.build.version }) }} ~
{{ $t("global.build", { build: status.build.commit }) }} {{ $t("global.build", { build: status.build.commit }) }}
@@ -42,17 +42,17 @@
<label for="my-drawer-2" class="drawer-overlay"></label> <label for="my-drawer-2" class="drawer-overlay"></label>
<!-- Top Section --> <!-- Top Section -->
<div class="bg-base-200 flex min-w-40 max-w-min flex-col p-5 md:py-10"> <div class="flex min-w-40 max-w-min flex-col bg-base-200 p-5 md:py-10">
<div class="space-y-8"> <div class="space-y-8">
<div class="flex flex-col items-center gap-4"> <div class="flex flex-col items-center gap-4">
<p>{{ $t("global.welcome", { username: username }) }}</p> <p>{{ $t("global.welcome", { username: username }) }}</p>
<NuxtLink class="avatar placeholder" to="/home"> <NuxtLink class="avatar placeholder" to="/home">
<div class="bg-base-300 text-neutral-content w-24 rounded-full p-4"> <div class="w-24 rounded-full bg-base-300 p-4 text-neutral-content">
<AppLogo /> <AppLogo />
</div> </div>
</NuxtLink> </NuxtLink>
</div> </div>
<div class="bg-base-200 flex flex-col"> <div class="flex flex-col bg-base-200">
<div class="mb-6"> <div class="mb-6">
<div class="dropdown visible w-full"> <div class="dropdown visible w-full">
<label tabindex="0" class="text-no-transform btn btn-primary btn-block text-lg"> <label tabindex="0" class="text-no-transform btn btn-primary btn-block text-lg">
@@ -61,7 +61,7 @@
</span> </span>
{{ $t("global.create") }} {{ $t("global.create") }}
</label> </label>
<ul tabindex="0" class="dropdown-content menu rounded-box bg-base-100 w-full p-2 shadow"> <ul tabindex="0" class="dropdown-content menu rounded-box w-full bg-base-100 p-2 shadow">
<li v-for="btn in dropdown" :key="btn.id"> <li v-for="btn in dropdown" :key="btn.id">
<button @click="btn.action"> <button @click="btn.action">
{{ btn.name.value }} {{ btn.name.value }}
@@ -89,7 +89,7 @@
</div> </div>
<!-- Bottom --> <!-- Bottom -->
<button class="rounded-btn hover:bg-base-300 mx-2 mt-auto p-3" @click="logout"> <button class="rounded-btn mx-2 mt-auto p-3 hover:bg-base-300" @click="logout">
{{ $t("global.sign_out") }} {{ $t("global.sign_out") }}
</button> </button>
</div> </div>

View File

@@ -148,9 +148,7 @@ describe("user should be able to create an item and add an attachment", () => {
{ {
const { response, data } = await api.items.maintenance.getLog(item.id); const { response, data } = await api.items.maintenance.getLog(item.id);
expect(response.status).toBe(200); expect(response.status).toBe(200);
expect(data.entries).toHaveLength(maintenanceEntries.length); expect(data).toHaveLength(maintenanceEntries.length);
expect(data.costAverage).toBeGreaterThan(0);
expect(data.costTotal).toBeGreaterThan(0);
} }
cleanup(); cleanup();

View File

@@ -12,7 +12,7 @@ import type {
MaintenanceEntryCreate, MaintenanceEntryCreate,
MaintenanceEntryWithDetails, MaintenanceEntryWithDetails,
} from "../types/data-contracts"; } from "../types/data-contracts";
import type { AttachmentTypes, PaginationResult } from "../types/non-generated"; import type { AttachmentTypes, ItemSummaryPaginationResult } from "../types/non-generated";
import type { MaintenanceFilters } from "./maintenance.ts"; import type { MaintenanceFilters } from "./maintenance.ts";
import type { Requests } from "~~/lib/requests"; import type { Requests } from "~~/lib/requests";
@@ -98,7 +98,7 @@ export class ItemsApi extends BaseAPI {
} }
getAll(q: ItemsQuery = {}) { getAll(q: ItemsQuery = {}) {
return this.http.get<PaginationResult<ItemSummary>>({ url: route("/items", q) }); return this.http.get<ItemSummaryPaginationResult<ItemSummary>>({ url: route("/items", q) });
} }
create(item: ItemCreate) { create(item: ItemCreate) {

View File

@@ -16,3 +16,7 @@ export interface PaginationResult<T> {
pageSize: number; pageSize: number;
total: number; total: number;
} }
export interface ItemSummaryPaginationResult<T> extends PaginationResult<T> {
totalPrice: number;
}

View File

@@ -8,7 +8,7 @@
"lint": "eslint --ext \".ts,.js,.vue\" --ignore-path ../.gitignore .", "lint": "eslint --ext \".ts,.js,.vue\" --ignore-path ../.gitignore .",
"lint:fix": "eslint --ext \".ts,.js,.vue\" --ignore-path ../.gitignore . --fix", "lint:fix": "eslint --ext \".ts,.js,.vue\" --ignore-path ../.gitignore . --fix",
"lint:ci": "eslint --ext \".ts,.js,.vue\" --ignore-path ../.gitignore . --max-warnings 1", "lint:ci": "eslint --ext \".ts,.js,.vue\" --ignore-path ../.gitignore . --max-warnings 1",
"typecheck": "nuxi typecheck", "typecheck": "pnpm dlx vue-tsc@2.1.6 --noEmit",
"test:ci": "TEST_SHUTDOWN_API_SERVER=true vitest --run --config ./test/vitest.config.ts", "test:ci": "TEST_SHUTDOWN_API_SERVER=true vitest --run --config ./test/vitest.config.ts",
"test:local": "TEST_SHUTDOWN_API_SERVER=false && vitest --run --config ./test/vitest.config.ts", "test:local": "TEST_SHUTDOWN_API_SERVER=false && vitest --run --config ./test/vitest.config.ts",
"test:watch": " TEST_SHUTDOWN_API_SERVER=false vitest --config ./test/vitest.config.ts" "test:watch": " TEST_SHUTDOWN_API_SERVER=false vitest --config ./test/vitest.config.ts"
@@ -23,6 +23,7 @@
"@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0", "@typescript-eslint/parser": "^6.21.0",
"@vite-pwa/nuxt": "^0.5.0", "@vite-pwa/nuxt": "^0.5.0",
"@vue/runtime-core": "^3.5.12",
"eslint": "^8.57.1", "eslint": "^8.57.1",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.2.1", "eslint-plugin-prettier": "^5.2.1",

View File

@@ -234,7 +234,7 @@
details.push({ details.push({
name, name,
text: "", text: "",
slot: slot, slot,
}); });
}; };
@@ -624,13 +624,4 @@
dialog::backdrop { dialog::backdrop {
background: rgba(0, 0, 0, 0.5); background: rgba(0, 0, 0, 0.5);
} }
.scroll-bg::-webkit-scrollbar {
width: 0.5rem;
}
.scroll-bg::-webkit-scrollbar-thumb {
border-radius: 0.25rem;
@apply bg-base-300;
}
</style> </style>

View File

@@ -106,7 +106,7 @@
if (item.value.soldPrice) { if (item.value.soldPrice) {
soldPrice = item.value.soldPrice; soldPrice = item.value.soldPrice;
} }
if (item.value.purchaseTime) { if (item.value.purchaseTime && typeof item.value.purchaseTime !== "string") {
purchaseTime = new Date(item.value.purchaseTime.getTime() - item.value.purchaseTime.getTimezoneOffset() * 60000); purchaseTime = new Date(item.value.purchaseTime.getTime() - item.value.purchaseTime.getTimezoneOffset() * 60000);
} }
@@ -121,7 +121,7 @@
assetId: item.value.assetId, assetId: item.value.assetId,
purchasePrice, purchasePrice,
soldPrice, soldPrice,
purchaseTime, purchaseTime: purchaseTime as Date,
}; };
const { error } = await api.items.update(itemId.value, payload); const { error } = await api.items.update(itemId.value, payload);
@@ -611,7 +611,7 @@
</div> </div>
</div> </div>
<div class="mt-4 flex justify-end px-5 pb-4"> <div class="mt-4 flex justify-end px-5 pb-4">
<BaseButton size="sm" @click="addField"> {{$t("global.add")}} </BaseButton> <BaseButton size="sm" @click="addField"> {{ $t("global.add") }} </BaseButton>
</div> </div>
</BaseCard> </BaseCard>
@@ -621,7 +621,7 @@
class="card overflow-visible bg-base-100 shadow-xl sm:rounded-lg" class="card overflow-visible bg-base-100 shadow-xl sm:rounded-lg"
> >
<div class="px-4 py-5 sm:px-6"> <div class="px-4 py-5 sm:px-6">
<h3 class="text-lg font-medium leading-6"> {{ $t("items.attachments") }} </h3> <h3 class="text-lg font-medium leading-6">{{ $t("items.attachments") }}</h3>
<p class="text-xs">{{ $t("items.changes_persisted_immediately") }}</p> <p class="text-xs">{{ $t("items.changes_persisted_immediately") }}</p>
</div> </div>
<div class="border-t border-gray-300 p-4"> <div class="border-t border-gray-300 p-4">

View File

@@ -76,7 +76,10 @@
const items = computedAsync(async () => { const items = computedAsync(async () => {
if (!label.value) { if (!label.value) {
return []; return {
items: [],
totalPrice: null,
};
} }
const resp = await api.items.getAll({ const resp = await api.items.getAll({
@@ -85,7 +88,10 @@
if (resp.error) { if (resp.error) {
toast.error("Failed to load items"); toast.error("Failed to load items");
return []; return {
items: [],
totalPrice: null,
};
} }
return resp.data; return resp.data;
@@ -104,9 +110,13 @@
:max-length="255" :max-length="255"
:min-length="1" :min-length="1"
/> />
<FormTextArea v-model="updateData.description" :label="$t('components.label.create_modal.label_description')" :max-length="255" /> <FormTextArea
v-model="updateData.description"
:label="$t('components.label.create_modal.label_description')"
:max-length="255"
/>
<div class="modal-action"> <div class="modal-action">
<BaseButton type="submit" :loading="updating"> {{$t("global.update")}} </BaseButton> <BaseButton type="submit" :loading="updating"> {{ $t("global.update") }} </BaseButton>
</div> </div>
</form> </form>
</BaseModal> </BaseModal>

View File

@@ -111,8 +111,18 @@
<BaseModal v-model="updateModal"> <BaseModal v-model="updateModal">
<template #title> {{ $t("locations.update_location") }} </template> <template #title> {{ $t("locations.update_location") }} </template>
<form v-if="location" @submit.prevent="update"> <form v-if="location" @submit.prevent="update">
<FormTextField v-model="updateData.name" :autofocus="true" :label="$t('components.location.create_modal.location_name')" :max-length="255" :min-length="1" /> <FormTextField
<FormTextArea v-model="updateData.description" :label="$t('components.location.create_modal.location_description')" :max-length="1000" /> v-model="updateData.name"
:autofocus="true"
:label="$t('components.location.create_modal.location_name')"
:max-length="255"
:min-length="1"
/>
<FormTextArea
v-model="updateData.description"
:label="$t('components.location.create_modal.location_description')"
:max-length="1000"
/>
<LocationSelector v-model="parent" /> <LocationSelector v-model="parent" />
<div class="modal-action"> <div class="modal-action">
<BaseButton type="submit" :loading="updating"> {{ $t("global.update") }} </BaseButton> <BaseButton type="submit" :loading="updating"> {{ $t("global.update") }} </BaseButton>
@@ -180,7 +190,7 @@
</section> </section>
<section v-if="location && location.children.length > 0" class="mt-6"> <section v-if="location && location.children.length > 0" class="mt-6">
<BaseSectionHeader class="mb-5"> {{ t("locations.child_locations") }} </BaseSectionHeader> <BaseSectionHeader class="mb-5"> {{ $t("locations.child_locations") }} </BaseSectionHeader>
<div class="grid grid-cols-1 gap-2 sm:grid-cols-3"> <div class="grid grid-cols-1 gap-2 sm:grid-cols-3">
<LocationCard v-for="item in location.children" :key="item.id" :location="item" /> <LocationCard v-for="item in location.children" :key="item.id" :location="item" />
</div> </div>

View File

@@ -8,7 +8,6 @@
import MdiFill from "~icons/mdi/fill"; import MdiFill from "~icons/mdi/fill";
import MdiPencil from "~icons/mdi/pencil"; import MdiPencil from "~icons/mdi/pencil";
import MdiAccountMultiple from "~icons/mdi/account-multiple"; import MdiAccountMultiple from "~icons/mdi/account-multiple";
import { useI18n } from "vue-i18n";
definePageMeta({ definePageMeta({
middleware: ["auth"], middleware: ["auth"],
@@ -20,7 +19,6 @@ import { useI18n } from "vue-i18n";
const api = useUserApi(); const api = useUserApi();
const confirm = useConfirm(); const confirm = useConfirm();
const notify = useNotifier(); const notify = useNotifier();
const { t } = useI18n();
const currencies = computedAsync(async () => { const currencies = computedAsync(async () => {
const resp = await api.group.currencies(); const resp = await api.group.currencies();
@@ -378,8 +376,15 @@ import { useI18n } from "vue-i18n";
<label class="label"> <label class="label">
<span class="label-text">{{ $t("profile.language") }}</span> <span class="label-text">{{ $t("profile.language") }}</span>
</label> </label>
<select v-model="$i18n.locale" @change="(event) => {setLanguage((event.target as HTMLSelectElement).value )}" <select
class="select select-bordered"> v-model="$i18n.locale"
class="select select-bordered"
@change="
event => {
setLanguage((event.target as HTMLSelectElement).value);
}
"
>
<option v-for="lang in $i18n.availableLocales" :key="lang" :value="lang"> <option v-for="lang in $i18n.availableLocales" :key="lang" :value="lang">
{{ $t(`languages.${lang}`) }} ({{ $t(`languages.${lang}`, 1, { locale: lang }) }}) {{ $t(`languages.${lang}`) }} ({{ $t(`languages.${lang}`, 1, { locale: lang }) }})
</option> </option>
@@ -447,7 +452,7 @@ import { useI18n } from "vue-i18n";
<div v-if="group && currencies && currencies.length > 0" class="p-5 pt-0"> <div v-if="group && currencies && currencies.length > 0" class="p-5 pt-0">
<FormSelect v-model="currency" :label="$t('profile.currency_format')" :items="currencies" /> <FormSelect v-model="currency" :label="$t('profile.currency_format')" :items="currencies" />
<p class="m-2 text-sm">{{$t("profile.example")}}: {{ currencyExample }}</p> <p class="m-2 text-sm">{{ $t("profile.example") }}: {{ currencyExample }}</p>
<div class="mt-4"> <div class="mt-4">
<BaseButton size="sm" @click="updateGroup"> {{ $t("profile.update_group") }} </BaseButton> <BaseButton size="sm" @click="updateGroup"> {{ $t("profile.update_group") }} </BaseButton>

View File

@@ -200,7 +200,9 @@
const { data, error } = await api.items.getAll(); const { data, error } = await api.items.getAll();
if (error) { if (error) {
return []; return {
items: [],
};
} }
return data; return data;
@@ -219,7 +221,12 @@
const items: LabelData[] = []; const items: LabelData[] = [];
for (let i = displayProperties.assetRange; i < displayProperties.assetRangeMax; i++) { for (let i = displayProperties.assetRange; i < displayProperties.assetRangeMax; i++) {
items.push(getItem(i, allFields?.value?.items?.[i] ?? null)); const item = allFields?.value?.items?.[i];
if (item?.location) {
items.push(getItem(i, item as { location: { name: string }; name: string }));
} else {
items.push(getItem(i, null));
}
} }
return items; return items;
}); });

View File

@@ -39,6 +39,7 @@
<div class="divide-y divide-gray-300 border-t border-gray-300 px-6 pb-3"> <div class="divide-y divide-gray-300 border-t border-gray-300 px-6 pb-3">
<DetailAction @action="modals.import = true"> <DetailAction @action="modals.import = true">
<template #title> {{ $t("tools.import_export_set.import") }} </template> <template #title> {{ $t("tools.import_export_set.import") }} </template>
<!-- eslint-disable-next-line vue/no-v-html -->
<div v-html="$t('tools.import_export_set.import_sub')"></div> <div v-html="$t('tools.import_export_set.import_sub')"></div>
<template #button> {{ $t("tools.import_export_set.import_button") }} </template> <template #button> {{ $t("tools.import_export_set.import_button") }} </template>
</DetailAction> </DetailAction>
@@ -55,6 +56,7 @@
<MdiAlert class="mr-2" /> <MdiAlert class="mr-2" />
<span> {{ $t("tools.actions") }} </span> <span> {{ $t("tools.actions") }} </span>
<template #description> <template #description>
<!-- eslint-disable-next-line vue/no-v-html -->
<div v-html="$t('tools.actions_sub')"></div> <div v-html="$t('tools.actions_sub')"></div>
</template> </template>
</BaseSectionHeader> </BaseSectionHeader>
@@ -72,11 +74,13 @@
</DetailAction> </DetailAction>
<DetailAction @action="resetItemDateTimes"> <DetailAction @action="resetItemDateTimes">
<template #title> {{ $t("tools.actions_set.zero_datetimes") }} </template> <template #title> {{ $t("tools.actions_set.zero_datetimes") }} </template>
<!-- eslint-disable-next-line vue/no-v-html -->
<div v-html="$t('tools.actions_set.zero_datetimes_sub')"></div> <div v-html="$t('tools.actions_set.zero_datetimes_sub')"></div>
<template #button> {{ $t("tools.actions_set.zero_datetimes_button") }} </template> <template #button> {{ $t("tools.actions_set.zero_datetimes_button") }} </template>
</DetailAction> </DetailAction>
<DetailAction @action="setPrimaryPhotos"> <DetailAction @action="setPrimaryPhotos">
<template #title> {{ $t("tools.actions_set.set_primary_photo") }} </template> <template #title> {{ $t("tools.actions_set.set_primary_photo") }} </template>
<!-- eslint-disable-next-line vue/no-v-html -->
<div v-html="$t('tools.actions_set.set_primary_photo_sub')"></div> <div v-html="$t('tools.actions_set.set_primary_photo_sub')"></div>
<template #button> {{ $t("tools.actions_set.set_primary_photo_button") }} </template> <template #button> {{ $t("tools.actions_set.set_primary_photo_button") }} </template>
</DetailAction> </DetailAction>

View File

@@ -105,6 +105,9 @@ importers:
'@vite-pwa/nuxt': '@vite-pwa/nuxt':
specifier: ^0.5.0 specifier: ^0.5.0
version: 0.5.0(magicast@0.3.5)(rollup@4.24.0)(vite@4.5.5(@types/node@22.7.4)(terser@5.34.1))(webpack-sources@3.2.3)(workbox-build@7.1.1)(workbox-window@7.1.0) version: 0.5.0(magicast@0.3.5)(rollup@4.24.0)(vite@4.5.5(@types/node@22.7.4)(terser@5.34.1))(webpack-sources@3.2.3)(workbox-build@7.1.1)(workbox-window@7.1.0)
'@vue/runtime-core':
specifier: ^3.5.12
version: 3.5.12
eslint: eslint:
specifier: ^8.57.1 specifier: ^8.57.1
version: 8.57.1 version: 8.57.1
@@ -2083,9 +2086,15 @@ packages:
'@vue/reactivity@3.4.8': '@vue/reactivity@3.4.8':
resolution: {integrity: sha512-UJYMQ3S2rqIGw9IvKomD4Xw2uS5VlcKEEmwcfboGOdrI79oqebxnCgTvXWLMClvg3M5SF0Cyn+9eDQoyGMLu9Q==} resolution: {integrity: sha512-UJYMQ3S2rqIGw9IvKomD4Xw2uS5VlcKEEmwcfboGOdrI79oqebxnCgTvXWLMClvg3M5SF0Cyn+9eDQoyGMLu9Q==}
'@vue/reactivity@3.5.12':
resolution: {integrity: sha512-UzaN3Da7xnJXdz4Okb/BGbAaomRHc3RdoWqTzlvd9+WBR5m3J39J1fGcHes7U3za0ruYn/iYy/a1euhMEHvTAg==}
'@vue/runtime-core@3.4.8': '@vue/runtime-core@3.4.8':
resolution: {integrity: sha512-sMRXOy89KnwY6fWG5epgPOsCWzpo/64FrA0QkjIeNeGnoA2YyZ6bBUxpFUyqhJ8VbrDhXEFH+6LHMOYrpzX/ZQ==} resolution: {integrity: sha512-sMRXOy89KnwY6fWG5epgPOsCWzpo/64FrA0QkjIeNeGnoA2YyZ6bBUxpFUyqhJ8VbrDhXEFH+6LHMOYrpzX/ZQ==}
'@vue/runtime-core@3.5.12':
resolution: {integrity: sha512-hrMUYV6tpocr3TL3Ad8DqxOdpDe4zuQY4HPY3X/VRh+L2myQO8MFXPAMarIOSGNu0bFAjh1yBkMPXZBqCk62Uw==}
'@vue/runtime-dom@3.4.8': '@vue/runtime-dom@3.4.8':
resolution: {integrity: sha512-L4gZcYo8f3d7rQqQIHkPvyczkjjQ55cJqz2G0v6Ptmqa1mO2zkqN9F8lBT6aGPYy3hd0RDiINbs4jxhSvvy10Q==} resolution: {integrity: sha512-L4gZcYo8f3d7rQqQIHkPvyczkjjQ55cJqz2G0v6Ptmqa1mO2zkqN9F8lBT6aGPYy3hd0RDiINbs4jxhSvvy10Q==}
@@ -2100,6 +2109,9 @@ packages:
'@vue/shared@3.5.11': '@vue/shared@3.5.11':
resolution: {integrity: sha512-W8GgysJVnFo81FthhzurdRAWP/byq3q2qIw70e0JWblzVhjgOMiC2GyovXrZTFQJnFVryYaKGP3Tc9vYzYm6PQ==} resolution: {integrity: sha512-W8GgysJVnFo81FthhzurdRAWP/byq3q2qIw70e0JWblzVhjgOMiC2GyovXrZTFQJnFVryYaKGP3Tc9vYzYm6PQ==}
'@vue/shared@3.5.12':
resolution: {integrity: sha512-L2RPSAwUFbgZH20etwrXyVyCBu9OxRSi8T/38QsvnkJyvq2LufW2lDCOzm7t/U9C1mkhJGWYfCuFBCmIuNivrg==}
'@vuepic/vue-datepicker@8.8.1': '@vuepic/vue-datepicker@8.8.1':
resolution: {integrity: sha512-8ehfUz1m69Vuc16Pm4ukgb3Mg1VT14x4EsG1ag4O/qbSNRWztTo+pUV4JnFt0FGLl5gGb6NXlxIvR7EjLgD7Gg==} resolution: {integrity: sha512-8ehfUz1m69Vuc16Pm4ukgb3Mg1VT14x4EsG1ag4O/qbSNRWztTo+pUV4JnFt0FGLl5gGb6NXlxIvR7EjLgD7Gg==}
peerDependencies: peerDependencies:
@@ -7271,7 +7283,7 @@ snapshots:
'@nuxtjs/eslint-config-typescript@12.1.0(eslint@8.57.1)(typescript@5.6.2)': '@nuxtjs/eslint-config-typescript@12.1.0(eslint@8.57.1)(typescript@5.6.2)':
dependencies: dependencies:
'@nuxtjs/eslint-config': 12.0.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1) '@nuxtjs/eslint-config': 12.0.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
'@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1)(typescript@5.6.2) '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint@8.57.1)(typescript@5.6.2)
'@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.6.2) '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.6.2)
eslint: 8.57.1 eslint: 8.57.1
@@ -7285,10 +7297,10 @@ snapshots:
- supports-color - supports-color
- typescript - typescript
'@nuxtjs/eslint-config@12.0.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1)': '@nuxtjs/eslint-config@12.0.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)':
dependencies: dependencies:
eslint: 8.57.1 eslint: 8.57.1
eslint-config-standard: 17.1.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1))(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1) eslint-config-standard: 17.1.0(eslint-plugin-import@2.31.0)(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1)
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
eslint-plugin-n: 15.7.0(eslint@8.57.1) eslint-plugin-n: 15.7.0(eslint@8.57.1)
eslint-plugin-node: 11.1.0(eslint@8.57.1) eslint-plugin-node: 11.1.0(eslint@8.57.1)
@@ -7953,11 +7965,20 @@ snapshots:
dependencies: dependencies:
'@vue/shared': 3.4.8 '@vue/shared': 3.4.8
'@vue/reactivity@3.5.12':
dependencies:
'@vue/shared': 3.5.12
'@vue/runtime-core@3.4.8': '@vue/runtime-core@3.4.8':
dependencies: dependencies:
'@vue/reactivity': 3.4.8 '@vue/reactivity': 3.4.8
'@vue/shared': 3.4.8 '@vue/shared': 3.4.8
'@vue/runtime-core@3.5.12':
dependencies:
'@vue/reactivity': 3.5.12
'@vue/shared': 3.5.12
'@vue/runtime-dom@3.4.8': '@vue/runtime-dom@3.4.8':
dependencies: dependencies:
'@vue/runtime-core': 3.4.8 '@vue/runtime-core': 3.4.8
@@ -7974,6 +7995,8 @@ snapshots:
'@vue/shared@3.5.11': {} '@vue/shared@3.5.11': {}
'@vue/shared@3.5.12': {}
'@vuepic/vue-datepicker@8.8.1(vue@3.4.8(typescript@5.6.2))': '@vuepic/vue-datepicker@8.8.1(vue@3.4.8(typescript@5.6.2))':
dependencies: dependencies:
date-fns: 3.6.0 date-fns: 3.6.0
@@ -8981,7 +9004,7 @@ snapshots:
dependencies: dependencies:
eslint: 8.57.1 eslint: 8.57.1
eslint-config-standard@17.1.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1))(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1): eslint-config-standard@17.1.0(eslint-plugin-import@2.31.0)(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1):
dependencies: dependencies:
eslint: 8.57.1 eslint: 8.57.1
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
@@ -9002,7 +9025,7 @@ snapshots:
debug: 4.3.7 debug: 4.3.7
enhanced-resolve: 5.17.1 enhanced-resolve: 5.17.1
eslint: 8.57.1 eslint: 8.57.1
eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1) eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
fast-glob: 3.3.2 fast-glob: 3.3.2
get-tsconfig: 4.8.1 get-tsconfig: 4.8.1
is-bun-module: 1.2.1 is-bun-module: 1.2.1
@@ -9015,7 +9038,7 @@ snapshots:
- eslint-import-resolver-webpack - eslint-import-resolver-webpack
- supports-color - supports-color
eslint-module-utils@2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1): eslint-module-utils@2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1):
dependencies: dependencies:
debug: 3.2.7 debug: 3.2.7
optionalDependencies: optionalDependencies:
@@ -9049,7 +9072,7 @@ snapshots:
doctrine: 2.1.0 doctrine: 2.1.0
eslint: 8.57.1 eslint: 8.57.1
eslint-import-resolver-node: 0.3.9 eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1) eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)
hasown: 2.0.2 hasown: 2.0.2
is-core-module: 2.15.1 is-core-module: 2.15.1
is-glob: 4.0.3 is-glob: 4.0.3

View File

@@ -2,6 +2,7 @@ import path from "path";
import { defineConfig } from "vite"; import { defineConfig } from "vite";
export default defineConfig({ export default defineConfig({
// @ts-ignore
test: { test: {
globalSetup: "./test/setup.ts", globalSetup: "./test/setup.ts",
}, },