feat: default tracker configs, email validation, expandable target links

- Tracker now has default_tracking_config_id and default_template_config_id
  that apply to all linked targets unless overridden per-target
- Dispatch falls back to tracker defaults when per-link configs are null
- Email bot creation validates SMTP connection before saving
- Email notifications sent as HTML (links render properly)
- Linked target items are expandable: collapsed shows config CrossLinks,
  expanded shows config selectors; action buttons always visible
- Fix email bot test button icon (mdiEmailSend → mdiSend)
- Fix target type icons in LinkedTargetsSection for all types
- Provider filter moved above search in sidebar
This commit is contained in:
2026-03-24 22:32:37 +03:00
parent d4cb388c74
commit 6e35926772
16 changed files with 246 additions and 102 deletions
@@ -16,11 +16,15 @@
collection_ids: string[];
scan_interval: number;
batch_duration: number;
default_tracking_config_id: number;
default_template_config_id: number;
filters: Record<string, any>;
};
providerItems: { value: number; label: string; icon: string; desc: string }[];
collections: any[];
collectionFilter?: string;
trackingConfigItems?: { value: number; label: string; icon: string }[];
templateConfigItems?: { value: number; label: string; icon: string }[];
editing: number | null;
submitting: boolean;
linkCheckLoading: boolean;
@@ -36,6 +40,8 @@
providerItems,
collections,
collectionFilter = $bindable(),
trackingConfigItems = [],
templateConfigItems = [],
editing,
submitting,
linkCheckLoading,
@@ -175,6 +181,24 @@
</div>
{/if}
<!-- Default configs -->
{#if trackingConfigItems.length > 0 || templateConfigItems.length > 0}
<div class="grid grid-cols-2 gap-3">
{#if trackingConfigItems.length > 0}
<div>
<label class="block text-sm font-medium mb-1">{t('notificationTracker.defaultTrackingConfig')}<Hint text={t('hints.defaultTrackingConfig')} /></label>
<EntitySelect items={[{value: 0, label: t('common.none'), icon: 'mdiMinus'}, ...trackingConfigItems]} bind:value={form.default_tracking_config_id} placeholder={t('common.none')} />
</div>
{/if}
{#if templateConfigItems.length > 0}
<div>
<label class="block text-sm font-medium mb-1">{t('notificationTracker.defaultTemplateConfig')}<Hint text={t('hints.defaultTemplateConfig')} /></label>
<EntitySelect items={[{value: 0, label: t('common.none'), icon: 'mdiMinus'}, ...templateConfigItems]} bind:value={form.default_template_config_id} placeholder={t('common.none')} />
</div>
{/if}
</div>
{/if}
<button type="submit" disabled={submitting || linkCheckLoading} class="px-4 py-2 bg-[var(--color-primary)] text-[var(--color-primary-foreground)] rounded-md text-sm font-medium hover:opacity-90 disabled:opacity-50">
{#if linkCheckLoading}{t('notificationTracker.checkingLinks')}{:else}{editing ? t('common.save') : t('notificationTracker.createTracker')}{/if}
</button>