feat: comprehensive code review fixes + receivers-only architecture
Security:
- Refuse startup with default secret_key in production (was just logging)
- Settings endpoint now requires admin role
- Password validation on initial setup
- DOM-based HTML sanitizer replaces regex in template previews
- Add *.log to .gitignore
Performance & reliability:
- Token refresh deduplication prevents race condition on concurrent 401s
- Theme media query listener registered once (no leak)
- IconPicker uses $derived instead of function call per render
- Snackbar uses single-batch state update instead of while loop
- Replace 11 inline hover handlers with CSS :hover in layout
Architecture - receivers-only:
- Delivery endpoints (chat_id, email, url, room_id, topic) now stored
exclusively in TargetReceiver rows, never in target.config
- Migration extracts existing delivery fields to receiver rows
- Notifier and dispatcher remove all config fallbacks
- Frontend targets page shows receivers list per target with
add/remove/toggle/test per receiver
- Single-receiver test endpoint: POST /targets/{id}/receivers/{id}/test
Code quality:
- Extract AuthLayout.svelte from login/setup (150 lines CSS dedup)
- Split telegram-bots page (754→51 lines + 3 tab components)
- Split notification-trackers page (547→432 lines + 4 components)
- Deduplicate _send_reply into shared handler.send_reply()
- Add locale column to template models, replace name-based detection
- Fix delete_notification_tracker dead protection check
- Fix check_telegram_bot query (filter by type, remove bogus OR)
- Add graceful scheduler shutdown in lifespan
- Consistent /bots?tab=telegram URLs across all nav links
i18n:
- Error page, chat actions, target types, provider types internationalized
- All new receiver UI strings in EN + RU
This commit is contained in:
@@ -79,24 +79,24 @@ export const sortFilterItems = (): GridItem[] => [
|
||||
// --- Chat action (Telegram targets) ---
|
||||
|
||||
export const chatActionItems = (): GridItem[] => [
|
||||
{ value: '', icon: 'mdiMinus', label: 'None' },
|
||||
{ value: 'typing', icon: 'mdiKeyboard', label: 'Typing' },
|
||||
{ value: 'upload_photo', icon: 'mdiImagePlus', label: 'Upload Photo' },
|
||||
{ value: 'upload_video', icon: 'mdiVideoPlus', label: 'Upload Video' },
|
||||
{ value: 'upload_document', icon: 'mdiFileUpload', label: 'Upload Doc' },
|
||||
{ value: 'record_video', icon: 'mdiVideo', label: 'Record Video' },
|
||||
{ value: 'record_voice', icon: 'mdiMicrophone', label: 'Record Voice' },
|
||||
{ value: '', icon: 'mdiMinus', label: t('targets.chatActionNone') },
|
||||
{ value: 'typing', icon: 'mdiKeyboard', label: t('targets.chatActionTyping') },
|
||||
{ value: 'upload_photo', icon: 'mdiImagePlus', label: t('targets.chatActionUploadPhoto') },
|
||||
{ value: 'upload_video', icon: 'mdiVideoPlus', label: t('targets.chatActionUploadVideo') },
|
||||
{ value: 'upload_document', icon: 'mdiFileUpload', label: t('targets.chatActionUploadDoc') },
|
||||
{ value: 'record_video', icon: 'mdiVideo', label: t('targets.chatActionRecordVideo') },
|
||||
{ value: 'record_voice', icon: 'mdiMicrophone', label: t('targets.chatActionRecordVoice') },
|
||||
];
|
||||
|
||||
// --- Preview target type ---
|
||||
|
||||
export const previewTargetTypeItems = (): GridItem[] => [
|
||||
{ value: 'telegram', icon: 'mdiSend', label: 'Telegram' },
|
||||
{ value: 'webhook', icon: 'mdiWebhook', label: 'Webhook' },
|
||||
{ value: 'telegram', icon: 'mdiSend', label: t('targets.typeTelegram') },
|
||||
{ value: 'webhook', icon: 'mdiWebhook', label: t('targets.typeWebhook') },
|
||||
];
|
||||
|
||||
// --- Provider type ---
|
||||
|
||||
export const providerTypeItems = (): GridItem[] => [
|
||||
{ value: 'immich', icon: 'mdiCamera', label: 'Immich' },
|
||||
{ value: 'immich', icon: 'mdiCamera', label: t('providers.typeImmich') },
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user