feat: replace all select dropdowns with IconGridSelect, fix EN template seed

Shared grid-items.ts with reusable item definitions for: sort by/order,
album mode, asset type, memory source, locale, response mode, event type
filter, chat action, preview target type, provider type.

Replaced selects on:
- Dashboard: event type, provider, sort (compact mode — auto-width)
- Tracking configs: sort by/order, album modes, asset types, memory source
- Command configs: locale, response mode, provider type
- Targets: chat action
- Template configs: preview target type, provider type
- Command template configs: provider type
- Providers: type selector (read-only during edit)

IconGridSelect: added compact prop for inline filter bars (auto-width,
smaller padding, shows icon + label text).

Backend: template seed now re-creates deleted system templates on startup
using raw SQL to handle legacy NOT NULL columns.

Added i18n: trackingConfig.providerType, trackingConfig.sortRandom
Added provider_type badge to tracking config cards.
This commit is contained in:
2026-03-22 01:17:06 +03:00
parent db7aac5fe8
commit a9bb912c30
11 changed files with 175 additions and 104 deletions
+20 -26
View File
@@ -8,9 +8,16 @@
import Loading from '$lib/components/Loading.svelte';
import MdiIcon from '$lib/components/MdiIcon.svelte';
import EventChart from '$lib/components/EventChart.svelte';
import IconGridSelect from '$lib/components/IconGridSelect.svelte';
import EntitySelect from '$lib/components/EntitySelect.svelte';
import { eventTypeFilterItems, sortFilterItems } from '$lib/grid-items';
let status = $state<any>(null);
let providers = $derived(providersCache.items);
const providerFilterItems = $derived([
{ value: '', label: t('dashboard.allProviders'), icon: 'mdiFilterOff' },
...providers.map(p => ({ value: p.id, label: p.name, icon: p.icon || 'mdiServer', desc: p.type })),
]);
let chartDays = $state<any[]>([]);
let loaded = $state(false);
let error = $state('');
@@ -88,6 +95,16 @@
} catch {}
}
// Auto-apply when filter values change (via IconGridSelect bind:value)
let _prevFilterKey = '';
$effect(() => {
const key = `${filterEventType}|${filterProviderId}|${filterSort}`;
if (loaded && key !== _prevFilterKey && _prevFilterKey !== '') {
applyFilters();
}
_prevFilterKey = key;
});
function applyFilters() {
eventsOffset = 0;
loadEvents();
@@ -190,14 +207,6 @@
collection_renamed: '#6366f1', collection_deleted: '#dc2626', sharing_changed: '#f59e0b',
};
const eventTypeOptions = $derived([
{ value: '', label: t('dashboard.allEvents') },
{ value: 'assets_added', label: t('dashboard.filterAssetsAdded') },
{ value: 'assets_removed', label: t('dashboard.filterAssetsRemoved') },
{ value: 'collection_renamed', label: t('dashboard.filterRenamed') },
{ value: 'collection_deleted', label: t('dashboard.filterDeleted') },
{ value: 'sharing_changed', label: t('dashboard.filterSharingChanged') },
]);
</script>
<PageHeader title={t('dashboard.title')} description={t('dashboard.description')} />
@@ -248,24 +257,9 @@
placeholder={t('dashboard.searchEvents')}
class="w-full px-3 py-1.5 border border-[var(--color-border)] rounded-md text-sm bg-[var(--color-background)]" />
</div>
<select bind:value={filterEventType} onchange={applyFilters}
class="px-2 py-1.5 border border-[var(--color-border)] rounded-md text-sm bg-[var(--color-background)]">
{#each eventTypeOptions as opt}
<option value={opt.value}>{opt.label}</option>
{/each}
</select>
<select bind:value={filterProviderId} onchange={applyFilters}
class="px-2 py-1.5 border border-[var(--color-border)] rounded-md text-sm bg-[var(--color-background)]">
<option value="">{t('dashboard.allProviders')}</option>
{#each providers as p}
<option value={p.id}>{p.name}</option>
{/each}
</select>
<select bind:value={filterSort} onchange={applyFilters}
class="px-2 py-1.5 border border-[var(--color-border)] rounded-md text-sm bg-[var(--color-background)]">
<option value="newest">{t('dashboard.newestFirst')}</option>
<option value="oldest">{t('dashboard.oldestFirst')}</option>
</select>
<IconGridSelect items={eventTypeFilterItems()} bind:value={filterEventType} columns={3} compact />
<IconGridSelect items={providerFilterItems} bind:value={filterProviderId} columns={2} compact />
<IconGridSelect items={sortFilterItems()} bind:value={filterSort} columns={2} compact />
</div>
<!-- Chart (now inside Events section, affected by filters) -->