feat(homelab)!: migrate to svelte kit, add more server stats endpoints
This commit is contained in:
13
nix/homelab/frontend/src/app.d.ts
vendored
Normal file
13
nix/homelab/frontend/src/app.d.ts
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
// See https://svelte.dev/docs/kit/types#app.d.ts
|
||||
// for information about these interfaces
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface PageState {}
|
||||
// interface Platform {}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
18
nix/homelab/frontend/src/app.html
Normal file
18
nix/homelab/frontend/src/app.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<!-- <link rel="stylesheet" href="/src/app.css" /> -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<!-- <title>Homelab</title> -->
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
|
||||
|
||||
</html>
|
||||
@@ -2,6 +2,12 @@
|
||||
import { createQuery } from "@tanstack/svelte-query";
|
||||
import { fetchStats } from "./stats";
|
||||
import { LoaderCircle } from "@lucide/svelte";
|
||||
import {
|
||||
formatDistance,
|
||||
formatDistanceToNow,
|
||||
formatDuration,
|
||||
intervalToDuration,
|
||||
} from "date-fns";
|
||||
|
||||
const query = createQuery(() => ({
|
||||
queryKey: ["minecraft-server-stats"],
|
||||
@@ -9,6 +15,21 @@
|
||||
refetchInterval: 10000,
|
||||
staleTime: 5000,
|
||||
}));
|
||||
|
||||
const formatUptime = () => {
|
||||
if (!query.data) {
|
||||
return "--";
|
||||
}
|
||||
const started_at = query.data.uptime.started_at;
|
||||
const duration = intervalToDuration({ start: started_at, end: new Date() });
|
||||
$inspect(duration);
|
||||
if (!duration.days && (duration.hours ?? 0) < 1) {
|
||||
return formatDistanceToNow(new Date(query.data.uptime.started_at));
|
||||
}
|
||||
return formatDuration(duration, {
|
||||
format: ["days", "hours", "minutes"],
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
{#snippet statItem(label: string, value?: string | number)}
|
||||
@@ -21,7 +42,7 @@
|
||||
<div class="border border-zinc-600 rounded-lg p-4">
|
||||
<h3 class="text-lg font-medium mb-3">
|
||||
Server Stats {#if query.isError}
|
||||
<span class="text-sm text-red-500"
|
||||
<span class="ml-1 text-sm text-red-500"
|
||||
>an error occured fetching server stats</span
|
||||
>
|
||||
{:else if query.isPending}
|
||||
@@ -31,7 +52,7 @@
|
||||
<div class="grid grid-cols-2 gap-4 text-zinc-400">
|
||||
{@render statItem("Players Online", query.data?.players_online ?? "--")}
|
||||
{@render statItem("Server Status", query.data?.status ?? "--")}
|
||||
{@render statItem("Uptime", query.data?.uptime ?? "--")}
|
||||
{@render statItem("Uptime", formatUptime())}
|
||||
{@render statItem("World Size", query.data?.world_size ?? "--")}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,13 +2,14 @@ type StatsResponse = {
|
||||
status: string;
|
||||
players_online: number;
|
||||
max_players: number;
|
||||
uptime: string;
|
||||
uptime: {
|
||||
seconds: number;
|
||||
started_at: string;
|
||||
};
|
||||
world_size: string;
|
||||
};
|
||||
|
||||
export const fetchStats = async () => {
|
||||
const response = await fetch(
|
||||
"http://localhost:5173/api/minecraft-server-stats",
|
||||
);
|
||||
const response = await fetch("/api/minecraft-server-stats");
|
||||
return (await response.json()) as StatsResponse;
|
||||
};
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import { mount } from 'svelte'
|
||||
import './app.css'
|
||||
import App from './App.svelte'
|
||||
|
||||
const app = mount(App, {
|
||||
target: document.getElementById('app')!,
|
||||
})
|
||||
|
||||
export default app
|
||||
7
nix/homelab/frontend/src/routes/+layout.svelte
Normal file
7
nix/homelab/frontend/src/routes/+layout.svelte
Normal file
@@ -0,0 +1,7 @@
|
||||
<script lang="ts">
|
||||
import "./layout.css";
|
||||
|
||||
let { children } = $props();
|
||||
</script>
|
||||
|
||||
{@render children()}
|
||||
2
nix/homelab/frontend/src/routes/+layout.ts
Normal file
2
nix/homelab/frontend/src/routes/+layout.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export const ssr = false;
|
||||
export const prerender = false;
|
||||
@@ -1,26 +1,22 @@
|
||||
<script lang="ts">
|
||||
import {
|
||||
createQuery,
|
||||
QueryClient,
|
||||
QueryClientProvider,
|
||||
} from "@tanstack/svelte-query";
|
||||
import Actions from "./lib/minecraft/Actions.svelte";
|
||||
import Stats from "./lib/minecraft/Stats.svelte";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/svelte-query";
|
||||
import Actions from "$lib/minecraft/Actions.svelte";
|
||||
import Stats from "$lib/minecraft/Stats.svelte";
|
||||
import { SvelteQueryDevtools } from "@tanstack/svelte-query-devtools";
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
</script>
|
||||
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<main class="flex justify-center mt-8">
|
||||
<main class="mt-8 flex justify-center">
|
||||
<div class="w-full max-w-2xl px-4">
|
||||
<div class="flex justify-center">
|
||||
<h1 class="text-2xl font-semibold mb-8">Management</h1>
|
||||
<h1 class="mb-8 text-2xl font-semibold">Management</h1>
|
||||
</div>
|
||||
|
||||
<!-- Minecraft Section -->
|
||||
<section class="bg-zinc-800 rounded-lg p-6">
|
||||
<h2 class="text-xl mb-4">Minecraft</h2>
|
||||
<section class="rounded-lg bg-zinc-800 p-6">
|
||||
<h2 class="mb-4 text-xl">Minecraft</h2>
|
||||
<Actions />
|
||||
<Stats />
|
||||
</section>
|
||||
Reference in New Issue
Block a user