Commit Graph

128 Commits

Author SHA1 Message Date
Edouard Vanbelle 9519c1fee2 refactor(ui): ensure types, resolve ci warning 2026-06-16 14:18:37 +02:00
Edouard Vanbelle 5eb4d9117c chore(front): apply biome formatter 2026-06-15 16:30:38 +02:00
DioCrafts 81a93a489b feat: photo/video capture-date pipeline + premium UI/UX overhaul
Backend — Photos timeline now groups by real capture date instead of upload time. New MediaMetadataService (FileLifecycleHook) extracts EXIF DateTimeOriginal from images and container creation_time from videos (mov/mp4/mkv) via nom-exif, timezone-correct (OffsetTimeOriginal), persisting captured_at so the existing media_sort_date trigger takes over. Adds POST /admin/photos/metadata/reextract to backfill existing media. Falls back to upload date when no embedded date exists.

Frontend — premium grid cards: combined metadata line (relative date · size, owner avatar when shared), custom selection checkbox with a clear checked state, uniform full-width 4:3 thumbnail tiles independent of filename length, centered file-type icons, and a hit-test fix so checkbox/star/kebab clicks reach the controls (the decorative thumbnail no longer captures pointer events). Notification messages internationalised across all 16 locales. Broader polish: design tokens, a11y/focus-visible states, brand + PWA assets.

Chore — bump semver-compatible dependencies (cargo upgrade); add nom-exif 3.6.1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 00:24:27 +02:00
Claude 635ef8baf6 perf(files): breadcrumb no longer blocks the listing; ancestors cached
Every folder navigation awaited rebuildBreadCrumb() — one sequential
fetch per ancestor level — before requesting the first page, so a
depth-8 folder paid ~8 RTTs of dead time before the content even
started loading. And nothing was cached: navigating between sibling
folders re-fetched the same ancestors every time.

- filesModel: session cache id → FolderItem for breadcrumb resolution
  (warm navigations rebuild the trail with zero fetches), invalidated
  on rename/move (single + batch) via invalidateFolderMeta. The trail
  is now built locally and committed atomically, guarded by a
  generation token so a rebuild superseded by a faster follow-up
  navigation can no longer interleave writes into the newer trail.
- filesView.loadFiles: the rebuild runs concurrently with the first
  page fetch; crumbs, history and title update when it resolves.
  Navigation latency becomes max(listing, ancestor chain) instead of
  their sum — and ~equal to the listing alone once the cache is warm.
  The home-folder fallback for inaccessible targets is preserved by
  reloading the listing when the rebuild had to reset app.currentPath.

https://claude.ai/code/session_01Dp3oWon5GBMVn4j3QXZdgx
2026-06-10 11:39:56 +00:00
Claude fd80a3de67 perf(files-ui): stream media/downloads natively, rAF rubber-band, Map selection
Four related fixes to stop buffering files in page memory and stop
hammering layout from the selection paths:

- Inline viewer media: video/audio fetched the ENTIRE file into a blob
  before the first frame (a 2 GB video = 2 GB of tab heap, no
  progressive playback, no seek). The <video>/<audio> src now points
  straight at the same-origin API URL — cookies travel automatically
  and the browser streams with native Range requests, exactly like the
  music player already did.

- Downloads (file, folder ZIP, batch ZIP, viewer button): the
  fetch → blob → objectURL pattern materialized the whole payload in
  RAM before the save dialog appeared (a 10 GB batch ZIP risked
  crashing the tab) with no download progress UI. New shared
  utils/download.js hands the URL to the browser, which streams to
  disk with its own progress UI. Batch download uses the existing GET
  endpoint (same URL contract as the drag-out DownloadURL, now shared
  via buildBatchDownloadUrl); selections whose id list cannot fit in a
  URL keep the buffered POST fallback. Trade-off: failed downloads now
  surface in the browser's download shelf instead of an in-app toast.

