better types
This commit is contained in:
@@ -1,9 +1,22 @@
|
|||||||
import type { User } from '~/types/user'
|
import type { Plan, User } from '~/types/user'
|
||||||
import { useFetch } from '#app'
|
import { useFetch } from '#app'
|
||||||
|
|
||||||
|
const uninitializedUser = {
|
||||||
|
id: "",
|
||||||
|
username: "",
|
||||||
|
email: "",
|
||||||
|
plan: <Plan>{
|
||||||
|
id: 0,
|
||||||
|
max_storage: 0
|
||||||
|
},
|
||||||
|
usage: 0,
|
||||||
|
created_at: "",
|
||||||
|
is_admin: false
|
||||||
|
}
|
||||||
|
|
||||||
export const useUser = () => {
|
export const useUser = () => {
|
||||||
// Global state for storing the user
|
// Global state for storing the user
|
||||||
const user = useState('user', () => { return { fetched: false, user: <User>{} } })
|
const user = useState('user', () => { return { fetched: false, user: uninitializedUser } })
|
||||||
|
|
||||||
// Fetch the user only if it's uninitialized (i.e., null)
|
// Fetch the user only if it's uninitialized (i.e., null)
|
||||||
const getUser = async () => {
|
const getUser = async () => {
|
||||||
@@ -24,9 +37,9 @@ export const useUser = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
user.value.user = data.value
|
user.value.user = data.value
|
||||||
} catch (e) {
|
} catch (e: any) {
|
||||||
console.error(e.message)
|
console.error(e.message)
|
||||||
user.value.user = {}
|
user.value.user = uninitializedUser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,7 +50,7 @@ export const useUser = () => {
|
|||||||
|
|
||||||
// Clear the user data (e.g., on logout)
|
// Clear the user data (e.g., on logout)
|
||||||
const resetUser = () => {
|
const resetUser = () => {
|
||||||
user.value.user = {}
|
user.value.user = uninitializedUser
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ definePageMeta({
|
|||||||
const user = await getUser();
|
const user = await getUser();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
const accordionMapping = {
|
const accordionMapping: Record<string, string> = {
|
||||||
'/admin/users': '',
|
'/admin/users': '',
|
||||||
'/admin/config/settings': 'item-2',
|
'/admin/config/settings': 'item-2',
|
||||||
'/admin': 'item-1',
|
'/admin': 'item-1',
|
||||||
@@ -30,7 +30,7 @@ const isActiveLink = (path: string) => route.path === path;
|
|||||||
<div class="w-auto md:w-60 flex-shrink-0">
|
<div class="w-auto md:w-60 flex-shrink-0">
|
||||||
<aside class="rounded-md border overflow-hidden w-full h-fit">
|
<aside class="rounded-md border overflow-hidden w-full h-fit">
|
||||||
<div class="px-4 py-3.5 bg-surface border-b">Admin Settings</div>
|
<div class="px-4 py-3.5 bg-surface border-b">Admin Settings</div>
|
||||||
<VlAccordion type="single" :defaultValue="getActiveAccordion()">
|
<VlAccordion type="single" :defaultValue="getActiveAccordion() || undefined">
|
||||||
<VlAccordionItem value="item-1" class="text-sm">
|
<VlAccordionItem value="item-1" class="text-sm">
|
||||||
<VlAccordionTrigger class="transition-bg hover:bg-muted/10 px-4 py-3.5">
|
<VlAccordionTrigger class="transition-bg hover:bg-muted/10 px-4 py-3.5">
|
||||||
Maintenance
|
Maintenance
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ export default defineNuxtRouteMiddleware(async (to, from) => {
|
|||||||
const { getUser } = useUser()
|
const { getUser } = useUser()
|
||||||
const user = await getUser()
|
const user = await getUser()
|
||||||
|
|
||||||
if (!user.is_admin) {
|
if (!user || !user.is_admin) {
|
||||||
return navigateTo('/home')
|
return navigateTo('/home')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,14 +1,26 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import type { NuxtError } from '#app';
|
||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
middleware: ["auth", "admin"],
|
middleware: ["auth", "admin"],
|
||||||
layout: "admin"
|
layout: "admin"
|
||||||
});
|
});
|
||||||
|
|
||||||
let {data: systemStatusData, refresh} = await useFetch("/api/admin/status")
|
let {data: systemStatusData, refresh} = await useFetch<
|
||||||
|
{ uptime: string, num_goroutine: number, cur_mem_usage: string, total_mem_usage: string,
|
||||||
|
mem_obtained: string, ptr_lookup_times: number, mem_allocations: number, mem_frees: number, cur_heap_usage: string, heap_mem_obtained: string,
|
||||||
|
heap_mem_idle: string, heap_mem_inuse: string, heap_mem_release: string, heap_objects: number, bootstrap_stack_usage: string, stack_mem_obtained: string,
|
||||||
|
mspan_structures_usage: string, mspan_structures_obtained: string, mcache_structures_usage: string, mcache_structures_obtained: string,
|
||||||
|
buck_hash_sys: string, gc_sys: string, other_sys: string, next_gc: string, last_gc_time: string, pause_total_ns: string, pause_ns: string, num_gc: number
|
||||||
|
}, NuxtError<{ message: string }>>("/api/admin/status")
|
||||||
|
|
||||||
const calculateTimeSince = (time) => {
|
if (systemStatusData.value === null) {
|
||||||
const now = new Date();
|
throw new Error("Failed to fetch system status")
|
||||||
const date = new Date(time);
|
}
|
||||||
|
|
||||||
|
const calculateTimeSince = (time: string) => {
|
||||||
|
const now: number = new Date().getTime();
|
||||||
|
const date: number = new Date(time).getTime();
|
||||||
const diffInSeconds = Math.floor((now - date) / 1000);
|
const diffInSeconds = Math.floor((now - date) / 1000);
|
||||||
|
|
||||||
const days = Math.floor(diffInSeconds / (3600 * 24));
|
const days = Math.floor(diffInSeconds / (3600 * 24));
|
||||||
@@ -29,10 +41,14 @@ const calculateTimeSince = (time) => {
|
|||||||
let uptime = ref(calculateTimeSince(systemStatusData.value.uptime));
|
let uptime = ref(calculateTimeSince(systemStatusData.value.uptime));
|
||||||
let lastGcTime = ref(calculateTimeSince(systemStatusData.value.last_gc_time));
|
let lastGcTime = ref(calculateTimeSince(systemStatusData.value.last_gc_time));
|
||||||
|
|
||||||
let systemStatusInterval;
|
let systemStatusInterval: NodeJS.Timeout;
|
||||||
let timeInterval;
|
let timeInterval: NodeJS.Timeout;
|
||||||
|
|
||||||
const updateTime = () => {
|
const updateTime = () => {
|
||||||
|
if (systemStatusData.value === null) {
|
||||||
|
throw new Error("Failed to fetch system status")
|
||||||
|
}
|
||||||
|
|
||||||
uptime.value = calculateTimeSince(systemStatusData.value.uptime);
|
uptime.value = calculateTimeSince(systemStatusData.value.uptime);
|
||||||
lastGcTime.value = calculateTimeSince(systemStatusData.value.last_gc_time)
|
lastGcTime.value = calculateTimeSince(systemStatusData.value.last_gc_time)
|
||||||
};
|
};
|
||||||
@@ -57,7 +73,7 @@ onUnmounted(() => {
|
|||||||
<div class="w-full overflow-hidden rounded-md border h-fit text-[15px]">
|
<div class="w-full overflow-hidden rounded-md border h-fit text-[15px]">
|
||||||
<h4 class="bg-surface px-3.5 py-3 border-b">System Status</h4>
|
<h4 class="bg-surface px-3.5 py-3 border-b">System Status</h4>
|
||||||
<div class="p-3.5 text-sm">
|
<div class="p-3.5 text-sm">
|
||||||
<dl class="flex-wrap">
|
<dl class="flex-wrap" v-if="systemStatusData !== null">
|
||||||
<dt>Server Uptime</dt>
|
<dt>Server Uptime</dt>
|
||||||
<dd>{{ uptime }}</dd>
|
<dd>{{ uptime }}</dd>
|
||||||
<dt>Current Goroutine</dt>
|
<dt>Current Goroutine</dt>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ const updateUser = async () => {
|
|||||||
let body = {
|
let body = {
|
||||||
username: username.value,
|
username: username.value,
|
||||||
email: email.value,
|
email: email.value,
|
||||||
password: password.value,
|
password: password.value as string || undefined,
|
||||||
plan_id: plan_id.value,
|
plan_id: plan_id.value,
|
||||||
is_admin: is_admin.value === 'checked' ? true : false,
|
is_admin: is_admin.value === 'checked' ? true : false,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,8 +33,7 @@ const fetchNextPage = async () => {
|
|||||||
</h4>
|
</h4>
|
||||||
<NuxtLink to="/admin/users/new">
|
<NuxtLink to="/admin/users/new">
|
||||||
<button
|
<button
|
||||||
class="transition-bg bg-pine/10 text-pine px-2 py-1.5 rounded-md hover:bg-pine/15 active:bg-pine/25 h-fit text-xs"
|
class="transition-bg bg-pine/10 text-pine px-2 py-1.5 rounded-md hover:bg-pine/15 active:bg-pine/25 h-fit text-xs">
|
||||||
v-on:click="updateUser">
|
|
||||||
Create User Account
|
Create User Account
|
||||||
</button>
|
</button>
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import type { NuxtError } from '#app';
|
||||||
import type { User } from '~/types/user';
|
import type { User } from '~/types/user';
|
||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
@@ -12,7 +13,7 @@ let password = ref('')
|
|||||||
|
|
||||||
let error = ref('')
|
let error = ref('')
|
||||||
|
|
||||||
let timeout;
|
let timeout: NodeJS.Timeout;
|
||||||
const submitForm = async () => {
|
const submitForm = async () => {
|
||||||
let { data, error: fetchError } = await useAsyncData<User, NuxtError<{ message: string }>>(
|
let { data, error: fetchError } = await useAsyncData<User, NuxtError<{ message: string }>>(
|
||||||
() => $fetch('/api/admin/users/new', {
|
() => $fetch('/api/admin/users/new', {
|
||||||
@@ -45,11 +46,11 @@ onUnmounted(() => {
|
|||||||
</h4>
|
</h4>
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<label for="username" class="block max-w-64 text-sm">Username</label>
|
<label for="username" class="block max-w-64 text-sm">Username</label>
|
||||||
<Input v-model="username" :value="username" id="username" placeholder="Username" class="w-full mb-2" />
|
<Input v-model="username" :value="username" id="username" placeholder="Username" autocomplete="off" class="w-full mb-2" />
|
||||||
<label for="email" class="block max-w-64 text-sm">Email</label>
|
<label for="email" class="block max-w-64 text-sm">Email</label>
|
||||||
<Input v-model="email" :value="email" id="email" placeholder="Email" class="w-full mb-2" />
|
<Input v-model="email" :value="email" id="email" placeholder="Email" autocomplete="off" class="w-full mb-2" />
|
||||||
<label for="password" class="block max-w-64 text-sm">Password</label>
|
<label for="password" class="block max-w-64 text-sm">Password</label>
|
||||||
<Input v-model="password" id="password" type="password" placeholder="Password" class="w-full mb-2" />
|
<Input v-model="password" :value="password" id="password" type="password" placeholder="Password" autocomplete="off" class="w-full mb-2" />
|
||||||
<p class="text-love mb-2">{{ error }}</p>
|
<p class="text-love mb-2">{{ error }}</p>
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ let password = ref('')
|
|||||||
|
|
||||||
let error = ref('')
|
let error = ref('')
|
||||||
|
|
||||||
let timeout;
|
let timeout: NodeJS.Timeout;
|
||||||
const submitForm = async () => {
|
const submitForm = async () => {
|
||||||
let { data, error: fetchError } = await useAsyncData<User, NuxtError<{ message: string }>>(
|
let { data, error: fetchError } = await useAsyncData<User, NuxtError<{ message: string }>>(
|
||||||
() => $fetch('/api/login', {
|
() => $fetch('/api/login', {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ let password = ref('')
|
|||||||
|
|
||||||
let error = ref('')
|
let error = ref('')
|
||||||
|
|
||||||
let timeout;
|
let timeout: NodeJS.Timeout;
|
||||||
const submitForm = async () => {
|
const submitForm = async () => {
|
||||||
let { data, error: fetchError } = await useAsyncData<User, NuxtError<{ message: string }>>(
|
let { data, error: fetchError } = await useAsyncData<User, NuxtError<{ message: string }>>(
|
||||||
() => $fetch('/api/signup', {
|
() => $fetch('/api/signup', {
|
||||||
|
|||||||
Reference in New Issue
Block a user