1082 Commits

Author SHA1 Message Date
Manuel Raynaud
805ef77521 🔥(backend) remove mirroring feature
The mirroring feature was hard to maintain and not performant. We should
rely on external tools made for that like RClone.
2026-04-23 17:42:48 +02:00
Manuel Raynaud
3ca5b0e296 🔖(minor) bump release version 0.17.0
Added

- (backend) make invitation validity duration configurable via env var
- (frontend) enhance upload toast with progress, errors and cancel support
- (frontend) add ErrorIcon component and support numeric icon sizes
- (frontend) make file upload abortable in driver layer
- (frontend) files preview v2
- 🔧(project) add DJANGO_EMAIL_URL_APP environment variable

Fixed

- 🐛(frontend) add actions menu on mobile My Files page
- 🐛(frontend) show actual selection count in hard delete modal
- 🐛(frontend) Responsive broken with long filters in search #659
- 🐛(front) set size and variant on trash navigate modal #666
- 🐛(frontend) fix uploads continuing after parent folder deletion
- 🐛(frontend) fix SDK picker link reach promotion
- 🐛(backend) route share invitation link to file view for files
- 🐛(frontend) fix "+ New" menu in read-only folders and virtual tabs
- 🐛(frontend) range selection freezes when there are many items in the list
- 🐛(backend) fix openapi schema for item access endpoints
- 🐛(backend) load jwks url when OIDC_RS_PRIVATE_KEY_STR is set
v0.17.0-preprod v0.17.0
2026-04-23 15:43:49 +02:00
Nathan Panchout
3731033f5b 🔧(project) add DJANGO_EMAIL_URL_APP environment variable
Share invitation emails embedded `Site.domain` directly, producing
schemeless links that mail clients failed to resolve. Introduce a
`DJANGO_EMAIL_URL_APP` environment variable holding the app's
absolute URL used when building invitation links, with a fallback
on the current Site domain when unset. Wire it in dev env, helm
dev values, the helm example and the env reference.
2026-04-23 12:05:26 +02:00
Nathan Panchout
af8ba1031f 🐛(backend) route share invitation link to file view for files
Clicking the invitation link for a shared file opened the folder
explorer page with an empty children listing, because
`Item.send_email` hardcoded `/explorer/items/<uuid>/` regardless of
the item type.

Branch on `item.type` to use the dedicated file route
`/explorer/items/files/<uuid>/` already served by nginx and used by
the in-app share-link copy button.
2026-04-23 12:05:23 +02:00
Nathan Vasse
77a67db6d8 (frontend) add e2e tests for SDK picker selection
Cover the two main picker outcomes: cancelling leaves the item
private, and confirming exposes a publicly reachable URL. The
reach check opens the returned URL in a fresh anonymous context
and waits for the download event, since the backend serves
attachments with Content-Disposition and navigation aborts.

To run the test in CI, build the drive SDK package and start the
sdk-consumer dev server before the playwright job.
2026-04-22 16:00:15 +02:00
Nathan Vasse
a12771fe08 🐛(frontend) fix SDK picker link reach promotion
Switch to useMutationUpdateLinkConfiguration and preserve the
item's existing link_role. Also add the missing sdk.explorer.cancel
translations for en and nl so the Cancel button label renders
correctly. This should have been done when migration to this new
API route. The existing update did not have any effect.
2026-04-22 16:00:15 +02:00
Manuel Raynaud
d120171944 🐛(backend) load jwks url when OIDC_RS_PRIVATE_KEY_STR is set
When the resource server is enabled and the backend used is
JWTResourceServerBackend, then the API should expose a JWKS endpoint
to share the RSA public key to the OIDC provider. Everything is made
in the Django LaSuite library, but the URL is not included in the
Drive URLs. This commit adds it when the setting OIDC_RS_PRIVATE_KEY_STR
is set.
2026-04-22 13:37:30 +02:00
renovate[bot]
d3cb848448 ⬆️(dependencies) update pytest to v9.0.3 [SECURITY] 2026-04-22 10:22:45 +00:00
Nathan Vasse
352e19580e (backend) make invitation validity duration configurable via env
The invitation validity duration was hardcoded to 7 days. Expose it as
an INVITATION_VALIDITY_DURATION env var so operators can tune it per
deployment without patching settings. Default remains 7 days.
2026-04-22 10:09:31 +02:00
renovate[bot]
6cc9c4de9c ⬆️(dependencies) update vite to v6.4.2 [SECURITY] 2026-04-21 14:38:00 +02:00
renovate[bot]
bb1a018e21 ⬆️(dependencies) update next to v15.5.15 [SECURITY] 2026-04-21 11:48:51 +02:00
Nathan Vasse
6655b8fbe8 🐛(backend) fix openapi schema for item access endpoints
`ItemAccessViewSet.get_serializer_class` depends on `self.item`, which
reads `self.kwargs["resource_id"]`. This is unavailable during
drf-spectacular introspection, so spectacular fails to resolve the
serializer and drops the requestBody for POST/PUT/PATCH operations.

Declare the schema statically via `@extend_schema` and
`@extend_schema_view` so the generated OpenAPI exposes the proper
request and response payloads for item access endpoints.
2026-04-21 10:24:18 +02:00
Nathan Panchout
5966e14c46 🐛(frontend) fix range selection freeze on large folders
Drop selectedItems / selectedItemsMap from GlobalExplorerContext and
move every call-site to the selection store introduced in the previous
commit. Rows of the embedded explorer grid are extracted into a memoed
EmbeddedExplorerGridRow that subscribes to its own id via
useIsItemSelected, and the name/actions/mobile cells are memoed and
read their selection status the same way.

High-level consumers that only need a boolean or a count use
useHasSelection / useSelectionCount so they no longer re-render on
every marquee tick:

- AppExplorerInner uses useHasSelection to toggle the selection bar
- ExplorerDndProvider splits the count consumers into dedicated child
  components (drag overlay and move confirmation modal)
- useTableKeyboardNavigation subscribes imperatively through
  selectionStore.subscribe so the focus effect runs without
  invalidating the host component

EmbeddedExplorer creates its own local store so the move modal and the
SDK picker keep their selection scoped and do not leak into the main
explorer selection.

Fixes #124
2026-04-20 17:09:53 +02:00
Nathan Panchout
3bae4e7d3b (frontend) add explorer selection store with per-id listeners
Introduce a lightweight external store compatible with
useSyncExternalStore. It exposes:

- a global subscription for consumers that need the full list or count
- per-id subscriptions so a row can bail out automatically when its own
  isSelected boolean has not changed
- setSelectedItems that diffs the previous and next id maps and
  notifies only the listeners whose status actually flipped

No React state, no context fan-out: a marquee tick that flips N rows
notifies exactly N listeners instead of invalidating the whole tree.
2026-04-20 17:09:53 +02:00
Nathan Panchout
3a730b87cf 📝(frontend) document explorer selection store architecture
Add an architecture doc covering the rationale behind the selection
store refactor: why React Context did not scale to 200+ rows during a
marquee drag, why useSyncExternalStore with per-id listeners enables
automatic bailout, and how global vs embedded scopes are wired.

Lives under docs/architecture/ for long-term reference.
2026-04-20 17:09:53 +02:00
Nathan Panchout
7ef7d56317 (front) add e2e tests for "+ New" fallback to My Files
Cover the four scenarios of the new "+ New" behavior:
- folder creation from a read-only shared folder redirects into the
  newly created folder under My Files
- document creation from a read-only shared folder redirects to the
  My Files view with the new file listed
- folder creation from the Recent / Shared with me / Starred virtual
  tabs creates in My Files
- folder creation in a writable folder still happens in place, with
  no fallback redirect