- Rubber-band lasso: every mousemove (>100/s) walked all cards
  interleaving getBoundingClientRect() reads with class writes — up to
  N forced reflows per event, freezing the frame rate on folders with
  thousands of loaded rows. Card rects (+ item info) are now snapshot
  once per drag (rebuilt on scroll), and a single rAF pass per frame
  compares against the cached geometry, touching only cards whose
  selection state changed.

- batchToolbar: getSelection() rebuilt the selection by scanning every
  .file-item in the document (the TODO admitted it); it now reads the
  _selected Map that every selection path already keeps in sync.
  clear() scopes its DOM sweep to #files-list (the only container the
  toolbar manages) instead of the whole document.

https://claude.ai/code/session_01Dp3oWon5GBMVn4j3QXZdgx
2026-06-10 09:02:13 +00:00
Claude ca698f73d1 perf(search): render result sets in one batched pass
displaySearchResults inserted up to 100 results one at a time via
addItem({ scroll: true, highlight: true }) — each insert ran two DOM
scans (duplicate guard + row lookup), a smooth scrollIntoView and a
highlight pulse, so every live-search keystroke triggered ~100 competing
smooth-scrolls and O(n²) container scans.

Add filesView.renderItems(): a single component.render() pass (one
DocumentFragment, zero per-item scans/scrolls). addItem keeps the
scroll/highlight affordances for its documented purpose — optimistic
single-item inserts after upload/create.

https://claude.ai/code/session_01Dp3oWon5GBMVn4j3QXZdgx
2026-06-10 09:01:42 +00:00
Edouard Vanbelle 46f8789f4f fix(folder): keep current folder view on refresh 2026-06-06 20:11:13 +02:00
Edouard Vanbelle 540c947e61 fix(ui): better handling of new folder creation
issue: on folder creation view was wiped and displaying only the new folder
    fix: add a "new" swimlane if in group mode and scroll up to the new created folder
2026-06-05 11:25:09 +02:00
Edouard Vanbelle ca0f5b3fc5 fix(ui): ensure usermenu always in viewport
- ensure also use of only one method to position different contextmenus
2026-06-05 11:25:09 +02:00
Edouard Vanbelle 7db27af7a6 feat(user.prefered_locale): save user's locale + invited have same locale as inviters
- OIDC JIT define the locale only at user creation, user can so change his preference later
    - invited users will inherit inviter's locale
    - email will use prefered_locale
    - login to a new browser will use prefered_locale
2026-06-03 14:37:22 +02:00
Edouard Vanbelle e0f59aa942 fix(ui): use email as fallback when username is not defined 2026-06-03 11:39:10 +02:00
Edouard Vanbelle 91f81027e4 fix(front:auth): fix issue with username that can now be empty 2026-06-03 11:39:10 +02:00
Edouard Vanbelle cdd62c29b5 feat(ui): use infinite scrolling on all sections (no need anymore to to click on "load more") 2026-06-03 00:31:59 +02:00
Edouard Vanbelle 9fac34f91e feat(ui): add share modal and users
- fix(external users): fix app starting for external users
2026-06-03 00:31:59 +02:00
Edouard Vanbelle 09985f8a95 feat(group): 1st implementation of Groups
this implements first version (manageable only by admin right now)

    routes:

        GET /api/groups
        List subject groups (paginated). Admin-only.

        POST /api/groups
        Create a new ReBAC subject group. Admin-only. The name must match the RFC 5321 local-part shape and be globally unique (case-insensitive).

        GET /api/groups/search
        Search non-virtual groups by name substring. Authenticated only (no admin role required) — backs the share-dialog recipient autocomplete.

        GET /api/groups/{id}
        Fetch a single group's details. Admin-only.

        DELETE /api/groups/{id}
        Delete a group. Cascades to `subject_group_members` (FK) and to `access_grants` rows referencing this group as a subject. Admin-only.

        PATCH /api/groups/{id}
        Update a group's metadata. Admin-only. v1 only persists name renames.

        GET /api/groups/{id}/effective-members
        List every user transitively reached through this group (members of members of members, etc.). Used by admin / audit tooling. Admin-only.

        GET /api/groups/{id}/members
        List the *direct* members of a group (one level only). Admin-only.

        POST /api/groups/{id}/members
        Add a member to a group. Exactly one of `user_id` / `group_id` must be provided. Adding a group-member runs a write-time cycle check and a nesting-depth check (max 8). Admin-only.

        DELETE /api/groups/{id}/members/group/{gid}
        Remove a nested group-member from a group. Admin-only.

        DELETE /api/groups/{id}/members/user/{uid}
        Remove a user-member from a group. Admin-only.

