Plug the ui-kit share modal file import onto the new batch share
endpoint. The option only shows up when ALLOW_SHARE_IMPORT_FILE is
enabled in the config. Errors are rendered inside the import modal
instead of the global toast so the user can fix the file and retry
without losing context.
The e2e environment enables the flag to cover the flow end to end.
Sharing a folder with many contacts one call at a time is slow and can
leave a partial state when one of them fails. This endpoint accepts a
list of email/role rows, validates them all before any write, then
creates accesses for known users and invitations for unknown emails.
Rows targeting users already covered by an equal or higher role are
skipped and reported so the client can inform the user.
The feature is disabled by default and gated by the new
ALLOW_SHARE_IMPORT_FILE setting exposed in the config endpoint.
Anonymous visitors have no help menu, so the homepage loads the
widget floating button instead when the widget is configured. This
gives them the same support entry point as logged-in users.
The frontend storage gauge deserved its own changelog entry, and the
local backend line moves after the already released entries to keep
the section in insertion order.
Deployments without a DeployCenter service had no way to enforce
storage quotas. This backend computes each user's usage locally and
applies a configurable default limit, overridable per user in the
admin (0 meaning unlimited) and skippable for users created before a
cutoff so quotas can be rolled out to new users only. The quota is
soft: can_upload runs before the file size is known, so one upload
can overshoot before the next one is blocked.
Detection records whose item is gone can only be cleaned up manually.
Add an "item exists" column and filter to the admin so orphan records
can be spotted and deleted easily.
When an item was purged while its analysis was still pending or
processing, the detection record was left behind: the analysis kept
being relaunched and crashed on the missing file, leaving the record
stuck forever and holding a processing slot.
GCS based storages like S3NS reject presigned PUT URLs signing the
x-amz-acl header: their S3 compatibility layer consumes x-amz-*
headers having an x-goog-* equivalent, so the signature check no
longer finds the header in the request. Objects are private by
default on S3 and GCS, so the ACL can simply be dropped by setting
AWS_S3_UPLOAD_ACL to an empty string. The setting is exposed in the
config endpoint so the frontend can send a header matching the
signature.
See https://documentation.s3ns.fr/storage/docs/aws-simple-migration
Address the maintainability findings raised by the new SonarCloud
docker analyzer: drop the floating pip upgrade (nothing uses pip in
the image, the build relies on uv, and the base image already ships
a current pip), stop storing apk indexes in the image layers, quote
DRIVE_STATIC_ROOT and sort the core package list.
The collabora/code image published on 2026-07-18 (26.04.2.2.1) drops
the shell and the start script: our CMD-SHELL healthcheck could not
run at all (no /bin/sh) and extra_params was no longer read, so SSL
came back on and broke the plain-http WOPI discovery. Every e2e job
failed with "container drive-collabora-1 is unhealthy".
Pin the image and migrate to the new contract: coolwsd options go
through command arguments, and the health probe relies on the
built-in coolwsd --probe, overridden to target the http endpoint
since it defaults to https.
Added
- ✨(backend) allow converting a file while it is being analyzed
- ✨(frontend) add file type, contact and modification date topbar filters
- ✨(frontend) add location, file type, contact and date search filters
Fixed
- 🐛(nginx) let search engines see the noindex directive to drop public URLs
- 🐛(backend) find deleted root items when searching the trashbin
- 🐛(backend) exclude folders from file type search results
- 🐛(frontend) keep uploaded items usable while malware analysis runs
- 🐛(backend) stream export files from S3 without buffering
robots.txt blocked all crawling, so crawlers could never fetch the
pages and never saw the noindex meta tag: URLs discovered through
external links could still end up listed in search results.
Allow crawling in robots.txt and add a X-Robots-Tag noindex header on
frontend pages and media files so every response carries the directive.
Search rebuilds the visible set from the user's accesses, skipping those
whose item was soft deleted. A root item holds its own access, so
deleting it made it unreachable from any location, trashbin included.
Hard deleted items remain excluded, and the scope filter still keeps
deleted items out of regular search results.
The category filter keeps folders on explorer listings so navigation
stays possible. A search is not a navigation: folders have no file type
and only add noise to the results.
Replace the search modal type/workspace/scope filters with the location,
file type, shared-with and modification date filters, matching the new
search design.
Add a "Modified" filter to the topbar with Today / Last 7 days /
Last 30 days / This year presets and a compact custom date range
picker, wired to the updated_at range filter.
default_storage.open() downloads the whole object in memory before the
first read, so exporting folders holding large files can exhaust the
worker memory. Stream straight from the boto3 response body instead.
Conversion reads the source bytes, so it must not run before malware
analysis confirms the file is safe. convert_file now waits while the
source is analyzing and drops the placeholder if it never clears.
Marking the analyzing state as transient locked freshly uploaded items in
the UI while malware detection ran. The uploader must keep full access
during analysis, so split polling from the transient UI lock and surface
the analyzing label as a non-blocking badge. The 404 conversion toast is
now limited to converting placeholders.
Added
- ✨(backend) manage reconciliation requests for user accounts
- ✨(backend) add recursive folder export as ZIP archive
- ✨(frontend) add folder export action
- ✨(backend) background conversion of legacy Office files
- ✨(backend) allow grist file upload
- ✨(frontend) add CTA on public link for anonymous and authenticated users
Changed
- 🐛(backend) replace VersionId by Etag for WOPI
- 🐛(backend) sanitize slash in template-created filenames
Removed
- 🔥(backend) drop deprecated numchild columns from item
Titles containing '/' (e.g. "30/03/30 - liste à faire") produced
a file_key with spurious path separators, crashing WOPI on open.
Extract `format_template_filename()` to replace '/' with '-' when
building the filename from a template title.
Closes#626
UserProfile now renders AnonymousCTA along with a dropdown menu
(copy link, language picker) when no user is authenticated, so
visitors on a public page can still act on it without the user
menu. CustomFilesPreview gains a CONTEXTUAL mode that swaps in
the right CTA based on auth state, used by the standalone file
preview page which is now wrapped in GlobalLayout to expose the
auth context.
The .grist extension was already in FILE_EXTENSIONS_ALLOWED but
upload failed at MIME type validation because python-magic detects
grist files as application/vnd.sqlite3.
The same polling loop fits any transient upload state.
Rename the duplicating poller to a transient one driven by
TRANSIENT_UPLOAD_STATES so converting items are picked up without copying
the hook, and the explorer refreshes automatically when background
conversion finishes.
Issue #412 asks for a way to download an entire folder. Add a
GET /items/<id>/export/ action that streams a recursive ZIP archive of
the folder, preserving the directory hierarchy and skipping soft-deleted
or not-yet-uploaded descendants.
The _deprecated_numchild and _deprecated_numchild_folder fields were
kept temporarily to preserve the underlying columns during the tree
model transition. The columns are no longer read or written, so the
fields and their columns can now be removed.
When we try to get the VersionId from the s3 response
but this one is not send by the s3 storage (garage for example),
we get a 500 error.
To fix this issue we use the ETag sent by the object storage to track
the version id. This ETag is present also when versionning is not
implemented.
Co-authored-by: RolletQuentin <rolletquen@gmail.com>
Duplication is currently invisible to product analytics because the
event is fired from the API rather than the UI. Emit it from the
viewset right after the duplicate row is created so the duplicated
item context (workspace, mimetype, ...) is attached to the event.
On the duplicate action we are using the decorator @transaction.atomic
to be sure that the duplicated item and its accesses are correctly
created. The problem with that is that the celery task doing the file
duplication on the object storage can be executed before the transaction
is commited leading to an error saying that the duplicated_item does not
exists.
Scalingo's Ubuntu runtime ships a newer libmagic that returns
application/CDFV2 for legacy .doc/.xls/.ppt files, where Alpine's
older libmagic (used in our Docker image) returns the older label
application/x-ole-storage. Both describe the same OLE2 / Composite
Document File V2 container.
detect_mimetype() already treats application/x-ole-storage as a
generic content-detection result and falls back to extension-based
detection (yielding application/msword, application/vnd.ms-excel,
etc.). Without the same handling for CDFV2, legacy .doc uploads on
Scalingo are rejected by the mimetype allow-list with
"mimetype not allowed application/CDFV2 for filename ...".
Record the metrics filter, entitlement payload additions, and the
frontend disclaimer feature shipped on this branch, alongside the
already-landed organization metrics entry.
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
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.
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.
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.
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.
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.
`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.
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
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.