2026-04-20 15:58:53 +02:00
Nathan Panchout
faee0de673 🐛(front) fix "+ New" menu in read-only folders and virtual tabs
The "+ New" dropdown used to hide all its entries when the user lacked
children_create on the current folder, leaving an empty popover. On
virtual tabs (Recent, My Files, Shared with me, Starred) there is no
real current folder either, so the same empty state could be reached.

Always populate the menu and, when the user cannot create in place,
fall back to creating the item in "My Files" (no parent). After a
fallback creation we redirect:
- into the new folder for folder creation
- to the My Files view for file creation, since a file is not a
  navigable route
The new item is pre-selected in both cases.
2026-04-20 15:58:53 +02:00
Nathan Vasse
26a522f2ae 🔧(ci) exclude ts file from print job
This job was detecting some legit code as false positive
for print statements.
2026-04-20 15:21:01 +02:00
Nathan Vasse
eefa620702 (other) route /wopi/<uuid> to the WOPI item page
The WOPI page is a dynamic route keyed by item UUID, so nginx needs to
fall back to the [id].html shell when the URL is hit directly (reload,
external link). Mirrors the existing /explorer/items/[id] rule.
2026-04-20 15:01:56 +02:00
Nathan Vasse
a8e71cdb38 (backend) add filename to e2e search fixtures
The search e2e fixture items lacked a filename, which made the seeded
file items diverge from real uploads where the filename is present.
We need the filename to be predictive so we can make assertion in the
e2e tests about the viewer that should open or not.
2026-04-20 15:01:56 +02:00
Nathan Vasse
7280b972c4 ♻️(frontend) small cleanups in file preview and wopi
Drop a redundant clearTimeout guard, reformat the WopiEditorFrame
props, assert launch_url is defined at render time, and add a comment
clarifying the WOPI page spinner branch.
2026-04-20 15:01:42 +02:00
Nathan Vasse
3030f71189 ♻️(frontend) unify preview messages into a shared component
The error, not-supported, suspicious and WOPI placeholder viewers all
rendered the same "icon + title + description + action" layout with
near-duplicate scss. Extract a PreviewMessage component so styling and
backdrop-close behaviour live in one place, and update the e2e
selectors to match the new markup.
2026-04-20 15:01:33 +02:00
Nathan Vasse
788cdba513 (frontend) add e2e tests for preview backdrop close
Cover the backdrop-click-to-close behavior for both image
and PDF viewers: clicking the backdrop closes the preview,
clicking the content does not, and dragging across the image
viewer does not trigger a close.
2026-04-20 15:01:33 +02:00
Nathan Vasse
afb4d2862d (frontend) close file preview on backdrop click
Users can now dismiss the preview by clicking the blurry area
around the content. Each viewer marks its backdrop zones with
a data attribute so the handler in FilesPreview can distinguish
backdrop from content clicks. The image viewer also guards
against accidental close during pan-drag gestures.
2026-04-20 15:01:33 +02:00
Nathan Vasse
b69e0fc218 (frontend) add e2e test for image print via hidden iframe
Ensures Print on an image creates a hidden iframe that loads the
same preview URL, waits for the image to decode, and calls
window.print() — all without opening a new tab.
2026-04-20 15:01:33 +02:00
Nathan Vasse
49c0821281 (frontend) print images via browser dialog instead of new tab
Previously clicking Print on an image opened it in a new tab,
leaving the user to trigger the print dialog themselves. Now a
hidden iframe loads the image and calls window.print() directly.
2026-04-20 15:01:33 +02:00
Nathan Vasse
140fb16292 (frontend) improve file preview e2e test stability
Switch the non-printable file test from DOCX to an audio
file so it no longer relies on WOPI (which opens in a new
tab). Wait for the PDF page to render before interacting
with the page input to avoid flaky failures. Remove an
unused variable.
2026-04-20 15:01:33 +02:00
Nathan Vasse
3c46a909e5 ♻️(frontend) remove unused props and CSS in preview viewers
Remove the unused isSidebarOpen prop from PdfControls and
strip unnecessary position/min-height rules from the video
player that were left over from earlier layout iterations.
2026-04-20 15:01:33 +02:00
Nathan Vasse
e6c657ced4 🐛(frontend) fix preview not updating on data change
Add data to the useEffect dependency array so the current
file index is recalculated when the file list changes,
e.g. after a refetch or when items are added/removed.
2026-04-20 15:01:33 +02:00
Nathan Vasse
77174705ea 🐛(frontend) fix image flash when navigating previews
Add a key prop to force React to remount the img element
when switching files. Without this, transitioning between
images of very different sizes causes a visual splash.
2026-04-20 15:01:33 +02:00
Nathan Vasse
26418bda18 💄(frontend) fix preview title layout and use design token
Extract a wrapper div for flex layout and overflow handling,
keeping the title element focused on typography. Replace the
hardcoded color with a design system variable for consistency.
2026-04-20 15:01:33 +02:00
Nathan Vasse
3f439a66ad (frontend) update wopi e2e tests for new-tab flow
Follow the WOPI-in-new-tab change: the double-click scenario now
asserts that a new page opens with the office iframe and that the
preview modal stays closed, a new test covers the "Open in editor"
placeholder reached by keyboard navigating onto a WOPI file, and the
copy/paste scenario drives the detached wopiPage. Refresh canvas
snapshots accordingly and drop the obsolete per-spec snapshot copies.
2026-04-20 15:01:33 +02:00
Nathan Vasse
42c34036e4 (frontend) open WOPI files in a new tab
WOPI editors (OnlyOffice / Collabora) work better as a full-page
experience than embedded inside the preview modal. Double-clicking a
WOPI file in the grid or activating one from the search modal now
opens /wopi/:id in a new tab. The preview modal still shows an
"Open in editor" placeholder when a user navigates onto a WOPI file
via keyboard, so the preview flow stays consistent.

The former WopiEditor component is renamed WopiEditorFrame and
hosted on the new page. The inline rename-sync path is removed
because the editor no longer lives inside the items list.
2026-04-20 15:01:33 +02:00
Nathan Vasse
f90c5c8b3a 💄(frontend) localize image viewer loading label
The loading spinner label was hardcoded in French. Use the translated
file_preview.image.loading key so other locales render correctly.
2026-04-20 15:01:33 +02:00
Nathan Vasse
d3c522058e 🌐(frontend) add wopi open in editor and image loading translations
Add the en/fr/nl entries needed by the upcoming WOPI "open in editor"
placeholder and the image viewer loading label.
2026-04-20 15:01:33 +02:00
Nathan Vasse
c288414827 🐛(frontend) clear pdf sidebar timeout on unmount
The effect that toggles the pdf-sidebar class scheduled a setTimeout
without returning a cleanup, so the timer could fire after the file
preview unmounted. Capture the timeout id and clear it on cleanup.
2026-04-20 15:01:33 +02:00
Nathan Vasse
3670cefb30 ♻️(frontend) rename ProgressBar to DurationBar in preview
The component lives in DurationBar.tsx but was exported as ProgressBar,
which was confusing. Rename the export and update the two call sites
in AudioPlayer and VideoPlayer.
2026-04-20 15:01:33 +02:00
Nathan Vasse
30cfcc7f46 📝(doc) update changelog
Add entry about the file preview v2 iteration.
2026-04-20 15:01:33 +02:00
Nathan Vasse
48ea4c0533 (frontend) add unsupported file preview e2e tests
Cover the fallback viewer that kicks in for file types the app
cannot render inline. A minimal .bin fixture exercises the redesign
so the filename, the "Unsupported format." disclaimer and the
secondary download button are all checked end to end.
2026-04-20 15:01:33 +02:00
Nathan Vasse
b203aa17de (frontend) add video preview e2e tests
Cover the video viewer with a dedicated spec that uploads a small
mp4 fixture, opens the preview and exercises the player controls.
Keeps the new viewer types consistently covered alongside the audio
and image specs.
2026-04-20 15:01:32 +02:00
Nathan Vasse
07ca57c79b (frontend) add image preview e2e tests
Cover the image viewer with a dedicated spec that uploads a small
png fixture, opens the preview and asserts the image renders and
reacts to the viewer controls. Mirrors the audio/video specs so
each viewer has its own file.
2026-04-20 15:01:32 +02:00
Nathan Vasse
43cb816e5d (frontend) add audio preview e2e tests
Cover the audio viewer with a dedicated spec that uploads a small
mp3 fixture, opens the preview and checks the playback controls.
Ensures the audio branch of the preview rewrite stays covered as we
iterate on the other viewers.
2026-04-20 15:01:32 +02:00
Nathan Vasse
a49f4b5dac ♻️(frontend) regroup preview e2e specs under file-preview/
The preview-related specs are now numerous enough to warrant their
own subfolder. Move pdf, heic and preview-actions specs into
__tests__/app-drive/file-preview/ so future preview tests land next
to them rather than at the drive-level root. Import and asset paths
are adjusted to the new depth, the heic row lookup is simplified to
getByRole("cell", ...), and the preview-actions spec gains a small
File Preview Header describe block to exercise the header controls.
2026-04-20 15:01:32 +02:00
Nathan Vasse
6b0ff1a0d1 🐛(frontend) fix className filter in file preview
The predicate in the preview close branch was (className) =>
className !== className, which compared the lambda parameter to
itself and therefore never matched, leaving stale class names on the
preview when the PDF thumbnail sidebar was closed. Rename the inner
parameter so the filter compares against the outer className as
intended.
2026-04-20 15:01:32 +02:00
Nathan Vasse
ab0d1897a7 💄(frontend) redesign unsupported file preview
The preview for files that cannot be rendered inline now shows the
filename as the title and folds the "unsupported format" notice into
the description paragraph as a bold disclaimer, so the panel reads as
"<filename> — Unsupported format. Download it to view." The download
CTA is promoted to a secondary neutral button to stand out on the
empty-state panel.

The i18n key file_preview.unsupported.title is renamed to disclaimer
in en/fr/nl and the copy shortened accordingly. search.spec.ts
assertions are updated to match the filename via getByRole("heading")
now that the preview wraps the title in a heading element.
2026-04-20 15:01:32 +02:00
Nathan Vasse
bceb4aee21 🐛(frontend) fix pdf preview e2e selectors
The preview refactor renamed CSS classes from
pdf-preview__controls / pdf-preview__zoom-controls
to file-preview__controls / file-preview__controls__zoom.
Update the e2e tests to match.
2026-04-20 15:01:32 +02:00
Nathan Vasse
0c84b4683f (frontend) add e2e test for file preview actions
Cover the download/print actions dropdown, keyboard
navigation between files, and the close button in the
new preview chrome.
2026-04-20 15:01:32 +02:00
Nathan Vasse
511ca27b30 ♻️(frontend) rewrite preview viewers and FilesPreview
Reorganize all viewer components under a viewers/ directory
and rewrite FilesPreview as the single orchestrator at the
preview root. Add ZoomControls shared component for image
and PDF viewers. The new layout centralizes the preview
chrome (header, controls bar, navigation) in FilesPreview
while each viewer only handles its own rendering.
2026-04-20 15:01:32 +02:00
Nathan Vasse
a776dbd059 🌐(frontend) add download and print translations
These labels are used by the new preview actions dropdown
menu across English, French and Dutch.
2026-04-20 15:01:32 +02:00
Nathan Vasse
9611dfed35 ♻️(frontend) refactor shared preview controls
Rename PreviewControls to PlayerPreviewControls and swap
material icons for ui-kit SVG icons. Move arrow-key seeking
from global keydown to the DurationBar input so it only
activates when the slider is focused, and add a focus-visible
outline for accessibility. Simplify VolumeBar styling by
removing unused btn-mute overrides.
2026-04-20 15:01:32 +02:00