mirror of
https://github.com/hay-kot/homebox.git
synced 2025-08-03 16:20:27 +00:00
use eslint for formatting
This commit is contained in:
parent
beefb88367
commit
a8780c942a
55 changed files with 456 additions and 457 deletions
51
frontend/.eslintrc.js
Normal file
51
frontend/.eslintrc.js
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
module.exports = {
|
||||||
|
env: {
|
||||||
|
browser: true,
|
||||||
|
es2021: true,
|
||||||
|
node: true,
|
||||||
|
},
|
||||||
|
extends: [
|
||||||
|
"eslint:recommended",
|
||||||
|
"plugin:vue/essential",
|
||||||
|
"plugin:@typescript-eslint/recommended",
|
||||||
|
"@nuxtjs/eslint-config-typescript",
|
||||||
|
"plugin:vue/vue3-recommended",
|
||||||
|
"plugin:prettier/recommended",
|
||||||
|
],
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: "latest",
|
||||||
|
parser: "@typescript-eslint/parser",
|
||||||
|
sourceType: "module",
|
||||||
|
},
|
||||||
|
plugins: ["vue", "@typescript-eslint"],
|
||||||
|
rules: {
|
||||||
|
"vue/multi-word-component-names": "off",
|
||||||
|
"vue/no-setup-props-destructure": 0,
|
||||||
|
"vue/no-multiple-template-root": 0,
|
||||||
|
"no-console": 0,
|
||||||
|
"vue/no-v-model-argument": 0,
|
||||||
|
"@typescript-eslint/ban-ts-comment": 0,
|
||||||
|
"no-unused-vars": "off",
|
||||||
|
"@typescript-eslint/no-unused-vars": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
ignoreRestSiblings: true,
|
||||||
|
destructuredArrayIgnorePattern: "_",
|
||||||
|
caughtErrors: "none",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"prettier/prettier": [
|
||||||
|
"warn",
|
||||||
|
{
|
||||||
|
arrowParens: "avoid",
|
||||||
|
semi: true,
|
||||||
|
tabWidth: 2,
|
||||||
|
useTabs: false,
|
||||||
|
vueIndentScriptAndStyle: true,
|
||||||
|
singleQuote: false,
|
||||||
|
trailingComma: "es5",
|
||||||
|
printWidth: 120,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
|
@ -1,42 +0,0 @@
|
||||||
{
|
|
||||||
"env": {
|
|
||||||
"browser": true,
|
|
||||||
"es2021": true,
|
|
||||||
"node": true
|
|
||||||
},
|
|
||||||
"extends": [
|
|
||||||
"eslint:recommended",
|
|
||||||
"plugin:vue/essential",
|
|
||||||
"plugin:@typescript-eslint/recommended",
|
|
||||||
"@nuxtjs/eslint-config-typescript",
|
|
||||||
"plugin:vue/vue3-recommended",
|
|
||||||
"plugin:prettier/recommended"
|
|
||||||
],
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": "latest",
|
|
||||||
"parser": "@typescript-eslint/parser",
|
|
||||||
"sourceType": "module"
|
|
||||||
},
|
|
||||||
"plugins": ["vue", "@typescript-eslint"],
|
|
||||||
"rules": {
|
|
||||||
"vue/multi-word-component-names": "off",
|
|
||||||
"vue/no-setup-props-destructure": 0,
|
|
||||||
"vue/no-multiple-template-root": 0,
|
|
||||||
"no-console": 1,
|
|
||||||
"vue/no-v-model-argument": 0,
|
|
||||||
"@typescript-eslint/ban-ts-comment": 0,
|
|
||||||
"prettier/prettier": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
"arrowParens": "avoid",
|
|
||||||
"semi": true,
|
|
||||||
"tabWidth": 2,
|
|
||||||
"useTabs": false,
|
|
||||||
"vueIndentScriptAndStyle": true,
|
|
||||||
"singleQuote": true,
|
|
||||||
"trailingComma": "es5",
|
|
||||||
"printWidth": 120
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"arrowParens": "avoid",
|
|
||||||
"semi": true,
|
|
||||||
"tabWidth": 2,
|
|
||||||
"useTabs": false,
|
|
||||||
"vueIndentScriptAndStyle": true,
|
|
||||||
"singleQuote": true,
|
|
||||||
"trailingComma": "es5",
|
|
||||||
"printWidth": 120
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useAuthStore } from '~~/stores/auth';
|
import { useAuthStore } from "~~/stores/auth";
|
||||||
|
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
const api = useUserApi();
|
const api = useUserApi();
|
||||||
|
@ -10,16 +10,16 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
navigateTo('/');
|
navigateTo("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
const links = [
|
const links = [
|
||||||
{
|
{
|
||||||
name: 'Home',
|
name: "Home",
|
||||||
href: '/home',
|
href: "/home",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Logout',
|
name: "Logout",
|
||||||
action: logout,
|
action: logout,
|
||||||
last: true,
|
last: true,
|
||||||
},
|
},
|
||||||
|
@ -33,19 +33,19 @@
|
||||||
|
|
||||||
const dropdown = [
|
const dropdown = [
|
||||||
{
|
{
|
||||||
name: 'Item / Asset',
|
name: "Item / Asset",
|
||||||
action: () => {
|
action: () => {
|
||||||
modals.item = true;
|
modals.item = true;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Location',
|
name: "Location",
|
||||||
action: () => {
|
action: () => {
|
||||||
modals.location = true;
|
modals.location = true;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Label',
|
name: "Label",
|
||||||
action: () => {
|
action: () => {
|
||||||
modals.label = true;
|
modals.label = true;
|
||||||
},
|
},
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useNotifications } from '@/composables/use-notifier';
|
import { useNotifications } from "@/composables/use-notifier";
|
||||||
|
|
||||||
const { notifications, dropNotification } = useNotifications();
|
const { notifications, dropNotification } = useNotifications();
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
type Sizes = 'sm' | 'md' | 'lg';
|
type Sizes = "sm" | "md" | "lg";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
loading: {
|
loading: {
|
||||||
|
@ -48,7 +48,7 @@
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
type: String as () => Sizes,
|
type: String as () => Sizes,
|
||||||
default: 'md',
|
default: "md",
|
||||||
},
|
},
|
||||||
to: {
|
to: {
|
||||||
type: String as () => string | null,
|
type: String as () => string | null,
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
defineProps({
|
defineProps({
|
||||||
cmp: {
|
cmp: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'div',
|
default: "div",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const emit = defineEmits(['cancel', 'update:modelValue']);
|
const emit = defineEmits(["cancel", "update:modelValue"]);
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
@ -34,12 +34,12 @@
|
||||||
|
|
||||||
function close() {
|
function close() {
|
||||||
if (props.readonly) {
|
if (props.readonly) {
|
||||||
emit('cancel');
|
emit("cancel");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
modal.value = false;
|
modal.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const modalId = useId();
|
const modalId = useId();
|
||||||
const modal = useVModel(props, 'modelValue', emit);
|
const modal = useVModel(props, "modelValue", emit);
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const emit = defineEmits(['update:modelValue', 'update:text']);
|
const emit = defineEmits(["update:modelValue", "update:text"]);
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: {
|
modelValue: {
|
||||||
|
@ -50,12 +50,12 @@
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const selected = useVModel(props, 'modelValue', emit);
|
const selected = useVModel(props, "modelValue", emit);
|
||||||
const dateText = computed(() => {
|
const dateText = computed(() => {
|
||||||
if (selected.value) {
|
if (selected.value) {
|
||||||
return selected.value.toLocaleDateString();
|
return selected.value.toLocaleDateString();
|
||||||
}
|
}
|
||||||
return '';
|
return "";
|
||||||
});
|
});
|
||||||
|
|
||||||
const time = ref(new Date());
|
const time = ref(new Date());
|
||||||
|
@ -69,7 +69,7 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
const month = computed(() => {
|
const month = computed(() => {
|
||||||
return time.value.toLocaleString('default', { month: 'long' });
|
return time.value.toLocaleString("default", { month: "long" });
|
||||||
});
|
});
|
||||||
|
|
||||||
const year = computed(() => {
|
const year = computed(() => {
|
||||||
|
@ -87,7 +87,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
const daysIdx = computed(() => {
|
const daysIdx = computed(() => {
|
||||||
return ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
|
return ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
|
||||||
});
|
});
|
||||||
|
|
||||||
function select(e: MouseEvent, day: Date) {
|
function select(e: MouseEvent, day: Date) {
|
||||||
|
@ -117,7 +117,7 @@
|
||||||
|
|
||||||
for (let i = 0; i < firstDay; i++) {
|
for (let i = 0; i < firstDay; i++) {
|
||||||
days.push({
|
days.push({
|
||||||
number: '',
|
number: "",
|
||||||
date: new Date(),
|
date: new Date(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<div class="dropdown dropdown-top sm:dropdown-end">
|
<div class="dropdown dropdown-top sm:dropdown-end">
|
||||||
<div tabindex="0" class="w-full min-h-[48px] flex gap-2 p-4 flex-wrap border border-gray-400 rounded-lg">
|
<div tabindex="0" class="w-full min-h-[48px] flex gap-2 p-4 flex-wrap border border-gray-400 rounded-lg">
|
||||||
<span v-for="itm in value" :key="name != '' ? itm[name] : itm" class="badge">
|
<span v-for="itm in value" :key="name != '' ? itm[name] : itm" class="badge">
|
||||||
{{ name != '' ? itm[name] : itm }}
|
{{ name != "" ? itm[name] : itm }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<ul
|
<ul
|
||||||
|
@ -21,7 +21,7 @@
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<button type="button" @click="toggle(idx)">
|
<button type="button" @click="toggle(idx)">
|
||||||
{{ name != '' ? obj[name] : obj }}
|
{{ name != "" ? obj[name] : obj }}
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -30,11 +30,11 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
const emit = defineEmits(['update:modelValue']);
|
const emit = defineEmits(["update:modelValue"]);
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
label: {
|
label: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: "",
|
||||||
},
|
},
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: Array as () => any[],
|
type: Array as () => any[],
|
||||||
|
@ -46,7 +46,7 @@
|
||||||
},
|
},
|
||||||
name: {
|
name: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'name',
|
default: "name",
|
||||||
},
|
},
|
||||||
selectFirst: {
|
selectFirst: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
@ -77,5 +77,5 @@
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const value = useVModel(props, 'modelValue', emit);
|
const value = useVModel(props, "modelValue", emit);
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<select v-model="value" class="select select-bordered">
|
<select v-model="value" class="select select-bordered">
|
||||||
<option disabled selected>Pick one</option>
|
<option disabled selected>Pick one</option>
|
||||||
<option v-for="obj in items" :key="name != '' ? obj[name] : obj" :value="obj">
|
<option v-for="obj in items" :key="name != '' ? obj[name] : obj" :value="obj">
|
||||||
{{ name != '' ? obj[name] : obj }}
|
{{ name != "" ? obj[name] : obj }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
<!-- <label class="label">
|
<!-- <label class="label">
|
||||||
|
@ -17,11 +17,11 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
const emit = defineEmits(['update:modelValue']);
|
const emit = defineEmits(["update:modelValue"]);
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
label: {
|
label: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: "",
|
||||||
},
|
},
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: Object as any,
|
type: Object as any,
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
},
|
},
|
||||||
name: {
|
name: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'name',
|
default: "name",
|
||||||
},
|
},
|
||||||
selectFirst: {
|
selectFirst: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
@ -50,5 +50,5 @@
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const value = useVModel(props, 'modelValue', emit);
|
const value = useVModel(props, "modelValue", emit);
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
const emit = defineEmits(['update:modelValue']);
|
const emit = defineEmits(["update:modelValue"]);
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: [String],
|
type: [String],
|
||||||
|
@ -35,7 +35,7 @@
|
||||||
},
|
},
|
||||||
type: {
|
type: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'text',
|
default: "text",
|
||||||
},
|
},
|
||||||
limit: {
|
limit: {
|
||||||
type: [Number, String],
|
type: [Number, String],
|
||||||
|
@ -43,7 +43,7 @@
|
||||||
},
|
},
|
||||||
placeholder: {
|
placeholder: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: "",
|
||||||
},
|
},
|
||||||
inline: {
|
inline: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
@ -51,7 +51,7 @@
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const value = useVModel(props, 'modelValue', emit);
|
const value = useVModel(props, "modelValue", emit);
|
||||||
const valueLen = computed(() => {
|
const valueLen = computed(() => {
|
||||||
return value.value ? value.value.length : 0;
|
return value.value ? value.value.length : 0;
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
label: {
|
label: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: "",
|
||||||
},
|
},
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: [String, Number],
|
type: [String, Number],
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
},
|
},
|
||||||
type: {
|
type: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'text',
|
default: "text",
|
||||||
},
|
},
|
||||||
triggerFocus: {
|
triggerFocus: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
@ -48,5 +48,5 @@
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const value = useVModel(props, 'modelValue');
|
const value = useVModel(props, "modelValue");
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { Ref } from 'vue';
|
import type { Ref } from "vue";
|
||||||
import type { IconifyIcon } from '@iconify/vue';
|
import type { IconifyIcon } from "@iconify/vue";
|
||||||
import { Icon as Iconify, loadIcon } from '@iconify/vue';
|
import { Icon as Iconify, loadIcon } from "@iconify/vue";
|
||||||
|
|
||||||
const nuxtApp = useNuxtApp();
|
const nuxtApp = useNuxtApp();
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
@ -14,12 +14,12 @@
|
||||||
const icon: Ref<IconifyIcon | null> = ref(null);
|
const icon: Ref<IconifyIcon | null> = ref(null);
|
||||||
const component = computed(() => nuxtApp.vueApp.component(props.name));
|
const component = computed(() => nuxtApp.vueApp.component(props.name));
|
||||||
|
|
||||||
icon.value = await loadIcon(props.name).catch(_ => null);
|
icon.value = await loadIcon(props.name).catch(() => null);
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.name,
|
() => props.name,
|
||||||
async () => {
|
async () => {
|
||||||
icon.value = await loadIcon(props.name).catch(_ => null);
|
icon.value = await loadIcon(props.name).catch(() => null);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Item } from '~~/lib/api/classes/items';
|
import { Item } from "~~/lib/api/classes/items";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
item: {
|
item: {
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { type Location } from '~~/lib/api/classes/locations';
|
import { type Location } from "~~/lib/api/classes/locations";
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
@ -36,21 +36,21 @@
|
||||||
|
|
||||||
const submitBtn = ref(null);
|
const submitBtn = ref(null);
|
||||||
|
|
||||||
const modal = useVModel(props, 'modelValue');
|
const modal = useVModel(props, "modelValue");
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const focused = ref(false);
|
const focused = ref(false);
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
location: {} as Location,
|
location: {} as Location,
|
||||||
name: '',
|
name: "",
|
||||||
description: '',
|
description: "",
|
||||||
color: '', // Future!
|
color: "", // Future!
|
||||||
labels: [],
|
labels: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
function reset() {
|
function reset() {
|
||||||
form.name = '';
|
form.name = "";
|
||||||
form.description = '';
|
form.description = "";
|
||||||
form.color = '';
|
form.color = "";
|
||||||
focused.value = false;
|
focused.value = false;
|
||||||
modal.value = false;
|
modal.value = false;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
@ -93,7 +93,7 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
toast.success('Item created');
|
toast.success("Item created");
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Label } from '~~/lib/api/classes/labels';
|
import { Label } from "~~/lib/api/classes/labels";
|
||||||
|
|
||||||
export type sizes = 'sm' | 'md' | 'lg';
|
export type sizes = "sm" | "md" | "lg";
|
||||||
defineProps({
|
defineProps({
|
||||||
label: {
|
label: {
|
||||||
type: Object as () => Label,
|
type: Object as () => Label,
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
type: String as () => sizes,
|
type: String as () => sizes,
|
||||||
default: 'md',
|
default: "md",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -25,19 +25,19 @@
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const modal = useVModel(props, 'modelValue');
|
const modal = useVModel(props, "modelValue");
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const focused = ref(false);
|
const focused = ref(false);
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
name: '',
|
name: "",
|
||||||
description: '',
|
description: "",
|
||||||
color: '', // Future!
|
color: "", // Future!
|
||||||
});
|
});
|
||||||
|
|
||||||
function reset() {
|
function reset() {
|
||||||
form.name = '';
|
form.name = "";
|
||||||
form.description = '';
|
form.description = "";
|
||||||
form.color = '';
|
form.color = "";
|
||||||
focused.value = false;
|
focused.value = false;
|
||||||
modal.value = false;
|
modal.value = false;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
@ -60,7 +60,7 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
toast.success('Label created');
|
toast.success("Label created");
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { Location } from '~~/lib/api/classes/locations';
|
import { Location } from "~~/lib/api/classes/locations";
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
location: {
|
location: {
|
||||||
|
|
|
@ -25,12 +25,12 @@
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const modal = useVModel(props, 'modelValue');
|
const modal = useVModel(props, "modelValue");
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const focused = ref(false);
|
const focused = ref(false);
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
name: '',
|
name: "",
|
||||||
description: '',
|
description: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
whenever(
|
whenever(
|
||||||
|
@ -41,8 +41,8 @@
|
||||||
);
|
);
|
||||||
|
|
||||||
function reset() {
|
function reset() {
|
||||||
form.name = '';
|
form.name = "";
|
||||||
form.description = '';
|
form.description = "";
|
||||||
focused.value = false;
|
focused.value = false;
|
||||||
modal.value = false;
|
modal.value = false;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
@ -61,7 +61,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
toast.success('Location created');
|
toast.success("Location created");
|
||||||
navigateTo(`/location/${data.id}`);
|
navigateTo(`/location/${data.id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
import { PublicApi } from '~~/lib/api/public';
|
import { PublicApi } from "~~/lib/api/public";
|
||||||
import { UserApi } from '~~/lib/api/user';
|
import { UserApi } from "~~/lib/api/user";
|
||||||
import { Requests } from '~~/lib/requests';
|
import { Requests } from "~~/lib/requests";
|
||||||
import { useAuthStore } from '~~/stores/auth';
|
import { useAuthStore } from "~~/stores/auth";
|
||||||
|
|
||||||
function logger(r: Response) {
|
function logger(r: Response) {
|
||||||
console.log(`${r.status} ${r.url} ${r.statusText}`);
|
console.log(`${r.status} ${r.url} ${r.statusText}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function usePublicApi(): PublicApi {
|
export function usePublicApi(): PublicApi {
|
||||||
const requests = new Requests('', '', {});
|
const requests = new Requests("", "", {});
|
||||||
return new PublicApi(requests);
|
return new PublicApi(requests);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useUserApi(): UserApi {
|
export function useUserApi(): UserApi {
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
|
|
||||||
const requests = new Requests('', () => authStore.token, {});
|
const requests = new Requests("", () => authStore.token, {});
|
||||||
requests.addResponseInterceptor(logger);
|
requests.addResponseInterceptor(logger);
|
||||||
requests.addResponseInterceptor(r => {
|
requests.addResponseInterceptor(r => {
|
||||||
if (r.status === 401) {
|
if (r.status === 401) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { UseConfirmDialogReturn } from '@vueuse/core';
|
import { UseConfirmDialogReturn } from "@vueuse/core";
|
||||||
import { Ref } from 'vue';
|
import { Ref } from "vue";
|
||||||
|
|
||||||
type Store = UseConfirmDialogReturn<any, boolean, boolean> & {
|
type Store = UseConfirmDialogReturn<any, boolean, boolean> & {
|
||||||
text: Ref<string>;
|
text: Ref<string>;
|
||||||
|
@ -7,7 +7,7 @@ type Store = UseConfirmDialogReturn<any, boolean, boolean> & {
|
||||||
};
|
};
|
||||||
|
|
||||||
const store: Partial<Store> = {
|
const store: Partial<Store> = {
|
||||||
text: ref('Are you sure you want to delete this item? '),
|
text: ref("Are you sure you want to delete this item? "),
|
||||||
setup: false,
|
setup: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,11 @@ function slugify(text: string) {
|
||||||
return text
|
return text
|
||||||
.toString()
|
.toString()
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replace(/\s+/g, '-') // Replace spaces with -
|
.replace(/\s+/g, "-") // Replace spaces with -
|
||||||
.replace(/[^\w-]+/g, '') // Remove all non-word chars
|
.replace(/[^\w-]+/g, "") // Remove all non-word chars
|
||||||
.replace(/--+/g, '-') // Replace multiple - with single -
|
.replace(/--+/g, "-") // Replace multiple - with single -
|
||||||
.replace(/^-+/, '') // Trim - from start of text
|
.replace(/^-+/, "") // Trim - from start of text
|
||||||
.replace(/-+$/, ''); // Trim - from end of text
|
.replace(/-+$/, ""); // Trim - from end of text
|
||||||
}
|
}
|
||||||
|
|
||||||
function idGenerator(): string {
|
function idGenerator(): string {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { useId } from './use-ids';
|
import { useId } from "./use-ids";
|
||||||
|
|
||||||
interface Notification {
|
interface Notification {
|
||||||
id: string;
|
id: string;
|
||||||
message: string;
|
message: string;
|
||||||
type: 'success' | 'error' | 'info';
|
type: "success" | "error" | "info";
|
||||||
}
|
}
|
||||||
|
|
||||||
const notifications = ref<Notification[]>([]);
|
const notifications = ref<Notification[]>([]);
|
||||||
|
@ -34,21 +34,21 @@ export function useNotifier() {
|
||||||
addNotification({
|
addNotification({
|
||||||
id: useId(),
|
id: useId(),
|
||||||
message,
|
message,
|
||||||
type: 'success',
|
type: "success",
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
error: (message: string) => {
|
error: (message: string) => {
|
||||||
addNotification({
|
addNotification({
|
||||||
id: useId(),
|
id: useId(),
|
||||||
message,
|
message,
|
||||||
type: 'error',
|
type: "error",
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
info: (message: string) => {
|
info: (message: string) => {
|
||||||
addNotification({
|
addNotification({
|
||||||
id: useId(),
|
id: useId(),
|
||||||
message,
|
message,
|
||||||
type: 'info',
|
type: "info",
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Ref } from 'vue';
|
import { Ref } from "vue";
|
||||||
|
|
||||||
export type LocationViewPreferences = {
|
export type LocationViewPreferences = {
|
||||||
showDetails: boolean;
|
showDetails: boolean;
|
||||||
|
@ -11,7 +11,7 @@ export type LocationViewPreferences = {
|
||||||
*/
|
*/
|
||||||
export function useViewPreferences(): Ref<LocationViewPreferences> {
|
export function useViewPreferences(): Ref<LocationViewPreferences> {
|
||||||
const results = useLocalStorage(
|
const results = useLocalStorage(
|
||||||
'homebox/preferences/location',
|
"homebox/preferences/location",
|
||||||
{
|
{
|
||||||
showDetails: true,
|
showDetails: true,
|
||||||
showEmpty: true,
|
showEmpty: true,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export function truncate(str: string, length: number) {
|
export function truncate(str: string, length: number) {
|
||||||
return str.length > length ? str.substring(0, length) + '...' : str;
|
return str.length > length ? str.substring(0, length) + "..." : str;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function capitalize(str: string) {
|
export function capitalize(str: string) {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { describe, test, expect } from 'vitest';
|
import { describe, test, expect } from "vitest";
|
||||||
import { client, userClient } from './test-utils';
|
import { client, userClient } from "./test-utils";
|
||||||
|
|
||||||
describe('[GET] /api/v1/status', () => {
|
describe("[GET] /api/v1/status", () => {
|
||||||
test('server should respond', async () => {
|
test("server should respond", async () => {
|
||||||
const api = client();
|
const api = client();
|
||||||
const { response, data } = await api.status();
|
const { response, data } = await api.status();
|
||||||
expect(response.status).toBe(200);
|
expect(response.status).toBe(200);
|
||||||
|
@ -10,23 +10,23 @@ describe('[GET] /api/v1/status', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('first time user workflow (register, login)', () => {
|
describe("first time user workflow (register, login)", () => {
|
||||||
const api = client();
|
const api = client();
|
||||||
const userData = {
|
const userData = {
|
||||||
groupName: 'test-group',
|
groupName: "test-group",
|
||||||
user: {
|
user: {
|
||||||
email: 'test-user@email.com',
|
email: "test-user@email.com",
|
||||||
name: 'test-user',
|
name: "test-user",
|
||||||
password: 'test-password',
|
password: "test-password",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
test('user should be able to register', async () => {
|
test("user should be able to register", async () => {
|
||||||
const { response } = await api.register(userData);
|
const { response } = await api.register(userData);
|
||||||
expect(response.status).toBe(204);
|
expect(response.status).toBe(204);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('user should be able to login', async () => {
|
test("user should be able to login", async () => {
|
||||||
const { response, data } = await api.login(userData.user.email, userData.user.password);
|
const { response, data } = await api.login(userData.user.email, userData.user.password);
|
||||||
expect(response.status).toBe(200);
|
expect(response.status).toBe(200);
|
||||||
expect(data.token).toBeTruthy();
|
expect(data.token).toBeTruthy();
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
import { beforeAll, expect } from 'vitest';
|
import { beforeAll, expect } from "vitest";
|
||||||
import { Requests } from '../../requests';
|
import { Requests } from "../../requests";
|
||||||
import { overrideParts } from '../base/urls';
|
import { overrideParts } from "../base/urls";
|
||||||
import { PublicApi } from '../public';
|
import { PublicApi } from "../public";
|
||||||
import * as config from '../../../test/config';
|
import * as config from "../../../test/config";
|
||||||
import { UserApi } from '../user';
|
import { UserApi } from "../user";
|
||||||
|
|
||||||
export function client() {
|
export function client() {
|
||||||
overrideParts(config.BASE_URL, '/api/v1');
|
overrideParts(config.BASE_URL, "/api/v1");
|
||||||
const requests = new Requests('');
|
const requests = new Requests("");
|
||||||
return new PublicApi(requests);
|
return new PublicApi(requests);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function userClient(token: string) {
|
export function userClient(token: string) {
|
||||||
overrideParts(config.BASE_URL, '/api/v1');
|
overrideParts(config.BASE_URL, "/api/v1");
|
||||||
const requests = new Requests('', token);
|
const requests = new Requests("", token);
|
||||||
return new UserApi(requests);
|
return new UserApi(requests);
|
||||||
}
|
}
|
||||||
|
|
||||||
const cache = {
|
const cache = {
|
||||||
token: '',
|
token: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -30,11 +30,11 @@ export async function sharedUserClient(): Promise<UserApi> {
|
||||||
return userClient(cache.token);
|
return userClient(cache.token);
|
||||||
}
|
}
|
||||||
const testUser = {
|
const testUser = {
|
||||||
groupName: 'test-group',
|
groupName: "test-group",
|
||||||
user: {
|
user: {
|
||||||
email: '__test__@__test__.com',
|
email: "__test__@__test__.com",
|
||||||
name: '__test__',
|
name: "__test__",
|
||||||
password: '__test__',
|
password: "__test__",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { describe, expect, test } from 'vitest';
|
import { describe, expect, test } from "vitest";
|
||||||
import { Label } from '../../classes/labels';
|
import { Label } from "../../classes/labels";
|
||||||
import { UserApi } from '../../user';
|
import { UserApi } from "../../user";
|
||||||
import { sharedUserClient } from '../test-utils';
|
import { sharedUserClient } from "../test-utils";
|
||||||
|
|
||||||
describe('locations lifecycle (create, update, delete)', () => {
|
describe("locations lifecycle (create, update, delete)", () => {
|
||||||
let increment = 0;
|
let increment = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -14,7 +14,7 @@ describe('locations lifecycle (create, update, delete)', () => {
|
||||||
const { response, data } = await api.labels.create({
|
const { response, data } = await api.labels.create({
|
||||||
name: `__test__.label.name_${increment}`,
|
name: `__test__.label.name_${increment}`,
|
||||||
description: `__test__.label.description_${increment}`,
|
description: `__test__.label.description_${increment}`,
|
||||||
color: '',
|
color: "",
|
||||||
});
|
});
|
||||||
expect(response.status).toBe(201);
|
expect(response.status).toBe(201);
|
||||||
increment++;
|
increment++;
|
||||||
|
@ -26,13 +26,13 @@ describe('locations lifecycle (create, update, delete)', () => {
|
||||||
return [data, cleanup];
|
return [data, cleanup];
|
||||||
}
|
}
|
||||||
|
|
||||||
test('user should be able to create a label', async () => {
|
test("user should be able to create a label", async () => {
|
||||||
const api = await sharedUserClient();
|
const api = await sharedUserClient();
|
||||||
|
|
||||||
const labelData = {
|
const labelData = {
|
||||||
name: 'test-label',
|
name: "test-label",
|
||||||
description: 'test-description',
|
description: "test-description",
|
||||||
color: '',
|
color: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
const { response, data } = await api.labels.create(labelData);
|
const { response, data } = await api.labels.create(labelData);
|
||||||
|
@ -53,14 +53,14 @@ describe('locations lifecycle (create, update, delete)', () => {
|
||||||
expect(deleteResponse.status).toBe(204);
|
expect(deleteResponse.status).toBe(204);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('user should be able to update a label', async () => {
|
test("user should be able to update a label", async () => {
|
||||||
const api = await sharedUserClient();
|
const api = await sharedUserClient();
|
||||||
const [label, cleanup] = await useLabel(api);
|
const [label, cleanup] = await useLabel(api);
|
||||||
|
|
||||||
const labelData = {
|
const labelData = {
|
||||||
name: 'test-label',
|
name: "test-label",
|
||||||
description: 'test-description',
|
description: "test-description",
|
||||||
color: '',
|
color: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
const { response, data } = await api.labels.update(label.id, labelData);
|
const { response, data } = await api.labels.update(label.id, labelData);
|
||||||
|
@ -78,7 +78,7 @@ describe('locations lifecycle (create, update, delete)', () => {
|
||||||
await cleanup();
|
await cleanup();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('user should be able to delete a label', async () => {
|
test("user should be able to delete a label", async () => {
|
||||||
const api = await sharedUserClient();
|
const api = await sharedUserClient();
|
||||||
const [label, _] = await useLabel(api);
|
const [label, _] = await useLabel(api);
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { describe, expect, test } from 'vitest';
|
import { describe, expect, test } from "vitest";
|
||||||
import { Location } from '../../classes/locations';
|
import { Location } from "../../classes/locations";
|
||||||
import { UserApi } from '../../user';
|
import { UserApi } from "../../user";
|
||||||
import { sharedUserClient } from '../test-utils';
|
import { sharedUserClient } from "../test-utils";
|
||||||
|
|
||||||
describe('locations lifecycle (create, update, delete)', () => {
|
describe("locations lifecycle (create, update, delete)", () => {
|
||||||
let increment = 0;
|
let increment = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -26,12 +26,12 @@ describe('locations lifecycle (create, update, delete)', () => {
|
||||||
return [data, cleanup];
|
return [data, cleanup];
|
||||||
}
|
}
|
||||||
|
|
||||||
test('user should be able to create a location', async () => {
|
test("user should be able to create a location", async () => {
|
||||||
const api = await sharedUserClient();
|
const api = await sharedUserClient();
|
||||||
|
|
||||||
const locationData = {
|
const locationData = {
|
||||||
name: 'test-location',
|
name: "test-location",
|
||||||
description: 'test-description',
|
description: "test-description",
|
||||||
};
|
};
|
||||||
|
|
||||||
const { response, data } = await api.locations.create(locationData);
|
const { response, data } = await api.locations.create(locationData);
|
||||||
|
@ -52,13 +52,13 @@ describe('locations lifecycle (create, update, delete)', () => {
|
||||||
expect(deleteResponse.status).toBe(204);
|
expect(deleteResponse.status).toBe(204);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('user should be able to update a location', async () => {
|
test("user should be able to update a location", async () => {
|
||||||
const api = await sharedUserClient();
|
const api = await sharedUserClient();
|
||||||
const [location, cleanup] = await useLocation(api);
|
const [location, cleanup] = await useLocation(api);
|
||||||
|
|
||||||
const updateData = {
|
const updateData = {
|
||||||
name: 'test-location-updated',
|
name: "test-location-updated",
|
||||||
description: 'test-description-updated',
|
description: "test-description-updated",
|
||||||
};
|
};
|
||||||
|
|
||||||
const { response } = await api.locations.update(location.id, updateData);
|
const { response } = await api.locations.update(location.id, updateData);
|
||||||
|
@ -75,7 +75,7 @@ describe('locations lifecycle (create, update, delete)', () => {
|
||||||
await cleanup();
|
await cleanup();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('user should be able to delete a location', async () => {
|
test("user should be able to delete a location", async () => {
|
||||||
const api = await sharedUserClient();
|
const api = await sharedUserClient();
|
||||||
const [location, _] = await useLocation(api);
|
const [location, _] = await useLocation(api);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Requests } from '../../requests';
|
import { Requests } from "../../requests";
|
||||||
// <
|
// <
|
||||||
// TGetResult,
|
// TGetResult,
|
||||||
// TPostData,
|
// TPostData,
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
import { describe, expect, it } from 'vitest';
|
import { describe, expect, it } from "vitest";
|
||||||
import { route } from '.';
|
import { route } from ".";
|
||||||
|
|
||||||
describe('UrlBuilder', () => {
|
describe("UrlBuilder", () => {
|
||||||
it('basic query parameter', () => {
|
it("basic query parameter", () => {
|
||||||
const result = route('/test', { a: 'b' });
|
const result = route("/test", { a: "b" });
|
||||||
expect(result).toBe('/api/v1/test?a=b');
|
expect(result).toBe("/api/v1/test?a=b");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('multiple query parameters', () => {
|
it("multiple query parameters", () => {
|
||||||
const result = route('/test', { a: 'b', c: 'd' });
|
const result = route("/test", { a: "b", c: "d" });
|
||||||
expect(result).toBe('/api/v1/test?a=b&c=d');
|
expect(result).toBe("/api/v1/test?a=b&c=d");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('no query parameters', () => {
|
it("no query parameters", () => {
|
||||||
const result = route('/test');
|
const result = route("/test");
|
||||||
expect(result).toBe('/api/v1/test');
|
expect(result).toBe("/api/v1/test");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('list-like query parameters', () => {
|
it("list-like query parameters", () => {
|
||||||
const result = route('/test', { a: ['b', 'c'] });
|
const result = route("/test", { a: ["b", "c"] });
|
||||||
expect(result).toBe('/api/v1/test?a=b&a=c');
|
expect(result).toBe("/api/v1/test?a=b&a=c");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
export { BaseAPI } from './base-api';
|
export { BaseAPI } from "./base-api";
|
||||||
export { route } from './urls';
|
export { route } from "./urls";
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
const parts = {
|
const parts = {
|
||||||
host: 'http://localhost.com',
|
host: "http://localhost.com",
|
||||||
prefix: '/api/v1',
|
prefix: "/api/v1",
|
||||||
};
|
};
|
||||||
|
|
||||||
export function overrideParts(host: string, prefix: string) {
|
export function overrideParts(host: string, prefix: string) {
|
||||||
|
@ -32,5 +32,5 @@ export function route(rest: string, params: Record<string, QueryValue> = {}): st
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return url.toString().replace('http://localhost.com', '');
|
return url.toString().replace("http://localhost.com", "");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { BaseAPI, route } from '../base';
|
import { BaseAPI, route } from "../base";
|
||||||
import { Label } from './labels';
|
import { Label } from "./labels";
|
||||||
import { Location } from './locations';
|
import { Location } from "./locations";
|
||||||
import { Results } from './types';
|
import { Results } from "./types";
|
||||||
|
|
||||||
export interface ItemCreate {
|
export interface ItemCreate {
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -36,11 +36,11 @@ export interface Item {
|
||||||
|
|
||||||
export class ItemsApi extends BaseAPI {
|
export class ItemsApi extends BaseAPI {
|
||||||
getAll() {
|
getAll() {
|
||||||
return this.http.get<Results<Item>>({ url: route('/items') });
|
return this.http.get<Results<Item>>({ url: route("/items") });
|
||||||
}
|
}
|
||||||
|
|
||||||
create(item: ItemCreate) {
|
create(item: ItemCreate) {
|
||||||
return this.http.post<ItemCreate, Item>({ url: route('/items'), body: item });
|
return this.http.post<ItemCreate, Item>({ url: route("/items"), body: item });
|
||||||
}
|
}
|
||||||
|
|
||||||
async get(id: string) {
|
async get(id: string) {
|
||||||
|
@ -68,8 +68,8 @@ export class ItemsApi extends BaseAPI {
|
||||||
|
|
||||||
import(file: File) {
|
import(file: File) {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('csv', file);
|
formData.append("csv", file);
|
||||||
|
|
||||||
return this.http.post<FormData, void>({ url: route('/items/import'), data: formData });
|
return this.http.post<FormData, void>({ url: route("/items/import"), data: formData });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { BaseAPI, route } from '../base';
|
import { BaseAPI, route } from "../base";
|
||||||
import { Item } from './items';
|
import { Item } from "./items";
|
||||||
import { Details, OutType, Results } from './types';
|
import { Details, OutType, Results } from "./types";
|
||||||
|
|
||||||
export type LabelCreate = Details & {
|
export type LabelCreate = Details & {
|
||||||
color: string;
|
color: string;
|
||||||
|
@ -16,11 +16,11 @@ export type Label = LabelCreate &
|
||||||
|
|
||||||
export class LabelsApi extends BaseAPI {
|
export class LabelsApi extends BaseAPI {
|
||||||
getAll() {
|
getAll() {
|
||||||
return this.http.get<Results<Label>>({ url: route('/labels') });
|
return this.http.get<Results<Label>>({ url: route("/labels") });
|
||||||
}
|
}
|
||||||
|
|
||||||
create(body: LabelCreate) {
|
create(body: LabelCreate) {
|
||||||
return this.http.post<LabelCreate, Label>({ url: route('/labels'), body });
|
return this.http.post<LabelCreate, Label>({ url: route("/labels"), body });
|
||||||
}
|
}
|
||||||
|
|
||||||
get(id: string) {
|
get(id: string) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { BaseAPI, route } from '../base';
|
import { BaseAPI, route } from "../base";
|
||||||
import { Item } from './items';
|
import { Item } from "./items";
|
||||||
import { Details, OutType, Results } from './types';
|
import { Details, OutType, Results } from "./types";
|
||||||
|
|
||||||
export type LocationCreate = Details;
|
export type LocationCreate = Details;
|
||||||
|
|
||||||
|
@ -15,11 +15,11 @@ export type LocationUpdate = LocationCreate;
|
||||||
|
|
||||||
export class LocationsApi extends BaseAPI {
|
export class LocationsApi extends BaseAPI {
|
||||||
getAll() {
|
getAll() {
|
||||||
return this.http.get<Results<Location>>({ url: route('/locations') });
|
return this.http.get<Results<Location>>({ url: route("/locations") });
|
||||||
}
|
}
|
||||||
|
|
||||||
create(body: LocationCreate) {
|
create(body: LocationCreate) {
|
||||||
return this.http.post<LocationCreate, Location>({ url: route('/locations'), body });
|
return this.http.post<LocationCreate, Location>({ url: route("/locations"), body });
|
||||||
}
|
}
|
||||||
|
|
||||||
get(id: string) {
|
get(id: string) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { BaseAPI, route } from './base';
|
import { BaseAPI, route } from "./base";
|
||||||
|
|
||||||
export type LoginResult = {
|
export type LoginResult = {
|
||||||
token: string;
|
token: string;
|
||||||
|
@ -28,12 +28,12 @@ export type StatusResult = {
|
||||||
|
|
||||||
export class PublicApi extends BaseAPI {
|
export class PublicApi extends BaseAPI {
|
||||||
public status() {
|
public status() {
|
||||||
return this.http.get<StatusResult>({ url: route('/status') });
|
return this.http.get<StatusResult>({ url: route("/status") });
|
||||||
}
|
}
|
||||||
|
|
||||||
public login(username: string, password: string) {
|
public login(username: string, password: string) {
|
||||||
return this.http.post<LoginPayload, LoginResult>({
|
return this.http.post<LoginPayload, LoginResult>({
|
||||||
url: route('/users/login'),
|
url: route("/users/login"),
|
||||||
body: {
|
body: {
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
|
@ -42,6 +42,6 @@ export class PublicApi extends BaseAPI {
|
||||||
}
|
}
|
||||||
|
|
||||||
public register(body: RegisterPayload) {
|
public register(body: RegisterPayload) {
|
||||||
return this.http.post<RegisterPayload, LoginResult>({ url: route('/users/register'), body });
|
return this.http.post<RegisterPayload, LoginResult>({ url: route("/users/register"), body });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { BaseAPI, route } from './base';
|
import { BaseAPI, route } from "./base";
|
||||||
import { ItemsApi } from './classes/items';
|
import { ItemsApi } from "./classes/items";
|
||||||
import { LabelsApi } from './classes/labels';
|
import { LabelsApi } from "./classes/labels";
|
||||||
import { LocationsApi } from './classes/locations';
|
import { LocationsApi } from "./classes/locations";
|
||||||
import { Requests } from '~~/lib/requests';
|
import { Requests } from "~~/lib/requests";
|
||||||
|
|
||||||
export type Result<T> = {
|
export type Result<T> = {
|
||||||
item: T;
|
item: T;
|
||||||
|
@ -30,14 +30,14 @@ export class UserApi extends BaseAPI {
|
||||||
}
|
}
|
||||||
|
|
||||||
public self() {
|
public self() {
|
||||||
return this.http.get<Result<User>>({ url: route('/users/self') });
|
return this.http.get<Result<User>>({ url: route("/users/self") });
|
||||||
}
|
}
|
||||||
|
|
||||||
public logout() {
|
public logout() {
|
||||||
return this.http.post<object, void>({ url: route('/users/logout') });
|
return this.http.post<object, void>({ url: route("/users/logout") });
|
||||||
}
|
}
|
||||||
|
|
||||||
public deleteAccount() {
|
public deleteAccount() {
|
||||||
return this.http.delete<void>({ url: route('/users/self') });
|
return this.http.delete<void>({ url: route("/users/self") });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
export { Requests, type TResponse } from './requests';
|
export { Requests, type TResponse } from "./requests";
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
export enum Method {
|
export enum Method {
|
||||||
GET = 'GET',
|
GET = "GET",
|
||||||
POST = 'POST',
|
POST = "POST",
|
||||||
PUT = 'PUT',
|
PUT = "PUT",
|
||||||
DELETE = 'DELETE',
|
DELETE = "DELETE",
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RequestInterceptor = (r: Response) => void;
|
export type RequestInterceptor = (r: Response) => void;
|
||||||
|
@ -40,9 +40,9 @@ export class Requests {
|
||||||
return this.baseUrl + rest;
|
return this.baseUrl + rest;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(baseUrl: string, token: string | (() => string) = '', headers: Record<string, string> = {}) {
|
constructor(baseUrl: string, token: string | (() => string) = "", headers: Record<string, string> = {}) {
|
||||||
this.baseUrl = baseUrl;
|
this.baseUrl = baseUrl;
|
||||||
this.token = typeof token === 'string' ? () => token : token;
|
this.token = typeof token === "string" ? () => token : token;
|
||||||
this.headers = headers;
|
this.headers = headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,19 +72,19 @@ export class Requests {
|
||||||
headers: {
|
headers: {
|
||||||
...rargs.headers,
|
...rargs.headers,
|
||||||
...this.headers,
|
...this.headers,
|
||||||
},
|
} as Record<string, string>,
|
||||||
};
|
};
|
||||||
|
|
||||||
const token = this.token();
|
const token = this.token();
|
||||||
if (token !== '' && payload.headers !== undefined) {
|
if (token !== "" && payload.headers !== undefined) {
|
||||||
payload.headers.Authorization = token;
|
payload.headers["Authorization"] = token; // eslint-disable-line dot-notation
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.methodSupportsBody(method)) {
|
if (this.methodSupportsBody(method)) {
|
||||||
if (rargs.data) {
|
if (rargs.data) {
|
||||||
payload.body = rargs.data;
|
payload.body = rargs.data;
|
||||||
} else {
|
} else {
|
||||||
payload.headers['Content-Type'] = 'application/json';
|
payload.headers["Content-Type"] = "application/json";
|
||||||
payload.body = JSON.stringify(rargs.body);
|
payload.body = JSON.stringify(rargs.body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import { defineNuxtConfig } from 'nuxt';
|
import { defineNuxtConfig } from "nuxt";
|
||||||
|
|
||||||
// https://v3.nuxtjs.org/api/configuration/nuxt.config
|
// https://v3.nuxtjs.org/api/configuration/nuxt.config
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
target: 'static',
|
target: "static",
|
||||||
ssr: false,
|
ssr: false,
|
||||||
modules: ['@nuxtjs/tailwindcss', '@pinia/nuxt', '@vueuse/nuxt'],
|
modules: ["@nuxtjs/tailwindcss", "@pinia/nuxt", "@vueuse/nuxt"],
|
||||||
meta: {
|
meta: {
|
||||||
title: 'Homebox',
|
title: "Homebox",
|
||||||
link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.svg' }],
|
link: [{ rel: "icon", type: "image/x-icon", href: "/favicon.svg" }],
|
||||||
},
|
},
|
||||||
vite: {
|
vite: {
|
||||||
server: {
|
server: {
|
||||||
proxy: {
|
proxy: {
|
||||||
'/api': 'http://localhost:7745',
|
"/api": "http://localhost:7745",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [],
|
plugins: [],
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
useHead({
|
useHead({
|
||||||
title: '404. Not Found',
|
title: "404. Not Found",
|
||||||
});
|
});
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: '404',
|
layout: "404",
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: 'home',
|
layout: "home",
|
||||||
});
|
});
|
||||||
useHead({
|
useHead({
|
||||||
title: 'Homebox | Home',
|
title: "Homebox | Home",
|
||||||
});
|
});
|
||||||
|
|
||||||
const api = useUserApi();
|
const api = useUserApi();
|
||||||
|
|
||||||
const { data: locations } = useAsyncData('locations', async () => {
|
const { data: locations } = useAsyncData("locations", async () => {
|
||||||
const { data } = await api.locations.getAll();
|
const { data } = await api.locations.getAll();
|
||||||
return data.items;
|
return data.items;
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: labels } = useAsyncData('labels', async () => {
|
const { data: labels } = useAsyncData("labels", async () => {
|
||||||
const { data } = await api.labels.getAll();
|
const { data } = await api.labels.getAll();
|
||||||
return data.items;
|
return data.items;
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: items } = useAsyncData('items', async () => {
|
const { data: items } = useAsyncData("items", async () => {
|
||||||
const { data } = await api.items.getAll();
|
const { data } = await api.items.getAll();
|
||||||
return data.items;
|
return data.items;
|
||||||
});
|
});
|
||||||
|
@ -29,15 +29,15 @@
|
||||||
|
|
||||||
const stats = [
|
const stats = [
|
||||||
{
|
{
|
||||||
label: 'Locations',
|
label: "Locations",
|
||||||
value: totalLocations,
|
value: totalLocations,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Items',
|
label: "Items",
|
||||||
value: totalItems,
|
value: totalItems,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Labels',
|
label: "Labels",
|
||||||
value: totalLabels,
|
value: totalLabels,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -55,7 +55,7 @@
|
||||||
|
|
||||||
function setFile(e: Event & { target: HTMLInputElement }) {
|
function setFile(e: Event & { target: HTMLInputElement }) {
|
||||||
importCsv.value = e.target.files[0];
|
importCsv.value = e.target.files[0];
|
||||||
console.log('importCsv.value', importCsv.value);
|
console.log("importCsv.value", importCsv.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const toast = useNotifier();
|
const toast = useNotifier();
|
||||||
|
@ -74,7 +74,7 @@
|
||||||
const { error } = await api.items.import(importCsv.value);
|
const { error } = await api.items.import(importCsv.value);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
toast.error('Import failed. Please try again later.');
|
toast.error("Import failed. Please try again later.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset
|
// Reset
|
||||||
|
@ -138,7 +138,7 @@
|
||||||
>
|
>
|
||||||
<div v-for="stat in stats" :key="stat.label" class="px-6 py-5 text-center text-sm font-medium">
|
<div v-for="stat in stats" :key="stat.label" class="px-6 py-5 text-center text-sm font-medium">
|
||||||
<span class="text-gray-900">{{ stat.value.value }}</span>
|
<span class="text-gray-900">{{ stat.value.value }}</span>
|
||||||
{{ ' ' }}
|
{{ " " }}
|
||||||
<span class="text-gray-600">{{ stat.label }}</span>
|
<span class="text-gray-600">{{ stat.label }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,43 +1,43 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import TextField from '@/components/Form/TextField.vue';
|
import TextField from "@/components/Form/TextField.vue";
|
||||||
import { useNotifier } from '@/composables/use-notifier';
|
import { useNotifier } from "@/composables/use-notifier";
|
||||||
import { usePublicApi } from '@/composables/use-api';
|
import { usePublicApi } from "@/composables/use-api";
|
||||||
import { useAuthStore } from '~~/stores/auth';
|
import { useAuthStore } from "~~/stores/auth";
|
||||||
useHead({
|
useHead({
|
||||||
title: 'Homebox | Organize and Tag Your Stuff',
|
title: "Homebox | Organize and Tag Your Stuff",
|
||||||
});
|
});
|
||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: 'empty',
|
layout: "empty",
|
||||||
});
|
});
|
||||||
|
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
if (!authStore.isTokenExpired) {
|
if (!authStore.isTokenExpired) {
|
||||||
navigateTo('/home');
|
navigateTo("/home");
|
||||||
}
|
}
|
||||||
|
|
||||||
const registerFields = [
|
const registerFields = [
|
||||||
{
|
{
|
||||||
label: "What's your name?",
|
label: "What's your name?",
|
||||||
value: '',
|
value: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "What's your email?",
|
label: "What's your email?",
|
||||||
value: '',
|
value: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Name your group',
|
label: "Name your group",
|
||||||
value: '',
|
value: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Set your password',
|
label: "Set your password",
|
||||||
value: '',
|
value: "",
|
||||||
type: 'password',
|
type: "password",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Confirm your password',
|
label: "Confirm your password",
|
||||||
value: '',
|
value: "",
|
||||||
type: 'password',
|
type: "password",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -57,11 +57,11 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
toast.error('Problem registering user');
|
toast.error("Problem registering user");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
toast.success('User registered');
|
toast.success("User registered");
|
||||||
|
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
loginFields[0].value = registerFields[1].value;
|
loginFields[0].value = registerFields[1].value;
|
||||||
|
@ -70,13 +70,13 @@
|
||||||
|
|
||||||
const loginFields = [
|
const loginFields = [
|
||||||
{
|
{
|
||||||
label: 'Email',
|
label: "Email",
|
||||||
value: '',
|
value: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Password',
|
label: "Password",
|
||||||
value: '',
|
value: "",
|
||||||
type: 'password',
|
type: "password",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -88,16 +88,16 @@
|
||||||
const { data, error } = await api.login(loginFields[0].value, loginFields[1].value);
|
const { data, error } = await api.login(loginFields[0].value, loginFields[1].value);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
toast.error('Invalid email or password');
|
toast.error("Invalid email or password");
|
||||||
} else {
|
} else {
|
||||||
toast.success('Logged in successfully');
|
toast.success("Logged in successfully");
|
||||||
|
|
||||||
authStore.$patch({
|
authStore.$patch({
|
||||||
token: data.token,
|
token: data.token,
|
||||||
expires: data.expiresAt,
|
expires: data.expiresAt,
|
||||||
});
|
});
|
||||||
|
|
||||||
navigateTo('/home');
|
navigateTo("/home");
|
||||||
}
|
}
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
|
@ -207,7 +207,7 @@
|
||||||
class="text-base-content text-lg hover:bg-primary hover:text-primary-content px-3 py-1 rounded-xl transition-colors duration-200"
|
class="text-base-content text-lg hover:bg-primary hover:text-primary-content px-3 py-1 rounded-xl transition-colors duration-200"
|
||||||
@click="toggleLogin"
|
@click="toggleLogin"
|
||||||
>
|
>
|
||||||
{{ registerForm ? 'Already a User? Login' : 'Not a User? Register' }}
|
{{ registerForm ? "Already a User? Login" : "Not a User? Register" }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: 'home',
|
layout: "home",
|
||||||
});
|
});
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
@ -12,85 +12,85 @@
|
||||||
const { data: item } = useAsyncData(async () => {
|
const { data: item } = useAsyncData(async () => {
|
||||||
const { data, error } = await api.items.get(itemId.value);
|
const { data, error } = await api.items.get(itemId.value);
|
||||||
if (error) {
|
if (error) {
|
||||||
toast.error('Failed to load item');
|
toast.error("Failed to load item");
|
||||||
navigateTo('/home');
|
navigateTo("/home");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
});
|
});
|
||||||
|
|
||||||
type FormField = {
|
type FormField = {
|
||||||
type: 'text' | 'textarea' | 'select' | 'date';
|
type: "text" | "textarea" | "select" | "date";
|
||||||
label: string;
|
label: string;
|
||||||
ref: string;
|
ref: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const mainFields: FormField[] = [
|
const mainFields: FormField[] = [
|
||||||
{
|
{
|
||||||
type: 'text',
|
type: "text",
|
||||||
label: 'Name',
|
label: "Name",
|
||||||
ref: 'name',
|
ref: "name",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'textarea',
|
type: "textarea",
|
||||||
label: 'Description',
|
label: "Description",
|
||||||
ref: 'description',
|
ref: "description",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'text',
|
type: "text",
|
||||||
label: 'Serial Number',
|
label: "Serial Number",
|
||||||
ref: 'serialNumber',
|
ref: "serialNumber",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'text',
|
type: "text",
|
||||||
label: 'Model Number',
|
label: "Model Number",
|
||||||
ref: 'modelNumber',
|
ref: "modelNumber",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'text',
|
type: "text",
|
||||||
label: 'Manufacturer',
|
label: "Manufacturer",
|
||||||
ref: 'manufacturer',
|
ref: "manufacturer",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'textarea',
|
type: "textarea",
|
||||||
label: 'Notes',
|
label: "Notes",
|
||||||
ref: 'notes',
|
ref: "notes",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const purchaseFields: FormField[] = [
|
const purchaseFields: FormField[] = [
|
||||||
{
|
{
|
||||||
type: 'text',
|
type: "text",
|
||||||
label: 'Purchased From',
|
label: "Purchased From",
|
||||||
ref: 'purchaseFrom',
|
ref: "purchaseFrom",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'text',
|
type: "text",
|
||||||
label: 'Purchased Price',
|
label: "Purchased Price",
|
||||||
ref: 'purchasePrice',
|
ref: "purchasePrice",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'date',
|
type: "date",
|
||||||
label: 'Purchased At',
|
label: "Purchased At",
|
||||||
ref: 'purchaseTime',
|
ref: "purchaseTime",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const soldFields = [
|
const soldFields = [
|
||||||
{
|
{
|
||||||
type: 'text',
|
type: "text",
|
||||||
label: 'Sold To',
|
label: "Sold To",
|
||||||
ref: 'soldTo',
|
ref: "soldTo",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'text',
|
type: "text",
|
||||||
label: 'Sold Price',
|
label: "Sold Price",
|
||||||
ref: 'soldPrice',
|
ref: "soldPrice",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'date',
|
type: "date",
|
||||||
label: 'Sold At',
|
label: "Sold At",
|
||||||
ref: 'soldTime',
|
ref: "soldTime",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: 'home',
|
layout: "home",
|
||||||
});
|
});
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
@ -13,8 +13,8 @@
|
||||||
const { data: item } = useAsyncData(async () => {
|
const { data: item } = useAsyncData(async () => {
|
||||||
const { data, error } = await api.items.get(itemId.value);
|
const { data, error } = await api.items.get(itemId.value);
|
||||||
if (error) {
|
if (error) {
|
||||||
toast.error('Failed to load item');
|
toast.error("Failed to load item");
|
||||||
navigateTo('/home');
|
navigateTo("/home");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
|
@ -22,12 +22,12 @@
|
||||||
|
|
||||||
const itemSummary = computed(() => {
|
const itemSummary = computed(() => {
|
||||||
return {
|
return {
|
||||||
Description: item.value?.description || '',
|
Description: item.value?.description || "",
|
||||||
'Serial Number': item.value?.serialNumber || '',
|
"Serial Number": item.value?.serialNumber || "",
|
||||||
'Model Number': item.value?.modelNumber || '',
|
"Model Number": item.value?.modelNumber || "",
|
||||||
Manufacturer: item.value?.manufacturer || '',
|
Manufacturer: item.value?.manufacturer || "",
|
||||||
Notes: item.value?.notes || '',
|
Notes: item.value?.notes || "",
|
||||||
Attachments: '', // TODO: Attachments
|
Attachments: "", // TODO: Attachments
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -42,12 +42,12 @@
|
||||||
const payload = {};
|
const payload = {};
|
||||||
|
|
||||||
if (item.value.lifetimeWarranty) {
|
if (item.value.lifetimeWarranty) {
|
||||||
payload['Lifetime Warranty'] = 'Yes';
|
payload["Lifetime Warranty"] = "Yes";
|
||||||
} else {
|
} else {
|
||||||
payload['Warranty Expires'] = item.value?.warrantyExpires || '';
|
payload["Warranty Expires"] = item.value?.warrantyExpires || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
payload['Warranty Details'] = item.value?.warrantyDetails || '';
|
payload["Warranty Details"] = item.value?.warrantyDetails || "";
|
||||||
|
|
||||||
return payload;
|
return payload;
|
||||||
});
|
});
|
||||||
|
@ -61,9 +61,9 @@
|
||||||
|
|
||||||
const purchaseDetails = computed(() => {
|
const purchaseDetails = computed(() => {
|
||||||
return {
|
return {
|
||||||
'Purchased From': item.value?.purchaseFrom || '',
|
"Purchased From": item.value?.purchaseFrom || "",
|
||||||
'Purchased Price': item.value?.purchasePrice || '',
|
"Purchased Price": item.value?.purchasePrice || "",
|
||||||
'Purchased At': item.value?.purchaseTime || '',
|
"Purchased At": item.value?.purchaseTime || "",
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -77,16 +77,16 @@
|
||||||
|
|
||||||
const soldDetails = computed(() => {
|
const soldDetails = computed(() => {
|
||||||
return {
|
return {
|
||||||
'Sold To': item.value?.soldTo || '',
|
"Sold To": item.value?.soldTo || "",
|
||||||
'Sold Price': item.value?.soldPrice || '',
|
"Sold Price": item.value?.soldPrice || "",
|
||||||
'Sold At': item.value?.soldTime || '',
|
"Sold At": item.value?.soldTime || "",
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const confirm = useConfirm();
|
const confirm = useConfirm();
|
||||||
|
|
||||||
async function deleteItem() {
|
async function deleteItem() {
|
||||||
const confirmed = await confirm.reveal('Are you sure you want to delete this item?');
|
const confirmed = await confirm.reveal("Are you sure you want to delete this item?");
|
||||||
|
|
||||||
if (!confirmed.data) {
|
if (!confirmed.data) {
|
||||||
return;
|
return;
|
||||||
|
@ -94,11 +94,11 @@
|
||||||
|
|
||||||
const { error } = await api.items.delete(itemId.value);
|
const { error } = await api.items.delete(itemId.value);
|
||||||
if (error) {
|
if (error) {
|
||||||
toast.error('Failed to delete item');
|
toast.error("Failed to delete item");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
toast.success('Item deleted');
|
toast.success("Item deleted");
|
||||||
navigateTo('/home');
|
navigateTo("/home");
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: 'home',
|
layout: "home",
|
||||||
});
|
});
|
||||||
|
|
||||||
const show = reactive({
|
const show = reactive({
|
||||||
|
@ -11,29 +11,29 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
name: '',
|
name: "",
|
||||||
description: '',
|
description: "",
|
||||||
notes: '',
|
notes: "",
|
||||||
|
|
||||||
// Item Identification
|
// Item Identification
|
||||||
serialNumber: '',
|
serialNumber: "",
|
||||||
modelNumber: '',
|
modelNumber: "",
|
||||||
manufacturer: '',
|
manufacturer: "",
|
||||||
|
|
||||||
// Purchase Information
|
// Purchase Information
|
||||||
purchaseTime: '',
|
purchaseTime: "",
|
||||||
purchasePrice: '',
|
purchasePrice: "",
|
||||||
purchaseFrom: '',
|
purchaseFrom: "",
|
||||||
|
|
||||||
// Sold Information
|
// Sold Information
|
||||||
soldTime: '',
|
soldTime: "",
|
||||||
soldPrice: '',
|
soldPrice: "",
|
||||||
soldTo: '',
|
soldTo: "",
|
||||||
soldNotes: '',
|
soldNotes: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
function submit() {
|
function submit() {
|
||||||
console.log('Submitted!');
|
console.log("Submitted!");
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ActionsDivider from '../../components/Base/ActionsDivider.vue';
|
import ActionsDivider from "../../components/Base/ActionsDivider.vue";
|
||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: 'home',
|
layout: "home",
|
||||||
});
|
});
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
@ -16,8 +16,8 @@
|
||||||
const { data: label } = useAsyncData(labelId.value, async () => {
|
const { data: label } = useAsyncData(labelId.value, async () => {
|
||||||
const { data, error } = await api.labels.get(labelId.value);
|
const { data, error } = await api.labels.get(labelId.value);
|
||||||
if (error) {
|
if (error) {
|
||||||
toast.error('Failed to load label');
|
toast.error("Failed to load label");
|
||||||
navigateTo('/home');
|
navigateTo("/home");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
|
@ -25,25 +25,25 @@
|
||||||
|
|
||||||
function maybeTimeAgo(date?: string): string {
|
function maybeTimeAgo(date?: string): string {
|
||||||
if (!date) {
|
if (!date) {
|
||||||
return '??';
|
return "??";
|
||||||
}
|
}
|
||||||
|
|
||||||
const time = new Date(date);
|
const time = new Date(date);
|
||||||
|
|
||||||
return `${useTimeAgo(time).value} (${useDateFormat(time, 'MM-DD-YYYY').value})`;
|
return `${useTimeAgo(time).value} (${useDateFormat(time, "MM-DD-YYYY").value})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const details = computed(() => {
|
const details = computed(() => {
|
||||||
const dt = {
|
const dt = {
|
||||||
Name: label.value?.name || '',
|
Name: label.value?.name || "",
|
||||||
Description: label.value?.description || '',
|
Description: label.value?.description || "",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (preferences.value.showDetails) {
|
if (preferences.value.showDetails) {
|
||||||
dt['Created At'] = maybeTimeAgo(label.value?.createdAt);
|
dt["Created At"] = maybeTimeAgo(label.value?.createdAt);
|
||||||
dt['Updated At'] = maybeTimeAgo(label.value?.updatedAt);
|
dt["Updated At"] = maybeTimeAgo(label.value?.updatedAt);
|
||||||
dt['Database ID'] = label.value?.id || '';
|
dt["Database ID"] = label.value?.id || "";
|
||||||
dt['Group Id'] = label.value?.groupId || '';
|
dt["Group Id"] = label.value?.groupId || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
return dt;
|
return dt;
|
||||||
|
@ -52,7 +52,7 @@
|
||||||
const { reveal } = useConfirm();
|
const { reveal } = useConfirm();
|
||||||
|
|
||||||
async function confirmDelete() {
|
async function confirmDelete() {
|
||||||
const { isCanceled } = await reveal('Are you sure you want to delete this label? This action cannot be undone.');
|
const { isCanceled } = await reveal("Are you sure you want to delete this label? This action cannot be undone.");
|
||||||
|
|
||||||
if (isCanceled) {
|
if (isCanceled) {
|
||||||
return;
|
return;
|
||||||
|
@ -61,24 +61,24 @@
|
||||||
const { error } = await api.labels.delete(labelId.value);
|
const { error } = await api.labels.delete(labelId.value);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
toast.error('Failed to delete label');
|
toast.error("Failed to delete label");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
toast.success('Label deleted');
|
toast.success("Label deleted");
|
||||||
navigateTo('/home');
|
navigateTo("/home");
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateModal = ref(false);
|
const updateModal = ref(false);
|
||||||
const updating = ref(false);
|
const updating = ref(false);
|
||||||
const updateData = reactive({
|
const updateData = reactive({
|
||||||
name: '',
|
name: "",
|
||||||
description: '',
|
description: "",
|
||||||
color: '',
|
color: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
function openUpdate() {
|
function openUpdate() {
|
||||||
updateData.name = label.value?.name || '';
|
updateData.name = label.value?.name || "";
|
||||||
updateData.description = label.value?.description || '';
|
updateData.description = label.value?.description || "";
|
||||||
updateModal.value = true;
|
updateModal.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,11 +87,11 @@
|
||||||
const { error, data } = await api.labels.update(labelId.value, updateData);
|
const { error, data } = await api.labels.update(labelId.value, updateData);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
toast.error('Failed to update label');
|
toast.error("Failed to update label");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
toast.success('Label updated');
|
toast.success("Label updated");
|
||||||
label.value = data;
|
label.value = data;
|
||||||
updateModal.value = false;
|
updateModal.value = false;
|
||||||
updating.value = false;
|
updating.value = false;
|
||||||
|
@ -112,7 +112,7 @@
|
||||||
</BaseModal>
|
</BaseModal>
|
||||||
<section>
|
<section>
|
||||||
<BaseSectionHeader class="mb-5" dark>
|
<BaseSectionHeader class="mb-5" dark>
|
||||||
{{ label ? label.name : '' }}
|
{{ label ? label.name : "" }}
|
||||||
</BaseSectionHeader>
|
</BaseSectionHeader>
|
||||||
<BaseDetails class="mb-2" :details="details">
|
<BaseDetails class="mb-2" :details="details">
|
||||||
<template #title> Label Details </template>
|
<template #title> Label Details </template>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ActionsDivider from '../../components/Base/ActionsDivider.vue';
|
import ActionsDivider from "../../components/Base/ActionsDivider.vue";
|
||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: 'home',
|
layout: "home",
|
||||||
});
|
});
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
@ -16,8 +16,8 @@
|
||||||
const { data: location } = useAsyncData(locationId.value, async () => {
|
const { data: location } = useAsyncData(locationId.value, async () => {
|
||||||
const { data, error } = await api.locations.get(locationId.value);
|
const { data, error } = await api.locations.get(locationId.value);
|
||||||
if (error) {
|
if (error) {
|
||||||
toast.error('Failed to load location');
|
toast.error("Failed to load location");
|
||||||
navigateTo('/home');
|
navigateTo("/home");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
|
@ -25,25 +25,25 @@
|
||||||
|
|
||||||
function maybeTimeAgo(date?: string): string {
|
function maybeTimeAgo(date?: string): string {
|
||||||
if (!date) {
|
if (!date) {
|
||||||
return '??';
|
return "??";
|
||||||
}
|
}
|
||||||
|
|
||||||
const time = new Date(date);
|
const time = new Date(date);
|
||||||
|
|
||||||
return `${useTimeAgo(time).value} (${useDateFormat(time, 'MM-DD-YYYY').value})`;
|
return `${useTimeAgo(time).value} (${useDateFormat(time, "MM-DD-YYYY").value})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const details = computed(() => {
|
const details = computed(() => {
|
||||||
const dt = {
|
const dt = {
|
||||||
Name: location.value?.name || '',
|
Name: location.value?.name || "",
|
||||||
Description: location.value?.description || '',
|
Description: location.value?.description || "",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (preferences.value.showDetails) {
|
if (preferences.value.showDetails) {
|
||||||
dt['Created At'] = maybeTimeAgo(location.value?.createdAt);
|
dt["Created At"] = maybeTimeAgo(location.value?.createdAt);
|
||||||
dt['Updated At'] = maybeTimeAgo(location.value?.updatedAt);
|
dt["Updated At"] = maybeTimeAgo(location.value?.updatedAt);
|
||||||
dt['Database ID'] = location.value?.id || '';
|
dt["Database ID"] = location.value?.id || "";
|
||||||
dt['Group Id'] = location.value?.groupId || '';
|
dt["Group Id"] = location.value?.groupId || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
return dt;
|
return dt;
|
||||||
|
@ -52,7 +52,7 @@
|
||||||
const { reveal } = useConfirm();
|
const { reveal } = useConfirm();
|
||||||
|
|
||||||
async function confirmDelete() {
|
async function confirmDelete() {
|
||||||
const { isCanceled } = await reveal('Are you sure you want to delete this location? This action cannot be undone.');
|
const { isCanceled } = await reveal("Are you sure you want to delete this location? This action cannot be undone.");
|
||||||
|
|
||||||
if (isCanceled) {
|
if (isCanceled) {
|
||||||
return;
|
return;
|
||||||
|
@ -61,23 +61,23 @@
|
||||||
const { error } = await api.locations.delete(locationId.value);
|
const { error } = await api.locations.delete(locationId.value);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
toast.error('Failed to delete location');
|
toast.error("Failed to delete location");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
toast.success('Location deleted');
|
toast.success("Location deleted");
|
||||||
navigateTo('/home');
|
navigateTo("/home");
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateModal = ref(false);
|
const updateModal = ref(false);
|
||||||
const updating = ref(false);
|
const updating = ref(false);
|
||||||
const updateData = reactive({
|
const updateData = reactive({
|
||||||
name: '',
|
name: "",
|
||||||
description: '',
|
description: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
function openUpdate() {
|
function openUpdate() {
|
||||||
updateData.name = location.value?.name || '';
|
updateData.name = location.value?.name || "";
|
||||||
updateData.description = location.value?.description || '';
|
updateData.description = location.value?.description || "";
|
||||||
updateModal.value = true;
|
updateModal.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,11 +86,11 @@
|
||||||
const { error, data } = await api.locations.update(locationId.value, updateData);
|
const { error, data } = await api.locations.update(locationId.value, updateData);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
toast.error('Failed to update location');
|
toast.error("Failed to update location");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
toast.success('Location updated');
|
toast.success("Location updated");
|
||||||
location.value = data;
|
location.value = data;
|
||||||
updateModal.value = false;
|
updateModal.value = false;
|
||||||
updating.value = false;
|
updating.value = false;
|
||||||
|
@ -111,7 +111,7 @@
|
||||||
</BaseModal>
|
</BaseModal>
|
||||||
<section>
|
<section>
|
||||||
<BaseSectionHeader class="mb-5" dark>
|
<BaseSectionHeader class="mb-5" dark>
|
||||||
{{ location ? location.name : '' }}
|
{{ location ? location.name : "" }}
|
||||||
</BaseSectionHeader>
|
</BaseSectionHeader>
|
||||||
<BaseDetails class="mb-2" :details="details">
|
<BaseDetails class="mb-2" :details="details">
|
||||||
<template #title> Location Details </template>
|
<template #title> Location Details </template>
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from "pinia";
|
||||||
import { useLocalStorage } from '@vueuse/core';
|
import { useLocalStorage } from "@vueuse/core";
|
||||||
import { UserApi } from '~~/lib/api/user';
|
import { UserApi } from "~~/lib/api/user";
|
||||||
|
|
||||||
export const useAuthStore = defineStore('auth', {
|
export const useAuthStore = defineStore("auth", {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
token: useLocalStorage('pinia/auth/token', ''),
|
token: useLocalStorage("pinia/auth/token", ""),
|
||||||
expires: useLocalStorage('pinia/auth/expires', ''),
|
expires: useLocalStorage("pinia/auth/expires", ""),
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
isTokenExpired: state => {
|
isTokenExpired: state => {
|
||||||
|
@ -13,7 +13,7 @@ export const useAuthStore = defineStore('auth', {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof state.expires === 'string') {
|
if (typeof state.expires === "string") {
|
||||||
return new Date(state.expires) < new Date();
|
return new Date(state.expires) < new Date();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,8 +28,8 @@ export const useAuthStore = defineStore('auth', {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.token = '';
|
this.token = "";
|
||||||
this.expires = '';
|
this.expires = "";
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
@ -38,9 +38,9 @@ export const useAuthStore = defineStore('auth', {
|
||||||
* must clear it's local session, usually when a 401 is received.
|
* must clear it's local session, usually when a 401 is received.
|
||||||
*/
|
*/
|
||||||
clearSession() {
|
clearSession() {
|
||||||
this.token = '';
|
this.token = "";
|
||||||
this.expires = '';
|
this.expires = "";
|
||||||
navigateTo('/');
|
navigateTo("/");
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
content: ['./app.vue', './{components,pages,layouts}/**/*.{vue,js,ts,jsx,tsx}'],
|
content: ["./app.vue", "./{components,pages,layouts}/**/*.{vue,js,ts,jsx,tsx}"],
|
||||||
darkMode: 'class', // or 'media' or 'class'
|
darkMode: "class", // or 'media' or 'class'
|
||||||
theme: {
|
theme: {
|
||||||
extend: {},
|
extend: {},
|
||||||
},
|
},
|
||||||
variants: {
|
variants: {
|
||||||
extend: {},
|
extend: {},
|
||||||
},
|
},
|
||||||
plugins: [require('@tailwindcss/aspect-ratio'), require('@tailwindcss/typography'), require('daisyui')],
|
plugins: [require("@tailwindcss/aspect-ratio"), require("@tailwindcss/typography"), require("daisyui")],
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
export const PORT = '7745';
|
export const PORT = "7745";
|
||||||
export const HOST = 'http://127.0.0.1';
|
export const HOST = "http://127.0.0.1";
|
||||||
export const BASE_URL = HOST + ':' + PORT;
|
export const BASE_URL = HOST + ":" + PORT;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { exec } from 'child_process';
|
import { exec } from "child_process";
|
||||||
import * as config from './config';
|
import * as config from "./config";
|
||||||
|
|
||||||
export const setup = () => {
|
export const setup = () => {
|
||||||
console.log('Starting Client Tests');
|
console.log("Starting Client Tests");
|
||||||
console.log({
|
console.log({
|
||||||
PORT: config.PORT,
|
PORT: config.PORT,
|
||||||
HOST: config.HOST,
|
HOST: config.HOST,
|
||||||
|
@ -12,8 +12,8 @@ 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}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
/// <reference types="vitest" />
|
/// <reference types="vitest" />
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from "vite";
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
test: {
|
test: {
|
||||||
globalSetup: './test/setup.ts',
|
globalSetup: "./test/setup.ts",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue