feat: locale-aware command templates, debounced auto-sync, entity pickers
- Locale-aware templates: CommandTemplateSlot now has a locale column, allowing each slot to have per-language variants (EN/RU). Templates are resolved at runtime from the Telegram user's language_code. - Merged system configs: "Default Commands (EN)" and "(RU)" merged into a single "Default Commands" config with locale-aware slots. Migration handles existing data automatically. - Configurable command descriptions: hardcoded COMMAND_DESCRIPTIONS replaced with desc_* template slots (desc_status, desc_help, etc.) that users can customize per locale. setMyCommands registers all locales explicitly. - Removed locale from CommandConfig: no longer needed since locale is derived from the Telegram user's language at runtime. - Debounced command auto-sync: after command config/tracker changes, affected bots are marked dirty and synced after a 30s debounce window. Manual "Sync with Telegram" button still works. - Entity pickers in LinkedTargetsSection: replaced 6 plain <select> elements with EntitySelect components (search, icons, keyboard nav). Added onselect callback and size="sm" props to EntitySelect.
This commit is contained in:
@@ -850,3 +850,95 @@ async def migrate_template_locale(engine: AsyncEngine) -> None:
|
||||
await conn.execute(text(
|
||||
f"UPDATE {table} SET locale = 'en' WHERE user_id = 0 AND locale = ''"
|
||||
))
|
||||
|
||||
|
||||
async def migrate_command_slot_locale(engine: AsyncEngine) -> None:
|
||||
"""Add locale column to command_template_slot and merge system EN/RU configs.
|
||||
|
||||
1. Recreate command_template_slot with locale column and new unique constraint
|
||||
2. Backfill locale from parent config's locale (or 'en')
|
||||
3. Merge "Default Commands (RU)" slots into "Default Commands (EN)" with locale='ru'
|
||||
4. Rename merged config, update references, delete orphan RU config
|
||||
"""
|
||||
async with engine.begin() as conn:
|
||||
if not await _has_table(conn, "command_template_slot"):
|
||||
return
|
||||
|
||||
# Skip if locale column already exists (idempotent)
|
||||
if await _has_column(conn, "command_template_slot", "locale"):
|
||||
return
|
||||
|
||||
logger.info("Adding locale column to command_template_slot and merging system configs")
|
||||
|
||||
# Step 1: Recreate table with locale column and new unique constraint
|
||||
await conn.execute(text(
|
||||
"CREATE TABLE command_template_slot_new ("
|
||||
" id INTEGER PRIMARY KEY,"
|
||||
" config_id INTEGER NOT NULL REFERENCES command_template_config(id),"
|
||||
" slot_name TEXT NOT NULL,"
|
||||
" locale TEXT NOT NULL DEFAULT 'en',"
|
||||
" template TEXT DEFAULT '',"
|
||||
" UNIQUE(config_id, slot_name, locale)"
|
||||
")"
|
||||
))
|
||||
|
||||
# Step 2: Copy existing data, deriving locale from parent config
|
||||
await conn.execute(text(
|
||||
"INSERT INTO command_template_slot_new (id, config_id, slot_name, locale, template) "
|
||||
"SELECT s.id, s.config_id, s.slot_name, "
|
||||
" CASE WHEN c.locale != '' THEN c.locale ELSE 'en' END, "
|
||||
" s.template "
|
||||
"FROM command_template_slot s "
|
||||
"LEFT JOIN command_template_config c ON s.config_id = c.id"
|
||||
))
|
||||
|
||||
await conn.execute(text("DROP TABLE command_template_slot"))
|
||||
await conn.execute(text(
|
||||
"ALTER TABLE command_template_slot_new RENAME TO command_template_slot"
|
||||
))
|
||||
|
||||
# Step 3: Merge system EN/RU configs into one
|
||||
# Find the system EN and RU config IDs
|
||||
en_row = (await conn.execute(text(
|
||||
"SELECT id FROM command_template_config "
|
||||
"WHERE user_id = 0 AND (locale = 'en' OR name LIKE '%(EN)%') "
|
||||
"LIMIT 1"
|
||||
))).fetchone()
|
||||
ru_row = (await conn.execute(text(
|
||||
"SELECT id FROM command_template_config "
|
||||
"WHERE user_id = 0 AND (locale = 'ru' OR name LIKE '%(RU)%') "
|
||||
"LIMIT 1"
|
||||
))).fetchone()
|
||||
|
||||
if en_row and ru_row and en_row[0] != ru_row[0]:
|
||||
en_id, ru_id = en_row[0], ru_row[0]
|
||||
|
||||
# Move RU slots to the EN config (they already have locale='ru')
|
||||
await conn.execute(text(
|
||||
"UPDATE command_template_slot SET config_id = :en_id "
|
||||
"WHERE config_id = :ru_id"
|
||||
), {"en_id": en_id, "ru_id": ru_id})
|
||||
|
||||
# Update any command_config references from RU to EN
|
||||
if await _has_table(conn, "command_config"):
|
||||
await conn.execute(text(
|
||||
"UPDATE command_config SET command_template_config_id = :en_id "
|
||||
"WHERE command_template_config_id = :ru_id"
|
||||
), {"en_id": en_id, "ru_id": ru_id})
|
||||
|
||||
# Delete the orphan RU config
|
||||
await conn.execute(text(
|
||||
"DELETE FROM command_template_config WHERE id = :ru_id"
|
||||
), {"ru_id": ru_id})
|
||||
|
||||
# Rename the merged config
|
||||
await conn.execute(text(
|
||||
"UPDATE command_template_config SET name = 'Default Commands', "
|
||||
"description = 'Default Immich command templates', locale = '' "
|
||||
"WHERE id = :en_id"
|
||||
), {"en_id": en_id})
|
||||
|
||||
logger.info(
|
||||
"Merged system command template configs (EN=%d, RU=%d) into single config %d",
|
||||
en_id, ru_id, en_id,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user