feat: add Scheduler provider + multi-provider UX fixes

Scheduler provider:
- Virtual provider (no external service) that emits SCHEDULED_MESSAGE
  events on user-defined intervals or cron expressions
- Custom variables stored in tracker filters, flattened into template context
- fire_count persists across triggers via tracker state
- APScheduler CronTrigger support for cron-mode schedules
- Default templates (EN+RU), seeded on startup

Multi-provider UX fixes:
- Tracking config hides Immich-specific sections (periodic, scheduled,
  memory, asset display) for non-Immich providers
- Command config driven by provider capabilities — hides commands/settings
  for providers without bot commands
- Template config hides empty "Scheduled Messages" group
- Test menu on tracker targets is provider-aware (Immich shows all 4 test
  types, others show only basic)
- Removed redundant Test button from tracker card
- System-owned tracking configs (user_id=0) seeded for Gitea + Scheduler
- Fixed ownership checks to allow system configs in tracker-target links
- Capabilities cache shared across template-configs and command-configs
- Command tracker bot selector uses EntitySelect instead of raw select
- Sample context includes Gitea + Scheduler variables for template preview
This commit is contained in:
2026-03-22 15:50:51 +03:00
parent 6d28cfb8d8
commit 0562f78b35
30 changed files with 688 additions and 56 deletions
@@ -40,6 +40,8 @@
scheduled_min_rating: 0, scheduled_order_by: 'random', scheduled_order: 'descending',
memory_enabled: false, memory_source: 'albums', memory_times: '09:00', memory_collection_mode: 'combined',
memory_limit: 10, memory_favorite_only: false, memory_asset_type: 'all', memory_min_rating: 0,
// Scheduler event tracking
track_scheduled_message: true,
// Gitea event tracking
track_push: true, track_issue_opened: true, track_issue_closed: true, track_issue_commented: false,
track_pr_opened: true, track_pr_closed: true, track_pr_merged: true, track_pr_commented: false,
@@ -117,7 +119,11 @@
<!-- Event tracking -->
<fieldset class="border border-[var(--color-border)] rounded-md p-3">
<legend class="text-sm font-medium px-1">{t('trackingConfig.eventTracking')}</legend>
{#if form.provider_type === 'gitea'}
{#if form.provider_type === 'scheduler'}
<div class="grid grid-cols-2 gap-2 mt-2">
<label class="flex items-center gap-2 text-sm"><input type="checkbox" bind:checked={form.track_scheduled_message} /> {t('trackingConfig.scheduledMessage')}</label>
</div>
{:else if form.provider_type === 'gitea'}
<div class="grid grid-cols-2 gap-2 mt-2">
<label class="flex items-center gap-2 text-sm"><input type="checkbox" bind:checked={form.track_push} /> {t('trackingConfig.push')}</label>
<label class="flex items-center gap-2 text-sm"><input type="checkbox" bind:checked={form.track_issue_opened} /> {t('trackingConfig.issueOpened')}</label>
@@ -143,7 +149,7 @@
<label class="flex items-center gap-2 text-sm"><input type="checkbox" bind:checked={form.include_asset_details} /> {t('trackingConfig.includeDetails')}</label>
</div>
{/if}
{#if form.provider_type !== 'gitea'}
{#if form.provider_type === 'immich'}
<div class="grid grid-cols-3 gap-3 mt-3">
<div>
<label for="tc-max" class="block text-xs mb-1">{t('trackingConfig.maxAssets')}<Hint text={t('hints.maxAssets')} /></label>
@@ -161,7 +167,7 @@
{/if}
</fieldset>
{#if form.provider_type !== 'gitea'}
{#if form.provider_type === 'immich'}
<!-- Periodic summary -->
<fieldset class="border border-[var(--color-border)] rounded-md p-3">
<legend class="text-sm font-medium px-1">{t('trackingConfig.periodicSummary')}<Hint text={t('hints.periodicSummary')} /></legend>