fix hurl

groups

round

groups
2026-05-31 20:57:45 +02:00
Edouard Vanbelle 19e8af84b7 feat(ui): improve groupby / sortby user experience + fix confusion in trash section 2026-05-30 11:15:46 +02:00
Edouard Vanbelle ca1a2bb649 feat(light-dark): normalize light/dark/like-os mode
permits user to define light, dark or like the desktop
2026-05-30 09:36:15 +02:00
Edouard Vanbelle ea83891a61 feat(trash): move trash API to normalized version (with cursor, orderBy) + normalize Trash section to existing components
normalize also component to format badges (expiry, role, etc)
2026-05-30 00:49:32 +02:00
Edouard Vanbelle 615657a7be fix(shares): fix outgoing shares when browsing in files, fix shareBadge action to open shareDialog 2026-05-29 14:08:41 +02:00
Edouard Vanbelle ae4fb7603a refactor(front): remove dead code (old Shared section) 2026-05-29 13:13:23 +02:00
Edouard Vanbelle 63722c868e feat(myshares): new version of myshares sections, supporting grants Users + Tokens 2026-05-29 13:12:59 +02:00
Edouard Vanbelle 29d8aab9c0 feat(resourceList): keep consistence in groupby options order accross sectons + add userVignette on owner's swimlane 2026-05-28 12:12:22 +02:00
Edouard Vanbelle 73e78904e7 feat(recent): add cursor + groupby support 2026-05-28 12:12:22 +02:00
Edouard Vanbelle bd474aa67e feat(viewPref): keep record of user view preferences per section (groupBy, order, list or grid) 2026-05-28 12:12:22 +02:00
Edouard Vanbelle 7f4b329718 feat(itemToolltip): fusion pathTooltip + ownerTooltip into itemToolltip, move it in the header for more visibility 2026-05-28 12:12:22 +02:00
Edouard Vanbelle 607ae5e6df feat(resources): add cursor, group by on /api/favorites/resources 2026-05-28 12:12:22 +02:00
Edouard Vanbelle 5790a1459f feat(folders): add curser and the normalized way to get foler's item list. add reverse order 2026-05-28 12:12:22 +02:00
Edouard Vanbelle 859f9b5f86 refactor: separate roles between ui, fileView, resourceList 2026-05-28 00:15:05 +02:00
Edouard Vanbelle 5afb30ebfd feat(swimlane): add swimlane engine with first version on SharedWithMe section
added group by:

        - None (= ordered by folders/file name)
        - Type (Folder first, then Image, Vidao, Audio, Document, etc...)
        - Owner
        - Size (With logarithmic groups))
        - Shared date (with groups: today, last 7 days, last 30 days, then year)
2026-05-28 00:15:05 +02:00
Edouard Vanbelle 720bf11168 use of resourceList 2026-05-28 00:15:05 +02:00
Edouard Vanbelle 6ac4e6177c refactor(js): move multiSelect into batchToolbar + move residual method into relevant components 2026-05-28 00:15:05 +02:00
Edouard Vanbelle b0c5e7827e feat(user-avatar): users can now edit there image (image is taken from OIDC picture) 2026-05-27 11:29:33 +02:00
Edouard Vanbelle 8365608bd5 feat(list view): show the owner of the File or Folder in list view 2026-05-25 22:48:59 +02:00
Edouard Vanbelle 79c1a37931 feat(ui): 1 modal to manage shares (users & public share)
fix(share): ensure Authz parent is created/updated on publicShare create/update

