From 5aaf49859ea66c289b0616d4576bb617e6eaf016 Mon Sep 17 00:00:00 2001 From: Edouard Vanbelle Date: Mon, 13 Jul 2026 19:26:19 +0200 Subject: [PATCH 1/5] feat(user-perf): add ui user-perf + dotfile filter - add resource kind filter (file, folder, drive) in shared section (localStorage stored) - add user preferences serverside store - add client side dotfile filter (show/hide dotfiles) (user perf stored, default: dotfiles are shown) for security trashed dotfile are always displayed protection added: if a folder has only hidden items, a notification invite user to display it if a user rename or create a hidden item, a notification tells it to user --- frontend/src/lib/api/endpoints/profile.ts | 10 + frontend/src/lib/api/types.ts | 16 ++ frontend/src/lib/components/AppShell.svelte | 37 ++++ .../src/lib/components/ListToolbar.svelte | 56 ++++- .../src/lib/components/ResourceList.svelte | 15 +- .../src/lib/components/SkeletonList.svelte | 8 +- frontend/src/lib/icons/registry.ts | 4 + frontend/src/lib/stores/files.svelte.ts | 19 +- frontend/src/lib/stores/files.test.ts | 12 +- frontend/src/lib/stores/preferences.svelte.ts | 167 +++++++++++++++ frontend/src/lib/utils/dotfileFilter.ts | 53 +++++ frontend/src/routes/favorites/+page.svelte | 9 + .../src/routes/files/[...path]/+page.svelte | 135 +++++++++++- frontend/src/routes/files/page.test.ts | 9 +- frontend/src/routes/photos/+page.svelte | 59 ++++-- frontend/src/routes/profile/+page.svelte | 32 +++ frontend/src/routes/recent/+page.svelte | 24 ++- frontend/src/routes/s/[token]/+page.svelte | 28 ++- frontend/src/routes/shared/+page.svelte | 194 +++++++++++++++++- frontend/src/routes/trash/+page.svelte | 7 + frontend/static/locales/ar.json | 30 ++- frontend/static/locales/de.json | 30 ++- frontend/static/locales/en.json | 34 ++- frontend/static/locales/es.json | 30 ++- frontend/static/locales/fa.json | 30 ++- frontend/static/locales/fr.json | 30 ++- frontend/static/locales/hi.json | 30 ++- frontend/static/locales/it.json | 30 ++- frontend/static/locales/ja.json | 30 ++- frontend/static/locales/ko.json | 30 ++- frontend/static/locales/nl.json | 30 ++- frontend/static/locales/pl.json | 30 ++- frontend/static/locales/pt.json | 30 ++- frontend/static/locales/ru.json | 30 ++- frontend/static/locales/zh-TW.json | 30 ++- frontend/static/locales/zh.json | 30 ++- .../20260913000000_users_ui_preferences.sql | 41 ++++ src/application/dtos/user_dto.rs | 22 ++ .../services/auth_application_service.rs | 49 ++++- src/domain/entities/user.rs | 40 ++++ .../repositories/pg/user_pg_repository.rs | 82 +++++++- tests/api/run.sh | 1 + tests/api/user_ui_preferences.hurl | 184 +++++++++++++++++ 43 files changed, 1676 insertions(+), 121 deletions(-) create mode 100644 frontend/src/lib/stores/preferences.svelte.ts create mode 100644 frontend/src/lib/utils/dotfileFilter.ts create mode 100644 migrations/20260913000000_users_ui_preferences.sql create mode 100644 tests/api/user_ui_preferences.hurl diff --git a/frontend/src/lib/api/endpoints/profile.ts b/frontend/src/lib/api/endpoints/profile.ts index b5e21cdb..0360168b 100644 --- a/frontend/src/lib/api/endpoints/profile.ts +++ b/frontend/src/lib/api/endpoints/profile.ts @@ -12,6 +12,16 @@ export interface ProfilePatch { family_name?: string; preferred_locale?: string; notify_on_share?: boolean; + /** + * Partial patch into the opaque UI preferences bag. Server does a + * SHALLOW merge — keys present here overwrite existing top-level + * keys; absent keys survive. Set a key to `null` to remove it + * (server runs `jsonb_strip_nulls` after the merge). + * + * Wire-side type is `Record`; the typed view over + * this bag lives in `lib/stores/preferences.svelte.ts`. + */ + ui_preferences?: Record; } export async function updateProfile(patch: ProfilePatch): Promise { diff --git a/frontend/src/lib/api/types.ts b/frontend/src/lib/api/types.ts index 82d695f1..69a3db6a 100644 --- a/frontend/src/lib/api/types.ts +++ b/frontend/src/lib/api/types.ts @@ -172,6 +172,22 @@ export interface User { email_verified_at?: string; preferred_locale?: string; notify_on_share: boolean; + /** + * Opaque UI preferences bag. Server-side JSONB column that persists + * pure UI toggles (hide-dotfiles, view mode, sidebar collapse, …) + * across devices. The server never inspects the contents — the SPA + * defines the keys (see `lib/stores/preferences.svelte.ts` for the + * typed view). Always an object on the wire (empty bag is `{}`, + * never `null` or missing). + * + * When PATCHing back to the server via + * `PATCH /api/auth/me/profile { ui_preferences: {...} }`, the + * server SHALLOW-merges — only the keys present in the patch are + * touched, so partial writes from one device don't clobber + * preferences set on another. Set a key to `null` in the patch to + * delete it from the bag. + */ + ui_preferences: Record; } export interface AuthResponse { diff --git a/frontend/src/lib/components/AppShell.svelte b/frontend/src/lib/components/AppShell.svelte index 57577510..09318d76 100644 --- a/frontend/src/lib/components/AppShell.svelte +++ b/frontend/src/lib/components/AppShell.svelte @@ -14,6 +14,7 @@ import { userInitials, avatarColorIndex } from '$lib/utils/avatar'; import { i18n, LANGUAGES, setLocale, t, type Locale } from '$lib/i18n/index.svelte'; import { apiFetch } from '$lib/api/client'; + import { preferences } from '$lib/stores/preferences.svelte'; import { session } from '$lib/stores/session.svelte'; import { theme, type Theme } from '$lib/stores/theme.svelte'; import { ui } from '$lib/stores/ui.svelte'; @@ -208,6 +209,19 @@ langOpen = false; } + /** + * True when the shortcut target is a text-input surface — , + *