mirror of
https://github.com/Dictionarry-Hub/profilarr.git
synced 2026-01-22 10:51:02 +01:00
feat: add conceptual tweaks management page
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import Tabs from '$ui/navigation/tabs/Tabs.svelte';
|
||||
import { GitBranch, History } from 'lucide-svelte';
|
||||
import { GitBranch, History, Wrench } from 'lucide-svelte';
|
||||
import { page } from '$app/stores';
|
||||
|
||||
$: database = $page.data.database;
|
||||
@@ -22,6 +22,12 @@
|
||||
href: `/databases/${database.id}/commits`,
|
||||
icon: History,
|
||||
active: currentPath.includes('/commits')
|
||||
},
|
||||
{
|
||||
label: 'Tweaks',
|
||||
href: `/databases/${database.id}/tweaks`,
|
||||
icon: Wrench,
|
||||
active: currentPath.includes('/tweaks')
|
||||
}
|
||||
] : [];
|
||||
|
||||
|
||||
21
src/routes/databases/[id]/tweaks/+page.server.ts
Normal file
21
src/routes/databases/[id]/tweaks/+page.server.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { error } from '@sveltejs/kit';
|
||||
import type { ServerLoad } from '@sveltejs/kit';
|
||||
import { databaseInstancesQueries } from '$db/queries/databaseInstances.ts';
|
||||
|
||||
export const load: ServerLoad = ({ params }) => {
|
||||
const id = parseInt(params.id || '', 10);
|
||||
|
||||
if (isNaN(id)) {
|
||||
error(400, 'Invalid database ID');
|
||||
}
|
||||
|
||||
const database = databaseInstancesQueries.getById(id);
|
||||
|
||||
if (!database) {
|
||||
error(404, 'Database not found');
|
||||
}
|
||||
|
||||
return {
|
||||
database
|
||||
};
|
||||
};
|
||||
167
src/routes/databases/[id]/tweaks/+page.svelte
Normal file
167
src/routes/databases/[id]/tweaks/+page.svelte
Normal file
@@ -0,0 +1,167 @@
|
||||
<script lang="ts">
|
||||
import { Save, Check, Code } from 'lucide-svelte';
|
||||
import ExpandableTable from '$ui/table/ExpandableTable.svelte';
|
||||
import IconCheckbox from '$ui/form/IconCheckbox.svelte';
|
||||
import type { Column } from '$ui/table/types';
|
||||
import type { PageData } from './$types';
|
||||
|
||||
export let data: PageData;
|
||||
|
||||
// Mock tweak data
|
||||
type Tweak = {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
sql: string;
|
||||
};
|
||||
|
||||
const mockTweaks: Tweak[] = [
|
||||
{
|
||||
id: 'enable-prereleases',
|
||||
name: 'Enable Prereleases',
|
||||
description: 'Adds a Prereleases quality group (CAM, Telesync, DVD Screener, etc.) to the bottom of all quality profiles, allowing early access to new releases.',
|
||||
sql: `-- Enable Prereleases
|
||||
-- Creates a Prereleases quality group for each profile and places it
|
||||
-- below the last enabled quality/group
|
||||
|
||||
-- Step 1: Create Prereleases group for each quality profile
|
||||
INSERT INTO quality_groups (quality_profile_id, name)
|
||||
SELECT id, 'Prereleases'
|
||||
FROM quality_profiles
|
||||
WHERE id NOT IN (
|
||||
SELECT quality_profile_id FROM quality_groups WHERE name = 'Prereleases'
|
||||
);
|
||||
|
||||
-- Step 2: Add prerelease qualities to the group
|
||||
INSERT INTO quality_group_members (quality_group_id, quality_id)
|
||||
SELECT qg.id, q.id
|
||||
FROM quality_groups qg
|
||||
CROSS JOIN qualities q
|
||||
WHERE qg.name = 'Prereleases'
|
||||
AND q.name IN ('CAM', 'TELESYNC', 'TELECINE', 'DVDSCR', 'REGIONAL', 'WORKPRINT')
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM quality_group_members qgm
|
||||
WHERE qgm.quality_group_id = qg.id AND qgm.quality_id = q.id
|
||||
);
|
||||
|
||||
-- Step 3: Add the group to each profile's quality list
|
||||
-- Position it below the last enabled quality/group
|
||||
INSERT INTO quality_profile_qualities (quality_profile_id, quality_group_id, position, enabled)
|
||||
SELECT
|
||||
qg.quality_profile_id,
|
||||
qg.id,
|
||||
COALESCE(
|
||||
(SELECT MAX(position) + 1
|
||||
FROM quality_profile_qualities
|
||||
WHERE quality_profile_id = qg.quality_profile_id AND enabled = 1),
|
||||
1
|
||||
),
|
||||
1
|
||||
FROM quality_groups qg
|
||||
WHERE qg.name = 'Prereleases'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM quality_profile_qualities qpq
|
||||
WHERE qpq.quality_group_id = qg.id
|
||||
);`
|
||||
}
|
||||
];
|
||||
|
||||
// Track enabled state (not persisted)
|
||||
let enabledTweaks: Set<string> = new Set();
|
||||
|
||||
function toggleTweak(id: string) {
|
||||
if (enabledTweaks.has(id)) {
|
||||
enabledTweaks.delete(id);
|
||||
} else {
|
||||
enabledTweaks.add(id);
|
||||
}
|
||||
enabledTweaks = enabledTweaks;
|
||||
}
|
||||
|
||||
const columns: Column<Tweak>[] = [
|
||||
{
|
||||
key: 'name',
|
||||
header: 'Name',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
key: 'description',
|
||||
header: 'Description'
|
||||
}
|
||||
];
|
||||
|
||||
function getRowId(row: Tweak): string {
|
||||
return row.id;
|
||||
}
|
||||
|
||||
$: hasChanges = enabledTweaks.size > 0;
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Tweaks - {data.database.name} - Profilarr</title>
|
||||
</svelte:head>
|
||||
|
||||
<div class="mt-6 space-y-4">
|
||||
<!-- Header with Save -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 class="text-xl font-semibold text-neutral-900 dark:text-neutral-100">Tweaks</h1>
|
||||
<p class="mt-1 text-sm text-neutral-500 dark:text-neutral-400">
|
||||
Optional modifications curated by databases. Enable tweaks to adjust quality profile behaviour.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
disabled={!hasChanges}
|
||||
class="flex items-center gap-2 rounded-lg bg-accent-600 px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-accent-700 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-accent-500 dark:hover:bg-accent-600"
|
||||
>
|
||||
<Save size={16} />
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Tweaks Table -->
|
||||
{#if mockTweaks.length > 0}
|
||||
<ExpandableTable
|
||||
{columns}
|
||||
data={mockTweaks}
|
||||
{getRowId}
|
||||
compact={true}
|
||||
flushExpanded={true}
|
||||
emptyMessage="No tweaks available"
|
||||
chevronPosition="right"
|
||||
>
|
||||
<svelte:fragment slot="cell" let:row let:column>
|
||||
{#if column.key === 'name'}
|
||||
<span class="font-medium text-neutral-900 dark:text-neutral-100">{row.name}</span>
|
||||
{:else if column.key === 'description'}
|
||||
<span class="text-sm text-neutral-600 dark:text-neutral-400">{row.description}</span>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="actions" let:row>
|
||||
<IconCheckbox
|
||||
icon={Check}
|
||||
checked={enabledTweaks.has(row.id)}
|
||||
on:click={() => toggleTweak(row.id)}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="expanded" let:row>
|
||||
<div class="px-6 py-4">
|
||||
<div class="flex items-center gap-2 text-xs font-medium text-neutral-500 dark:text-neutral-400 mb-2">
|
||||
<Code size={12} />
|
||||
SQL
|
||||
</div>
|
||||
<pre class="rounded-lg bg-neutral-100 p-3 text-xs font-mono text-neutral-800 dark:bg-neutral-800 dark:text-neutral-200 overflow-x-auto">{row.sql}</pre>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</ExpandableTable>
|
||||
{:else}
|
||||
<div class="rounded-lg border border-neutral-200 bg-white p-8 text-center dark:border-neutral-800 dark:bg-neutral-900">
|
||||
<p class="text-neutral-500 dark:text-neutral-400">
|
||||
No tweaks available for this database.
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
Reference in New Issue
Block a user