rename clients to devices
This commit is contained in:
@@ -24,7 +24,7 @@
|
||||
{#if user}
|
||||
<li><a href="/user" class={getNavClass(/^\/user$/)}>Profile</a></li>
|
||||
<li><a href="/connections" class={getNavClass(/^\/connections$/)}>Connections</a></li>
|
||||
<li><a href="/clients" class={getNavClass(/^\/clients(\/\d+)?$/)}>Clients</a></li>
|
||||
<li><a href="/devices" class={getNavClass(/^\/devices(\/\d+)?$/)}>Devices</a></li>
|
||||
{/if}
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<section id="get-started" class="border-l-2 pl-6">
|
||||
<p>
|
||||
To get started,
|
||||
<Button class="ml-2" href="/clients?add=New+Client">Create a New Client</Button>
|
||||
<Button class="ml-2" href="/devices?add=New+Device">Add a New Device</Button>
|
||||
</p>
|
||||
</section>
|
||||
<!-- <section id="using-wireguard">-->
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import { error } from '@sveltejs/kit';
|
||||
import type { RequestHandler } from './$types';
|
||||
import { findClient, mapClientToDetails } from '$lib/server/clients';
|
||||
|
||||
export const GET: RequestHandler = async (event) => {
|
||||
if (!event.locals.user) {
|
||||
return error(401, 'Unauthorized');
|
||||
}
|
||||
|
||||
const { id } = event.params;
|
||||
const clientId = parseInt(id);
|
||||
if (isNaN(clientId)) {
|
||||
return error(400, 'Invalid client ID');
|
||||
}
|
||||
const client = await findClient(event.locals.user.id, clientId);
|
||||
if (!client) {
|
||||
return error(404, 'Client not found');
|
||||
}
|
||||
return new Response(JSON.stringify(mapClientToDetails(client)));
|
||||
};
|
||||
@@ -1,29 +1,29 @@
|
||||
import { error } from '@sveltejs/kit';
|
||||
import type { RequestHandler } from './$types';
|
||||
import { createClient, findClients, mapClientToDetails } from '$lib/server/clients';
|
||||
import { createDevice, findDevices, mapDeviceToDetails } from '$lib/server/devices';
|
||||
|
||||
export const GET: RequestHandler = async (event) => {
|
||||
if (!event.locals.user) {
|
||||
return error(401, 'Unauthorized');
|
||||
}
|
||||
|
||||
const clients = await findClients(event.locals.user.id);
|
||||
const devices = await findDevices(event.locals.user.id);
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
clients: clients.map(mapClientToDetails),
|
||||
devices: devices.map(mapDeviceToDetails),
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export type Clients = Awaited<ReturnType<typeof findClients>>;
|
||||
export type Devices = Awaited<ReturnType<typeof findDevices>>;
|
||||
|
||||
export const POST: RequestHandler = async (event) => {
|
||||
if (!event.locals.user) {
|
||||
return error(401, 'Unauthorized');
|
||||
}
|
||||
const { name } = await event.request.json();
|
||||
const res = await createClient({
|
||||
const res = await createDevice({
|
||||
name,
|
||||
user: event.locals.user,
|
||||
});
|
||||
20
src/routes/api/devices/[id]/+server.ts
Normal file
20
src/routes/api/devices/[id]/+server.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { error } from '@sveltejs/kit';
|
||||
import type { RequestHandler } from './$types';
|
||||
import { findDevice, mapDeviceToDetails } from '$lib/server/devices';
|
||||
|
||||
export const GET: RequestHandler = async (event) => {
|
||||
if (!event.locals.user) {
|
||||
return error(401, 'Unauthorized');
|
||||
}
|
||||
|
||||
const { id } = event.params;
|
||||
const deviceId = parseInt(id);
|
||||
if (isNaN(deviceId)) {
|
||||
return error(400, 'Invalid device ID');
|
||||
}
|
||||
const device = await findDevice(event.locals.user.id, deviceId);
|
||||
if (!device) {
|
||||
return error(404, 'Device not found');
|
||||
}
|
||||
return new Response(JSON.stringify(mapDeviceToDetails(device)));
|
||||
};
|
||||
@@ -1,9 +0,0 @@
|
||||
import type { PageLoad } from './$types';
|
||||
import type { ClientDetails } from '$lib/types/clients';
|
||||
|
||||
export const load: PageLoad = async ({ fetch }) => {
|
||||
const res = await fetch('/api/clients');
|
||||
const { clients } = await res.json() as { clients: ClientDetails[] };
|
||||
|
||||
return { clients };
|
||||
};
|
||||
@@ -1,16 +0,0 @@
|
||||
import type { PageLoad } from './$types';
|
||||
import type { ClientDetails } from '$lib/types/clients';
|
||||
import { clientDetailsToConfig } from '$lib/clients';
|
||||
import { error } from '@sveltejs/kit';
|
||||
|
||||
export const load: PageLoad = async ({ fetch, params }) => {
|
||||
const res = await fetch(`/api/clients/${params.id}`);
|
||||
const resJson = await res.json();
|
||||
if (!res.ok) {
|
||||
return error(res.status, resJson['message']);
|
||||
}
|
||||
const client = resJson as ClientDetails;
|
||||
const config = clientDetailsToConfig(client);
|
||||
|
||||
return { client, config };
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Actions } from './$types';
|
||||
import { createClient } from '$lib/server/clients';
|
||||
import { createDevice } from '$lib/server/devices';
|
||||
import { error, redirect } from '@sveltejs/kit';
|
||||
|
||||
export const actions = {
|
||||
@@ -8,14 +8,14 @@ export const actions = {
|
||||
const formData = await event.request.formData();
|
||||
const name = formData.get('name');
|
||||
if (typeof name !== 'string' || name.trim() === '') return error(400, 'Invalid name');
|
||||
const res = await createClient({
|
||||
const res = await createDevice({
|
||||
name: name.trim(),
|
||||
user: event.locals.user,
|
||||
});
|
||||
|
||||
switch (res._tag) {
|
||||
case 'ok': {
|
||||
return redirect(303, `/clients/${res.value}`);
|
||||
return redirect(303, `/devices/${res.value}`);
|
||||
}
|
||||
case 'err': {
|
||||
const [status, message] = res.error;
|
||||
@@ -23,7 +23,7 @@
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Clients</title>
|
||||
<title>Devices</title>
|
||||
</svelte:head>
|
||||
|
||||
<Table.Root class="divide-y-2 divide-background overflow-hidden rounded-lg bg-accent">
|
||||
@@ -37,21 +37,21 @@
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body class="divide-y-2 divide-background">
|
||||
{#each data.clients as client}
|
||||
{#each data.devices as device}
|
||||
<Table.Row class="hover:bg-surface group">
|
||||
<Table.Head scope="row">
|
||||
<a
|
||||
href={`/clients/${client.id}`}
|
||||
href={`/devices/${device.id}`}
|
||||
class="flex size-full items-center group-hover:underline"
|
||||
>
|
||||
{client.name}
|
||||
{device.name}
|
||||
</a>
|
||||
</Table.Head>
|
||||
<Table.Cell class="truncate">{client.publicKey}</Table.Cell>
|
||||
<!-- <Table.Cell class="truncate max-w-[10ch]">{client.privateKey}</Table.Cell>-->
|
||||
<!-- <Table.Cell class="truncate max-w-[10ch]">{client.preSharedKey}</Table.Cell>-->
|
||||
<Table.Cell class="truncate">{device.publicKey}</Table.Cell>
|
||||
<!-- <Table.Cell class="truncate max-w-[10ch]">{device.privateKey}</Table.Cell>-->
|
||||
<!-- <Table.Cell class="truncate max-w-[10ch]">{device.preSharedKey}</Table.Cell>-->
|
||||
<Table.Cell class="flex flex-wrap gap-1">
|
||||
{#each client.ips as ip}
|
||||
{#each device.ips as ip}
|
||||
<Badge class="select-auto bg-background" variant="secondary">{ip}</Badge>
|
||||
{/each}
|
||||
</Table.Cell>
|
||||
@@ -60,18 +60,18 @@
|
||||
</Table.Body>
|
||||
</Table.Root>
|
||||
|
||||
<!--Floating action button for adding a new client-->
|
||||
<!--Floating action button for adding a new device-->
|
||||
<Dialog.Root bind:open={dialogOpen}>
|
||||
<div class="mt-auto flex self-end pt-4">
|
||||
<Dialog.Trigger class={buttonVariants({ variant: 'default' }) + ' flex gap-4'}>
|
||||
<LucidePlus />
|
||||
New Client
|
||||
New Device
|
||||
</Dialog.Trigger>
|
||||
</div>
|
||||
<Dialog.Content class="max-w-xs">
|
||||
<form class="contents" method="post" action="?/create">
|
||||
<Dialog.Header class="">
|
||||
<Dialog.Title>Create a new client</Dialog.Title>
|
||||
<Dialog.Title>Add a new device</Dialog.Title>
|
||||
</Dialog.Header>
|
||||
<div class="flex flex-wrap items-center justify-between gap-4">
|
||||
<Label for="name">Name</Label>
|
||||
@@ -81,12 +81,12 @@
|
||||
pattern=".*[^\s]+.*"
|
||||
type="text"
|
||||
name="name"
|
||||
placeholder="New Client"
|
||||
placeholder="New Device"
|
||||
class="max-w-[20ch]"
|
||||
/>
|
||||
</div>
|
||||
<Dialog.Footer>
|
||||
<Button type="submit">Create</Button>
|
||||
<Button type="submit">Add</Button>
|
||||
</Dialog.Footer>
|
||||
</form>
|
||||
</Dialog.Content>
|
||||
9
src/routes/devices/+page.ts
Normal file
9
src/routes/devices/+page.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import type { PageLoad } from './$types';
|
||||
import type { DeviceDetails } from '$lib/devices';
|
||||
|
||||
export const load: PageLoad = async ({ fetch }) => {
|
||||
const res = await fetch('/api/devices');
|
||||
const { devices } = await res.json() as { devices: DeviceDetails[] };
|
||||
|
||||
return { devices };
|
||||
};
|
||||
@@ -6,11 +6,11 @@
|
||||
|
||||
const { data }: { data: PageData } = $props();
|
||||
|
||||
// Clean the client name for the file name,
|
||||
// Clean the device name for the wg config filename,
|
||||
// things can break otherwise (too long or invalid characters)
|
||||
// https://github.com/pirate/wireguard-docs
|
||||
const clientWgCleanedName =
|
||||
data.client.name.slice(0, 15).replace(/[^a-zA-Z0-9_=+.-]/g, '_') + '.conf';
|
||||
const deviceWgCleanedName =
|
||||
data.device.name.slice(0, 15).replace(/[^a-zA-Z0-9_=+.-]/g, '_') + '.conf';
|
||||
|
||||
let qrCode = new QRCode({
|
||||
content: data.config,
|
||||
@@ -22,13 +22,13 @@
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{data.client.name}</title>
|
||||
<title>{data.device.name}</title>
|
||||
</svelte:head>
|
||||
|
||||
<h1 class="w-fit rounded-lg bg-accent p-2 text-lg">{data.client.name}</h1>
|
||||
<h1 class="w-fit rounded-lg bg-accent p-2 text-lg">{data.device.name}</h1>
|
||||
|
||||
<section id="client-configuration" class="flex flex-wrap items-center justify-center gap-4">
|
||||
<CodeSnippet data={data.config} filename={clientWgCleanedName} copy download />
|
||||
<section id="device-configuration" class="flex flex-wrap items-center justify-center gap-4">
|
||||
<CodeSnippet data={data.config} filename={deviceWgCleanedName} copy download />
|
||||
|
||||
<div class="size-fit overflow-auto rounded-lg">
|
||||
{@html qrCode.svg()}
|
||||
15
src/routes/devices/[id]/+page.ts
Normal file
15
src/routes/devices/[id]/+page.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import type { PageLoad } from './$types';
|
||||
import { type DeviceDetails, deviceDetailsToConfig } from '$lib/devices';
|
||||
import { error } from '@sveltejs/kit';
|
||||
|
||||
export const load: PageLoad = async ({ fetch, params }) => {
|
||||
const res = await fetch(`/api/devices/${params.id}`);
|
||||
const resJson = await res.json();
|
||||
if (!res.ok) {
|
||||
return error(res.status, resJson['message']);
|
||||
}
|
||||
const device = resJson as DeviceDetails;
|
||||
const config = deviceDetailsToConfig(device);
|
||||
|
||||
return { device, config };
|
||||
};
|
||||
Reference in New Issue
Block a user