mirror of
https://github.com/Dictionarry-Hub/profilarr.git
synced 2026-01-28 13:30:56 +01:00
feat(customFormats): implement general queries and update related types and components
This commit is contained in:
43
src/lib/server/pcd/queries/customFormats/general.ts
Normal file
43
src/lib/server/pcd/queries/customFormats/general.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Custom format general queries
|
||||
*/
|
||||
|
||||
import type { PCDCache } from '../../cache.ts';
|
||||
import type { CustomFormatGeneral } from './types.ts';
|
||||
|
||||
/**
|
||||
* Get general information for a single custom format
|
||||
*/
|
||||
export async function general(cache: PCDCache, formatId: number): Promise<CustomFormatGeneral | null> {
|
||||
const db = cache.kb;
|
||||
|
||||
// Get the custom format
|
||||
const format = await db
|
||||
.selectFrom('custom_formats')
|
||||
.select(['id', 'name', 'description', 'include_in_rename'])
|
||||
.where('id', '=', formatId)
|
||||
.executeTakeFirst();
|
||||
|
||||
if (!format) return null;
|
||||
|
||||
// Get tags for this format
|
||||
const tags = await db
|
||||
.selectFrom('custom_format_tags as cft')
|
||||
.innerJoin('tags as t', 't.id', 'cft.tag_id')
|
||||
.select(['t.id as tag_id', 't.name as tag_name', 't.created_at as tag_created_at'])
|
||||
.where('cft.custom_format_id', '=', formatId)
|
||||
.orderBy('t.name')
|
||||
.execute();
|
||||
|
||||
return {
|
||||
id: format.id,
|
||||
name: format.name,
|
||||
description: format.description || '',
|
||||
include_in_rename: format.include_in_rename === 1,
|
||||
tags: tags.map((tag) => ({
|
||||
id: tag.tag_id,
|
||||
name: tag.tag_name,
|
||||
created_at: tag.tag_created_at
|
||||
}))
|
||||
};
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
// Export all types
|
||||
export type { CustomFormatTableRow, ConditionRef, CustomFormatBasic, CustomFormatTest } from './types.ts';
|
||||
export type { CustomFormatTableRow, ConditionRef, CustomFormatBasic, CustomFormatGeneral, CustomFormatTest } from './types.ts';
|
||||
export type { CreateTestInput, CreateTestOptions } from './testCreate.ts';
|
||||
export type { UpdateTestInput, UpdateTestOptions } from './testUpdate.ts';
|
||||
export type { DeleteTestOptions } from './testDelete.ts';
|
||||
@@ -12,6 +12,7 @@ export type { ConditionResult, EvaluationResult, ParsedInfo } from './evaluator.
|
||||
|
||||
// Export query functions (reads)
|
||||
export { list } from './list.ts';
|
||||
export { general } from './general.ts';
|
||||
export { getById, listTests, getTestById } from './tests.ts';
|
||||
export { getConditionsForEvaluation } from './conditions.ts';
|
||||
export { evaluateCustomFormat, getParsedInfo } from './evaluator.ts';
|
||||
|
||||
@@ -13,11 +13,16 @@ export async function getById(cache: PCDCache, formatId: number): Promise<Custom
|
||||
|
||||
const format = await db
|
||||
.selectFrom('custom_formats')
|
||||
.select(['id', 'name', 'description'])
|
||||
.select(['id', 'name', 'description', 'include_in_rename'])
|
||||
.where('id', '=', formatId)
|
||||
.executeTakeFirst();
|
||||
|
||||
return format ?? null;
|
||||
if (!format) return null;
|
||||
|
||||
return {
|
||||
...format,
|
||||
include_in_rename: format.include_in_rename === 1
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,6 +27,16 @@ export interface CustomFormatBasic {
|
||||
id: number;
|
||||
name: string;
|
||||
description: string | null;
|
||||
include_in_rename: boolean;
|
||||
}
|
||||
|
||||
/** Custom format general information (for general tab) */
|
||||
export interface CustomFormatGeneral {
|
||||
id: number;
|
||||
name: string;
|
||||
description: string;
|
||||
include_in_rename: boolean;
|
||||
tags: Tag[];
|
||||
}
|
||||
|
||||
/** Custom format test case */
|
||||
|
||||
@@ -50,6 +50,7 @@ export interface CustomFormatsTable {
|
||||
id: Generated<number>;
|
||||
name: string;
|
||||
description: string | null;
|
||||
include_in_rename: Generated<number>;
|
||||
created_at: Generated<string>;
|
||||
updated_at: Generated<string>;
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ export const load: ServerLoad = async ({ params }) => {
|
||||
throw error(500, 'Database cache not available');
|
||||
}
|
||||
|
||||
// Get custom format basic info
|
||||
const format = await customFormatQueries.getById(cache, formatId);
|
||||
// Load general information for the custom format
|
||||
const format = await customFormatQueries.general(cache, formatId);
|
||||
if (!format) {
|
||||
throw error(404, 'Custom format not found');
|
||||
}
|
||||
|
||||
@@ -1,15 +1,78 @@
|
||||
<script lang="ts">
|
||||
import { Check } from 'lucide-svelte';
|
||||
import FormInput from '$ui/form/FormInput.svelte';
|
||||
import TagInput from '$ui/form/TagInput.svelte';
|
||||
import IconCheckbox from '$ui/form/IconCheckbox.svelte';
|
||||
import UnsavedChangesModal from '$ui/modal/UnsavedChangesModal.svelte';
|
||||
import { useUnsavedChanges } from '$lib/client/utils/unsavedChanges.svelte';
|
||||
import type { PageData } from './$types';
|
||||
|
||||
export let data: PageData;
|
||||
|
||||
const unsavedChanges = useUnsavedChanges();
|
||||
|
||||
let name = data.format.name;
|
||||
let description = data.format.description;
|
||||
let tags: string[] = data.format.tags.map((t) => t.name);
|
||||
let includeInRename = data.format.include_in_rename;
|
||||
|
||||
// Mark as dirty when any field changes
|
||||
$: if (
|
||||
name !== data.format.name ||
|
||||
description !== data.format.description ||
|
||||
includeInRename !== data.format.include_in_rename
|
||||
) {
|
||||
unsavedChanges.markDirty();
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{data.format.name} - General - Profilarr</title>
|
||||
</svelte:head>
|
||||
|
||||
<UnsavedChangesModal />
|
||||
|
||||
<div class="mt-6 space-y-6">
|
||||
<p class="text-neutral-600 dark:text-neutral-400">
|
||||
General tab placeholder - conditions and settings will go here.
|
||||
</p>
|
||||
<FormInput
|
||||
label="Name"
|
||||
description="The name of this custom format"
|
||||
placeholder="Enter custom format name"
|
||||
bind:value={name}
|
||||
/>
|
||||
|
||||
<FormInput
|
||||
label="Description"
|
||||
description="Add any notes or details about this custom format's purpose and configuration. Use markdown to format your description."
|
||||
placeholder=""
|
||||
bind:value={description}
|
||||
textarea={true}
|
||||
/>
|
||||
|
||||
<div class="space-y-2">
|
||||
<div class="block text-sm font-medium text-neutral-900 dark:text-neutral-100">Tags</div>
|
||||
<p class="text-xs text-neutral-600 dark:text-neutral-400">
|
||||
Add tags to organize and categorize this custom format.
|
||||
</p>
|
||||
<TagInput bind:tags />
|
||||
<input type="hidden" name="tags" value={tags.length > 0 ? JSON.stringify(tags) : ''} />
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<div class="block text-sm font-medium text-neutral-900 dark:text-neutral-100">
|
||||
Include In Rename
|
||||
</div>
|
||||
<p class="text-xs text-neutral-600 dark:text-neutral-400">
|
||||
When enabled, this custom format's name will be included in the renamed filename.
|
||||
</p>
|
||||
<div class="flex items-center gap-2">
|
||||
<IconCheckbox
|
||||
icon={Check}
|
||||
bind:checked={includeInRename}
|
||||
on:click={() => (includeInRename = !includeInRename)}
|
||||
/>
|
||||
<span class="text-sm text-neutral-700 dark:text-neutral-300">
|
||||
{includeInRename ? 'Enabled' : 'Disabled'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user