Skip to content

fix: handle non-string user/team prefs to prevent Preferences UI crash#2885

Merged
HarshMN2345 merged 1 commit intomainfrom
fix-pref-bug
Feb 26, 2026
Merged

fix: handle non-string user/team prefs to prevent Preferences UI crash#2885
HarshMN2345 merged 1 commit intomainfrom
fix-pref-bug

Conversation

@HarshMN2345
Copy link
Member

@HarshMN2345 HarshMN2345 commented Feb 25, 2026

What does this PR do?

(Provide a description of what this PR does.)

Test Plan

(Write your test plan here. If you changed any code, please provide us with clear instructions on how you verified your changes work.)

Related PRs and Issues

(If this PR is related to any other PR or resolves any issue or related to any issue link all related PR and issues here.)

Have you read the Contributing Guidelines on issues?

(Write your answer here.)

Summary by CodeRabbit

  • Refactor
    • Enhanced preference handling utilities with improved input flexibility and consistent string normalization for preference keys and values across management components.

@appwrite
Copy link

appwrite bot commented Feb 25, 2026

Console (appwrite/console)

Project ID: 688b7bf400350cbd60e9

Sites (1)
Site Status Logs Preview QR
 console-stage
688b7cf6003b1842c9dc
Ready Ready View Logs Preview URL QR Code

Tip

Build commands execute in runtime containers during deployment

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 25, 2026

Walkthrough

The pull request updates the preferences handling system to improve type flexibility and consistency. The normalizePrefs function signature is broadened to accept multiple input types ([string, unknown][], PrefRow[], or {key: unknown; value: unknown}[]) and explicitly converts values to strings using a new private stringTrim helper function. A new exported utility createPrefRow is introduced to standardize preference row construction. Two Svelte component files are updated to remove explicit type casts and instead rely on explicit String() coercion when creating preference rows with keys and values.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: handling non-string user/team preferences to prevent UI crashes. It directly reflects the core modifications across all three files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-pref-bug

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 25, 2026

Greptile Summary

Prevented UI crashes by adding defensive type coercion to handle non-string user/team preference values throughout the preferences system.

Key changes:

  • Created stringTrim() helper to safely handle unknown types with nullish coalescing
  • Updated normalizePrefs() to accept unknown types and coerce them to strings
  • Added explicit String() coercion in both user and team preference components when mapping Object.entries() results
  • Removed unsafe type assertions (as Record<string, string>) that assumed preference values would always be strings

Why this matters:
The Appwrite backend can store preferences as any JSON type (strings, numbers, booleans, objects), but the Console UI expected only strings. When non-string values were present, calling .trim() on them would throw errors and crash the Preferences UI.

Confidence Score: 5/5

  • Safe to merge - defensive fix that prevents crashes without changing existing behavior
  • The changes add robust type coercion to handle edge cases where preferences contain non-string values. The fix is defensive (handles unexpected data gracefully), follows TypeScript best practices with proper nullish coalescing, and maintains backward compatibility since String() coercion on strings is a no-op
  • No files require special attention

Important Files Changed

Filename Overview
src/lib/helpers/prefs.ts Added defensive type coercion to handle non-string preference values, preventing UI crashes when preferences contain unexpected types
src/routes/(console)/project-[region]-[project]/auth/teams/team-[team]/updatePrefs.svelte Removed unsafe type assertion and added explicit String() coercion when mapping preference entries to PrefRow objects
src/routes/(console)/project-[region]-[project]/auth/user-[user]/updatePrefs.svelte Added explicit String() coercion when mapping preference entries, matching the team preferences implementation

Last reviewed commit: 5525372

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (5)
src/routes/(console)/project-[region]-[project]/auth/teams/team-[team]/updatePrefs.svelte (1)

37-39: Same String(key ?? '') over-defensiveness as in the user updatePrefs.svelte.

Object.entries keys are always string; the fix needed here is only for values. Consider simplifying to createPrefRow(key, String(value ?? '')).

