Merge pull request #89 from maxdorninger/enhance-frontend

Enhance frontend
This commit is contained in:
Maximilian Dorninger
2025-07-19 15:17:14 +02:00
committed by GitHub
10 changed files with 53 additions and 31 deletions

View File

@@ -229,7 +229,7 @@
<p class="text-red-500">Error: {torrentsError}</p>
{:else if torrents.length > 0}
<h3 class="mb-2 text-lg font-semibold">Found Torrents:</h3>
<div class="max-h-[200px] overflow-y-auto rounded-md border p-2">
<div class="overflow-y-auto rounded-md border p-2">
<Table.Root>
<Table.Header>
<Table.Row>

View File

@@ -266,7 +266,7 @@
<p class="text-red-500">Error: {torrentsError}</p>
{:else if torrents.length > 0}
<h3 class="mb-2 text-lg font-semibold">Found Torrents:</h3>
<div class="max-h-[200px] overflow-y-auto rounded-md border p-2">
<div class="overflow-y-auto rounded-md border p-2">
<Table.Root>
<Table.Header>
<Table.Row>

View File

@@ -43,7 +43,7 @@
})
});
if (response.status === 204) {
if (response.ok) {
dialogOpen = false;
minQuality = undefined;
wantedQuality = undefined;

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { getFullyQualifiedMediaName, getTorrentQualityString } from '$lib/utils.js';
import type { SeasonRequest, User } from '$lib/types.js';
import type { MovieRequest, SeasonRequest, User } from '$lib/types.js';
import CheckmarkX from '$lib/components/checkmark-x.svelte';
import * as Table from '$lib/components/ui/table/index.js';
import { getContext } from 'svelte';
@@ -13,13 +13,11 @@
const apiUrl = env.PUBLIC_API_URL;
let {
requests,
filter = () => {
return true;
},
filter = () => true,
isShow = true
}: {
requests: SeasonRequest[];
filter?: (request: SeasonRequest) => boolean;
requests: (SeasonRequest | MovieRequest)[];
filter?: (request: SeasonRequest | MovieRequest) => boolean;
isShow: boolean;
} = $props();
const user: () => User = getContext('user');
@@ -114,14 +112,14 @@
<Table.Row>
<Table.Cell>
{#if isShow}
{getFullyQualifiedMediaName(request.show)}
{getFullyQualifiedMediaName((request as SeasonRequest).show)}
{:else}
{getFullyQualifiedMediaName(request.show)}
{getFullyQualifiedMediaName((request as MovieRequest).movie)}
{/if}
</Table.Cell>
{#if isShow}
<Table.Cell>
{request.season.number}
{(request as SeasonRequest).season.number}
</Table.Cell>
{/if}
<Table.Cell>
@@ -154,7 +152,7 @@
class=""
size="sm"
variant="outline"
onclick={() => goto(base + '/dashboard/tv/' + request.show.id)}
onclick={() => goto(base + '/dashboard/tv/' + (request as SeasonRequest).show.id)}
>
Download manually
</Button>
@@ -163,7 +161,8 @@
class=""
size="sm"
variant="outline"
onclick={() => goto(base + '/dashboard/tv/' + request.show.id)}
onclick={() =>
goto(base + '/dashboard/movies/' + (request as MovieRequest).movie.id)}
>
Download manually
</Button>

View File

@@ -9,12 +9,14 @@
import { Label } from '$lib/components/ui/label/index.js';
import * as RadioGroup from '$lib/components/ui/radio-group/index.js';
import { Input } from '$lib/components/ui/input/index.js';
import { invalidateAll } from '$app/navigation';
const apiUrl = env.PUBLIC_API_URL;
let { users }: { users: User[] } = $props();
let sortedUsers = $derived(users.sort((a, b) => a.email.localeCompare(b.email)));
let selectedUser: User | null = $state(null);
let newPassword: string = $state('');
let newEmail: string = $state('');
let dialogOpen = $state(false);
async function saveUser() {
@@ -31,20 +33,18 @@
is_verified: selectedUser.is_verified,
is_active: selectedUser.is_active,
is_superuser: selectedUser.is_superuser,
...(newPassword !== '' && { password: newPassword })
...(newPassword !== '' && { password: newPassword }),
...(newEmail !== '' && { email: newEmail })
})
});
if (response.ok) {
toast.success(`User ${selectedUser.email} updated successfully.`);
dialogOpen = false;
const idx = sortedUsers.findIndex((u) => u.id === selectedUser!.id);
if (idx !== -1) {
sortedUsers[idx] = selectedUser!;
}
selectedUser = null;
newPassword = '';
newEmail = '';
await invalidateAll();
} else {
const errorText = await response.text();
console.error(`Failed to update user ${response.statusText}`, errorText);
@@ -172,6 +172,17 @@
</div>
</RadioGroup.Root>
</div>
<!-- Email -->
<div>
<Label class="mb-1 block text-sm font-medium" for="email">Email</Label>
<Input
bind:value={newEmail}
class="w-full"
id="email"
placeholder={selectedUser?.email}
type="text"
/>
</div>
<!-- Password -->
<div>
<Label class="mb-1 block text-sm font-medium" for="superuser">Password</Label>

View File

@@ -215,20 +215,20 @@ export interface RichMovieTorrent {
torrents: Torrent[];
}
interface SeasonRequestBase {
interface RequestBase {
min_quality: Quality;
wanted_quality: Quality;
}
export interface CreateSeasonRequest extends SeasonRequestBase {
export interface CreateSeasonRequest extends RequestBase {
season_id: string;
}
export interface UpdateSeasonRequest extends SeasonRequestBase {
export interface UpdateRequest extends RequestBase {
id: string;
}
export interface SeasonRequest extends SeasonRequestBase {
export interface SeasonRequest extends RequestBase {
id: string;
season: Season;
requested_by?: User;
@@ -237,6 +237,15 @@ export interface SeasonRequest extends SeasonRequestBase {
show: Show;
}
export interface MovieRequest extends RequestBase {
id: string;
movie: Movie;
movie_id: string;
requested_by?: User;
authorized: boolean;
authorized_by?: User;
}
export interface LibraryItem {
name: string;
path: string;

View File

@@ -6,7 +6,7 @@
import RequestsTable from '$lib/components/season-requests-table.svelte';
import { base } from '$app/paths';
let requests = $state(page.data.requestsData);
let requests = page.data.requestsData;
</script>
<svelte:head>

View File

@@ -1,8 +1,8 @@
import { env } from '$env/dynamic/public';
import type { LayoutLoad } from './$types';
import type { PageLoad } from './$types';
const apiUrl = env.PUBLIC_API_URL;
export const load: LayoutLoad = async ({ fetch }) => {
export const load: PageLoad = async ({ fetch }) => {
try {
const requests = await fetch(`${apiUrl}/movies/requests`, {
method: 'GET',

View File

@@ -48,7 +48,7 @@
</Breadcrumb.Item>
<Breadcrumb.Separator class="hidden md:block" />
<Breadcrumb.Item>
<Breadcrumb.Link href="{base}/dashboard/tv">Shows</Breadcrumb.Link>
<Breadcrumb.Link href="{base}/dashboard/movies">Movies</Breadcrumb.Link>
</Breadcrumb.Item>
<Breadcrumb.Separator class="hidden md:block" />
<Breadcrumb.Item>

View File

@@ -11,7 +11,10 @@
import type { User } from '$lib/types';
let currentUser: () => User = getContext('user');
let users = $state(page.data.users);
let users: User[] = $derived(
page.data.users.filter((user: User) => user.id !== currentUser().id)
);
console.log('Current user:', currentUser());
</script>
<svelte:head>
@@ -54,7 +57,7 @@
<Card.Root id="users">
<Card.Header>
<Card.Title>Users</Card.Title>
<Card.Description>Edit or delete users</Card.Description>
<Card.Description>Edit, delete or change the permissions of other users</Card.Description>
</Card.Header>
<Card.Content>
<UserTable {users} />