🚚 Change routes
This commit is contained in:
parent
d6fdeed46c
commit
c7c510f1ce
@ -1,5 +1,5 @@
|
|||||||
import axios, {type AxiosInstance} from "axios";
|
import axios, {type AxiosInstance} from "axios";
|
||||||
|
|
||||||
export const Api: AxiosInstance = axios.create({
|
export const Api: AxiosInstance = axios.create({
|
||||||
baseURL: 'http://localhost:8080'
|
baseURL: '/api'
|
||||||
});
|
});
|
||||||
12
app/app.vue
12
app/app.vue
@ -1,3 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<div class="app">
|
||||||
<NuxtPage></NuxtPage>
|
<NuxtPage></NuxtPage>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.app {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -119,8 +119,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.narrow {
|
.narrow {
|
||||||
width: min(100%, 1340px);
|
width: min(100%, 1140px);
|
||||||
padding: 0 0.5rem;
|
padding: 2rem 0.5rem;
|
||||||
}
|
}
|
||||||
.narrow.s {
|
.narrow.s {
|
||||||
width: min(100%, 320px);
|
width: min(100%, 320px);
|
||||||
@ -133,11 +133,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tile, *[class^='tile-'], *[class*=' tile-'] {
|
.tile, *[class^='tile-'], *[class*=' tile-'] {
|
||||||
background-color: var(--tile-color);
|
border-radius: 0.5rem;
|
||||||
border-radius: 0.25rem;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: 1px solid #cddaff;
|
border: 1px solid #555555;
|
||||||
|
background-color: #222222;
|
||||||
|
display: grid;
|
||||||
|
gap: 1.5rem;
|
||||||
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tile-s {
|
.tile-s {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@100..900&display=swap');
|
@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@100..900&display=swap');
|
||||||
@import url('https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap');
|
@import url('https://fonts.googleapis.com/css2?family=Source+Code+Pro:ital,wght@0,200..900;1,200..900&display=swap');
|
||||||
|
|
||||||
* {
|
* {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|||||||
36
app/components/RatioComponent.vue
Normal file
36
app/components/RatioComponent.vue
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<template>
|
||||||
|
<div class="ratio center" :class="status.toLowerCase()" v-for="value in [(ratio * 100).toFixed(2)]">
|
||||||
|
<p v-if="value === '100.00'">100%</p>
|
||||||
|
<p v-else>{{ value }}%</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
defineProps<{
|
||||||
|
ratio: number,
|
||||||
|
status: string
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.ratio {
|
||||||
|
width: 4rem;
|
||||||
|
border-radius: 1rem;
|
||||||
|
}
|
||||||
|
.ratio * {
|
||||||
|
color: black;
|
||||||
|
font-weight: 550;
|
||||||
|
}
|
||||||
|
.up {
|
||||||
|
background-color: #74f474;
|
||||||
|
}
|
||||||
|
.up * {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
.down {
|
||||||
|
background-color: #ff4534;
|
||||||
|
}
|
||||||
|
.down * {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
73
app/components/pings/PingComponent.vue
Normal file
73
app/components/pings/PingComponent.vue
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<template>
|
||||||
|
<div class="ping tile-m">
|
||||||
|
<p class="left-center">{{ dayjs(ping.timestamp).format("DD.MM.YYYY HH:mm") }}</p>
|
||||||
|
<div class="center">
|
||||||
|
<p class="indicator center" :class="ping.result">{{ ping.code }}</p>
|
||||||
|
</div>
|
||||||
|
<p @click="open = !open" class="dropdown-icon">
|
||||||
|
<UiIcon class="pointer" v-if="!open">keyboard_arrow_down</UiIcon>
|
||||||
|
<UiIcon class="pointer" v-if="open">keyboard_arrow_up</UiIcon>
|
||||||
|
</p>
|
||||||
|
<div class="dropdown" v-if="open">
|
||||||
|
<pre>{{ JSON.stringify(JSON.parse(ping.body), null, 2) }}</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import type {Ping} from "~/components/targets/Target";
|
||||||
|
|
||||||
|
const open = ref(false);
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
ping: Ping
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.ping {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr auto auto;
|
||||||
|
grid-column-gap: 1rem;
|
||||||
|
grid-row-gap: 0.25rem;
|
||||||
|
align-content: center;
|
||||||
|
height: max-content;
|
||||||
|
}
|
||||||
|
.ping > * {
|
||||||
|
min-height: 1.75rem;
|
||||||
|
}
|
||||||
|
.indicator {
|
||||||
|
color: black;
|
||||||
|
border-radius: 1rem;
|
||||||
|
width: 3.5rem;
|
||||||
|
height: 1.5rem;
|
||||||
|
}
|
||||||
|
.dropdown {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
.dropdown > * {
|
||||||
|
font-family: "Source Code Pro", monospace;
|
||||||
|
font-optical-sizing: auto;
|
||||||
|
font-weight: 600;
|
||||||
|
background-color: #151515;
|
||||||
|
padding: 0.5rem;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
}
|
||||||
|
.dropdown-icon {
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
padding-top: 0.125rem;
|
||||||
|
|
||||||
|
}
|
||||||
|
.dropdown-icon * {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
.UP {
|
||||||
|
background-color: #74f474;
|
||||||
|
}
|
||||||
|
.DOWN {
|
||||||
|
background-color: #ff4534;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,18 +1,36 @@
|
|||||||
import {Api} from "~/api/Api";
|
import {Api} from "~/api/Api";
|
||||||
|
|
||||||
|
export class Group
|
||||||
|
{
|
||||||
|
constructor (
|
||||||
|
public key: string,
|
||||||
|
public displayName: string,
|
||||||
|
public targets: Target[],
|
||||||
|
) {}
|
||||||
|
|
||||||
|
static get(onSuccess: (groups: Group[]) => void)
|
||||||
|
{
|
||||||
|
Api.get<Group[]>("/groups")
|
||||||
|
.then((response) => {
|
||||||
|
onSuccess(response.data)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class Target
|
export class Target
|
||||||
{
|
{
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
public key: string,
|
public key: string,
|
||||||
public display: string,
|
public displayName: string,
|
||||||
public status: string,
|
public status: string,
|
||||||
public pings: Ping[],
|
public pings: Ping[],
|
||||||
|
public last1Hour: number,
|
||||||
|
public last24Hour: number
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
static get(onSuccess: (targets: Target[]) => void)
|
static getByKey(key: string, onSuccess: (_target: Target) => void)
|
||||||
{
|
{
|
||||||
Api.get<Target[]>("/targets")
|
Api.get<Target>("/healthchecks/" + key)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
onSuccess(response.data)
|
onSuccess(response.data)
|
||||||
});
|
});
|
||||||
@ -22,6 +40,9 @@ export class Target
|
|||||||
export class Ping
|
export class Ping
|
||||||
{
|
{
|
||||||
constructor (
|
constructor (
|
||||||
public result: string
|
public result: string,
|
||||||
|
public timestamp: Date,
|
||||||
|
public code: string,
|
||||||
|
public body: string
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
14
app/components/ui/UiIcon.vue
Normal file
14
app/components/ui/UiIcon.vue
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<template>
|
||||||
|
<span class="material-symbols-outlined"><slot></slot></span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.material-symbols-outlined {
|
||||||
|
font-variation-settings:
|
||||||
|
'FILL' 0,
|
||||||
|
'wght' 400,
|
||||||
|
'GRAD' 0,
|
||||||
|
'opsz' 24;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
57
app/pages/healthchecks/[group]/[target].vue
Normal file
57
app/pages/healthchecks/[group]/[target].vue
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<template>
|
||||||
|
<div class="narrow ping-page" v-if="target">
|
||||||
|
<div class="content-xl">
|
||||||
|
<h1>{{ target.displayName }}</h1>
|
||||||
|
<div class="col-2">
|
||||||
|
<div class="tile-l uptime">
|
||||||
|
<h3>1-Hour Uptime</h3>
|
||||||
|
<RatioComponent :ratio="target.last1Hour" :status="target.status"></RatioComponent>
|
||||||
|
</div>
|
||||||
|
<div class="tile-l uptime">
|
||||||
|
<h3>24-Hours Uptime</h3>
|
||||||
|
<RatioComponent :ratio="target.last24Hour" :status="target.status"></RatioComponent>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="main">
|
||||||
|
<PingComponent :ping="ping" v-for="ping in target.pings"></PingComponent>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {Target} from "~/components/targets/Target";
|
||||||
|
import PingComponent from "~/components/pings/PingComponent.vue";
|
||||||
|
|
||||||
|
const target: Ref<Target | undefined> = ref();
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const key = useRoute().params.target as string;
|
||||||
|
Target.getByKey(key, (_target: Target) => {
|
||||||
|
target.value = _target;
|
||||||
|
})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.ping-page {
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: auto 1fr;
|
||||||
|
gap: 2rem;
|
||||||
|
height: 100vh;
|
||||||
|
padding: 2rem;
|
||||||
|
}
|
||||||
|
.main {
|
||||||
|
overflow-y: auto;
|
||||||
|
min-height: 0;
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
.main > *:not(*:last-of-type) {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
.uptime {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,9 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="app">
|
<div class="narrow">
|
||||||
<div class="page">
|
<div>
|
||||||
<h1>Uptime Dashboard</h1>
|
<h1>Tavolio Uptime Dashboard</h1>
|
||||||
<div v-for="target in targets" class="target">
|
</div>
|
||||||
<p class="healthcheck"><span class="indicator">99.86%</span> {{ target.display }}</p>
|
<div class="tile" v-for="group in groups">
|
||||||
|
<h2>{{ group.displayName }}</h2>
|
||||||
|
<div v-for="target in group.targets" class="target" @click="useRouter().push('/healthchecks/' + group.key + '/' + target.key)">
|
||||||
|
<div class="left-center">
|
||||||
|
<RatioComponent :ratio="target.last24Hour" :status="target.status"></RatioComponent>
|
||||||
|
<p>{{ target.displayName }}</p>
|
||||||
|
</div>
|
||||||
<div class="ping-container">
|
<div class="ping-container">
|
||||||
<div style="user-select: none" v-for="ping in target.pings" :class="ping.result"> </div>
|
<div style="user-select: none" v-for="ping in target.pings" :class="ping.result"> </div>
|
||||||
</div>
|
</div>
|
||||||
@ -13,30 +19,24 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {Target} from "~/components/targets/Target";
|
import {Group} from "~/components/targets/Target";
|
||||||
|
|
||||||
const targets: Ref<Target[] | undefined> = ref();
|
const groups: Ref<Group[] | undefined> = ref();
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
Target.get((_targets: Target[]) => {
|
Group.get((_groups: Group[]) => {
|
||||||
targets.value = _targets;
|
groups.value = _groups;
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.app {
|
.narrow {
|
||||||
|
width: min(1140px, 100%);
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 2rem;
|
flex-direction: column;
|
||||||
}
|
gap: 1rem;
|
||||||
.page {
|
|
||||||
width: min(1140px, 100%);
|
|
||||||
background-color: #222222;
|
|
||||||
border-radius: 1rem;
|
|
||||||
padding: 2rem;
|
|
||||||
display: grid;
|
|
||||||
gap: 1.5rem;
|
|
||||||
}
|
}
|
||||||
.target {
|
.target {
|
||||||
display: grid;
|
display: grid;
|
||||||
@ -52,6 +52,9 @@ onMounted(() => {
|
|||||||
.healthcheck {
|
.healthcheck {
|
||||||
font-size: 1.125rem;
|
font-size: 1.125rem;
|
||||||
}
|
}
|
||||||
|
h2 {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
.UP {
|
.UP {
|
||||||
background-color: #74f474;
|
background-color: #74f474;
|
||||||
border-radius: 0.25rem;
|
border-radius: 0.25rem;
|
||||||
|
|||||||
42
app/utils/Optional.ts
Normal file
42
app/utils/Optional.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
export class Optional<T>
|
||||||
|
{
|
||||||
|
private object?: T;
|
||||||
|
|
||||||
|
private constructor(object?: T)
|
||||||
|
{
|
||||||
|
this.object = object;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ofNullable<T>(object?: T): Optional<T>
|
||||||
|
{
|
||||||
|
return new Optional(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
isEmpty()
|
||||||
|
{
|
||||||
|
return this.object == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
isPresent()
|
||||||
|
{
|
||||||
|
return this.object != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
orElse(other: T): T
|
||||||
|
{
|
||||||
|
if(this.object != null)
|
||||||
|
{
|
||||||
|
return this.object;
|
||||||
|
}
|
||||||
|
return other;
|
||||||
|
}
|
||||||
|
|
||||||
|
get(): T
|
||||||
|
{
|
||||||
|
if(this.object != null)
|
||||||
|
{
|
||||||
|
return this.object;
|
||||||
|
}
|
||||||
|
throw new Error("No value present in Optional.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,9 +1,19 @@
|
|||||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||||
|
import {Optional} from "./app/utils/Optional";
|
||||||
|
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
compatibilityDate: '2025-07-15',
|
compatibilityDate: '2025-07-15',
|
||||||
devtools: { enabled: true },
|
devtools: { enabled: true },
|
||||||
css: [
|
css: [
|
||||||
'@/assets/style.css',
|
'@/assets/style.css',
|
||||||
'@/assets/base-style.css'
|
'@/assets/base-style.css'
|
||||||
|
],
|
||||||
|
app: {
|
||||||
|
head: {
|
||||||
|
link: [
|
||||||
|
{ rel: 'stylesheet', href: 'https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200' }
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
baseURL: Optional.ofNullable(process.env.NUXT_ROOT_PATH).orElse("/")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
27
package-lock.json
generated
27
package-lock.json
generated
@ -8,9 +8,13 @@
|
|||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.13.4",
|
"axios": "^1.13.4",
|
||||||
|
"dayjs": "^1.11.19",
|
||||||
"nuxt": "^4.3.0",
|
"nuxt": "^4.3.0",
|
||||||
"vue": "^3.5.27",
|
"vue": "^3.5.27",
|
||||||
"vue-router": "^4.6.4"
|
"vue-router": "^4.6.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^25.2.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/code-frame": {
|
"node_modules/@babel/code-frame": {
|
||||||
@ -3430,6 +3434,16 @@
|
|||||||
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
|
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/node": {
|
||||||
|
"version": "25.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz",
|
||||||
|
"integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==",
|
||||||
|
"devOptional": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"undici-types": "~7.16.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/parse-path": {
|
"node_modules/@types/parse-path": {
|
||||||
"version": "7.0.3",
|
"version": "7.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/parse-path/-/parse-path-7.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/parse-path/-/parse-path-7.0.3.tgz",
|
||||||
@ -4877,6 +4891,12 @@
|
|||||||
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
|
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/dayjs": {
|
||||||
|
"version": "1.11.19",
|
||||||
|
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz",
|
||||||
|
"integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/db0": {
|
"node_modules/db0": {
|
||||||
"version": "0.3.4",
|
"version": "0.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/db0/-/db0-0.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/db0/-/db0-0.3.4.tgz",
|
||||||
@ -9051,6 +9071,13 @@
|
|||||||
"@types/estree": "^1.0.0"
|
"@types/estree": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/undici-types": {
|
||||||
|
"version": "7.16.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
|
||||||
|
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
|
||||||
|
"devOptional": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/unenv": {
|
"node_modules/unenv": {
|
||||||
"version": "2.0.0-rc.24",
|
"version": "2.0.0-rc.24",
|
||||||
"resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.24.tgz",
|
"resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.24.tgz",
|
||||||
|
|||||||
@ -11,8 +11,12 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.13.4",
|
"axios": "^1.13.4",
|
||||||
|
"dayjs": "^1.11.19",
|
||||||
"nuxt": "^4.3.0",
|
"nuxt": "^4.3.0",
|
||||||
"vue": "^3.5.27",
|
"vue": "^3.5.27",
|
||||||
"vue-router": "^4.6.4"
|
"vue-router": "^4.6.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^25.2.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,5 +14,8 @@
|
|||||||
{
|
{
|
||||||
"path": "./.nuxt/tsconfig.node.json"
|
"path": "./.nuxt/tsconfig.node.json"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"compilerOptions": {
|
||||||
|
"types": ["node"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user