♻️ Proposed simplification
-                ? entries.map(([key, value]) =>
-                      createPrefRow(String(key ?? ''), String(value ?? ''))
-                  )
+                ? entries.map(([key, value]) =>
+                      createPrefRow(key, String(value ?? ''))
+                  )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/routes/`(console)/project-[region]-[project]/auth/teams/team-[team]/updatePrefs.svelte
around lines 37 - 39, The code is over-defensive converting entry keys with
String(key ?? ''), but Object.entries always yields string keys; update the map
call to pass the key directly and only coerce values: use createPrefRow(key,
String(value ?? '')) in the entries.map callback so createPrefRow receives the
original string key and a safe stringified value; locate the mapping that
currently calls createPrefRow(String(key ?? ''), String(value ?? '')) and
replace it accordingly.
src/lib/helpers/prefs.ts (3)

32-33: stringTrim is redundant in sanitizePrefsPrefRow fields are already string.

sanitizePrefs accepts PrefRow[] where both fields are typed string, so the String(s ?? '') wrapping inside stringTrim is a no-op. Using .trim() directly keeps the intent clear.

♻️ Proposed simplification
 export function sanitizePrefs(prefs: PrefRow[]) {
-    return prefs.filter((p) => stringTrim(p.key).length > 0 && stringTrim(p.value).length > 0);
+    return prefs.filter((p) => p.key.trim().length > 0 && p.value.trim().length > 0);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/helpers/prefs.ts` around lines 32 - 33, The sanitizePrefs function
uses stringTrim on PrefRow.key and PrefRow.value even though PrefRow fields are
already strings; replace stringTrim(p.key) and stringTrim(p.value) with direct
p.key.trim() and p.value.trim() to simplify and clarify intent, updating the
sanitizePrefs function accordingly (refer to sanitizePrefs and stringTrim to
locate the code).

7-9: PrefRow[] branch in the union is a subtype of { key: unknown; value: unknown }[] and is redundant.

PrefRow is { key: string; value: string }, which satisfies { key: unknown; value: unknown }. Listing it explicitly in the union adds noise without widening the accepted type.

