feat: add basic machine page

This commit is contained in:
Aarnav Tale 2024-03-17 23:24:40 -04:00
parent 9594468bf4
commit fdc3cdde39
No known key found for this signature in database
GPG Key ID: 1CA889B6ACCAF2F2
6 changed files with 137 additions and 8 deletions

View File

@ -0,0 +1,32 @@
<script lang="ts">
import { IconCopy } from "@tabler/icons-svelte";
import { toast } from "@zerodevx/svelte-toast";
import clsx from "clsx";
export let key: string;
export let value: string;
export let copyable = false;
</script>
<dl class="flex gap-1 text-sm">
<dt class="w-1/3 sm:w-1/4 lg:w-1/3 shrink-0 min-w-0 truncate text-gray-700">
{key}
</dt>
{#if copyable}
<button
class="focus:outline-none flex items-center gap-x-1 truncate hover:bg-gray-100 rounded-md"
on:click={() => {
navigator.clipboard.writeText(value);
toast.push("Copied " + key);
}}
>
<dd class="min-w-0 truncate px-2 py-1">
{value}
</dd>
<IconCopy stroke={1} size={24} class="text-gray-600 pr-2" />
</button>
{:else}
<dd class="min-w-0 truncate px-2 py-1">
{value}
</dd>
{/if}
</dl>

View File

@ -12,7 +12,7 @@
href={`${base}${to}`}
class={clsx(
"flex items-center gap-x-2 p-2 border-b-2 text-sm",
$page.url.pathname === `${base}${to}`
$page.url.pathname.startsWith(`${base}${to}`)
? "border-white"
: "border-transparent",
)}

View File

@ -17,9 +17,9 @@ export type Machine = {
createdAt: Date;
registerMethod: 'REGISTER_METHOD_UNSPECIFIED'
| 'REGISTER_METHOD_AUTH_KEY'
| 'REGISTER_METHOD_CLI'
| 'REGISTER_METHOD_OIDC'
| 'REGISTER_METHOD_AUTH_KEY'
| 'REGISTER_METHOD_CLI'
| 'REGISTER_METHOD_OIDC'
forcedTags: string[];
invalidTags: string[];

View File

@ -36,10 +36,12 @@
{#each $query.data as machine}
<tr class="hover:bg-gray-100">
<td class="pt-2 pb-4 pl-4">
<h1>{machine.givenName}</h1>
<span class="text-sm font-mono text-gray-500"
>{machine.name}</span
>
<a href={`machines/${machine.id}`}>
<h1>{machine.givenName}</h1>
<span class="text-sm font-mono text-gray-500"
>{machine.name}</span
>
</a>
</td>
<td class="pt-2 pb-4 font-mono text-gray-600">
{#each machine.ipAddresses as ip, i}

View File

@ -0,0 +1,78 @@
<script lang="ts">
import type { PageData } from "./$types";
import { createQuery } from "@tanstack/svelte-query";
import { pull } from "$lib/api";
import type { Machine } from "$lib/types";
import { IconCircleFilled, IconCopy } from "@tabler/icons-svelte";
import Attribute from "$lib/components/Attribute.svelte";
import clsx from "clsx";
export let data: PageData;
const query = createQuery({
queryKey: [`machines/${data.id}`],
queryFn: async () => {
const response = await pull<{ node: Machine }>(
`v1/node/${data.id}`,
);
return response.node;
},
});
</script>
<svelte:head>
<title>
{$query.isSuccess ? `${$query.data.givenName} - Machines` : "Machines"}
</title>
</svelte:head>
{#if $query.isLoading}
<p>Loading...</p>
{:else if $query.isError}
<p>Error: {$query.error.message}</p>
{:else if $query.isSuccess}
<div>
<span class="flex items-baseline gap-x-4 text-sm mb-4">
<h1 class="text-2xl font-bold">
{$query.data.givenName}
</h1>
<IconCircleFilled
stroke={1}
size={24}
class={clsx(
"w-4 h-4",
$query.data.online ? "text-green-700" : "text-gray-300",
)}
/>
</span>
<div
class="p-4 md:p-6 border rounded-md grid grid-cols-1 lg:grid-cols-2 gap-y-2 sm:gap-x-12"
>
<Attribute key="Creator" value={$query.data.user.name} />
<Attribute key="Node ID" value={$query.data.id} />
<Attribute key="Node Name" value={$query.data.givenName} />
<Attribute key="Hostname" value={$query.data.name} />
<Attribute
key="Node Key"
value={$query.data.nodeKey}
copyable={true}
/>
<Attribute
key="Created"
value={new Date($query.data.createdAt).toLocaleString()}
/>
<Attribute
key="Last Seen"
value={new Date($query.data.lastSeen).toLocaleString()}
/>
<Attribute
key="Expiry"
value={new Date($query.data.expiry).toLocaleString()}
/>
<Attribute
key="Domain"
value={`${$query.data.givenName}.${$query.data.user.name}.ts.net`}
copyable={true}
/>
</div>
</div>
{/if}

View File

@ -0,0 +1,17 @@
import { pull } from "$lib/api";
import type { Machine } from "$lib/types";
import type { PageLoad } from './$types';
export async function load({ parent, params }: Parameters<PageLoad>[0]) {
const { queryClient } = await parent();
await queryClient.prefetchQuery({
queryKey: [`machines/${params.id}`],
queryFn: async () => {
const data = await pull<{ node: Machine }>(`v1/node/${params.id}`);
return data.node;
},
});
return { id: params.id }
}