feat: locale-aware notification templates + UX improvements
- Add locale support to notification templates (matching command template
pattern): TemplateSlot now has locale field with (config_id, slot_name,
locale) uniqueness, nested API format {slot: {locale: template}}
- Migration merges separate EN/RU system configs into unified per-provider
configs; seeds create one config per provider with multi-locale slots
- Locale-aware dispatch with EN fallback in NotificationDispatcher
- Frontend locale tabs (EN/RU) on template config editor
- Fix tracking config cards not showing default provider icons
- Global provider filter, search palette, and various UX polish
This commit is contained in:
@@ -14,6 +14,8 @@
|
||||
import EntitySelect from '$lib/components/EntitySelect.svelte';
|
||||
import { snackSuccess, snackError } from '$lib/stores/snackbar.svelte';
|
||||
import { highlightFromUrl } from '$lib/highlight';
|
||||
import { providerDefaultIcon } from '$lib/grid-items';
|
||||
import { globalProviderFilter } from '$lib/stores/provider-filter.svelte';
|
||||
import type { Tracker, TrackerTarget, TrackingConfig, TemplateConfig, NotificationTarget } from '$lib/types';
|
||||
|
||||
import TrackerForm from './TrackerForm.svelte';
|
||||
@@ -26,12 +28,13 @@
|
||||
let allNotificationTrackers = $state<Tracker[]>([]);
|
||||
let filterText = $state('');
|
||||
let filterProviderId = $state(0);
|
||||
let effectiveProviderId = $derived(globalProviderFilter.id || filterProviderId);
|
||||
let notificationTrackers = $derived(allNotificationTrackers.filter(t =>
|
||||
(!filterText || t.name.toLowerCase().includes(filterText.toLowerCase())) &&
|
||||
(!filterProviderId || t.provider_id === filterProviderId)
|
||||
(!effectiveProviderId || t.provider_id === effectiveProviderId)
|
||||
));
|
||||
let providers = $derived(providersCache.items);
|
||||
const providerItems = $derived(providers.map(p => ({ value: p.id, label: p.name, icon: p.icon || 'mdiServer', desc: p.type })));
|
||||
const providerItems = $derived(providers.map(p => ({ value: p.id, label: p.name, icon: providerDefaultIcon(p), desc: p.type })));
|
||||
let targets = $derived(targetsCache.items);
|
||||
let trackingConfigs = $derived(trackingConfigsCache.items);
|
||||
let templateConfigs = $derived(templateConfigsCache.items);
|
||||
@@ -379,9 +382,11 @@
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<input type="text" bind:value={filterText} placeholder={t('common.filterByName')}
|
||||
class="flex-1 px-3 py-1.5 border border-[var(--color-border)] rounded-md text-sm bg-[var(--color-background)]" />
|
||||
{#if !globalProviderFilter.id}
|
||||
<div class="w-48">
|
||||
<EntitySelect items={[{value: 0, label: t('common.allProviders'), icon: 'mdiFilterOff'}, ...providerItems]} bind:value={filterProviderId} placeholder={t('common.allProviders')} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user