fix(ShareModal): do not show Token (public) grants in People section
2026-05-25 22:47:36 +02:00
Edouard Vanbelle a88e4c2733 refactor: move modal into components (prepare a mode autonomous components) 2026-05-25 22:47:36 +02:00
Edouard Vanbelle 7fd444259f fix(breadcrumb): simplify breadcrumb logic and fix issue with shared items 2026-05-25 22:47:36 +02:00
Edouard Vanbelle 60d53ea779 feat(ui): add section 'Shared with me' 2026-05-25 22:47:32 +02:00
Edouard Vanbelle 191f725199 feat(ui/trash): show original file path in tooltip on mouse over + display thumbnails
* fix: permission also check elements trashed elements
 * tested manually
 * all automated tests ok
2026-05-22 02:26:11 +02:00
Edouard Vanbelle 0fba4ce7bc fix(ui): clear empty state on folder creation 2026-05-19 11:16:27 +02:00
Edouard Vanbelle 82561a2b90 fix(ui): add RecentItem type + ad protection while building items 2026-05-19 10:18:40 +02:00
Edouard Vanbelle fac184ccfe style(front/js): apply types on all objects
- reduce amount of warnings in IDE
    - maximize API type mapping with static/js/core/types.js
2026-05-19 10:18:33 +02:00
Kamil Alekberov fe0a8c7f72 feat(ui): improve mobile search and consolidate language selector
- On mobile (≤768px), replace the full search bar in the topbar with a
  search icon button; tapping it expands a full-width search overlay
  with a back arrow to collapse (Google Drive-style pattern)
- Escape key also collapses the mobile search overlay
- Hide the redundant inline search icon when the mobile search bar is
  active (submit button already has one)
- Move the language selector from the topbar into the user menu for all
  screen sizes, reducing topbar clutter; it renders as an accordion row
  matching other menu items
- Fix user menu positioning in RTL layouts (Arabic/Persian): anchor to
  left:0 instead of right:0 so the panel opens inward rather than
  off-screen
2026-05-17 18:41:34 +05:00
Edouard Vanbelle 85c8c086ac fix(ui): fix go to parent + refactor types 2026-05-12 00:22:51 +02:00
Edouard Vanbelle 6e4699ff9c feat(ui): drop from system available only on files section
* prevent dropzone if not on files section
 * show a notification to user to use files section
 * solve #357
2026-05-09 19:22:15 +02:00
Edouard Vanbelle 7697f3d35b feat(ui): handle errors on folder creation or folder/file renaming
- protect file_management_service::rename_file with validate_storage_name
 - remove specific rename modal and use the generic modal class (less duplicate)
 - handle errors on modal action: do not close the modal on error and display this error
 - hide "Go to parent folder" contextMenu if section is files and folder is the same as current one
2026-05-09 00:06:36 +02:00
Dionisio Pozo 52f4a865a9 Merge pull request #349 from EdouardVanbelle/feat/item-path-tool-tip+go-to-parent
show item path on Recent + Favorite, add go to parent folder, fix Folder browsing in Favorites
2026-05-08 01:22:08 +02:00
Dionisio Pozo 71fd84dd9d Merge pull request #350 from EdouardVanbelle/fix/blank-section-on-token-expired
fix(ui): handle any session expired and trigger transparently a refresh token
2026-05-08 01:21:42 +02:00
Edouard Vanbelle 93d9a21013 fix(ui): admin panel, profile: restore missing icons library 2026-05-07 22:43:02 +02:00
Edouard Vanbelle a69dde35ce fix(ui): handle any session expired and trigger transparently a refresh token
this change replace original window.fetch by a wrapper that check any 401 response, is so it will request a refresh token
this solve current issue with Favorites & Recent sections that give blank page when token is expired

- exclusion of requests to other domain (401 will not be handled here)
- security with shares /api/s is not handled

- check with CSRF, no risk
2026-05-07 00:55:21 +02:00
Edouard Vanbelle 8e1e9fe201 show item path on Recent + Favorites, add go to parent folder, fix Folder browsing in Favorites 2026-05-06 23:36:05 +02:00