Compare commits

...

18 Commits

Author SHA1 Message Date
Anthony LC cd6e0ef9e1 🔖(release) patch release 3.4.2
Changed:
- ️(docker) Optimize Dockerfile to use apk with --no-cache

Fixed:
- 🐛(backend) improve prompt to not use code blocks delimiter
2025-07-18 12:30:01 +02:00
AntoLC 02acc7233f 🌐(i18n) update translated strings
Update translated files with new translations
2025-07-18 12:30:01 +02:00
Anthony LC 1c71e830a2 🐛(backend) improve prompt to not use code blocks delimiter
The AI answer was activating the code block feature
in the editor, which was not desired.
The prompt for AI actions has been updated to
instruct the AI to return content directly
without wrapping it in code blocks or markdown
delimiters.
2025-07-18 12:03:48 +02:00
Peter Dave Hello ac0c16a44a ️(docker) Optimize Dockerfile to use apk with --no-cache
Using the `apk` commands with the `--no-cache` parameter for package
installation and upgrade will prevent the package index from being
cached and reduce the built image size.
2025-07-18 10:08:13 +02:00
virgile-dev ca09f9a158 📝(contributing) update contributing policy (#1192)
## Purpose
Update the issue template to help contributors

Please ensure the following items are checked before submitting your
pull request:
- [x] I have read and followed the [contributing
guidelines](https://github.com/suitenumerique/docs/blob/main/CONTRIBUTING.md)
- [x] I have read and agreed to the [Code of
Conduct](https://github.com/suitenumerique/docs/blob/main/CODE_OF_CONDUCT.md)
- [x] I have signed off my commits with `git commit --signoff` (DCO
compliance)
- [x] I have signed my commits with my SSH or GPG key (`git commit -S`)
- [x] My commit messages follow the required format: `<gitmoji>(type)
title description`
- [ ] I have added a changelog entry under `## [Unreleased]` section (if
noticeable change)
- [ ] I have added corresponding tests for new features or bug fixes (if
applicable)

---------

Signed-off-by: virgile-dev <virgile.deville@beta.gouv.fr>
2025-07-17 09:58:31 +00:00
Anthony LC d12b608db9 🔖(patch) release 3.4.1
Fixed:
- 🌐(frontend) keep simple tag during export
- 🐛(back) manage can-edit endpoint without created room in the ws
- 🐛(frontend) fix action buttons not clickable
- 🐛(frontend) fix crash share modal on grid options
2025-07-15 16:14:43 +02:00
Anthony LC 08a0eb59c8 🐛(frontend) fix crash share modal on grid options
The share modal in the DocsGridItem component
was crashing when opened due to a provider not
initialized.
2025-07-15 11:36:44 +02:00
renovate[bot] 0afc50fb93 ⬆️(dependencies) update js dependencies 2025-07-15 03:15:51 +00:00
renovate[bot] c48a4309c1 ⬆️(dependencies) update python dependencies 2025-07-11 06:14:43 +00:00
Anthony LC a212417fb8 🐛(frontend) fix action buttons not clickable (#1162)
If the title was too long, or the children deepness too deep, the action
buttons in the doc tree were not clickable.
This commit fixes the issue by ensuring that the action buttons are
always clickable, regardless of the title length or children depth.
2025-07-11 08:13:01 +02:00
Manuel Raynaud 500d4ea5ac 🐛(back) manage can-edit endpoint without created room in the ws (#1152)
In a scenario where the first user is editing a docs without websocket
and nobody has reached the websocket server first, the y-provider
service will return a 404 and we don't handle this case in the can-edit
endpoint leading to a server error.
2025-07-10 12:24:38 +00:00
Anthony LC 8a057b9c39 🌐(i18n) update translated strings
Update translated files with new translations
2025-07-10 12:48:52 +02:00
Anthony LC 6a12ac560e 🌐(frontend) keep simple tag during export
When we export translations, we want to keep the
simple tags like `<strong>` instead of converting
it to `<1>` and `</1>`.
2025-07-10 12:38:28 +02:00
Anthony LC 2e6cb109ef 🔖(minor) release 3.4.0
Added:
- (frontend) multi-pages
- (frontend) Duplicate a doc
- Ask for access
- (frontend) add customization for translations
- (backend) add ancestors links definitions to document abilities
- (backend) include ancestors accesses on document accesses list view
- (backend) add ancestors links reach and role to document API
- 📝(project) add troubleshoot doc
- 📝(project) add system-requirement doc
- 🔧(front) configure x-frame-options to DENY in nginx conf
- (backend) allow to disable checking unsafe mimetype on attachment upload
- (doc) add documentation to install with compose
-  Give priority to users connected to collaboration server
  (aka no websocket feature)

Changed:
- ♻️(backend) stop requiring owner for non-root documents
- ♻️(backend) simplify roles by ranking them and return only the max role
- 📌(yjs) stop pinning node to minor version on yjs docker image
- 🧑‍💻(docker) add .next to .dockerignore
- 🧑‍💻(docker) handle frontend development images with docker compose
- 🧑‍💻(docker) add y-provider config to development environment
- ️(frontend) optimize document fetch error handling

Fixed:
- 🐛(backend) fix link definition select options linked to ancestors
- 🐛(frontend) table of content disappearing
- 🐛(frontend) fix multiple EmojiPicker
- 🐛(frontend) fix meta title
- 🔧(git) set LF line endings for all text files
- 📝(docs) minor fixes to docs/env.md
- support `_FILE` environment variables for secrets

Removed:
- 🔥(frontend) remove Beta from logo
2025-07-09 17:26:02 +02:00
Manuel Raynaud 70635136cb 🐛(back) duplicating a child should not create accesses
Children does not have accesses created for now, they inherit from their
parent for now. We have to ignore access creation while owrk on the
children accesses has not been made.
2025-07-09 17:26:02 +02:00
Anthony LC 52a8dd0b5c 🩹(frontend) refresh tree after duplicate
After duplicating a document, the tree is now
refreshed to reflect the new structure.
This ensures that the user sees the updated
document tree immediately after the duplication
action.
2025-07-09 17:26:02 +02:00
Anthony LC 8a3dfe0252 🛂(frontend) blocked edition if multiple ancestors
With child documents we need to check the parent
documents to know if the parent doc are collaborative
or not.
2025-07-09 17:26:02 +02:00
Anthony LC 1110ec92d5 (backend) fix test access create
Importing the french translation broke a test
because the subject was not in english anymore.
We change the admin user language to english
to keep the subject in english.
2025-07-09 17:26:02 +02:00
48 changed files with 1063 additions and 626 deletions
-6
View File
@@ -1,6 +0,0 @@
<!---
Thanks for filing an issue 😄 ! Before you submit, please read the following:
Check the other issue templates if you are trying to submit a bug report, feature request, or question
Search open/closed issues before submitting since someone might have asked the same thing before!
-->
+4
View File
@@ -6,6 +6,10 @@ labels: ["bug", "triage"]
## Bug Report
**Before you file your issue**
- Check the other [issues](https://github.com/suitenumerique/docs/issues) before filing your own
- If your report is related to the ([BlockNote](https://github.com/TypeCellOS/BlockNote)) text editor, [file it on their repo](https://github.com/TypeCellOS/BlockNote/issues). If you're not sure whether your issue is with BlockNote or Docs, file it on our repo: if we support it, we'll backport it upstream ourselves 😊, otherwise we'll ask you to do so.
**Problematic behavior**
A clear and concise description of the behavior.
+35 -9
View File
@@ -8,19 +8,43 @@ and this project adheres to
## [Unreleased]
## [3.4.2] - 2025-07-18
### Changed
- ⚡️(docker) Optimize Dockerfile to use apk with --no-cache #743
### Fixed
- 🐛(backend) improve prompt to not use code blocks delimiter #1188
## [3.4.1] - 2025-07-15
### Fixed
- 🌐(frontend) keep simple tag during export #1154
- 🐛(back) manage can-edit endpoint without created room
in the ws #1152
- 🐛(frontend) fix action buttons not clickable #1162
- 🐛(frontend) fix crash share modal on grid options #1174
## [3.4.0] - 2025-07-09
### Added
- ✨(frontend) multi-pages #701
- ✨(backend) add ancestors links definitions to document abilities #846
- ✨(backend) include ancestors accesses on document accesses list view # 846
- ✨(backend) add ancestors links reach and role to document API #846
- ✨(frontend) add customization for translations #857
- ✨(frontend) Duplicate a doc #1078
- ✨Ask for access #1081
- ✨(frontend) add customization for translations #857
- ✨(backend) add ancestors links definitions to document abilities #846
- ✨(backend) include ancestors accesses on document accesses list view #846
- ✨(backend) add ancestors links reach and role to document API #846
- 📝(project) add troubleshoot doc #1066
- 📝(project) add system-requirement doc #1066
- 🔧(front) configure x-frame-options to DENY in nginx conf #1084
- ✨(backend) allow to disable checking unsafe mimetype on attachment upload
- ✨Ask for access #1081
- ✨(backend) allow to disable checking unsafe mimetype on
attachment upload #1099
- ✨(doc) add documentation to install with compose #855
- ✨ Give priority to users connected to collaboration server
(aka no websocket feature) #1093
@@ -43,8 +67,7 @@ and this project adheres to
- 🐛(frontend) fix meta title #1017
- 🔧(git) set LF line endings for all text files #1032
- 📝(docs) minor fixes to docs/env.md
-(backend) support `_FILE` environment variables for secrets #912
- ✨(frontend) support `_FILE` environment variables for secrets #912
- ✨support `_FILE` environment variables for secrets #912
### Removed
@@ -634,7 +657,10 @@ and this project adheres to
- ✨(frontend) Coming Soon page (#67)
- 🚀 Impress, project to manage your documents easily and collaboratively.
[unreleased]: https://github.com/numerique-gouv/impress/compare/v3.3.0...main
[unreleased]: https://github.com/numerique-gouv/impress/compare/v3.4.2...main
[v3.4.2]: https://github.com/numerique-gouv/impress/releases/v3.4.2
[v3.4.1]: https://github.com/numerique-gouv/impress/releases/v3.4.1
[v3.4.0]: https://github.com/numerique-gouv/impress/releases/v3.4.0
[v3.3.0]: https://github.com/numerique-gouv/impress/releases/v3.3.0
[v3.2.1]: https://github.com/numerique-gouv/impress/releases/v3.2.1
[v3.2.0]: https://github.com/numerique-gouv/impress/releases/v3.2.0
+4 -5
View File
@@ -7,8 +7,7 @@ FROM python:3.13.3-alpine AS base
RUN python -m pip install --upgrade pip setuptools
# Upgrade system packages to install security updates
RUN apk update && \
apk upgrade
RUN apk update && apk upgrade --no-cache
# ---- Back-end builder image ----
FROM base AS back-builder
@@ -45,7 +44,7 @@ FROM base AS link-collector
ARG IMPRESS_STATIC_ROOT=/data/static
# Install pango & rdfind
RUN apk add \
RUN apk add --no-cache \
pango \
rdfind
@@ -71,7 +70,7 @@ FROM base AS core
ENV PYTHONUNBUFFERED=1
# Install required system libs
RUN apk add \
RUN apk add --no-cache \
cairo \
file \
font-noto \
@@ -117,7 +116,7 @@ FROM core AS backend-development
USER root:root
# Install psql
RUN apk add postgresql-client
RUN apk add --no-cache postgresql-client
# Uninstall impress and re-install it in editable mode along with development
# dependencies
+24 -23
View File
@@ -948,33 +948,34 @@ class DocumentViewSet(
**link_kwargs,
)
# Always add the logged-in user as OWNER
accesses_to_create = [
models.DocumentAccess(
document=duplicated_document,
user=request.user,
role=models.RoleChoices.OWNER,
)
]
# If accesses should be duplicated, add other users' accesses as per original document
if with_accesses and is_owner_or_admin:
original_accesses = models.DocumentAccess.objects.filter(
document=document
).exclude(user=request.user)
accesses_to_create.extend(
# Always add the logged-in user as OWNER for root documents
if document.is_root():
accesses_to_create = [
models.DocumentAccess(
document=duplicated_document,
user_id=access.user_id,
team=access.team,
role=access.role,
user=request.user,
role=models.RoleChoices.OWNER,
)
for access in original_accesses
)
]
# Bulk create all the duplicated accesses
models.DocumentAccess.objects.bulk_create(accesses_to_create)
# If accesses should be duplicated, add other users' accesses as per original document
if with_accesses and is_owner_or_admin:
original_accesses = models.DocumentAccess.objects.filter(
document=document
).exclude(user=request.user)
accesses_to_create.extend(
models.DocumentAccess(
document=duplicated_document,
user_id=access.user_id,
team=access.team,
role=access.role,
)
for access in original_accesses
)
# Bulk create all the duplicated accesses
models.DocumentAccess.objects.bulk_create(accesses_to_create)
return drf_response.Response(
{"id": str(duplicated_document.id)}, status=status.HTTP_201_CREATED
+2 -1
View File
@@ -9,7 +9,8 @@ from core import enums
AI_ACTIONS = {
"prompt": (
"Answer the prompt in markdown format. "
"Answer the prompt using markdown formatting for structure and emphasis. "
"Return the content directly without wrapping it in code blocks or markdown delimiters. "
"Preserve the language and markdown formatting. "
"Do not provide any other information. "
"Preserve the language."
@@ -62,10 +62,14 @@ class CollaborationService:
except requests.RequestException as e:
raise requests.HTTPError("Failed to get document connection info.") from e
if response.status_code != 200:
raise requests.HTTPError(
f"Failed to get document connection info. Status code: {response.status_code}, "
f"Response: {response.text}"
)
result = response.json()
return result.get("count", 0), result.get("exists", False)
if response.status_code == 200:
result = response.json()
return result.get("count", 0), result.get("exists", False)
if response.status_code == 404:
return 0, False
raise requests.HTTPError(
f"Failed to get document connection info. Status code: {response.status_code}, "
f"Response: {response.text}"
)
@@ -175,8 +175,11 @@ def test_api_documents_ai_transform_authenticated_success(mock_create, reach, ro
{
"role": "system",
"content": (
"Answer the prompt in markdown format. Preserve the language and markdown "
"formatting. Do not provide any other information. Preserve the language."
"Answer the prompt using markdown formatting for structure and emphasis. "
"Return the content directly without wrapping it in code blocks or markdown delimiters. "
"Preserve the language and markdown formatting. "
"Do not provide any other information. "
"Preserve the language."
),
},
{"role": "user", "content": "Hello"},
@@ -249,8 +252,11 @@ def test_api_documents_ai_transform_success(mock_create, via, role, mock_user_te
{
"role": "system",
"content": (
"Answer the prompt in markdown format. Preserve the language and markdown "
"formatting. Do not provide any other information. Preserve the language."
"Answer the prompt using markdown formatting for structure and emphasis. "
"Return the content directly without wrapping it in code blocks or markdown delimiters. "
"Preserve the language and markdown formatting. "
"Do not provide any other information. "
"Preserve the language."
),
},
{"role": "user", "content": "Hello"},
@@ -48,7 +48,7 @@ def test_api_documents_ask_for_access_create_authenticated():
An email should be sent to document owners and admins to notify them.
"""
owner_user = UserFactory(language="en-us")
admin_user = UserFactory(language="fr-fr")
admin_user = UserFactory(language="en-us")
document = DocumentFactory(
users=[
(owner_user, RoleChoices.OWNER),
@@ -246,3 +246,73 @@ def test_api_documents_can_edit_websocket_server_unreachable_fallback_to_no_webs
assert cache.get(f"docs:no-websocket:{document.id}") == "other_session_key"
assert ws_resp.call_count == 1
@responses.activate
def test_api_documents_can_edit_websocket_server_room_not_found(
settings,
):
"""
When the websocket server returns a 404, the document can be updated like if the user was
not connected to the websocket.
"""
user = factories.UserFactory(with_owned_document=True)
client = APIClient()
client.force_login(user)
session_key = client.session.session_key
document = factories.DocumentFactory(users=[(user, "editor")])
settings.COLLABORATION_API_URL = "http://example.com/"
settings.COLLABORATION_SERVER_SECRET = "secret-token"
settings.COLLABORATION_WS_NOT_CONNECTED_READY_ONLY = True
endpoint_url = (
f"{settings.COLLABORATION_API_URL}get-connections/"
f"?room={document.id}&sessionKey={session_key}"
)
ws_resp = responses.get(endpoint_url, status=404)
assert cache.get(f"docs:no-websocket:{document.id}") is None
response = client.get(
f"/api/v1.0/documents/{document.id!s}/can-edit/",
)
assert response.status_code == 200
assert response.json() == {"can_edit": True}
assert ws_resp.call_count == 1
@responses.activate
def test_api_documents_can_edit_websocket_server_room_not_found_other_already_editing(
settings,
):
"""
When the websocket server returns a 404 and another user is editing the document,
the response should be can-edit=False.
"""
user = factories.UserFactory(with_owned_document=True)
client = APIClient()
client.force_login(user)
session_key = client.session.session_key
document = factories.DocumentFactory(users=[(user, "editor")])
settings.COLLABORATION_API_URL = "http://example.com/"
settings.COLLABORATION_SERVER_SECRET = "secret-token"
settings.COLLABORATION_WS_NOT_CONNECTED_READY_ONLY = True
endpoint_url = (
f"{settings.COLLABORATION_API_URL}get-connections/"
f"?room={document.id}&sessionKey={session_key}"
)
ws_resp = responses.get(endpoint_url, status=404)
cache.set(f"docs:no-websocket:{document.id}", "other_session_key")
response = client.get(
f"/api/v1.0/documents/{document.id!s}/can-edit/",
)
assert response.status_code == 200
assert response.json() == {"can_edit": False}
assert ws_resp.call_count == 1
@@ -252,3 +252,44 @@ def test_api_documents_duplicate_with_accesses_non_admin(role):
duplicated_accesses = duplicated_document.accesses
assert duplicated_accesses.count() == 1
assert duplicated_accesses.get(user=user).role == "owner"
@pytest.mark.parametrize("role", ["editor", "reader"])
def test_api_documents_duplicate_non_root_document(role):
"""
Non-root documents can be duplicated but without accesses.
"""
user = factories.UserFactory()
client = APIClient()
client.force_login(user)
document = factories.DocumentFactory(users=[(user, "owner")])
child = factories.DocumentFactory(
parent=document, users=[(user, role)], title="document with accesses"
)
assert child.accesses.count() == 1
# Duplicate the document via the API endpoint requesting to duplicate accesses
response = client.post(
f"/api/v1.0/documents/{child.id!s}/duplicate/",
{"with_accesses": True},
format="json",
)
assert response.status_code == 201
duplicated_document = models.Document.objects.get(id=response.json()["id"])
assert duplicated_document.title == "Copy of document with accesses"
assert duplicated_document.content == child.content
assert duplicated_document.link_reach == child.link_reach
assert duplicated_document.link_role == child.link_role
assert duplicated_document.creator == user
assert duplicated_document.duplicated_from == child
assert duplicated_document.attachments == []
# No access should be created for non root documents
duplicated_accesses = duplicated_document.accesses
assert duplicated_accesses.count() == 0
assert duplicated_document.is_sibling_of(child)
assert duplicated_document.is_child_of(document)
@@ -539,6 +539,47 @@ def test_api_documents_update_websocket_server_unreachable_fallback_to_no_websoc
assert ws_resp.call_count == 1
@responses.activate
def test_api_documents_update_websocket_server_room_not_found_fallback_to_no_websocket_other_users(
settings,
):
"""
When the WebSocket server does not have the room created, the logic should fallback to
no-WebSocket. If another user is already editing, the update must be denied.
"""
user = factories.UserFactory(with_owned_document=True)
client = APIClient()
client.force_login(user)
session_key = client.session.session_key
document = factories.DocumentFactory(users=[(user, "editor")])
new_document_values = serializers.DocumentSerializer(
instance=factories.DocumentFactory()
).data
new_document_values["websocket"] = False
settings.COLLABORATION_API_URL = "http://example.com/"
settings.COLLABORATION_SERVER_SECRET = "secret-token"
settings.COLLABORATION_WS_NOT_CONNECTED_READY_ONLY = True
endpoint_url = (
f"{settings.COLLABORATION_API_URL}get-connections/"
f"?room={document.id}&sessionKey={session_key}"
)
ws_resp = responses.get(endpoint_url, status=404)
cache.set(f"docs:no-websocket:{document.id}", "other_session_key")
response = client.put(
f"/api/v1.0/documents/{document.id!s}/",
new_document_values,
format="json",
)
assert response.status_code == 403
assert cache.get(f"docs:no-websocket:{document.id}") == "other_session_key"
assert ws_resp.call_count == 1
@responses.activate
def test_api_documents_update_force_websocket_param_to_true(settings):
"""
+60 -60
View File
@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: lasuite-docs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-08 15:21+0000\n"
"PO-Revision-Date: 2025-07-09 10:42\n"
"PO-Revision-Date: 2025-07-18 10:25\n"
"Last-Translator: \n"
"Language-Team: Breton\n"
"Language: br_FR\n"
@@ -79,7 +79,7 @@ msgstr "Lenner"
#: build/lib/core/choices.py:36 build/lib/core/choices.py:43 core/choices.py:36
#: core/choices.py:43
msgid "Editor"
msgstr ""
msgstr "Embanner"
#: build/lib/core/choices.py:44 core/choices.py:44
msgid "Administrator"
@@ -91,11 +91,11 @@ msgstr "Perc'henn"
#: build/lib/core/choices.py:56 core/choices.py:56
msgid "Restricted"
msgstr ""
msgstr "Strishaet"
#: build/lib/core/choices.py:60 core/choices.py:60
msgid "Authenticated"
msgstr ""
msgstr "Anavezet"
#: build/lib/core/choices.py:62 core/choices.py:62
msgid "Public"
@@ -111,11 +111,11 @@ msgstr "Bugel diwezhañ"
#: build/lib/core/enums.py:38 core/enums.py:38
msgid "First sibling"
msgstr ""
msgstr "Breur pe c'hoar kentañ"
#: build/lib/core/enums.py:39 core/enums.py:39
msgid "Last sibling"
msgstr ""
msgstr "Liamm diwezhañ"
#: build/lib/core/enums.py:40 core/enums.py:40
msgid "Left"
@@ -131,7 +131,7 @@ msgstr "id"
#: build/lib/core/models.py:80 core/models.py:80
msgid "primary key for the record as UUID"
msgstr ""
msgstr "alc'hwez kentañ evit an enrollañ evel UIID"
#: build/lib/core/models.py:86 core/models.py:86
msgid "created on"
@@ -139,7 +139,7 @@ msgstr "krouet d'ar/al"
#: build/lib/core/models.py:87 core/models.py:87
msgid "date and time at which a record was created"
msgstr ""
msgstr "deiziad hag eurvezh krouidigezh an enrolladenn"
#: build/lib/core/models.py:92 core/models.py:92
msgid "updated on"
@@ -147,23 +147,23 @@ msgstr "hizivaet d'ar/al"
#: build/lib/core/models.py:93 core/models.py:93
msgid "date and time at which a record was last updated"
msgstr ""
msgstr "deiziad hag eurvezh m'eo bet hizivaet an enrolladenn"
#: build/lib/core/models.py:129 core/models.py:129
msgid "We couldn't find a user with this sub but the email is already associated with a registered user."
msgstr ""
msgstr "N'hon eus kavet implijer ebet gant an isstrollad-mañ met ar postel a zo liammet ouzh un implijer enrollet."
#: build/lib/core/models.py:142 core/models.py:142
msgid "Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/_/: characters."
msgstr ""
msgstr "Ebarzhit un isstrollad mat. An talvoud-mañ a c'hall enderc'hel lizhiri, sifroù hag arouezioù @/./+/-/_/: hepken."
#: build/lib/core/models.py:148 core/models.py:148
msgid "sub"
msgstr ""
msgstr "isstrollad"
#: build/lib/core/models.py:150 core/models.py:150
msgid "Required. 255 characters or fewer. Letters, numbers, and @/./+/-/_/: characters only."
msgstr ""
msgstr "Rekis. 255 arouezenn pe nebeutoc'h. Lizhiri, sifroù hag arouezioù @/./+/-/_/: hepken."
#: build/lib/core/models.py:159 core/models.py:159
msgid "full name"
@@ -175,11 +175,11 @@ msgstr "anv berr"
#: build/lib/core/models.py:162 core/models.py:162
msgid "identity email address"
msgstr ""
msgstr "postel identelezh"
#: build/lib/core/models.py:167 core/models.py:167
msgid "admin email address"
msgstr ""
msgstr "postel ar merour"
#: build/lib/core/models.py:174 core/models.py:174
msgid "language"
@@ -187,11 +187,11 @@ msgstr "yezh"
#: build/lib/core/models.py:175 core/models.py:175
msgid "The language in which the user wants to see the interface."
msgstr ""
msgstr "Ar yezh en deus c'hoant da welet an implijer an etrefas enni."
#: build/lib/core/models.py:183 core/models.py:183
msgid "The timezone in which the user wants to see times."
msgstr ""
msgstr "Ar gwerzhid-eur en deus c'hoant da welet an implijer an eur drezañ."
#: build/lib/core/models.py:186 core/models.py:186
msgid "device"
@@ -199,23 +199,23 @@ msgstr "trevnad"
#: build/lib/core/models.py:188 core/models.py:188
msgid "Whether the user is a device or a real user."
msgstr ""
msgstr "Pe vefe an implijer un aparailh pe un implijer gwirion."
#: build/lib/core/models.py:191 core/models.py:191
msgid "staff status"
msgstr ""
msgstr "statud ar skipailh"
#: build/lib/core/models.py:193 core/models.py:193
msgid "Whether the user can log into this admin site."
msgstr ""
msgstr "Ma c'hall an implijer kevreañ ouzh al lec'hienn verañ-mañ."
#: build/lib/core/models.py:196 core/models.py:196
msgid "active"
msgstr ""
msgstr "oberiant"
#: build/lib/core/models.py:199 core/models.py:199
msgid "Whether this user should be treated as active. Unselect this instead of deleting accounts."
msgstr ""
msgstr "Ma rank bezañ tretet an implijer-mañ evel oberiant. Diziuzit an dra-mañ e-plas dilemel kontoù."
#: build/lib/core/models.py:211 core/models.py:211
msgid "user"
@@ -232,115 +232,115 @@ msgstr "titl"
#: build/lib/core/models.py:369 core/models.py:369
msgid "excerpt"
msgstr ""
msgstr "bomm"
#: build/lib/core/models.py:418 core/models.py:418
msgid "Document"
msgstr ""
msgstr "Teul"
#: build/lib/core/models.py:419 core/models.py:419
msgid "Documents"
msgstr ""
msgstr "Teulioù"
#: build/lib/core/models.py:431 build/lib/core/models.py:820 core/models.py:431
#: core/models.py:820
msgid "Untitled Document"
msgstr ""
msgstr "Teuliad hep titl"
#: build/lib/core/models.py:855 core/models.py:855
#, python-brace-format
msgid "{name} shared a document with you!"
msgstr ""
msgstr "{name} en deus rannet un teul ganeoc'h!"
#: build/lib/core/models.py:859 core/models.py:859
#, python-brace-format
msgid "{name} invited you with the role \"{role}\" on the following document:"
msgstr ""
msgstr "{name} en deus pedet ac'hanoc'h gant ar rol \"{role}\" war an teul da-heul:"
#: build/lib/core/models.py:865 core/models.py:865
#, python-brace-format
msgid "{name} shared a document with you: {title}"
msgstr ""
msgstr "{name} en deus rannet un teul ganeoc'h: {title}"
#: build/lib/core/models.py:964 core/models.py:964
msgid "Document/user link trace"
msgstr ""
msgstr "Roud liamm an teuliad/an implijer"
#: build/lib/core/models.py:965 core/models.py:965
msgid "Document/user link traces"
msgstr ""
msgstr "Roudoù liamm an teuliad/an implijer"
#: build/lib/core/models.py:971 core/models.py:971
msgid "A link trace already exists for this document/user."
msgstr ""
msgstr "Ur roud liamm a zo dija evit an teul/an implijer."
#: build/lib/core/models.py:994 core/models.py:994
msgid "Document favorite"
msgstr ""
msgstr "Teuliad muiañ-karet"
#: build/lib/core/models.py:995 core/models.py:995
msgid "Document favorites"
msgstr ""
msgstr "Teuliadoù muiañ-karet"
#: build/lib/core/models.py:1001 core/models.py:1001
msgid "This document is already targeted by a favorite relation instance for the same user."
msgstr ""
msgstr "An teul-mañ a zo un teul muiañ karet gant an implijer-mañ."
#: build/lib/core/models.py:1023 core/models.py:1023
msgid "Document/user relation"
msgstr ""
msgstr "Liamm teul/implijer"
#: build/lib/core/models.py:1024 core/models.py:1024
msgid "Document/user relations"
msgstr ""
msgstr "Liammoù teul/implijer"
#: build/lib/core/models.py:1030 core/models.py:1030
msgid "This user is already in this document."
msgstr ""
msgstr "An implijer-mañ a zo dija en teul-mañ."
#: build/lib/core/models.py:1036 core/models.py:1036
msgid "This team is already in this document."
msgstr ""
msgstr "Ar skipailh-mañ a zo dija en teul-mañ."
#: build/lib/core/models.py:1042 build/lib/core/models.py:1367
#: core/models.py:1042 core/models.py:1367
msgid "Either user or team must be set, not both."
msgstr ""
msgstr "An implijer pe ar skipailh a rank bezañ termenet, ket an daou avat."
#: build/lib/core/models.py:1188 core/models.py:1188
msgid "Document ask for access"
msgstr ""
msgstr "Goulenn tizhout an teul"
#: build/lib/core/models.py:1189 core/models.py:1189
msgid "Document ask for accesses"
msgstr ""
msgstr "Goulennoù tizhout an teul"
#: build/lib/core/models.py:1195 core/models.py:1195
msgid "This user has already asked for access to this document."
msgstr ""
msgstr "An implijer en deus goulennet tizhout an teul-mañ."
#: build/lib/core/models.py:1260 core/models.py:1260
#, python-brace-format
msgid "{name} would like access to a document!"
msgstr ""
msgstr "{name} en defe c'hoant da dizhout an teul-mañ!"
#: build/lib/core/models.py:1264 core/models.py:1264
#, python-brace-format
msgid "{name} would like access to the following document:"
msgstr ""
msgstr "{name} en defe c'hoant da dizhout an teul da-heul:"
#: build/lib/core/models.py:1270 core/models.py:1270
#, python-brace-format
msgid "{name} is asking for access to the document: {title}"
msgstr ""
msgstr "{name} en defe c'hoant da dizhout an teul: {title}"
#: build/lib/core/models.py:1282 core/models.py:1282
msgid "description"
msgstr ""
msgstr "deskrivadur"
#: build/lib/core/models.py:1283 core/models.py:1283
msgid "code"
msgstr ""
msgstr "kod"
#: build/lib/core/models.py:1284 core/models.py:1284
msgid "css"
@@ -352,7 +352,7 @@ msgstr "publik"
#: build/lib/core/models.py:1288 core/models.py:1288
msgid "Whether this template is public for anyone to use."
msgstr ""
msgstr "M'eo foran ar patrom-mañ hag implijus gant n'eus forzh piv."
#: build/lib/core/models.py:1294 core/models.py:1294
msgid "Template"
@@ -364,40 +364,40 @@ msgstr "Patromoù"
#: build/lib/core/models.py:1348 core/models.py:1348
msgid "Template/user relation"
msgstr ""
msgstr "Liamm patrom/implijer"
#: build/lib/core/models.py:1349 core/models.py:1349
msgid "Template/user relations"
msgstr ""
msgstr "Liammoù patrom/implijer"
#: build/lib/core/models.py:1355 core/models.py:1355
msgid "This user is already in this template."
msgstr ""
msgstr "An implijer-mañ a zo dija er patrom-mañ."
#: build/lib/core/models.py:1361 core/models.py:1361
msgid "This team is already in this template."
msgstr ""
msgstr "Ar skipailh-mañ a zo dija er patrom-mañ."
#: build/lib/core/models.py:1438 core/models.py:1438
msgid "email address"
msgstr ""
msgstr "postel"
#: build/lib/core/models.py:1457 core/models.py:1457
msgid "Document invitation"
msgstr ""
msgstr "Pedadenn d'un teul"
#: build/lib/core/models.py:1458 core/models.py:1458
msgid "Document invitations"
msgstr ""
msgstr "Pedadennoù d'un teul"
#: build/lib/core/models.py:1478 core/models.py:1478
msgid "This email is already associated to a registered user."
msgstr ""
msgstr "Ar postel-mañ a zo liammet ouzh un implijer enskrivet."
#: core/templates/mail/html/template.html:162
#: core/templates/mail/text/template.txt:3
msgid "Logo email"
msgstr ""
msgstr "Logo ar postel"
#: core/templates/mail/html/template.html:209
#: core/templates/mail/text/template.txt:10
@@ -407,11 +407,11 @@ msgstr "Digeriñ"
#: core/templates/mail/html/template.html:226
#: core/templates/mail/text/template.txt:14
msgid " Docs, your new essential tool for organizing, sharing and collaborating on your documents as a team. "
msgstr ""
msgstr " Docs, hoc'h ostilh nevez ret-holl evit aozañ, rannañ ha kenlabourat war an teulioù e skipailh. "
#: core/templates/mail/html/template.html:233
#: core/templates/mail/text/template.txt:16
#, python-format
msgid " Brought to you by %(brandname)s "
msgstr ""
msgstr " Kinniget gant %(brandname)s "
@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: lasuite-docs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-08 15:21+0000\n"
"PO-Revision-Date: 2025-07-09 10:42\n"
"PO-Revision-Date: 2025-07-18 10:25\n"
"Last-Translator: \n"
"Language-Team: German\n"
"Language: de_DE\n"
@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: lasuite-docs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-08 15:21+0000\n"
"PO-Revision-Date: 2025-07-09 10:42\n"
"PO-Revision-Date: 2025-07-18 10:25\n"
"Last-Translator: \n"
"Language-Team: English\n"
"Language: en_US\n"
@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: lasuite-docs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-08 15:21+0000\n"
"PO-Revision-Date: 2025-07-09 10:42\n"
"PO-Revision-Date: 2025-07-18 10:25\n"
"Last-Translator: \n"
"Language-Team: Spanish\n"
"Language: es_ES\n"
@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: lasuite-docs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-08 15:21+0000\n"
"PO-Revision-Date: 2025-07-09 11:52\n"
"PO-Revision-Date: 2025-07-18 10:25\n"
"Last-Translator: \n"
"Language-Team: French\n"
"Language: fr_FR\n"
@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: lasuite-docs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-08 15:21+0000\n"
"PO-Revision-Date: 2025-07-09 10:42\n"
"PO-Revision-Date: 2025-07-18 10:25\n"
"Last-Translator: \n"
"Language-Team: Italian\n"
"Language: it_IT\n"
@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: lasuite-docs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-08 15:21+0000\n"
"PO-Revision-Date: 2025-07-09 10:42\n"
"PO-Revision-Date: 2025-07-18 10:25\n"
"Last-Translator: \n"
"Language-Team: Dutch\n"
"Language: nl_NL\n"
+21 -21
View File
@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: lasuite-docs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-08 15:21+0000\n"
"PO-Revision-Date: 2025-07-09 10:42\n"
"PO-Revision-Date: 2025-07-18 10:25\n"
"Last-Translator: \n"
"Language-Team: Portuguese\n"
"Language: pt_PT\n"
@@ -19,87 +19,87 @@ msgstr ""
#: build/lib/core/admin.py:37 core/admin.py:37
msgid "Personal info"
msgstr ""
msgstr "Informações Pessoais"
#: build/lib/core/admin.py:50 build/lib/core/admin.py:138 core/admin.py:50
#: core/admin.py:138
msgid "Permissions"
msgstr ""
msgstr "Permissões"
#: build/lib/core/admin.py:62 core/admin.py:62
msgid "Important dates"
msgstr ""
msgstr "Datas importantes"
#: build/lib/core/admin.py:148 core/admin.py:148
msgid "Tree structure"
msgstr ""
msgstr "Estrutura de árvore"
#: build/lib/core/api/filters.py:47 core/api/filters.py:47
msgid "Title"
msgstr ""
msgstr "Título"
#: build/lib/core/api/filters.py:61 core/api/filters.py:61
msgid "Creator is me"
msgstr ""
msgstr "Eu sou o criador"
#: build/lib/core/api/filters.py:64 core/api/filters.py:64
msgid "Favorite"
msgstr ""
msgstr "Favorito"
#: build/lib/core/api/serializers.py:467 core/api/serializers.py:467
msgid "A new document was created on your behalf!"
msgstr ""
msgstr "Um novo documento foi criado em seu nome!"
#: build/lib/core/api/serializers.py:471 core/api/serializers.py:471
msgid "You have been granted ownership of a new document:"
msgstr ""
msgstr "A propriedade de um novo documento foi concedida a você:"
#: build/lib/core/api/serializers.py:608 core/api/serializers.py:608
msgid "Body"
msgstr ""
msgstr "Corpo"
#: build/lib/core/api/serializers.py:611 core/api/serializers.py:611
msgid "Body type"
msgstr ""
msgstr "Tipo de corpo"
#: build/lib/core/api/serializers.py:617 core/api/serializers.py:617
msgid "Format"
msgstr ""
msgstr "Formato"
#: build/lib/core/api/viewsets.py:943 core/api/viewsets.py:943
#, python-brace-format
msgid "copy of {title}"
msgstr ""
msgstr "cópia de {title}"
#: build/lib/core/choices.py:35 build/lib/core/choices.py:42 core/choices.py:35
#: core/choices.py:42
msgid "Reader"
msgstr ""
msgstr "Leitor"
#: build/lib/core/choices.py:36 build/lib/core/choices.py:43 core/choices.py:36
#: core/choices.py:43
msgid "Editor"
msgstr ""
msgstr "Editor"
#: build/lib/core/choices.py:44 core/choices.py:44
msgid "Administrator"
msgstr ""
msgstr "Administrador"
#: build/lib/core/choices.py:45 core/choices.py:45
msgid "Owner"
msgstr ""
msgstr "Dono"
#: build/lib/core/choices.py:56 core/choices.py:56
msgid "Restricted"
msgstr ""
msgstr "Restrito"
#: build/lib/core/choices.py:60 core/choices.py:60
msgid "Authenticated"
msgstr ""
msgstr "Autenticado"
#: build/lib/core/choices.py:62 core/choices.py:62
msgid "Public"
msgstr ""
msgstr "Público"
#: build/lib/core/enums.py:36 core/enums.py:36
msgid "First child"
@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: lasuite-docs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-08 15:21+0000\n"
"PO-Revision-Date: 2025-07-09 10:42\n"
"PO-Revision-Date: 2025-07-18 10:25\n"
"Last-Translator: \n"
"Language-Team: Slovenian\n"
"Language: sl_SI\n"
@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: lasuite-docs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-08 15:21+0000\n"
"PO-Revision-Date: 2025-07-09 10:42\n"
"PO-Revision-Date: 2025-07-18 10:25\n"
"Last-Translator: \n"
"Language-Team: Swedish\n"
"Language: sv_SE\n"
@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: lasuite-docs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-08 15:21+0000\n"
"PO-Revision-Date: 2025-07-09 10:42\n"
"PO-Revision-Date: 2025-07-18 10:25\n"
"Last-Translator: \n"
"Language-Team: Turkish\n"
"Language: tr_TR\n"
@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: lasuite-docs\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-08 15:21+0000\n"
"PO-Revision-Date: 2025-07-09 10:42\n"
"PO-Revision-Date: 2025-07-18 10:25\n"
"Last-Translator: \n"
"Language-Team: Chinese Simplified\n"
"Language: zh_CN\n"
+5 -5
View File
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "impress"
version = "3.3.0"
version = "3.4.2"
authors = [{ "name" = "DINUM", "email" = "dev@mail.numerique.gouv.fr" }]
classifiers = [
"Development Status :: 5 - Production/Stable",
@@ -26,7 +26,7 @@ readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"beautifulsoup4==4.13.4",
"boto3==1.39.3",
"boto3==1.39.4",
"Brotli==1.1.0",
"celery[redis]==5.5.3",
"django-configurations==2.5.1",
@@ -34,7 +34,7 @@ dependencies = [
"django-countries==7.6.1",
"django-csp==4.0",
"django-filter==25.1",
"django-lasuite[all]==0.0.10",
"django-lasuite[all]==0.0.11",
"django-parler==2.3",
"django-redis==6.0.0",
"django-storages[s3]==1.14.6",
@@ -52,9 +52,9 @@ dependencies = [
"markdown==3.8.2",
"mozilla-django-oidc==4.0.1",
"nested-multipart-parser==1.5.0",
"openai==1.93.0",
"openai==1.95.0",
"psycopg[binary]==3.2.9",
"pycrdt==0.12.23",
"pycrdt==0.12.25",
"PyJWT==2.10.1",
"python-magic==0.4.27",
"redis<6.0.0",
@@ -10,6 +10,7 @@ import {
overrideConfig,
verifyDocName,
} from './common';
import { createRootSubPage } from './sub-pages-utils';
test.beforeEach(async ({ page }) => {
await page.goto('/');
@@ -524,6 +525,8 @@ test.describe('Doc Editor', () => {
page,
browserName,
}) => {
test.slow();
/**
* The good port is 4444, but we want to simulate a not connected
* collaborative server.
@@ -536,7 +539,12 @@ test.describe('Doc Editor', () => {
await page.goto('/');
const [title] = await createDoc(page, 'editing-blocking', browserName, 1);
const [parentTitle] = await createDoc(
page,
'editing-blocking',
browserName,
1,
);
const card = page.getByLabel('It is the card information');
await expect(
@@ -571,12 +579,20 @@ test.describe('Doc Editor', () => {
// Close the modal
await page.getByRole('button', { name: 'close' }).first().click();
const urlParentDoc = page.url();
const { name: childTitle } = await createRootSubPage(
page,
browserName,
'editing-blocking - child',
);
let responseCanEdit = await responseCanEditPromise;
expect(responseCanEdit.ok()).toBeTruthy();
let jsonCanEdit = (await responseCanEdit.json()) as { can_edit: boolean };
expect(jsonCanEdit.can_edit).toBeTruthy();
const urlDoc = page.url();
const urlChildDoc = page.url();
/**
* We open another browser that will connect to the collaborative server
@@ -603,14 +619,14 @@ test.describe('Doc Editor', () => {
},
);
await otherPage.goto(urlDoc);
await otherPage.goto(urlChildDoc);
const webSocket = await webSocketPromise;
expect(webSocket.url()).toContain(
'ws://localhost:4444/collaboration/ws/?room=',
);
await verifyDocName(otherPage, title);
await verifyDocName(otherPage, childTitle);
await page.reload();
@@ -633,6 +649,10 @@ test.describe('Doc Editor', () => {
await expect(editor).toHaveAttribute('contenteditable', 'false');
await page.goto(urlParentDoc);
await verifyDocName(page, parentTitle);
await page.getByRole('button', { name: 'Share' }).click();
await page.getByLabel('Visibility mode').click();
@@ -641,18 +661,9 @@ test.describe('Doc Editor', () => {
// Close the modal
await page.getByRole('button', { name: 'close' }).first().click();
await page.reload();
await page.goto(urlChildDoc);
responseCanEditPromise = page.waitForResponse(
(response) =>
response.url().includes(`/can-edit/`) && response.status() === 200,
);
responseCanEdit = await responseCanEditPromise;
expect(responseCanEdit.ok()).toBeTruthy();
jsonCanEdit = (await responseCanEdit.json()) as { can_edit: boolean };
expect(jsonCanEdit.can_edit).toBeTruthy();
await expect(editor).toHaveAttribute('contenteditable', 'true');
await expect(
card.getByText('Others are editing. Your network prevent changes.'),
@@ -91,6 +91,22 @@ test.describe('Document grid item options', () => {
await page.goto('/');
});
test('it checks the share modal', async ({ page, browserName }) => {
const [docTitle] = await createDoc(page, `check share modal`, browserName);
await page.goto('/');
await expect(page.getByText(docTitle)).toBeVisible();
const row = await getGridRow(page, docTitle);
await row.getByText(`more_horiz`).click();
await page.getByRole('menuitem', { name: 'Share' }).click();
await expect(
page.getByRole('dialog').getByText('Share the document'),
).toBeVisible();
});
test('it pins a document', async ({ page, browserName }) => {
const [docTitle] = await createDoc(page, `Favorite doc`, browserName);
@@ -9,6 +9,7 @@ import {
mockedInvitations,
verifyDocName,
} from './common';
import { createRootSubPage } from './sub-pages-utils';
test.beforeEach(async ({ page }) => {
await page.goto('/');
@@ -456,6 +457,32 @@ test.describe('Doc Header', () => {
await page.getByText(duplicateDuplicateTitle).click();
await expect(page.getByText('Hello Duplicated World')).toBeVisible();
});
test('it duplicates a child document', async ({ page, browserName }) => {
await createDoc(page, `Duplicate doc`, browserName);
const { name: childTitle } = await createRootSubPage(
page,
browserName,
'Duplicate doc - child',
);
const editor = page.locator('.ProseMirror');
await editor.click();
await editor.fill('Hello Duplicated World');
await page.getByLabel('Open the document options').click();
await page.getByRole('menuitem', { name: 'Duplicate' }).click();
await expect(
page.getByText('Document duplicated successfully!'),
).toBeVisible();
const duplicateDuplicateTitle = 'Copy of ' + childTitle;
await expect(
page.getByTestId('doc-tree').getByText(duplicateDuplicateTitle),
).toBeVisible();
});
});
test.describe('Documents Header mobile', () => {
@@ -441,7 +441,7 @@ test.describe('Doc Visibility: Authenticated', () => {
const { name: childTitle } = await createRootSubPage(
page,
browserName,
'Authenticated read onlyc - child',
'Authenticated read only - child',
);
const urlChildDoc = page.url();
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "app-e2e",
"version": "3.3.0",
"version": "3.4.2",
"private": true,
"scripts": {
"lint": "eslint . --ext .ts",
@@ -12,7 +12,7 @@
"test:ui::chromium": "yarn test:ui --project=chromium"
},
"devDependencies": {
"@playwright/test": "1.53.2",
"@playwright/test": "1.54.1",
"@types/node": "*",
"@types/pdf-parse": "1.1.5",
"eslint-config-impress": "*",
+11 -11
View File
@@ -1,6 +1,6 @@
{
"name": "app-impress",
"version": "3.3.0",
"version": "3.4.2",
"private": true,
"scripts": {
"dev": "next dev",
@@ -32,27 +32,27 @@
"@hocuspocus/provider": "2.15.2",
"@openfun/cunningham-react": "3.1.0",
"@react-pdf/renderer": "4.3.0",
"@sentry/nextjs": "9.35.0",
"@tanstack/react-query": "5.81.5",
"@sentry/nextjs": "9.38.0",
"@tanstack/react-query": "5.83.0",
"canvg": "4.0.3",
"clsx": "2.1.1",
"cmdk": "1.1.1",
"crisp-sdk-web": "1.0.25",
"docx": "9.5.0",
"emoji-mart": "5.6.0",
"i18next": "25.3.1",
"i18next": "25.3.2",
"i18next-browser-languagedetector": "8.2.0",
"idb": "8.0.3",
"lodash": "4.17.21",
"luxon": "3.6.1",
"next": "15.3.5",
"posthog-js": "1.256.2",
"luxon": "3.7.1",
"next": "15.4.1",
"posthog-js": "1.257.0",
"react": "*",
"react-aria-components": "1.10.1",
"react-dom": "*",
"react-i18next": "15.6.0",
"react-intersection-observer": "9.16.0",
"react-select": "5.10.1",
"react-select": "5.10.2",
"styled-components": "6.1.19",
"use-debounce": "10.0.5",
"y-protocols": "1.0.6",
@@ -61,7 +61,7 @@
},
"devDependencies": {
"@svgr/webpack": "8.1.0",
"@tanstack/react-query-devtools": "5.81.5",
"@tanstack/react-query-devtools": "5.83.0",
"@testing-library/dom": "10.4.0",
"@testing-library/jest-dom": "6.6.3",
"@testing-library/react": "16.3.0",
@@ -73,7 +73,7 @@
"@types/react": "*",
"@types/react-dom": "*",
"cross-env": "7.0.3",
"dotenv": "17.1.0",
"dotenv": "17.2.0",
"eslint-config-impress": "*",
"fetch-mock": "9.11.0",
"jest": "30.0.4",
@@ -84,7 +84,7 @@
"stylelint-config-standard": "38.0.0",
"stylelint-prettier": "5.0.3",
"typescript": "*",
"webpack": "5.99.9",
"webpack": "5.100.1",
"workbox-webpack-plugin": "7.1.0"
}
}
@@ -7,6 +7,7 @@ import * as Y from 'yjs';
import { APIError, errorCauses, fetchAPI } from '@/api';
import { toBase64 } from '@/docs/doc-editor';
import { KEY_DOC_TREE } from '@/docs/doc-tree';
import { KEY_LIST_DOC_VERSIONS } from '@/docs/doc-versioning';
import { useProviderStore } from '../stores';
@@ -85,6 +86,9 @@ export function useDuplicateDoc(options: DuplicateDocOptions) {
void queryClient.resetQueries({
queryKey: [KEY_LIST_DOC],
});
void queryClient.resetQueries({
queryKey: [KEY_DOC_TREE],
});
void options.onSuccess?.(data, variables, context);
},
});
@@ -5,15 +5,20 @@ import { useIsOffline } from '@/features/service-worker';
import { KEY_CAN_EDIT, useDocCanEdit } from '../api/useDocCanEdit';
import { useProviderStore } from '../stores';
import { Doc, LinkReach } from '../types';
import { Doc, LinkReach, LinkRole } from '../types';
export const useIsCollaborativeEditable = (doc: Doc) => {
const { isConnected } = useProviderStore();
const { data: conf } = useConfig();
const docIsPublic = doc.link_reach === LinkReach.PUBLIC;
const docIsAuth = doc.link_reach === LinkReach.AUTHENTICATED;
const docHasMember = doc.nb_accesses_direct > 1;
const docIsPublic =
doc.computed_link_reach === LinkReach.PUBLIC &&
doc.computed_link_role === LinkRole.EDITOR;
const docIsAuth =
doc.computed_link_reach === LinkReach.AUTHENTICATED &&
doc.computed_link_role === LinkRole.EDITOR;
const docHasMember =
doc.nb_accesses_direct > 1 || doc.nb_accesses_ancestors > 1;
const isUserReader = !doc.abilities.partial_update;
const isShared = docIsPublic || docIsAuth || docHasMember;
const { isOffline } = useIsOffline();
@@ -21,23 +26,23 @@ export const useIsCollaborativeEditable = (doc: Doc) => {
const [isEditable, setIsEditable] = useState(true);
const [isLoading, setIsLoading] = useState(!_isEditable);
const timeout = useRef<NodeJS.Timeout | null>(null);
const {
data: { can_edit } = { can_edit: _isEditable },
isLoading: isLoadingCanEdit,
} = useDocCanEdit(doc.id, {
enabled: !_isEditable,
queryKey: [KEY_CAN_EDIT, doc.id],
staleTime: 0,
});
const { data: editingRight, isLoading: isLoadingCanEdit } = useDocCanEdit(
doc.id,
{
enabled: !_isEditable,
queryKey: [KEY_CAN_EDIT, doc.id],
staleTime: 0,
},
);
useEffect(() => {
if (isLoadingCanEdit) {
if (isLoadingCanEdit || _isEditable || !editingRight) {
return;
}
// Connection to the WebSocket can take some time, so we set a timeout to ensure the loading state is cleared after a reasonable time.
timeout.current = setTimeout(() => {
setIsEditable(can_edit);
setIsEditable(editingRight.can_edit);
setIsLoading(false);
}, 1500);
@@ -46,7 +51,7 @@ export const useIsCollaborativeEditable = (doc: Doc) => {
clearTimeout(timeout.current);
}
};
}, [can_edit, isLoadingCanEdit]);
}, [editingRight, isLoadingCanEdit, _isEditable]);
useEffect(() => {
if (!_isEditable) {
@@ -59,7 +64,7 @@ export const useIsCollaborativeEditable = (doc: Doc) => {
setIsEditable(true);
setIsLoading(false);
}, [_isEditable, isLoading]);
}, [_isEditable]);
if (!conf?.COLLABORATION_WS_NOT_CONNECTED_READY_ONLY) {
return {
@@ -1,3 +1,4 @@
export * from './useCreateChildren';
export * from './useDocChildren';
export * from './useDocTree';
export * from './useMove';
@@ -25,7 +25,7 @@ export const getDocTree = async ({ docId }: DocsTreeParams): Promise<Doc> => {
return response.json() as Promise<Doc>;
};
export const KEY_LIST_DOC_CHILDREN = 'doc-tree';
export const KEY_DOC_TREE = 'doc-tree';
export function useDocTree(
params: DocsTreeParams,
@@ -35,7 +35,7 @@ export function useDocTree(
>,
) {
return useQuery<Doc, APIError, Doc>({
queryKey: [KEY_LIST_DOC_CHILDREN, params],
queryKey: [KEY_DOC_TREE, params],
queryFn: () => getDocTree(params),
staleTime: 0,
refetchOnWindowFocus: false,
@@ -18,7 +18,7 @@ import {
import { useLeftPanelStore } from '@/features/left-panel';
import { useResponsiveStore } from '@/stores';
import Logo from './../assets/sub-page-logo.svg';
import SubPageIcon from './../assets/sub-page-logo.svg';
import { DocTreeItemActions } from './DocTreeItemActions';
const ItemTextCss = css`
@@ -99,6 +99,7 @@ export const DocSubPageItem = (props: Props) => {
return (
<Box
className="--docs-sub-page-item"
$position="relative"
$css={css`
background-color: ${actionsOpen
? 'var(--c--theme--colors--greyscale-100)'
@@ -106,6 +107,17 @@ export const DocSubPageItem = (props: Props) => {
.light-doc-item-actions {
display: ${actionsOpen || !isDesktop ? 'flex' : 'none'};
position: absolute;
right: 0;
background: ${isDesktop
? 'var(--c--theme--colors--greyscale-100)'
: 'var(--c--theme--colors--greyscale-000)'};
}
.c__tree-view--node.isSelected {
.light-doc-item-actions {
background: var(--c--theme--colors--greyscale-100);
}
}
&:hover {
@@ -114,6 +126,7 @@ export const DocSubPageItem = (props: Props) => {
.light-doc-item-actions {
display: flex;
background: var(--c--theme--colors--greyscale-100);
}
}
`}
@@ -136,7 +149,7 @@ export const DocSubPageItem = (props: Props) => {
$minHeight="24px"
>
<Box $width="16px" $height="16px">
<Logo />
<SubPageIcon />
</Box>
<Box
@@ -136,6 +136,10 @@ export const DocTree = ({ initialTargetId }: DocTreeProps) => {
.c__tree-view--container {
z-index: 1;
margin-top: -10px;
.c__tree-view {
overflow: hidden !important;
}
}
`}
>
@@ -1,3 +1,4 @@
import { TreeProvider } from '@gouvfr-lasuite/ui-kit';
import { Tooltip, useModal } from '@openfun/cunningham-react';
import { DateTime } from 'luxon';
import { useTranslation } from 'react-i18next';
@@ -143,7 +144,9 @@ export const DocsGridItem = ({ doc, dragMode = false }: DocsGridItemProps) => {
</Box>
</Box>
{shareModal.isOpen && (
<DocShareModal doc={doc} onClose={shareModal.close} />
<TreeProvider initialNodeId={doc.id}>
<DocShareModal doc={doc} onClose={shareModal.close} />
</TreeProvider>
)}
</>
);
@@ -1,40 +1,130 @@
{
"br": {
"translation": {
"AI Actions": "Obererezh AI",
"AI seems busy! Please try again.": "IA a seblant bezañ ac'hubet. Klaskit adarre, mar plij.",
"Accessible to anyone": "Aes da gaout evit an holl",
"Add": "Ouzhpennañ",
"Add a callout block": "Ouzhpennañ ur bloc'had kemenn-son",
"Add a horizontal line": "Ouzhpennañ ul linenn a-blaen",
"Administrator": "Merour",
"All docs": "An holl restroù",
"Analyzing file...": "Oc'h analizañ ar restr...",
"Anonymous": "Dianav",
"Approve": "Aprouiñ",
"Available soon": "Hegerz a-benn nebeut",
"Beautify": "Bravaat",
"Callout": "Kemenn-son",
"Cancel": "Nullañ",
"Close the modal": "Serriñ ar modal",
"Collaborate": "Kenlabourat",
"Confirm": "Kadarnaat",
"Confirm deletion": "Kadarnaat an dilamadenn",
"Confirmation button": "Bouton kadarnaat",
"Connected": "Kevreet",
"Copy as {{format}}": "Eilañ evel {{format}}",
"Copy link": "Eilañ al liamm",
"Correct": "Reizhañ",
"Current doc": "Teul red",
"Delete": "Dilemel",
"Delete a doc": "Dilemel un doc",
"Delete document": "Dilemel an teul",
"Divider": "Skejer",
"Docs": "Docs",
"Docs Logo": "Logo Docs",
"Docx": "Docx",
"Download": "Pellgargañ",
"Download anyway": "Pellgargañ memestra",
"Duplicate": "Eilañ",
"Editing": "Oc'h aozañ",
"Editor": "Embanner",
"Emojify": "Emojifiañ",
"Empty template": "Patrom ebet",
"Export": "Ezporzhiañ",
"Failed to copy link": "Eilañ al liamm c'hwitet",
"Format": "Stumm",
"Govs ❤️ Open Source.": "Gouarnamantoù ❤️ ar c'hod mammenn digor.",
"History": "Roll-istor",
"Home": "Degemer",
"I understand": "Kompren a ran",
"Illustration": "Skeudenn",
"Image 401": "Skeudenn 401",
"Image 403": "Skeudenn 403",
"Invite": "Pediñ",
"It is the document title": "Titl an teul eo",
"Language": "Yezh",
"Last update: {{update}}": "Hizivadur diwezhañ: {{update}}",
"Learn more": "Gouzout hiroc'h",
"Link Copied !": "Liamm eilet!",
"Link parameters": "Arventennoù al liamm",
"List members card": "Listennad kartennoù an izili",
"Load more": "Kargañ muioc'h",
"Login": "Kevreañ",
"Logo": "Logo",
"Logout": "Digevreañ",
"More docs": "Restroù ouzhpenn",
"Move": "Fiñval",
"Move document": "Fiñval an teul",
"Move to my docs": "Fiñval davet ma zeulioù",
"My docs": "Ma restroù",
"Name": "Anv",
"New doc": "Restr nevez",
"No document found": "Teul ebet kavet",
"No documents found": "Teul ebet kavet",
"No text selected": "Testenn ebet diuzet",
"No versions": "Stumm ebet",
"OK": "Mat eo",
"Offline ?!": "Ezlinenn?!",
"Only invited people can access": "An dud pedet hepken a c'hall haeziñ",
"Open Source": "Kod mammenn digor",
"Open the document options": "Digeriñ dibarzhioù an teul",
"Organize": "Aozañ",
"Owner": "Perc'henn",
"PDF": "PDF",
"Page Not Found - Error 404": "N'eo ket bet kavet ar bajenn - Fazi 404",
"Pin": "Spilhennañ",
"Pin document icon": "Ikon spilhennañ un teuliad",
"Private": "Prevez",
"Proconnect Login": "Kevreañ Proconnect",
"Public": "Publik",
"Public document": "Teul publik",
"Quick search input": "Bizskrivañ an enklask buan",
"Reader": "Lenner",
"Reading": "Lenn hepken",
"Remove": "Dilemel",
"Rename": "Adenvel",
"Rephrase": "Adformulenniñ",
"Reset": "Adderaouiñ",
"Restore": "Assevel",
"Search": "Klask",
"Search modal": "Modal rannañ",
"Select a document": "Diuzañ un teul",
"Select a page": "Diuzañ ur bajenn",
"Share": "Rannañ",
"Share modal": "Modal rannañ",
"Share the document": "Rannañ an teul",
"Share with {{count}} users_other": "Rannet etre {{count}} implijer",
"Shared with me": "Rannet ganin",
"Show more": "Diskouez muioc'h",
"Simple document icon": "Ikon teuliad eeun",
"Something bad happens, please retry.": "Un dra bennak a zo c'hoarvezet, klaskit en-dro.",
"Start Writing": "Stagañ da skrivañ",
"Summarize": "Diverrañ",
"Summary": "Taolenn",
"Template": "Patrom",
"The export failed": "Ezporzhiañ c'hwitet",
"Too many requests. Please wait 60 seconds.": "Re a c'houlennoù. Gortozit 60 eilenn mar plij.",
"Type a name or email": "Skrivit hoc'h anv pe ur postel",
"Unnamed document": "Teul hep titl",
"Unpin": "Dispilhennañ",
"Updated at": "Hizivaet d'ar/al",
"Use as prompt": "Implijout evel ur prompt",
"Version history": "Roll-istor ar stummoù",
"Warning": "Diwallit"
"Version restored successfully": "Stumm assavet gant berzh",
"Visibility": "Gwelusted",
"Visibility mode": "Mod gwelusted",
"Warning": "Diwallit",
"Write": "Skrivañ"
}
},
"de": {
@@ -44,6 +134,8 @@
"A new way to organize knowledge.": "Wissen organisieren: mal ganz anders.",
"AI Actions": "KI-Aktionen",
"AI seems busy! Please try again.": "KI scheint beschäftigt! Bitte versuchen Sie es erneut.",
"Access Denied - Error 403": "Zugriff verweigert - Fehler 403",
"Access Requests": "Zugriffsanfragen",
"Accessible to anyone": "Für alle zugänglich",
"Accessible to authenticated users": "Für authentifizierte Benutzer zugänglich",
"Add": "Hinzufügen",
@@ -51,22 +143,26 @@
"Administrator": "Administrator",
"All docs": "Alle Dokumente",
"An uncompromising writing experience.": "Ein kompromissloses Schreiberlebnis.",
"Analyzing file...": "Analysiere Datei...",
"Anonymous": "Gast",
"Anyone with the link can edit the document": "Jeder mit dem Link kann das Dokument bearbeiten",
"Anyone with the link can edit the document if they are logged in": "Jeder mit dem Link kann das Dokument bearbeiten, wenn er angemeldet ist",
"Anyone with the link can see the document": "Jeder mit dem Link kann das Dokument ansehen",
"Anyone with the link can view the document if they are logged in": "Jeder mit dem Link kann das Dokument ansehen, wenn er angemeldet ist",
"Approve": "Freigeben",
"Available soon": "Bald verfügbar",
"Banner image": "Bannerbild",
"Beautify": "Verschönern",
"Can't load this page, please check your internet connection.": "Diese Seite kann nicht geladen werden. Bitte überprüfen Sie Ihre Internetverbindung.",
"Cancel": "Abbrechen",
"Close the modal": "Pop up schliessen",
"Close the modal": "Pop-up schließen",
"Collaborate": "Zusammenarbeiten",
"Collaborate and write in real time, without layout constraints.": "In Echtzeit und ohne Layout-Beschränkungen schreiben und zusammenarbeiten.",
"Collaborative writing, Simplified.": "Kollaboratives Schreiben, vereinfacht.",
"Confirm": "Bestätigen",
"Confirm deletion": "Löschung bestätigen",
"Connected": "Verbunden",
"Confirmation button": "Bestätigungsbutton",
"Connected": "Angemeldet",
"Content modal to delete document": "Inhalts-Modal zum Löschen des Dokuments",
"Content modal to export the document": "Inhalte zum Exportieren des Dokuments",
"Convert Markdown": "Markdown konvertieren",
@@ -74,6 +170,7 @@
"Copy as {{format}}": "Als {{format}} kopieren",
"Copy link": "Link kopieren",
"Correct": "Korrigieren",
"Current doc": "Aktuelles Dokument",
"Delete": "Löschen",
"Delete a doc": "Dokument löschen",
"Delete document": "Dokument löschen",
@@ -86,38 +183,47 @@
"Docs offers an intuitive writing experience. Its minimalist interface favors content over layout, while offering the essentials: media import, offline mode and keyboard shortcuts for greater efficiency.": "Docs bietet ein intuitives Schreiberlebnis. Seine minimalistische Oberfläche bevorzugt Inhalte über Layout, bietet aber das Wesentliche: Medien-Import, Offline-Modus und Tastaturkürzel für mehr Effizienz.",
"Docs transforms your documents into knowledge bases thanks to subpages, powerful search and the ability to pin your important documents.": "Dank Unterseiten, leistungsstarker Suche und der Möglichkeit, wichtige Dokumente zu fixieren, verwandelt Docs Ihre Dokumente in Wissensdatenbanken.",
"Docs: Your new companion to collaborate on documents efficiently, intuitively, and securely.": "Pages: Ihr neuer Begleiter für eine effiziente, intuitive und sichere Zusammenarbeit bei Dokumenten.",
"Document accessible to any connected person": "Dokument für jeden verbundenen Benutzer zugänglich",
"Document accessible to any connected person": "Dokument für jeden angemeldeten Benutzer zugänglich",
"Document duplicated successfully!": "Dokument erfolgreich dupliziert!",
"Document owner": "Besitzer des Dokuments",
"Docx": "Docx",
"Download": "Herunterladen",
"Download anyway": "Trotzdem herunterladen",
"Download your document in a .docx or .pdf format.": "Ihr Dokument als .docx- oder .pdf-Datei herunterladen.",
"Editor": "Editor",
"Duplicate": "Duplizieren",
"Editing": "Bearbeiten",
"Editor": "Mitbearbeiter",
"Editor unavailable": "Editor nicht verfügbar",
"Emojify": "Emojifizieren",
"Empty template": "Leere Vorlage",
"Error during delete invitation": "Fehler beim Löschen der Einladung",
"Error during update invitation": "Fehler beim Aktualisieren der Einladung",
"Error while deleting invitation": "Fehler beim Löschen der Einladung",
"Error while removing the request.": "Fehler beim Zurückziehen der Anfrage.",
"Export": "Exportieren",
"Failed to add the member in the document.": "Fehler beim Hinzufügen des Mitglieds zum Dokument.",
"Failed to copy link": "Link konnte nicht kopiert werden",
"Failed to copy to clipboard": "Fehler beim Kopieren in die Zwischenablage",
"Failed to create the invitation for {{email}}.": "Fehler beim Erstellen der Einladung für {{email}}.",
"Failed to duplicate the document...": "Fehler beim Duplizieren des Dokuments...",
"Flexible export.": "Flexibler Export.",
"Format": "Format",
"Govs ❤️ Open Source.": "Regierungen ❤️ Open Source.",
"History": "Versionsverlauf",
"Home": "Start",
"I understand": "Verstanden",
"If a member is editing, his works can be lost.": "Wenn ein Mitglied editiert, können seine Änderungen verloren gehen.",
"Illustration": "Abbildung",
"Image 401": "Bild 401",
"Image 403": "Bild 403",
"Insufficient access rights to view the document.": "Unzureichende Zugriffsrechte zur Ansicht des Dokuments.",
"Invite": "Einladen",
"It is the card information about the document.": "Es handelt sich um die Karteninformationen zum Dokument.",
"It is the document title": "Es ist der Titel des Dokuments",
"It seems that the page you are looking for does not exist or cannot be displayed correctly.": "Es scheint, dass die von Ihnen gesuchte Seite nicht existiert oder nicht korrekt angezeigt werden kann.",
"Language": "Sprache",
"Last update: {{update}}": "Zuletzt aktualisiert: {{update}}",
"Learn more": "Mehr erfahren",
"Link Copied !": "Link kopiert!",
"Link parameters": "Link-Parameter",
"List invitation card": "Einladungsliste anzeigen",
@@ -129,6 +235,9 @@
"Modal confirmation to download the attachment": "Modale Bestätigung zum Herunterladen des Anhangs",
"Modal confirmation to restore the version": "Modale Bestätigung um die Version wiederherzustellen",
"More docs": "Weitere Dokumente",
"Move": "Verschieben",
"Move document": "Dokument verschieben",
"Move to my docs": "In \"Meine Dokumente\" verschieben",
"My docs": "Meine Dokumente",
"Name": "Name",
"New doc": "Neues Dokument",
@@ -144,9 +253,12 @@
"Open the document options": "Öffnen Sie die Dokumentoptionen",
"Open the header menu": "Öffne das Kopfzeilen-Menü",
"Organize": "Organisieren",
"Others are editing. Your network prevent changes.": "Ihre Änderung konnte nicht übernommen werden, da andere Benutzer diesen Bereich zurzeit bearbeiten.",
"Owner": "Besitzer",
"PDF": "PDF",
"Page Not Found - Error 404": "Seite nicht gefunden - Fehler 404",
"Pending invitations": "Ausstehende Einladungen",
"People with access via the parent document": "Benutzer, die den Zugriff von einem übergeordneten Dokument erben",
"Pin": "Anheften",
"Pin document icon": "Pinne das Dokumentenlogo an",
"Pinned documents": "Angepinnte Dokumente",
@@ -159,13 +271,17 @@
"Reader": "Leser",
"Reading": "Lesen",
"Remove": "Löschen",
"Remove access": "Zugriff entziehen",
"Rename": "Umbenennen",
"Rephrase": "Umformulieren",
"Request access": "Zugriff anfragen",
"Reset": "Zurücksetzen",
"Restore": "Wiederherstellen",
"Search": "Suchen",
"Search modal": "Suche Modal",
"Search user result": "Suchergebnis",
"Select a document": "Dokument auswählen",
"Select a page": "Seite wählen",
"Select a version on the right to restore": "Wählen Sie rechts eine Version zum Wiederherstellen aus",
"Share": "Teilen",
"Share modal": "Teilen-Modal",
@@ -185,14 +301,18 @@
"Summarize": "Zusammenfassen",
"Summary": "Zusammenfassung",
"Template": "Vorlage",
"The antivirus has detected an anomaly in your file.": "Das Antivirus hat eine Anomalie in Ihrer Datei festgestellt.",
"The document has been deleted.": "Das Dokument wurde gelöscht.",
"The document visibility has been updated.": "Die Sichtbarkeit des Dokuments wurde aktualisiert.",
"The export failed": "Export fehlgeschlagen",
"This document and <strong>any sub-documents</strong> will be permanently deleted. This action is irreversible.": "Dieses Dokument und <strong>alle Unterdokumente</strong> werden unwiderruflich gelöscht.",
"This file is flagged as unsafe.": "Diese Datei wurde als unsicher markiert.",
"This user has access inherited from a parent page.": "Dieser Benutzer erbt den Zugriff von einem übergeordneten Dokument.",
"To facilitate the circulation of documents, Docs allows you to export your content to the most common formats: PDF, Word or OpenDocument.": "Docs erleichtert die Verbreitung von Dokumenten, da es den Export in die gängigsten Formate unterstützt: PDF, Word und OpenDocument.",
"Too many requests. Please wait 60 seconds.": "Zu viele Anfragen. Bitte warten Sie 60 Sekunden.",
"Type a name or email": "Geben Sie einen Namen oder eine E-Mail-Adresse ein",
"Type the name of a document": "Geben Sie den Namen eines Dokuments ein",
"Unnamed document": "Unbenanntes Dokument",
"Unpin": "Lösen",
"Untitled document": "Unbenanntes Dokument",
"Updated at": "Aktualisiert am",
@@ -202,8 +322,12 @@
"Visibility": "Sichtbarkeit",
"Visibility mode": "Sichtbarkeitseinstellungen",
"Warning": "Warnung",
"Why you can't edit the document?": "Warum können Sie dieses Dokument nicht bearbeiten?",
"Write": "Schreiben",
"You are the sole owner of this group, make another member the group owner before you can change your own role or be removed from your document.": "Sie sind der einzige Besitzer dieser Gruppe. Machen Sie ein anderes Mitglied zum Gruppenbesitzer, bevor Sie Ihre eigene Rolle ändern oder aus Ihrem Dokument entfernen können.",
"You must be at least the editor of the target document": "Sie müssen dafür mindestens die Rolle \"Mitbearbeiter\" haben",
"You must be the owner to move the document": "Sie müssen Besitzer des Dokuments sein, um es zu verschieben",
"Your access request for this document is pending.": "Ihre Zugriffsanfrage für dieses Dokument steht noch aus.",
"Your current document will revert to this version.": "Ihr aktuelles Dokument wird auf diese Version zurückgesetzt.",
"Your {{format}} was downloaded succesfully": "Ihr {{format}} wurde erfolgreich heruntergeladen",
"home-content-open-source-part1": "Doms ist auf <2>Django Rest Framework</2> und <6>Next.js</6> aufgebaut. Wir verwenden auch <9>Yjs</9> und <13>BlockNote.js</13>, zwei Projekte, die wir mit Stolz sponsern.",
@@ -591,7 +715,7 @@
"The document has been deleted.": "Le document a bien été supprimé.",
"The document visibility has been updated.": "La visibilité du document a été mise à jour.",
"The export failed": "Lexportation a échoué",
"This document and <1>any sub-documents</1> will be permanently deleted. This action is irreversible.": "Ce document et <1>tous les sous-documents</1> seront définitivement supprimés. Cette action est irréversible.",
"This document and <strong>any sub-documents</strong> will be permanently deleted. This action is irreversible.": "Ce document et <strong>tous les sous-documents</strong> seront définitivement supprimés. Cette action est irréversible.",
"This file is flagged as unsafe.": "Ce fichier est marqué comme non sûr.",
"This means you can't edit until others leave.": "Cela signifie que vous ne pouvez pas éditer tant que d'autres éditeurs sont présents sur le document.",
"This user has access inherited from a parent page.": "Cet utilisateur a un accès hérité d'une page parente.",
+4 -4
View File
@@ -1,6 +1,6 @@
{
"name": "impress",
"version": "3.3.0",
"version": "3.4.2",
"private": true,
"workspaces": {
"packages": [
@@ -28,11 +28,11 @@
"server:test": "yarn COLLABORATION_SERVER run test"
},
"resolutions": {
"@types/node": "22.16.0",
"@types/node": "22.16.3",
"@types/react": "19.1.8",
"@types/react-dom": "19.1.6",
"@typescript-eslint/eslint-plugin": "8.36.0",
"@typescript-eslint/parser": "8.36.0",
"@typescript-eslint/eslint-plugin": "8.37.0",
"@typescript-eslint/parser": "8.37.0",
"eslint": "8.57.0",
"react": "19.1.0",
"react-dom": "19.1.0",
@@ -1,24 +1,24 @@
{
"name": "eslint-config-impress",
"version": "3.3.0",
"version": "3.4.2",
"license": "MIT",
"scripts": {
"lint": "eslint --ext .js ."
},
"dependencies": {
"@next/eslint-plugin-next": "15.3.5",
"@next/eslint-plugin-next": "15.4.1",
"@tanstack/eslint-plugin-query": "5.81.2",
"@typescript-eslint/eslint-plugin": "*",
"@typescript-eslint/parser": "*",
"eslint": "*",
"eslint-config-next": "15.3.5",
"eslint-config-next": "15.4.1",
"eslint-config-prettier": "10.1.5",
"eslint-plugin-import": "2.32.0",
"eslint-plugin-jest": "29.0.1",
"eslint-plugin-jsx-a11y": "6.10.2",
"eslint-plugin-playwright": "2.2.0",
"eslint-plugin-prettier": "5.5.1",
"eslint-plugin-testing-library": "7.5.3",
"eslint-plugin-testing-library": "7.6.0",
"prettier": "3.6.2"
}
}
@@ -7,6 +7,16 @@ const config = {
keySeparator: false,
nsSeparator: false,
namespaceSeparator: false,
lexers: {
tsx: [
{
lexer: 'JsxLexer',
functions: ['t'],
transSupportBasicHtmlNodes: true, // Disable automatic conversion
transKeepBasicHtmlNodesFor: ['strong', 'b', 'i', 'code', 'br'],
},
],
},
};
export default config;
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "packages-i18n",
"version": "3.3.0",
"version": "3.4.2",
"private": true,
"scripts": {
"extract-translation": "yarn extract-translation:impress",
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "server-y-provider",
"version": "3.3.0",
"version": "3.4.2",
"description": "Y.js provider for docs",
"repository": "https://github.com/numerique-gouv/impress",
"license": "MIT",
@@ -18,8 +18,8 @@
"dependencies": {
"@blocknote/server-util": "0.33.0",
"@hocuspocus/server": "2.15.2",
"@sentry/node": "9.35.0",
"@sentry/profiling-node": "9.35.0",
"@sentry/node": "9.38.0",
"@sentry/profiling-node": "9.38.0",
"axios": "1.10.0",
"cors": "2.8.5",
"express": "5.1.0",
+435 -403
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,7 +1,7 @@
environments:
dev:
values:
- version: 3.3.0
- version: 3.4.2
---
repositories:
- name: bitnami
+1 -1
View File
@@ -1,5 +1,5 @@
apiVersion: v2
type: application
name: docs
version: 3.4.0-beta.2
version: 3.4.2
appVersion: latest
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "mail_mjml",
"version": "3.3.0",
"version": "3.4.2",
"description": "An util to generate html and text django's templates from mjml templates",
"type": "module",
"dependencies": {