feat: add device settings page
- Add device CRUD operations (create, delete, regenerate api keys) - Add API key visibility toggle and copy button
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
import { command, form, getRequestEvent, query } from '$app/server';
|
||||
import { createDeviceSchema, type Device } from '$lib/schema/device';
|
||||
import { error } from '@sveltejs/kit';
|
||||
import z from 'zod';
|
||||
|
||||
export const listDevices = query(async (): Promise<Device[]> => {
|
||||
const { locals } = getRequestEvent();
|
||||
|
||||
const response = await locals.api.get(`/devices`);
|
||||
|
||||
if (!response.ok) error(500, 'An unkown error occurred');
|
||||
|
||||
const deviceResult = await response.json();
|
||||
return deviceResult.items
|
||||
});
|
||||
|
||||
export const createDevice = form(createDeviceSchema, async (data): Promise<Device> => {
|
||||
const { locals } = getRequestEvent();
|
||||
|
||||
const response = await locals.api.post(`/devices`, data);
|
||||
|
||||
if (!response.ok) error(500, 'An unknown error occurred');
|
||||
|
||||
return await response.json();
|
||||
});
|
||||
|
||||
export const regenerateDeviceApiKey = command(z.string(), async (deviceId): Promise<Device> => {
|
||||
const { locals } = getRequestEvent();
|
||||
|
||||
const response = await locals.api.get(`/devices/${deviceId}/regenerate`);
|
||||
|
||||
if (!response.ok) error(500, 'An unknown error occurred');
|
||||
|
||||
return await response.json();
|
||||
})
|
||||
|
||||
export const deleteDevice = command(z.string(), async (deviceId): Promise<void> => {
|
||||
const { locals } = getRequestEvent();
|
||||
|
||||
const response = await locals.api.delete(`/devices/${deviceId}`);
|
||||
|
||||
if (!response.ok) error(500, 'An unknown error occurred');
|
||||
});
|
||||
@@ -0,0 +1,50 @@
|
||||
<script lang="ts">
|
||||
import { createDevice } from '$lib/api/device.remote';
|
||||
import * as Field from '$lib/components/ui/field/index.js';
|
||||
import { Input } from '$lib/components/ui/input/index.js';
|
||||
import { Button } from '$lib/components/ui/button/index.js';
|
||||
import { toast } from 'svelte-sonner';
|
||||
|
||||
interface Props {
|
||||
onSuccess?: () => void;
|
||||
}
|
||||
|
||||
let { onSuccess }: Props = $props();
|
||||
</script>
|
||||
|
||||
<form
|
||||
{...createDevice.enhance(async ({ form, submit }) => {
|
||||
try {
|
||||
await submit();
|
||||
|
||||
const issues = createDevice.fields.allIssues();
|
||||
if (issues && issues.length > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const deviceName = createDevice.fields.name.value();
|
||||
|
||||
form.reset();
|
||||
toast.success(`Device '${deviceName}' created`);
|
||||
onSuccess?.();
|
||||
} catch (error) {
|
||||
console.error('Failed to create device: ', error);
|
||||
toast.error('Failed to create device');
|
||||
}
|
||||
})}
|
||||
class="flex flex-col gap-3"
|
||||
>
|
||||
<Field.Set>
|
||||
<Field.Group>
|
||||
<Field.Field>
|
||||
<Field.Label for="name">Device name</Field.Label>
|
||||
<Input {...createDevice.fields.name.as('text')} placeholder="e.g. Kindle Paperwhite" />
|
||||
{#each createDevice.fields.name.issues() ?? [] as issue}
|
||||
<Field.Error>{issue.message}</Field.Error>
|
||||
{/each}
|
||||
</Field.Field>
|
||||
</Field.Group>
|
||||
</Field.Set>
|
||||
|
||||
<Button type="submit" class="ml-auto w-24">Create</Button>
|
||||
</form>
|
||||
@@ -0,0 +1,8 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import type { components } from './openapi/schema';
|
||||
export type Device = components['schemas']['KosyncDeviceRead']
|
||||
|
||||
export const createDeviceSchema = z.object({
|
||||
name: z.string().min(1, 'Name cannot be empty')
|
||||
})
|
||||
Reference in New Issue
Block a user