diff --git a/scripts/pb-init-v3.sh b/scripts/pb-init-v3.sh index eb9f62f..ca932f4 100755 --- a/scripts/pb-init-v3.sh +++ b/scripts/pb-init-v3.sh @@ -62,6 +62,39 @@ create() { esac } +# add_index COLLECTION INDEX_NAME SQL_EXPR +# Fetches current schema, adds index if absent by name, PATCHes collection. +add_index() { + COLL="$1"; INAME="$2"; ISQL="$3" + SCHEMA=$(curl -sf -H "Authorization: Bearer $TOK" "$PB/api/collections/$COLL" 2>/dev/null) + PARSED=$(echo "$SCHEMA" | python3 -c " +import sys, json +d = json.load(sys.stdin) +indexes = d.get('indexes', []) +exists = any('$INAME' in idx for idx in indexes) +print('exists=' + str(exists)) +print('id=' + d.get('id', '')) +if not exists: + indexes.append('$ISQL') + print('indexes=' + json.dumps(indexes)) +" 2>/dev/null) + if echo "$PARSED" | grep -q "^exists=True"; then + log "index exists (skip): $COLL.$INAME"; return + fi + COLL_ID=$(echo "$PARSED" | grep "^id=" | sed 's/^id=//') + [ -z "$COLL_ID" ] && { log "WARNING: cannot resolve id for $COLL"; return; } + NEW_INDEXES=$(echo "$PARSED" | grep "^indexes=" | sed 's/^indexes=//') + STATUS=$(curl -s -o /dev/null -w "%{http_code}" \ + -X PATCH "$PB/api/collections/$COLL_ID" \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $TOK" \ + -d "{\"indexes\":${NEW_INDEXES}}") + case "$STATUS" in + 200|201) log "added index: $COLL.$INAME" ;; + *) log "WARNING: add_index $COLL.$INAME returned $STATUS" ;; + esac +} + # add_field COLLECTION FIELD_NAME FIELD_TYPE # Fetches current schema, appends field if absent, PATCHes collection. # Requires python3 for safe JSON manipulation. @@ -294,4 +327,8 @@ add_field "app_users" "polar_subscription_id" "text" add_field "user_library" "shelf" "text" add_field "user_sessions" "device_fingerprint" "text" +# ── 6. Indexes ──────────────────────────────────────────────────────────────── +add_index "chapters_idx" "idx_chapters_idx_slug_number" \ + "CREATE UNIQUE INDEX idx_chapters_idx_slug_number ON chapters_idx (slug, number)" + log "done" diff --git a/ui/src/lib/paraglide/messages.js b/ui/src/lib/paraglide/messages.js index 608d20d..83a0d9d 100644 --- a/ui/src/lib/paraglide/messages.js +++ b/ui/src/lib/paraglide/messages.js @@ -1,4 +1,2 @@ /* eslint-disable */ -export * from './messages/_index.js' -// enabling auto-import by exposing all messages as m -export * as m from './messages/_index.js' \ No newline at end of file +export * from './messages/_index.js' \ No newline at end of file diff --git a/ui/src/routes/+layout.server.ts b/ui/src/routes/+layout.server.ts index d08b713..62fb80e 100644 --- a/ui/src/routes/+layout.server.ts +++ b/ui/src/routes/+layout.server.ts @@ -28,7 +28,7 @@ export const load: LayoutServerLoad = async ({ locals, url, cookies }) => { theme: row.theme ?? 'amber', locale: row.locale ?? 'en', fontFamily: row.font_family ?? 'system', - fontSize: row.font_size ?? 1.0 + fontSize: row.font_size || 1.0 }; } } catch (e) { diff --git a/ui/src/routes/+layout.svelte b/ui/src/routes/+layout.svelte index 969bb12..73af50e 100644 --- a/ui/src/routes/+layout.svelte +++ b/ui/src/routes/+layout.svelte @@ -100,7 +100,7 @@ // Always sync theme + font (profile page calls invalidateAll after saving) currentTheme = data.settings.theme ?? 'amber'; currentFontFamily = data.settings.fontFamily ?? 'system'; - currentFontSize = data.settings.fontSize ?? 1.0; + currentFontSize = data.settings.fontSize || 1.0; // Mark dirty only after the synchronous apply is done so the save // effect doesn't fire for this initial load. setTimeout(() => { settingsDirty = true; }, 0); diff --git a/ui/src/routes/api/settings/+server.ts b/ui/src/routes/api/settings/+server.ts index 552c15a..d449a16 100644 --- a/ui/src/routes/api/settings/+server.ts +++ b/ui/src/routes/api/settings/+server.ts @@ -18,7 +18,7 @@ export const GET: RequestHandler = async ({ locals }) => { theme: settings?.theme ?? 'amber', locale: settings?.locale ?? 'en', fontFamily: settings?.font_family ?? 'system', - fontSize: settings?.font_size ?? 1.0 + fontSize: settings?.font_size || 1.0 }); } catch (e) { log.error('settings', 'GET failed', { err: String(e) }); @@ -61,9 +61,9 @@ export const PUT: RequestHandler = async ({ request, locals }) => { error(400, `Invalid fontFamily — must be one of: ${validFontFamilies.join(', ')}`); } - // fontSize is optional — if provided (and non-zero) it must be one of the valid steps + // fontSize is optional — if provided it must be one of the valid steps (0 is not valid) const validFontSizes = [0.9, 1.0, 1.15, 1.3]; - if (body.fontSize !== undefined && body.fontSize !== 0 && !validFontSizes.includes(body.fontSize)) { + if (body.fontSize !== undefined && !validFontSizes.includes(body.fontSize)) { error(400, `Invalid fontSize — must be one of: ${validFontSizes.join(', ')}`); }