♻️ Proposed simplification
 export function normalizePrefs(
-    entries: [string, unknown][] | PrefRow[] | { key: unknown; value: unknown }[]
+    entries: [string, unknown][] | { key: unknown; value: unknown }[]
 ): [string, string][] {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/helpers/prefs.ts` around lines 7 - 9, The function signature for
normalizePrefs includes a redundant branch PrefRow[] in the union because
PrefRow is { key: string; value: string } which already matches { key: unknown;
value: unknown }; update the parameter type to remove PrefRow[] (i.e., change
entries: [string, unknown][] | { key: unknown; value: unknown }[]), leaving
normalizePrefs and any callers unchanged, and run type-check to ensure no other
places relied on the explicit PrefRow[] union member.

16-16: Redundant re-stringification in filter after map already yields [string, string].

After the .map() step every element is a [string, string] tuple, so stringTrim(k) just adds a needless String(k ?? '') wrap. Use .trim() directly on the already-string values.

♻️ Proposed simplification
-        .filter(([k, v]) => stringTrim(k).length > 0 && stringTrim(v).length > 0)
+        .filter(([k, v]) => k.trim().length > 0 && v.trim().length > 0)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/helpers/prefs.ts` at line 16, The filter currently calls
stringTrim(k) and stringTrim(v) even though the preceding .map already produced
[string, string], so change the predicate in the .filter to use the native
.trim() on the existing strings (e.g. .filter(([k, v]) => k.trim().length > 0 &&
v.trim().length > 0)); remove the redundant stringTrim wrapping while keeping
the same semantics; reference the existing stringTrim identifier only if needed
elsewhere but do not re-stringify k or v in the filter.
src/routes/(console)/project-[region]-[project]/auth/user-[user]/updatePrefs.svelte (1)

37-39: String(key ?? '') is over-defensive — Object.entries keys are always string.

Object.entries always returns string keys, so key is never null/undefined and the String(key ?? '') wrapper adds no protection. The value coercion String(value ?? '') is the meaningful part of the fix and is correct.

♻️ Proposed simplification
-                ? entries.map(([key, value]) =>
-                      createPrefRow(String(key ?? ''), String(value ?? ''))
-                  )
+                ? entries.map(([key, value]) =>
+                      createPrefRow(key, String(value ?? ''))
+                  )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/routes/`(console)/project-[region]-[project]/auth/user-[user]/updatePrefs.svelte
around lines 37 - 39, The map callback is over-defensive by coercing the
Object.entries key with String(key ?? ''), since keys from Object.entries are
always strings; update the entries.map call that builds createPrefRow (the arrow
callback using [key, value]) to pass the existing key directly (or at most
String(key)) and keep the value coercion as String(value ?? ''), e.g. replace
the first argument to createPrefRow with key instead of String(key ?? '') so
locate the entries.map callback and change its first parameter usage
accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/lib/helpers/prefs.ts`:
- Around line 32-33: The sanitizePrefs function uses stringTrim on PrefRow.key
and PrefRow.value even though PrefRow fields are already strings; replace
stringTrim(p.key) and stringTrim(p.value) with direct p.key.trim() and
p.value.trim() to simplify and clarify intent, updating the sanitizePrefs
function accordingly (refer to sanitizePrefs and stringTrim to locate the code).
- Around line 7-9: The function signature for normalizePrefs includes a
redundant branch PrefRow[] in the union because PrefRow is { key: string; value:
string } which already matches { key: unknown; value: unknown }; update the
parameter type to remove PrefRow[] (i.e., change entries: [string, unknown][] |
{ key: unknown; value: unknown }[]), leaving normalizePrefs and any callers
unchanged, and run type-check to ensure no other places relied on the explicit
PrefRow[] union member.
- Line 16: The filter currently calls stringTrim(k) and stringTrim(v) even
though the preceding .map already produced [string, string], so change the
predicate in the .filter to use the native .trim() on the existing strings (e.g.
.filter(([k, v]) => k.trim().length > 0 && v.trim().length > 0)); remove the
redundant stringTrim wrapping while keeping the same semantics; reference the
existing stringTrim identifier only if needed elsewhere but do not re-stringify
k or v in the filter.

In
`@src/routes/`(console)/project-[region]-[project]/auth/teams/team-[team]/updatePrefs.svelte:
- Around line 37-39: The code is over-defensive converting entry keys with
String(key ?? ''), but Object.entries always yields string keys; update the map
call to pass the key directly and only coerce values: use createPrefRow(key,
String(value ?? '')) in the entries.map callback so createPrefRow receives the
original string key and a safe stringified value; locate the mapping that
currently calls createPrefRow(String(key ?? ''), String(value ?? '')) and
replace it accordingly.

In
`@src/routes/`(console)/project-[region]-[project]/auth/user-[user]/updatePrefs.svelte:
- Around line 37-39: The map callback is over-defensive by coercing the
Object.entries key with String(key ?? ''), since keys from Object.entries are
always strings; update the entries.map call that builds createPrefRow (the arrow
callback using [key, value]) to pass the existing key directly (or at most
String(key)) and keep the value coercion as String(value ?? ''), e.g. replace
the first argument to createPrefRow with key instead of String(key ?? '') so
locate the entries.map callback and change its first parameter usage
accordingly.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 301caeb and 5525372.

📒 Files selected for processing (3)
  • src/lib/helpers/prefs.ts
  • src/routes/(console)/project-[region]-[project]/auth/teams/team-[team]/updatePrefs.svelte
  • src/routes/(console)/project-[region]-[project]/auth/user-[user]/updatePrefs.svelte

@HarshMN2345 HarshMN2345 merged commit 260c6eb into main Feb 26, 2026
5 checks passed
@HarshMN2345 HarshMN2345 deleted the fix-pref-bug branch February 26, 2026 09:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants