Compare commits
2 Commits
accessibil
...
test/other
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ad708aac6 | ||
|
|
a63afffbd6 |
17
CHANGELOG.md
@@ -9,25 +9,15 @@ and this project adheres to
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [2.2.0] - 2025-02-10
|
||||
|
||||
## Added
|
||||
|
||||
- 📝(doc) Add security.md and codeofconduct.md #604
|
||||
- ✨(frontend) add home page #608
|
||||
- ✨(frontend) cursor display on activity #609
|
||||
- ✨(frontend) Add export page break #623
|
||||
- ✨(frontend) add home page #553
|
||||
|
||||
## Changed
|
||||
|
||||
- 🔧(backend) make AI feature reach configurable #628
|
||||
|
||||
## Fixed
|
||||
|
||||
- 🌐(CI) Fix email partially translated #616
|
||||
- 🐛(frontend) fix cursor breakline #609
|
||||
- 🐛(frontend) fix style pdf export #609
|
||||
|
||||
🌐(CI) Fix email partially translated #616
|
||||
|
||||
## [2.1.0] - 2025-01-29
|
||||
|
||||
@@ -411,8 +401,7 @@ and this project adheres to
|
||||
- 🚀 Impress, project to manage your documents easily and collaboratively.
|
||||
|
||||
|
||||
[unreleased]: https://github.com/numerique-gouv/impress/compare/v2.2.0...main
|
||||
[v2.2.0]: https://github.com/numerique-gouv/impress/releases/v2.2.0
|
||||
[unreleased]: https://github.com/numerique-gouv/impress/compare/v2.1.0...main
|
||||
[v2.1.0]: https://github.com/numerique-gouv/impress/releases/v2.1.0
|
||||
[v2.0.1]: https://github.com/numerique-gouv/impress/releases/v2.0.1
|
||||
[v2.0.0]: https://github.com/numerique-gouv/impress/releases/v2.0.0
|
||||
|
||||
@@ -15,8 +15,3 @@ the following command inside your docker container:
|
||||
(Note : in your development environment, you can `make migrate`.)
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- AI features are now limited to users who are authenticated. Before this release, even anonymous
|
||||
users who gained editor access on a document with link reach used to get AI feature.
|
||||
IF you want anonymous users to keep access on AI features, you must now define the
|
||||
`AI_ALLOW_REACH_FROM` setting to "public".
|
||||
|
||||
@@ -15,7 +15,7 @@ services:
|
||||
- "1081:1080"
|
||||
|
||||
minio:
|
||||
# user: ${DOCKER_USER:-1000}
|
||||
user: ${DOCKER_USER:-1000}
|
||||
image: minio/minio
|
||||
environment:
|
||||
- MINIO_ROOT_USER=impress
|
||||
|
||||
3853
package-lock.json
generated
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@blocknote/core": "^0.23.4",
|
||||
"next": "^15.1.7"
|
||||
}
|
||||
}
|
||||
@@ -629,9 +629,6 @@ class Document(MP_Node, BaseModel):
|
||||
# which date to allow them anyway)
|
||||
# Anonymous users should also not see document accesses
|
||||
has_access_role = bool(roles) and not is_deleted
|
||||
can_update_from_access = (
|
||||
is_owner_or_admin or RoleChoices.EDITOR in roles
|
||||
) and not is_deleted
|
||||
|
||||
# Add roles provided by the document link, taking into account its ancestors
|
||||
|
||||
@@ -650,23 +647,11 @@ class Document(MP_Node, BaseModel):
|
||||
is_owner_or_admin or RoleChoices.EDITOR in roles
|
||||
) and not is_deleted
|
||||
|
||||
ai_allow_reach_from = settings.AI_ALLOW_REACH_FROM
|
||||
ai_access = any(
|
||||
[
|
||||
ai_allow_reach_from == LinkReachChoices.PUBLIC and can_update,
|
||||
ai_allow_reach_from == LinkReachChoices.AUTHENTICATED
|
||||
and user.is_authenticated
|
||||
and can_update,
|
||||
ai_allow_reach_from == LinkReachChoices.RESTRICTED
|
||||
and can_update_from_access,
|
||||
]
|
||||
)
|
||||
|
||||
return {
|
||||
"accesses_manage": is_owner_or_admin,
|
||||
"accesses_view": has_access_role,
|
||||
"ai_transform": ai_access,
|
||||
"ai_translate": ai_access,
|
||||
"ai_transform": can_update,
|
||||
"ai_translate": can_update,
|
||||
"attachment_upload": can_update,
|
||||
"children_list": can_get,
|
||||
"children_create": can_update and user.is_authenticated,
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
Test AI transform API endpoint for users in impress's core app.
|
||||
"""
|
||||
|
||||
import random
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from django.core.cache import cache
|
||||
@@ -32,9 +31,6 @@ def ai_settings():
|
||||
yield
|
||||
|
||||
|
||||
@override_settings(
|
||||
AI_ALLOW_REACH_FROM=random.choice(["public", "authenticated", "restricted"])
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"reach, role",
|
||||
[
|
||||
@@ -61,7 +57,6 @@ def test_api_documents_ai_transform_anonymous_forbidden(reach, role):
|
||||
}
|
||||
|
||||
|
||||
@override_settings(AI_ALLOW_REACH_FROM="public")
|
||||
@pytest.mark.usefixtures("ai_settings")
|
||||
@patch("openai.resources.chat.completions.Completions.create")
|
||||
def test_api_documents_ai_transform_anonymous_success(mock_create):
|
||||
@@ -98,27 +93,6 @@ def test_api_documents_ai_transform_anonymous_success(mock_create):
|
||||
)
|
||||
|
||||
|
||||
@override_settings(AI_ALLOW_REACH_FROM=random.choice(["authenticated", "restricted"]))
|
||||
@pytest.mark.usefixtures("ai_settings")
|
||||
@patch("openai.resources.chat.completions.Completions.create")
|
||||
def test_api_documents_ai_transform_anonymous_limited_by_setting(mock_create):
|
||||
"""
|
||||
Anonymous users should be able to request AI transform to a document
|
||||
if the link reach and role permit it.
|
||||
"""
|
||||
document = factories.DocumentFactory(link_reach="public", link_role="editor")
|
||||
|
||||
answer = '{"answer": "Salut"}'
|
||||
mock_create.return_value = MagicMock(
|
||||
choices=[MagicMock(message=MagicMock(content=answer))]
|
||||
)
|
||||
|
||||
url = f"/api/v1.0/documents/{document.id!s}/ai-transform/"
|
||||
response = APIClient().post(url, {"text": "Hello", "action": "summarize"})
|
||||
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"reach, role",
|
||||
[
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
Test AI translate API endpoint for users in impress's core app.
|
||||
"""
|
||||
|
||||
import random
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from django.core.cache import cache
|
||||
@@ -52,9 +51,6 @@ def test_api_documents_ai_translate_viewset_options_metadata():
|
||||
}
|
||||
|
||||
|
||||
@override_settings(
|
||||
AI_ALLOW_REACH_FROM=random.choice(["public", "authenticated", "restricted"])
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"reach, role",
|
||||
[
|
||||
@@ -81,7 +77,6 @@ def test_api_documents_ai_translate_anonymous_forbidden(reach, role):
|
||||
}
|
||||
|
||||
|
||||
@override_settings(AI_ALLOW_REACH_FROM="public")
|
||||
@pytest.mark.usefixtures("ai_settings")
|
||||
@patch("openai.resources.chat.completions.Completions.create")
|
||||
def test_api_documents_ai_translate_anonymous_success(mock_create):
|
||||
@@ -118,27 +113,6 @@ def test_api_documents_ai_translate_anonymous_success(mock_create):
|
||||
)
|
||||
|
||||
|
||||
@override_settings(AI_ALLOW_REACH_FROM=random.choice(["authenticated", "restricted"]))
|
||||
@pytest.mark.usefixtures("ai_settings")
|
||||
@patch("openai.resources.chat.completions.Completions.create")
|
||||
def test_api_documents_ai_translate_anonymous_limited_by_setting(mock_create):
|
||||
"""
|
||||
Anonymous users should be able to request AI translate to a document
|
||||
if the link reach and role permit it.
|
||||
"""
|
||||
document = factories.DocumentFactory(link_reach="public", link_role="editor")
|
||||
|
||||
answer = '{"answer": "Salut"}'
|
||||
mock_create.return_value = MagicMock(
|
||||
choices=[MagicMock(message=MagicMock(content=answer))]
|
||||
)
|
||||
|
||||
url = f"/api/v1.0/documents/{document.id!s}/ai-translate/"
|
||||
response = APIClient().post(url, {"text": "Hello", "language": "es"})
|
||||
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"reach, role",
|
||||
[
|
||||
|
||||
@@ -28,8 +28,8 @@ def test_api_documents_retrieve_anonymous_public_standalone():
|
||||
"abilities": {
|
||||
"accesses_manage": False,
|
||||
"accesses_view": False,
|
||||
"ai_transform": False,
|
||||
"ai_translate": False,
|
||||
"ai_transform": document.link_role == "editor",
|
||||
"ai_translate": document.link_role == "editor",
|
||||
"attachment_upload": document.link_role == "editor",
|
||||
"children_create": False,
|
||||
"children_list": True,
|
||||
@@ -84,8 +84,8 @@ def test_api_documents_retrieve_anonymous_public_parent():
|
||||
"abilities": {
|
||||
"accesses_manage": False,
|
||||
"accesses_view": False,
|
||||
"ai_transform": False,
|
||||
"ai_translate": False,
|
||||
"ai_transform": grand_parent.link_role == "editor",
|
||||
"ai_translate": grand_parent.link_role == "editor",
|
||||
"attachment_upload": grand_parent.link_role == "editor",
|
||||
"children_create": False,
|
||||
"children_list": True,
|
||||
|
||||
@@ -12,7 +12,6 @@ from django.core import mail
|
||||
from django.core.cache import cache
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.files.storage import default_storage
|
||||
from django.test.utils import override_settings
|
||||
from django.utils import timezone
|
||||
|
||||
import pytest
|
||||
@@ -125,9 +124,6 @@ def test_models_documents_soft_delete(depth):
|
||||
# get_abilities
|
||||
|
||||
|
||||
@override_settings(
|
||||
AI_ALLOW_REACH_FROM=random.choice(["public", "authenticated", "restricted"])
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"is_authenticated,reach,role",
|
||||
[
|
||||
@@ -179,9 +175,6 @@ def test_models_documents_get_abilities_forbidden(
|
||||
assert document.get_abilities(user) == expected_abilities
|
||||
|
||||
|
||||
@override_settings(
|
||||
AI_ALLOW_REACH_FROM=random.choice(["public", "authenticated", "restricted"])
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"is_authenticated,reach",
|
||||
[
|
||||
@@ -250,8 +243,8 @@ def test_models_documents_get_abilities_editor(
|
||||
expected_abilities = {
|
||||
"accesses_manage": False,
|
||||
"accesses_view": False,
|
||||
"ai_transform": is_authenticated,
|
||||
"ai_translate": is_authenticated,
|
||||
"ai_transform": True,
|
||||
"ai_translate": True,
|
||||
"attachment_upload": True,
|
||||
"children_create": is_authenticated,
|
||||
"children_list": True,
|
||||
@@ -278,9 +271,6 @@ def test_models_documents_get_abilities_editor(
|
||||
assert all(value is False for value in document.get_abilities(user).values())
|
||||
|
||||
|
||||
@override_settings(
|
||||
AI_ALLOW_REACH_FROM=random.choice(["public", "authenticated", "restricted"])
|
||||
)
|
||||
def test_models_documents_get_abilities_owner(django_assert_num_queries):
|
||||
"""Check abilities returned for the owner of a document."""
|
||||
user = factories.UserFactory()
|
||||
@@ -310,16 +300,12 @@ def test_models_documents_get_abilities_owner(django_assert_num_queries):
|
||||
}
|
||||
with django_assert_num_queries(1):
|
||||
assert document.get_abilities(user) == expected_abilities
|
||||
|
||||
document.soft_delete()
|
||||
document.refresh_from_db()
|
||||
expected_abilities["move"] = False
|
||||
assert document.get_abilities(user) == expected_abilities
|
||||
|
||||
|
||||
@override_settings(
|
||||
AI_ALLOW_REACH_FROM=random.choice(["public", "authenticated", "restricted"])
|
||||
)
|
||||
def test_models_documents_get_abilities_administrator(django_assert_num_queries):
|
||||
"""Check abilities returned for the administrator of a document."""
|
||||
user = factories.UserFactory()
|
||||
@@ -349,15 +335,11 @@ def test_models_documents_get_abilities_administrator(django_assert_num_queries)
|
||||
}
|
||||
with django_assert_num_queries(1):
|
||||
assert document.get_abilities(user) == expected_abilities
|
||||
|
||||
document.soft_delete()
|
||||
document.refresh_from_db()
|
||||
assert all(value is False for value in document.get_abilities(user).values())
|
||||
|
||||
|
||||
@override_settings(
|
||||
AI_ALLOW_REACH_FROM=random.choice(["public", "authenticated", "restricted"])
|
||||
)
|
||||
def test_models_documents_get_abilities_editor_user(django_assert_num_queries):
|
||||
"""Check abilities returned for the editor of a document."""
|
||||
user = factories.UserFactory()
|
||||
@@ -387,31 +369,23 @@ def test_models_documents_get_abilities_editor_user(django_assert_num_queries):
|
||||
}
|
||||
with django_assert_num_queries(1):
|
||||
assert document.get_abilities(user) == expected_abilities
|
||||
|
||||
document.soft_delete()
|
||||
document.refresh_from_db()
|
||||
assert all(value is False for value in document.get_abilities(user).values())
|
||||
|
||||
|
||||
@pytest.mark.parametrize("ai_access_setting", ["public", "authenticated", "restricted"])
|
||||
def test_models_documents_get_abilities_reader_user(
|
||||
ai_access_setting, django_assert_num_queries
|
||||
):
|
||||
def test_models_documents_get_abilities_reader_user(django_assert_num_queries):
|
||||
"""Check abilities returned for the reader of a document."""
|
||||
user = factories.UserFactory()
|
||||
document = factories.DocumentFactory(users=[(user, "reader")])
|
||||
|
||||
access_from_link = (
|
||||
document.link_reach != "restricted" and document.link_role == "editor"
|
||||
)
|
||||
|
||||
expected_abilities = {
|
||||
"accesses_manage": False,
|
||||
"accesses_view": True,
|
||||
# If you get your editor rights from the link role and not your access role
|
||||
# You should not access AI if it's restricted to users with specific access
|
||||
"ai_transform": access_from_link and ai_access_setting != "restricted",
|
||||
"ai_translate": access_from_link and ai_access_setting != "restricted",
|
||||
"ai_transform": access_from_link,
|
||||
"ai_translate": access_from_link,
|
||||
"attachment_upload": access_from_link,
|
||||
"children_create": access_from_link,
|
||||
"children_list": True,
|
||||
@@ -430,14 +404,11 @@ def test_models_documents_get_abilities_reader_user(
|
||||
"versions_list": True,
|
||||
"versions_retrieve": True,
|
||||
}
|
||||
|
||||
with override_settings(AI_ALLOW_REACH_FROM=ai_access_setting):
|
||||
with django_assert_num_queries(1):
|
||||
assert document.get_abilities(user) == expected_abilities
|
||||
|
||||
document.soft_delete()
|
||||
document.refresh_from_db()
|
||||
assert all(value is False for value in document.get_abilities(user).values())
|
||||
with django_assert_num_queries(1):
|
||||
assert document.get_abilities(user) == expected_abilities
|
||||
document.soft_delete()
|
||||
document.refresh_from_db()
|
||||
assert all(value is False for value in document.get_abilities(user).values())
|
||||
|
||||
|
||||
def test_models_documents_get_abilities_preset_role(django_assert_num_queries):
|
||||
@@ -475,44 +446,6 @@ def test_models_documents_get_abilities_preset_role(django_assert_num_queries):
|
||||
}
|
||||
|
||||
|
||||
@override_settings(AI_ALLOW_REACH_FROM="public")
|
||||
@pytest.mark.parametrize(
|
||||
"is_authenticated,reach",
|
||||
[
|
||||
(True, "public"),
|
||||
(False, "public"),
|
||||
(True, "authenticated"),
|
||||
],
|
||||
)
|
||||
def test_models_document_get_abilities_ai_access_authenticated(is_authenticated, reach):
|
||||
"""Validate AI abilities when AI is available to any anonymous user with editor rights."""
|
||||
user = factories.UserFactory() if is_authenticated else AnonymousUser()
|
||||
document = factories.DocumentFactory(link_reach=reach, link_role="editor")
|
||||
|
||||
abilities = document.get_abilities(user)
|
||||
assert abilities["ai_transform"] is True
|
||||
assert abilities["ai_translate"] is True
|
||||
|
||||
|
||||
@override_settings(AI_ALLOW_REACH_FROM="authenticated")
|
||||
@pytest.mark.parametrize(
|
||||
"is_authenticated,reach",
|
||||
[
|
||||
(True, "public"),
|
||||
(False, "public"),
|
||||
(True, "authenticated"),
|
||||
],
|
||||
)
|
||||
def test_models_document_get_abilities_ai_access_public(is_authenticated, reach):
|
||||
"""Validate AI abilities when AI is available only to authenticated users with editor rights."""
|
||||
user = factories.UserFactory() if is_authenticated else AnonymousUser()
|
||||
document = factories.DocumentFactory(link_reach=reach, link_role="editor")
|
||||
|
||||
abilities = document.get_abilities(user)
|
||||
assert abilities["ai_transform"] == is_authenticated
|
||||
assert abilities["ai_translate"] == is_authenticated
|
||||
|
||||
|
||||
def test_models_documents_get_versions_slice_pagination(settings):
|
||||
"""
|
||||
The "get_versions_slice" method should allow navigating all versions of
|
||||
|
||||
@@ -516,12 +516,7 @@ class Base(Configuration):
|
||||
AI_API_KEY = values.Value(None, environ_name="AI_API_KEY", environ_prefix=None)
|
||||
AI_BASE_URL = values.Value(None, environ_name="AI_BASE_URL", environ_prefix=None)
|
||||
AI_MODEL = values.Value(None, environ_name="AI_MODEL", environ_prefix=None)
|
||||
AI_ALLOW_REACH_FROM = values.Value(
|
||||
choices=("public", "authenticated", "restricted"),
|
||||
default="authenticated",
|
||||
environ_name="AI_ALLOW_REACH_FROM",
|
||||
environ_prefix=None,
|
||||
)
|
||||
|
||||
AI_DOCUMENT_RATE_THROTTLE_RATES = {
|
||||
"minute": 5,
|
||||
"hour": 100,
|
||||
|
||||
@@ -3,7 +3,7 @@ msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-02-06 15:30+0000\n"
|
||||
"PO-Revision-Date: 2025-02-10 14:14\n"
|
||||
"PO-Revision-Date: 2025-02-06 15:59\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-02-06 15:30+0000\n"
|
||||
"PO-Revision-Date: 2025-02-10 14:14\n"
|
||||
"PO-Revision-Date: 2025-02-06 15:57\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-02-06 15:30+0000\n"
|
||||
"PO-Revision-Date: 2025-02-10 14:14\n"
|
||||
"PO-Revision-Date: 2025-02-06 15:59\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-02-06 15:30+0000\n"
|
||||
"PO-Revision-Date: 2025-02-10 14:14\n"
|
||||
"PO-Revision-Date: 2025-02-06 15:57\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Dutch\n"
|
||||
"Language: nl_NL\n"
|
||||
|
||||
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "impress"
|
||||
version = "2.2.0"
|
||||
version = "2.1.0"
|
||||
authors = [{ "name" = "DINUM", "email" = "dev@mail.numerique.gouv.fr" }]
|
||||
classifiers = [
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
/* eslint-disable playwright/no-conditional-expect */
|
||||
/* eslint-disable playwright/no-conditional-in-test */
|
||||
import path from 'path';
|
||||
|
||||
import { expect, test } from '@playwright/test';
|
||||
@@ -370,77 +368,4 @@ test.describe('Doc Editor', () => {
|
||||
|
||||
await expect(editor.getByText('Bonjour le monde')).toBeVisible();
|
||||
});
|
||||
|
||||
[
|
||||
{ ai_transform: false, ai_translate: false },
|
||||
{ ai_transform: true, ai_translate: false },
|
||||
{ ai_transform: false, ai_translate: true },
|
||||
].forEach(({ ai_transform, ai_translate }) => {
|
||||
test(`it checks AI buttons when can transform is at "${ai_transform}" and can translate is at "${ai_translate}"`, async ({
|
||||
page,
|
||||
}) => {
|
||||
await mockedDocument(page, {
|
||||
accesses: [
|
||||
{
|
||||
id: 'b0df4343-c8bd-4c20-9ff6-fbf94fc94egg',
|
||||
role: 'owner',
|
||||
user: {
|
||||
email: 'super@owner.com',
|
||||
full_name: 'Super Owner',
|
||||
},
|
||||
},
|
||||
],
|
||||
abilities: {
|
||||
destroy: true, // Means owner
|
||||
link_configuration: true,
|
||||
ai_transform,
|
||||
ai_translate,
|
||||
accesses_manage: true,
|
||||
accesses_view: true,
|
||||
update: true,
|
||||
partial_update: true,
|
||||
retrieve: true,
|
||||
},
|
||||
link_reach: 'public',
|
||||
link_role: 'editor',
|
||||
created_at: '2021-09-01T09:00:00Z',
|
||||
});
|
||||
|
||||
await goToGridDoc(page);
|
||||
|
||||
await verifyDocName(page, 'Mocked document');
|
||||
|
||||
await page.locator('.bn-block-outer').last().fill('Hello World');
|
||||
|
||||
const editor = page.locator('.ProseMirror');
|
||||
await editor.getByText('Hello').dblclick();
|
||||
|
||||
if (!ai_transform && !ai_translate) {
|
||||
await expect(page.getByRole('button', { name: 'AI' })).toBeHidden();
|
||||
return;
|
||||
}
|
||||
|
||||
await page.getByRole('button', { name: 'AI' }).click();
|
||||
|
||||
if (ai_transform) {
|
||||
await expect(
|
||||
page.getByRole('menuitem', { name: 'Use as prompt' }),
|
||||
).toBeVisible();
|
||||
} else {
|
||||
await expect(
|
||||
page.getByRole('menuitem', { name: 'Use as prompt' }),
|
||||
).toBeHidden();
|
||||
}
|
||||
|
||||
if (ai_translate) {
|
||||
await expect(
|
||||
page.getByRole('menuitem', { name: 'Language' }),
|
||||
).toBeVisible();
|
||||
} else {
|
||||
await expect(
|
||||
page.getByRole('menuitem', { name: 'Language' }),
|
||||
).toBeHidden();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -41,16 +41,8 @@ test.describe('Doc Export', () => {
|
||||
await expect(page.getByRole('button', { name: 'Download' })).toBeVisible();
|
||||
});
|
||||
|
||||
test('it exports the doc with pdf line break', async ({
|
||||
page,
|
||||
browserName,
|
||||
}) => {
|
||||
const [randomDoc] = await createDoc(
|
||||
page,
|
||||
'doc-editor-line-break',
|
||||
browserName,
|
||||
1,
|
||||
);
|
||||
test('it exports the doc to pdf', async ({ page, browserName }) => {
|
||||
const [randomDoc] = await createDoc(page, 'doc-editor', browserName, 1);
|
||||
|
||||
const downloadPromise = page.waitForEvent('download', (download) => {
|
||||
return download.suggestedFilename().includes(`${randomDoc}.pdf`);
|
||||
@@ -58,20 +50,8 @@ test.describe('Doc Export', () => {
|
||||
|
||||
await verifyDocName(page, randomDoc);
|
||||
|
||||
const editor = page.locator('.ProseMirror.bn-editor');
|
||||
|
||||
await editor.click();
|
||||
await editor.locator('.bn-block-outer').last().fill('Hello');
|
||||
|
||||
await page.keyboard.press('Enter');
|
||||
await editor.locator('.bn-block-outer').last().fill('/');
|
||||
await page.getByText('Page Break').click();
|
||||
|
||||
await expect(editor.locator('.bn-page-break')).toBeVisible();
|
||||
|
||||
await page.keyboard.press('Enter');
|
||||
|
||||
await editor.locator('.bn-block-outer').last().fill('World');
|
||||
await page.locator('.ProseMirror.bn-editor').click();
|
||||
await page.locator('.ProseMirror.bn-editor').fill('Hello World');
|
||||
|
||||
await page
|
||||
.getByRole('button', {
|
||||
@@ -89,10 +69,9 @@ test.describe('Doc Export', () => {
|
||||
expect(download.suggestedFilename()).toBe(`${randomDoc}.pdf`);
|
||||
|
||||
const pdfBuffer = await cs.toBuffer(await download.createReadStream());
|
||||
const pdfData = await pdf(pdfBuffer);
|
||||
const pdfText = (await pdf(pdfBuffer)).text;
|
||||
|
||||
expect(pdfData.numpages).toBe(2);
|
||||
expect(pdfData.text).toContain('\n\nHello\n\nWorld'); // This is the doc text
|
||||
expect(pdfText).toContain('Hello World'); // This is the doc text
|
||||
});
|
||||
|
||||
test('it exports the doc to docx', async ({ page, browserName }) => {
|
||||
|
||||
@@ -395,7 +395,9 @@ test.describe('Doc Header', () => {
|
||||
navigator.clipboard.readText(),
|
||||
);
|
||||
const clipboardContent = await handle.jsonValue();
|
||||
expect(clipboardContent.trim()).toBe(`<h1>Hello World</h1><p></p>`);
|
||||
expect(clipboardContent.trim()).toBe(
|
||||
`<h1 data-level=\"1\">Hello World</h1><p></p>`,
|
||||
);
|
||||
});
|
||||
|
||||
test('it checks the copy link button', async ({ page }) => {
|
||||
|
||||
@@ -10,7 +10,7 @@ test.describe('Header', () => {
|
||||
test('checks all the elements are visible', async ({ page }) => {
|
||||
const header = page.locator('header').first();
|
||||
|
||||
await expect(header.getByLabel('Docs Logo')).toBeVisible();
|
||||
await expect(header.getByAltText('Docs Logo')).toBeVisible();
|
||||
await expect(header.locator('h2').getByText('Docs')).toHaveCSS(
|
||||
'color',
|
||||
'rgb(0, 0, 145)',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "app-e2e",
|
||||
"version": "2.2.0",
|
||||
"version": "2.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"lint": "eslint . --ext .ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "app-impress",
|
||||
"version": "2.2.0",
|
||||
"version": "2.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
@@ -23,7 +23,7 @@
|
||||
"@gouvfr-lasuite/integration": "1.0.2",
|
||||
"@hocuspocus/provider": "2.15.2",
|
||||
"@openfun/cunningham-react": "2.9.4",
|
||||
"@react-pdf/renderer": "4.1.6",
|
||||
"@react-pdf/renderer": "4.2.1",
|
||||
"@sentry/nextjs": "8.54.0",
|
||||
"@tanstack/react-query": "5.66.0",
|
||||
"cmdk": "1.0.4",
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { FocusScope } from '@react-aria/focus';
|
||||
import {
|
||||
PropsWithChildren,
|
||||
ReactNode,
|
||||
@@ -7,16 +6,16 @@ import {
|
||||
useState,
|
||||
} from 'react';
|
||||
import { Button, Popover } from 'react-aria-components';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import styled from 'styled-components';
|
||||
|
||||
const StyledPopover = styled(Popover)`
|
||||
background-color: white;
|
||||
border-radius: 4px;
|
||||
box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.1);
|
||||
|
||||
border: 1px solid #dddddd;
|
||||
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
padding: 1rem;
|
||||
`;
|
||||
|
||||
const StyledButton = styled(Button)`
|
||||
@@ -30,10 +29,6 @@ const StyledButton = styled(Button)`
|
||||
font-size: 0.938rem;
|
||||
padding: 0;
|
||||
text-wrap: nowrap;
|
||||
|
||||
&:focus-within {
|
||||
outline: 2px solid #007bff;
|
||||
}
|
||||
`;
|
||||
|
||||
export interface DropButtonProps {
|
||||
@@ -48,17 +43,15 @@ export const DropButton = ({
|
||||
isOpen = false,
|
||||
onOpenChange,
|
||||
children,
|
||||
label,
|
||||
}: PropsWithChildren<DropButtonProps>) => {
|
||||
const { t } = useTranslation();
|
||||
const [isLocalOpen, setIsLocalOpen] = useState(isOpen);
|
||||
const triggerRef = useRef<HTMLButtonElement>(null);
|
||||
const firstFocusableRef = useRef<HTMLButtonElement>(null);
|
||||
|
||||
const triggerRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (isLocalOpen && firstFocusableRef.current) {
|
||||
firstFocusableRef.current.focus();
|
||||
}
|
||||
}, [isLocalOpen]);
|
||||
setIsLocalOpen(isOpen);
|
||||
}, [isOpen]);
|
||||
|
||||
const onOpenChangeHandler = (isOpen: boolean) => {
|
||||
setIsLocalOpen(isOpen);
|
||||
@@ -70,30 +63,18 @@ export const DropButton = ({
|
||||
<StyledButton
|
||||
ref={triggerRef}
|
||||
onPress={() => onOpenChangeHandler(true)}
|
||||
aria-haspopup="true"
|
||||
aria-expanded={isLocalOpen}
|
||||
aria-label={t('Open the document options')}
|
||||
aria-label={label}
|
||||
>
|
||||
<span aria-hidden="true">{button}</span>
|
||||
{button}
|
||||
</StyledButton>
|
||||
|
||||
{isLocalOpen && (
|
||||
<StyledPopover
|
||||
triggerRef={triggerRef}
|
||||
isOpen={isLocalOpen}
|
||||
onOpenChange={onOpenChangeHandler}
|
||||
>
|
||||
<FocusScope contain restoreFocus>
|
||||
{children}
|
||||
<button
|
||||
ref={firstFocusableRef}
|
||||
onClick={() => setIsLocalOpen(false)}
|
||||
>
|
||||
{t('Close the modal')}
|
||||
</button>
|
||||
</FocusScope>
|
||||
</StyledPopover>
|
||||
)}
|
||||
<StyledPopover
|
||||
triggerRef={triggerRef}
|
||||
isOpen={isLocalOpen}
|
||||
onOpenChange={onOpenChangeHandler}
|
||||
>
|
||||
{children}
|
||||
</StyledPopover>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
//import { t } from 'i18next';
|
||||
import { PropsWithChildren, useState } from 'react';
|
||||
import { css } from 'styled-components';
|
||||
|
||||
|
||||
@@ -47,11 +47,7 @@ export const QuickSearchInput = ({
|
||||
$gap={spacing['2xs']}
|
||||
$padding={{ all: 'base' }}
|
||||
>
|
||||
{!loading && (
|
||||
<span aria-hidden="true">
|
||||
<Icon iconName="search" $variation="600" />
|
||||
</span>
|
||||
)}
|
||||
{!loading && <Icon iconName="search" $variation="600" />}
|
||||
{loading && (
|
||||
<div>
|
||||
<Loader size="small" />
|
||||
|
||||
@@ -203,7 +203,6 @@ input:-webkit-autofill:focus {
|
||||
|
||||
.c__select__wrapper .c__select__inner__actions__open:focus {
|
||||
outline: none;
|
||||
|
||||
}
|
||||
|
||||
.c__select__wrapper .labelled-box__label.c__offscreen {
|
||||
@@ -606,31 +605,3 @@ input:-webkit-autofill:focus {
|
||||
.c__tooltip {
|
||||
padding: 4px 6px;
|
||||
}
|
||||
|
||||
/**
|
||||
* lecture ou non des icons
|
||||
*/
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
[data-icon]:before {
|
||||
font-family: 'Material Icons';
|
||||
content: attr(data-icon);
|
||||
}
|
||||
|
||||
button:focus {
|
||||
background-color: var(
|
||||
--c--components--button--primary-text--background--color-hover
|
||||
);
|
||||
border-radius: var(--c--components--button--border-radius--focus);
|
||||
box-shadow: 0 0 0 2px var(--c--theme--colors--primary-400)
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Button } from '@openfun/cunningham-react';
|
||||
import Image from 'next/image';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { css } from 'styled-components';
|
||||
|
||||
import { BoxButton } from '@/components';
|
||||
|
||||
import ProConnectImg from '../assets/button-proconnect.svg';
|
||||
import ProConnectImg from '../assets/button-proconnect.svg?url';
|
||||
import { useAuth } from '../hooks';
|
||||
import { gotoLogin, gotoLogout } from '../utils';
|
||||
|
||||
@@ -40,9 +41,8 @@ export const ProConnectButton = () => {
|
||||
background-color: var(--c--theme--colors--primary-action);
|
||||
}
|
||||
`}
|
||||
$radius="4px"
|
||||
>
|
||||
<ProConnectImg />
|
||||
<Image src={ProConnectImg} alt={t('ProConnect Image')} />
|
||||
</BoxButton>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -92,13 +92,6 @@ export function AIGroupButton() {
|
||||
return null;
|
||||
}
|
||||
|
||||
const canAITransform = currentDoc.abilities.ai_transform;
|
||||
const canAITranslate = currentDoc.abilities.ai_translate;
|
||||
|
||||
if (!canAITransform && !canAITranslate) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Components.Generic.Menu.Root>
|
||||
<Components.Generic.Menu.Trigger>
|
||||
@@ -118,85 +111,79 @@ export function AIGroupButton() {
|
||||
className="bn-menu-dropdown bn-drag-handle-menu"
|
||||
sub={true}
|
||||
>
|
||||
{canAITransform && (
|
||||
<>
|
||||
<AIMenuItemTransform
|
||||
action="prompt"
|
||||
docId={currentDoc.id}
|
||||
icon={
|
||||
<Text $isMaterialIcon $size="s">
|
||||
text_fields
|
||||
</Text>
|
||||
}
|
||||
<AIMenuItemTransform
|
||||
action="prompt"
|
||||
docId={currentDoc.id}
|
||||
icon={
|
||||
<Text $isMaterialIcon $size="s">
|
||||
text_fields
|
||||
</Text>
|
||||
}
|
||||
>
|
||||
{t('Use as prompt')}
|
||||
</AIMenuItemTransform>
|
||||
<AIMenuItemTransform
|
||||
action="rephrase"
|
||||
docId={currentDoc.id}
|
||||
icon={
|
||||
<Text $isMaterialIcon $size="s">
|
||||
refresh
|
||||
</Text>
|
||||
}
|
||||
>
|
||||
{t('Rephrase')}
|
||||
</AIMenuItemTransform>
|
||||
<AIMenuItemTransform
|
||||
action="summarize"
|
||||
docId={currentDoc.id}
|
||||
icon={
|
||||
<Text $isMaterialIcon $size="s">
|
||||
summarize
|
||||
</Text>
|
||||
}
|
||||
>
|
||||
{t('Summarize')}
|
||||
</AIMenuItemTransform>
|
||||
<AIMenuItemTransform
|
||||
action="correct"
|
||||
docId={currentDoc.id}
|
||||
icon={
|
||||
<Text $isMaterialIcon $size="s">
|
||||
check
|
||||
</Text>
|
||||
}
|
||||
>
|
||||
{t('Correct')}
|
||||
</AIMenuItemTransform>
|
||||
<Components.Generic.Menu.Root position="right" sub={true}>
|
||||
<Components.Generic.Menu.Trigger sub={false}>
|
||||
<Components.Generic.Menu.Item
|
||||
className="bn-menu-item"
|
||||
subTrigger={true}
|
||||
>
|
||||
{t('Use as prompt')}
|
||||
</AIMenuItemTransform>
|
||||
<AIMenuItemTransform
|
||||
action="rephrase"
|
||||
docId={currentDoc.id}
|
||||
icon={
|
||||
<Box $direction="row" $gap="0.6rem">
|
||||
<Text $isMaterialIcon $size="s">
|
||||
refresh
|
||||
translate
|
||||
</Text>
|
||||
}
|
||||
>
|
||||
{t('Rephrase')}
|
||||
</AIMenuItemTransform>
|
||||
<AIMenuItemTransform
|
||||
action="summarize"
|
||||
docId={currentDoc.id}
|
||||
icon={
|
||||
<Text $isMaterialIcon $size="s">
|
||||
summarize
|
||||
</Text>
|
||||
}
|
||||
>
|
||||
{t('Summarize')}
|
||||
</AIMenuItemTransform>
|
||||
<AIMenuItemTransform
|
||||
action="correct"
|
||||
docId={currentDoc.id}
|
||||
icon={
|
||||
<Text $isMaterialIcon $size="s">
|
||||
check
|
||||
</Text>
|
||||
}
|
||||
>
|
||||
{t('Correct')}
|
||||
</AIMenuItemTransform>
|
||||
</>
|
||||
)}
|
||||
{canAITranslate && (
|
||||
<Components.Generic.Menu.Root position="right" sub={true}>
|
||||
<Components.Generic.Menu.Trigger sub={false}>
|
||||
<Components.Generic.Menu.Item
|
||||
className="bn-menu-item"
|
||||
subTrigger={true}
|
||||
{t('Language')}
|
||||
</Box>
|
||||
</Components.Generic.Menu.Item>
|
||||
</Components.Generic.Menu.Trigger>
|
||||
<Components.Generic.Menu.Dropdown
|
||||
sub={true}
|
||||
className="bn-menu-dropdown"
|
||||
>
|
||||
{languages.map((language) => (
|
||||
<AIMenuItemTranslate
|
||||
key={language.value}
|
||||
language={language.value}
|
||||
docId={currentDoc.id}
|
||||
>
|
||||
<Box $direction="row" $gap="0.6rem">
|
||||
<Text $isMaterialIcon $size="s">
|
||||
translate
|
||||
</Text>
|
||||
{t('Language')}
|
||||
</Box>
|
||||
</Components.Generic.Menu.Item>
|
||||
</Components.Generic.Menu.Trigger>
|
||||
<Components.Generic.Menu.Dropdown
|
||||
sub={true}
|
||||
className="bn-menu-dropdown"
|
||||
>
|
||||
{languages.map((language) => (
|
||||
<AIMenuItemTranslate
|
||||
key={language.value}
|
||||
language={language.value}
|
||||
docId={currentDoc.id}
|
||||
>
|
||||
{language.display_name}
|
||||
</AIMenuItemTranslate>
|
||||
))}
|
||||
</Components.Generic.Menu.Dropdown>
|
||||
</Components.Generic.Menu.Root>
|
||||
)}
|
||||
{language.display_name}
|
||||
</AIMenuItemTranslate>
|
||||
))}
|
||||
</Components.Generic.Menu.Dropdown>
|
||||
</Components.Generic.Menu.Root>
|
||||
</Components.Generic.Menu.Dropdown>
|
||||
</Components.Generic.Menu.Root>
|
||||
);
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
import {
|
||||
BlockNoteSchema,
|
||||
Dictionary,
|
||||
locales,
|
||||
withPageBreak,
|
||||
} from '@blocknote/core';
|
||||
import { Dictionary, locales } from '@blocknote/core';
|
||||
import '@blocknote/core/fonts/inter.css';
|
||||
import { BlockNoteView } from '@blocknote/mantine';
|
||||
import '@blocknote/mantine/style.css';
|
||||
@@ -11,6 +6,7 @@ import { useCreateBlockNote } from '@blocknote/react';
|
||||
import { HocuspocusProvider } from '@hocuspocus/provider';
|
||||
import { useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { css } from 'styled-components';
|
||||
import * as Y from 'yjs';
|
||||
|
||||
import { Box, TextErrors } from '@/components';
|
||||
@@ -21,13 +17,125 @@ import { useUploadFile } from '../hook';
|
||||
import { useHeadings } from '../hook/useHeadings';
|
||||
import useSaveDoc from '../hook/useSaveDoc';
|
||||
import { useEditorStore } from '../stores';
|
||||
import { cssEditor } from '../styles';
|
||||
import { randomColor } from '../utils';
|
||||
|
||||
import { BlockNoteSuggestionMenu } from './BlockNoteSuggestionMenu';
|
||||
import { BlockNoteToolbar } from './BlockNoteToolbar';
|
||||
|
||||
export const blockNoteSchema = withPageBreak(BlockNoteSchema.create());
|
||||
const cssEditor = (readonly: boolean) => css`
|
||||
&,
|
||||
& > .bn-container,
|
||||
& .ProseMirror {
|
||||
height: 100%;
|
||||
|
||||
.collaboration-cursor__label2 {
|
||||
color: #0d0d0d;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
line-height: normal;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
position: absolute;
|
||||
transform: translate(0%, -17px);
|
||||
background-color: #e2b1f2;
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
white-space: nowrap;
|
||||
pointer-events: none;
|
||||
height: 37px;
|
||||
color: black;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
clip-path: polygon(
|
||||
0% 0%,
|
||||
100% 0%,
|
||||
100% 50%,
|
||||
50% 50%,
|
||||
5% 50%,
|
||||
0 100%,
|
||||
0% 75%
|
||||
);
|
||||
}
|
||||
|
||||
.bn-side-menu[data-block-type='heading'][data-level='1'] {
|
||||
height: 50px;
|
||||
}
|
||||
.bn-side-menu[data-block-type='heading'][data-level='2'] {
|
||||
height: 43px;
|
||||
}
|
||||
.bn-side-menu[data-block-type='heading'][data-level='3'] {
|
||||
height: 35px;
|
||||
}
|
||||
h1 {
|
||||
font-size: 1.875rem;
|
||||
}
|
||||
h2 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
h3 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
a {
|
||||
color: var(--c--theme--colors--greyscale-500);
|
||||
cursor: pointer;
|
||||
}
|
||||
.bn-block-group
|
||||
.bn-block-group
|
||||
.bn-block-outer:not([data-prev-depth-changed]):before {
|
||||
border-left: none;
|
||||
}
|
||||
}
|
||||
|
||||
.bn-editor {
|
||||
color: var(--c--theme--colors--greyscale-700);
|
||||
}
|
||||
|
||||
.bn-block-outer:not(:first-child) {
|
||||
&:has(h1) {
|
||||
padding-top: 32px;
|
||||
}
|
||||
&:has(h2) {
|
||||
padding-top: 24px;
|
||||
}
|
||||
&:has(h3) {
|
||||
padding-top: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
& .bn-inline-content code {
|
||||
background-color: gainsboro;
|
||||
padding: 2px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
@media screen and (width <= 560px) {
|
||||
& .bn-editor {
|
||||
${readonly && `padding-left: 10px;`}
|
||||
}
|
||||
.bn-side-menu[data-block-type='heading'][data-level='1'] {
|
||||
height: 46px;
|
||||
}
|
||||
.bn-side-menu[data-block-type='heading'][data-level='2'] {
|
||||
height: 40px;
|
||||
}
|
||||
.bn-side-menu[data-block-type='heading'][data-level='3'] {
|
||||
height: 40px;
|
||||
}
|
||||
& .bn-editor h1 {
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
& .bn-editor h2 {
|
||||
font-size: 1.35rem;
|
||||
}
|
||||
& .bn-editor h3 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
.bn-block-content[data-is-empty-and-focused][data-content-type='paragraph']
|
||||
.bn-inline-content:has(> .ProseMirror-trailingBreak:only-child)::before {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
interface BlockNoteEditorProps {
|
||||
doc: Doc;
|
||||
@@ -49,7 +157,6 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
|
||||
const collabName = readOnly
|
||||
? 'Reader'
|
||||
: user?.full_name || user?.email || t('Anonymous');
|
||||
const showCursorLabels: 'always' | 'activity' | (string & {}) = 'activity';
|
||||
|
||||
const editor = useCreateBlockNote(
|
||||
{
|
||||
@@ -61,50 +168,37 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
|
||||
color: randomColor(),
|
||||
},
|
||||
/**
|
||||
* We render the cursor with a custom element to:
|
||||
* - fix rendering issue with the default cursor
|
||||
* - hide the cursor when anonymous users
|
||||
* We re-use the blocknote code to render the cursor but we:
|
||||
* - fix rendering issue with Firefox
|
||||
* - We don't want to show the cursor when anonymous users
|
||||
*/
|
||||
renderCursor: (user: { color: string; name: string }) => {
|
||||
const cursorElement = document.createElement('span');
|
||||
const cursor = document.createElement('span');
|
||||
|
||||
if (user.name === 'Reader') {
|
||||
return cursorElement;
|
||||
return cursor;
|
||||
}
|
||||
|
||||
cursorElement.classList.add('collaboration-cursor-custom__base');
|
||||
const caretElement = document.createElement('span');
|
||||
caretElement.classList.add('collaboration-cursor-custom__caret');
|
||||
caretElement.setAttribute('spellcheck', `false`);
|
||||
caretElement.setAttribute('style', `background-color: ${user.color}`);
|
||||
cursor.classList.add('collaboration-cursor__caret-new-empty');
|
||||
cursor.setAttribute('spellcheck', `false`);
|
||||
|
||||
if (showCursorLabels === 'always') {
|
||||
cursorElement.setAttribute('data-active', '');
|
||||
}
|
||||
const label = document.createElement('span');
|
||||
|
||||
const labelElement = document.createElement('span');
|
||||
label.classList.add('collaboration-cursor__label2');
|
||||
label.setAttribute('spellcheck', `false`);
|
||||
label.setAttribute('style', `background-color: ${user.color}`);
|
||||
label.insertBefore(document.createTextNode(user.name), null);
|
||||
|
||||
labelElement.classList.add('collaboration-cursor-custom__label');
|
||||
labelElement.setAttribute('spellcheck', `false`);
|
||||
labelElement.setAttribute(
|
||||
'style',
|
||||
`background-color: ${user.color};border: 1px solid ${user.color};`,
|
||||
);
|
||||
labelElement.insertBefore(document.createTextNode(user.name), null);
|
||||
cursor.insertBefore(document.createTextNode('\u2060'), null); // Non-breaking space
|
||||
cursor.insertBefore(label, null);
|
||||
cursor.insertBefore(document.createTextNode('\u2060'), null); // Non-breaking space
|
||||
|
||||
caretElement.insertBefore(labelElement, null);
|
||||
|
||||
cursorElement.insertBefore(document.createTextNode('\u2060'), null); // Non-breaking space
|
||||
cursorElement.insertBefore(caretElement, null);
|
||||
cursorElement.insertBefore(document.createTextNode('\u2060'), null); // Non-breaking space
|
||||
|
||||
return cursorElement;
|
||||
return cursor;
|
||||
},
|
||||
showCursorLabels: showCursorLabels as 'always' | 'activity',
|
||||
showCursorLabels: 'activity',
|
||||
},
|
||||
dictionary: locales[lang as keyof typeof locales] as Dictionary,
|
||||
uploadFile,
|
||||
schema: blockNoteSchema,
|
||||
},
|
||||
[collabName, lang, provider, uploadFile],
|
||||
);
|
||||
@@ -137,12 +231,10 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
|
||||
<BlockNoteView
|
||||
editor={editor}
|
||||
formattingToolbar={false}
|
||||
slashMenu={false}
|
||||
editable={!readOnly}
|
||||
theme="light"
|
||||
>
|
||||
<BlockNoteToolbar />
|
||||
<BlockNoteSuggestionMenu />
|
||||
</BlockNoteView>
|
||||
</Box>
|
||||
);
|
||||
@@ -167,7 +259,6 @@ export const BlockNoteEditorVersion = ({
|
||||
},
|
||||
provider: undefined,
|
||||
},
|
||||
schema: blockNoteSchema,
|
||||
},
|
||||
[initialContent],
|
||||
);
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
import { combineByGroup, filterSuggestionItems } from '@blocknote/core';
|
||||
import '@blocknote/mantine/style.css';
|
||||
import {
|
||||
SuggestionMenuController,
|
||||
getDefaultReactSlashMenuItems,
|
||||
getPageBreakReactSlashMenuItems,
|
||||
useBlockNoteEditor,
|
||||
} from '@blocknote/react';
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
import { DocsBlockNoteEditor } from '../types';
|
||||
|
||||
export const BlockNoteSuggestionMenu = () => {
|
||||
const editor = useBlockNoteEditor() as DocsBlockNoteEditor;
|
||||
|
||||
const getSlashMenuItems = useMemo(() => {
|
||||
return async (query: string) =>
|
||||
Promise.resolve(
|
||||
filterSuggestionItems(
|
||||
combineByGroup(
|
||||
getDefaultReactSlashMenuItems(editor),
|
||||
getPageBreakReactSlashMenuItems(editor),
|
||||
),
|
||||
query,
|
||||
),
|
||||
);
|
||||
}, [editor]);
|
||||
|
||||
return (
|
||||
<SuggestionMenuController
|
||||
triggerCharacter="/"
|
||||
getItems={getSlashMenuItems}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -65,7 +65,7 @@ export const DocEditor = ({ doc, versionId }: DocEditorProps) => {
|
||||
$css="overflow-x: clip; flex: 1;"
|
||||
$position="relative"
|
||||
>
|
||||
<Box $css="flex:1;" $position="relative" $width="100%">
|
||||
<Box $css="flex:1;" $overflow="auto" $position="relative">
|
||||
{isVersion ? (
|
||||
<DocVersionEditor docId={doc.id} versionId={versionId} />
|
||||
) : (
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { BlockNoteEditor } from '@blocknote/core';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { useHeadingStore } from '../stores';
|
||||
import { DocsBlockNoteEditor } from '../types';
|
||||
|
||||
export const useHeadings = (editor: DocsBlockNoteEditor) => {
|
||||
export const useHeadings = (editor: BlockNoteEditor) => {
|
||||
const { setHeadings, resetHeadings } = useHeadingStore();
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { BlockNoteEditor } from '@blocknote/core';
|
||||
import { create } from 'zustand';
|
||||
|
||||
import { DocsBlockNoteEditor } from '../types';
|
||||
|
||||
export interface UseEditorstore {
|
||||
editor?: DocsBlockNoteEditor;
|
||||
setEditor: (editor: DocsBlockNoteEditor | undefined) => void;
|
||||
editor?: BlockNoteEditor;
|
||||
setEditor: (editor: BlockNoteEditor | undefined) => void;
|
||||
}
|
||||
|
||||
export const useEditorStore = create<UseEditorstore>((set) => ({
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { BlockNoteEditor } from '@blocknote/core';
|
||||
import { create } from 'zustand';
|
||||
|
||||
import { DocsBlockNoteEditor, HeadingBlock } from '../types';
|
||||
import { HeadingBlock } from '../types';
|
||||
|
||||
const recursiveTextContent = (content: HeadingBlock['content']): string => {
|
||||
if (!content) {
|
||||
@@ -20,7 +21,7 @@ const recursiveTextContent = (content: HeadingBlock['content']): string => {
|
||||
|
||||
export interface UseHeadingStore {
|
||||
headings: HeadingBlock[];
|
||||
setHeadings: (editor: DocsBlockNoteEditor) => void;
|
||||
setHeadings: (editor: BlockNoteEditor) => void;
|
||||
resetHeadings: () => void;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
import { css } from 'styled-components';
|
||||
|
||||
export const cssEditor = (readonly: boolean) => css`
|
||||
&,
|
||||
& > .bn-container,
|
||||
& .ProseMirror {
|
||||
height: 100%;
|
||||
|
||||
.collaboration-cursor-custom__base {
|
||||
position: relative;
|
||||
}
|
||||
.collaboration-cursor-custom__caret {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 2px;
|
||||
bottom: 4%;
|
||||
left: -1px;
|
||||
}
|
||||
.collaboration-cursor-custom__label {
|
||||
color: #0d0d0d;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
position: absolute;
|
||||
top: -17px;
|
||||
padding: 0px 6px;
|
||||
border-radius: 0px;
|
||||
white-space: nowrap;
|
||||
transition: clip-path 0.3s ease-in-out;
|
||||
border-radius: 4px 4px 4px 0;
|
||||
box-shadow: inset -2px 2px 6px #ffffff00;
|
||||
clip-path: polygon(0 85%, 4% 85%, 4% 100%, 0% 100%);
|
||||
}
|
||||
.collaboration-cursor-custom__base[data-active]
|
||||
.collaboration-cursor-custom__label {
|
||||
pointer-events: none;
|
||||
box-shadow: inset -2px 2px 6px #ffffff88;
|
||||
clip-path: polygon(0 0, 100% 0%, 100% 100%, 0% 100%);
|
||||
}
|
||||
|
||||
.bn-side-menu[data-block-type='heading'][data-level='1'] {
|
||||
height: 50px;
|
||||
}
|
||||
.bn-side-menu[data-block-type='heading'][data-level='2'] {
|
||||
height: 43px;
|
||||
}
|
||||
.bn-side-menu[data-block-type='heading'][data-level='3'] {
|
||||
height: 35px;
|
||||
}
|
||||
h1 {
|
||||
font-size: 1.875rem;
|
||||
}
|
||||
h2 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
h3 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
a {
|
||||
color: var(--c--theme--colors--greyscale-500);
|
||||
cursor: pointer;
|
||||
}
|
||||
.bn-block-group
|
||||
.bn-block-group
|
||||
.bn-block-outer:not([data-prev-depth-changed]):before {
|
||||
border-left: none;
|
||||
}
|
||||
}
|
||||
|
||||
.bn-editor {
|
||||
color: var(--c--theme--colors--greyscale-700);
|
||||
}
|
||||
|
||||
.bn-block-outer:not(:first-child) {
|
||||
&:has(h1) {
|
||||
padding-top: 32px;
|
||||
}
|
||||
&:has(h2) {
|
||||
padding-top: 24px;
|
||||
}
|
||||
&:has(h3) {
|
||||
padding-top: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
& .bn-inline-content code {
|
||||
background-color: gainsboro;
|
||||
padding: 2px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
@media screen and (width <= 560px) {
|
||||
& .bn-editor {
|
||||
${readonly && `padding-left: 10px;`}
|
||||
}
|
||||
.bn-side-menu[data-block-type='heading'][data-level='1'] {
|
||||
height: 46px;
|
||||
}
|
||||
.bn-side-menu[data-block-type='heading'][data-level='2'] {
|
||||
height: 40px;
|
||||
}
|
||||
.bn-side-menu[data-block-type='heading'][data-level='3'] {
|
||||
height: 40px;
|
||||
}
|
||||
& .bn-editor h1 {
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
& .bn-editor h2 {
|
||||
font-size: 1.35rem;
|
||||
}
|
||||
& .bn-editor h3 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
.bn-block-content[data-is-empty-and-focused][data-content-type='paragraph']
|
||||
.bn-inline-content:has(> .ProseMirror-trailingBreak:only-child)::before {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -1,7 +1,3 @@
|
||||
import { BlockNoteEditor } from '@blocknote/core';
|
||||
|
||||
import { blockNoteSchema } from './components/BlockNoteEditor';
|
||||
|
||||
export interface DocAttachment {
|
||||
file: string;
|
||||
}
|
||||
@@ -16,9 +12,3 @@ export type HeadingBlock = {
|
||||
level: number;
|
||||
};
|
||||
};
|
||||
|
||||
export type DocsBlockNoteEditor = BlockNoteEditor<
|
||||
typeof blockNoteSchema.blockSchema,
|
||||
typeof blockNoteSchema.inlineContentSchema,
|
||||
typeof blockNoteSchema.styleSchema
|
||||
>;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
/* eslint-disable jsx-a11y/click-events-have-key-events */
|
||||
/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */
|
||||
import {
|
||||
Tooltip,
|
||||
VariantType,
|
||||
@@ -112,6 +114,7 @@ const DocTitleInput = ({ doc }: DocTitleProps) => {
|
||||
defaultValue={isUntitled ? undefined : titleDisplay}
|
||||
onKeyDownCapture={handleKeyDown}
|
||||
suppressContentEditableWarning={true}
|
||||
aria-label="doc title input"
|
||||
onBlurCapture={(event) =>
|
||||
handleTitleSubmit(event.target.textContent || '')
|
||||
}
|
||||
|
||||
@@ -98,61 +98,7 @@ export const ModalExport = ({ onClose, doc }: ModalExportProps) => {
|
||||
|
||||
const exporter = new PDFExporter(
|
||||
editor.schema,
|
||||
{
|
||||
...pdfDefaultSchemaMappings,
|
||||
blockMapping: {
|
||||
...pdfDefaultSchemaMappings.blockMapping,
|
||||
heading: (block, exporter) => {
|
||||
const PIXELS_PER_POINT = 0.75;
|
||||
const MERGE_RATIO = 7.5;
|
||||
const FONT_SIZE = 16;
|
||||
const fontSizeEM =
|
||||
block.props.level === 1
|
||||
? 2
|
||||
: block.props.level === 2
|
||||
? 1.5
|
||||
: 1.17;
|
||||
return (
|
||||
<Text
|
||||
style={{
|
||||
fontSize: fontSizeEM * FONT_SIZE * PIXELS_PER_POINT,
|
||||
fontWeight: 700,
|
||||
marginTop: `${fontSizeEM * MERGE_RATIO}px`,
|
||||
marginBottom: `${fontSizeEM * MERGE_RATIO}px`,
|
||||
}}
|
||||
>
|
||||
{exporter.transformInlineContent(block.content)}
|
||||
</Text>
|
||||
);
|
||||
},
|
||||
paragraph: (block, exporter) => {
|
||||
/**
|
||||
* Breakline in the editor are not rendered in the PDF
|
||||
* By adding a space if the block is empty we ensure that the block is rendered
|
||||
*/
|
||||
if (Array.isArray(block.content)) {
|
||||
block.content.forEach((content) => {
|
||||
if (content.type === 'text' && !content.text) {
|
||||
content.text = ' ';
|
||||
}
|
||||
});
|
||||
|
||||
if (!block.content.length) {
|
||||
block.content.push({
|
||||
styles: {},
|
||||
text: ' ',
|
||||
type: 'text',
|
||||
});
|
||||
}
|
||||
}
|
||||
return (
|
||||
<Text key={block.id}>
|
||||
{exporter.transformInlineContent(block.content)}
|
||||
</Text>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
pdfDefaultSchemaMappings,
|
||||
{
|
||||
resolveFileUrl: async (url) =>
|
||||
exportResolveFileUrl(url, defaultExporter.options.resolveFileUrl),
|
||||
|
||||
@@ -48,20 +48,10 @@ export interface Doc {
|
||||
abilities: {
|
||||
accesses_manage: boolean;
|
||||
accesses_view: boolean;
|
||||
ai_transform: boolean;
|
||||
ai_translate: boolean;
|
||||
attachment_upload: boolean;
|
||||
children_create: boolean;
|
||||
children_list: boolean;
|
||||
collaboration_auth: boolean;
|
||||
attachment_upload: true;
|
||||
destroy: boolean;
|
||||
favorite: boolean;
|
||||
invite_owner: boolean;
|
||||
link_configuration: boolean;
|
||||
media_auth: boolean;
|
||||
move: boolean;
|
||||
partial_update: boolean;
|
||||
restore: boolean;
|
||||
retrieve: boolean;
|
||||
update: boolean;
|
||||
versions_destroy: boolean;
|
||||
|
||||
@@ -51,7 +51,7 @@ export const DocSearchModal = ({ ...modalProps }: DocSearchModalProps) => {
|
||||
return {
|
||||
groupName: docs.length > 0 ? t('Select a document') : '',
|
||||
elements: search ? docs : [],
|
||||
//emptyString: t('No document found'),
|
||||
emptyString: t('No document found'),
|
||||
endActions: hasNextPage
|
||||
? [{ content: <InView onChange={() => void fetchNextPage()} /> }]
|
||||
: [],
|
||||
@@ -96,20 +96,6 @@ export const DocSearchModal = ({ ...modalProps }: DocSearchModalProps) => {
|
||||
renderElement={(doc) => <DocSearchItem doc={doc} />}
|
||||
/>
|
||||
)}
|
||||
{/* Message accessible pour les résultats vides */}
|
||||
{search && docsData.elements.length === 0 && (
|
||||
<p
|
||||
role="alert"
|
||||
aria-live="polite"
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
marginTop: '1rem',
|
||||
color: '#666',
|
||||
}}
|
||||
>
|
||||
{t('No document found')}
|
||||
</p>
|
||||
)}
|
||||
</Box>
|
||||
</QuickSearch>
|
||||
</Box>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { BlockNoteEditor } from '@blocknote/core';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { BoxButton, Text } from '@/components';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { DocsBlockNoteEditor } from '@/features/docs/doc-editor';
|
||||
import { useResponsiveStore } from '@/stores';
|
||||
|
||||
const leftPaddingMap: { [key: number]: string } = {
|
||||
@@ -17,7 +17,7 @@ export type HeadingsHighlight = {
|
||||
}[];
|
||||
|
||||
interface HeadingProps {
|
||||
editor: DocsBlockNoteEditor;
|
||||
editor: BlockNoteEditor;
|
||||
level: number;
|
||||
text: string;
|
||||
headingId: string;
|
||||
|
||||
@@ -49,6 +49,7 @@ export const DocsGridActions = ({
|
||||
callback: () => {
|
||||
openShareModal?.();
|
||||
},
|
||||
|
||||
testId: `docs-grid-actions-share-${doc.id}`,
|
||||
},
|
||||
|
||||
@@ -69,7 +70,6 @@ export const DocsGridActions = ({
|
||||
iconName="more_horiz"
|
||||
$theme="primary"
|
||||
$variation="600"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</DropdownMenu>
|
||||
|
||||
|
||||
@@ -54,9 +54,6 @@ export const DocsGridItem = ({ doc }: DocsGridItemProps) => {
|
||||
$css={css`
|
||||
flex: ${flexLeft};
|
||||
align-items: center;
|
||||
&:focus {
|
||||
outline: 2px solidrgb(33, 34, 82);
|
||||
}
|
||||
`}
|
||||
href={`/docs/${doc.id}`}
|
||||
>
|
||||
@@ -82,11 +79,7 @@ export const DocsGridItem = ({ doc }: DocsGridItemProps) => {
|
||||
>
|
||||
<Tooltip
|
||||
content={
|
||||
<Text
|
||||
id={`tooltip-access-${doc.id}`}
|
||||
$textAlign="center"
|
||||
$variation="000"
|
||||
>
|
||||
<Text $textAlign="center" $variation="000">
|
||||
{isPublic
|
||||
? t('Accessible to anyone')
|
||||
: t('Accessible to authenticated users')}
|
||||
@@ -94,17 +87,12 @@ export const DocsGridItem = ({ doc }: DocsGridItemProps) => {
|
||||
}
|
||||
placement="top"
|
||||
>
|
||||
<div
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-labelledby={`tooltip-access-${doc.id}`}
|
||||
>
|
||||
<div>
|
||||
<Icon
|
||||
$theme="greyscale"
|
||||
$variation="600"
|
||||
$size="14px"
|
||||
iconName={isPublic ? 'public' : 'vpn_lock'}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
|
||||
@@ -9,7 +9,6 @@ type Props = {
|
||||
doc: Doc;
|
||||
handleClick: () => void;
|
||||
};
|
||||
|
||||
export const DocsGridItemSharedButton = ({ doc, handleClick }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const sharedCount = doc.nb_accesses;
|
||||
@@ -19,15 +18,11 @@ export const DocsGridItemSharedButton = ({ doc, handleClick }: Props) => {
|
||||
return <Box $minWidth="50px"> </Box>;
|
||||
}
|
||||
|
||||
const tooltipContent = t('Shared with {{count}} users', {
|
||||
count: sharedCount,
|
||||
});
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
content={
|
||||
<Text $variation="000" $textAlign="center">
|
||||
{tooltipContent}
|
||||
<Text $textAlign="center" $variation="000">
|
||||
{t('Shared with {{count}} users', { count: sharedCount })}
|
||||
</Text>
|
||||
}
|
||||
placement="top"
|
||||
@@ -41,14 +36,8 @@ export const DocsGridItemSharedButton = ({ doc, handleClick }: Props) => {
|
||||
}}
|
||||
color="tertiary"
|
||||
size="nano"
|
||||
aria-label={tooltipContent} // Lecture directe pour les lecteurs d'écran
|
||||
icon={<Icon $variation="800" $theme="primary" iconName="group" />}
|
||||
>
|
||||
<Icon
|
||||
$variation="800"
|
||||
$theme="primary"
|
||||
iconName="group"
|
||||
aria-hidden="true" // Empêche la lecture de l'icône
|
||||
/>
|
||||
{sharedCount}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
||||
@@ -47,9 +47,9 @@ export const SimpleDocItem = ({
|
||||
`}
|
||||
>
|
||||
{isPinned ? (
|
||||
<PinnedDocumentIcon aria-label={t('Pinned document.')} />
|
||||
<PinnedDocumentIcon aria-label={t('Pin document icon')} />
|
||||
) : (
|
||||
<SimpleFileIcon aria-label="" />
|
||||
<SimpleFileIcon aria-label={t('Simple document icon')} />
|
||||
)}
|
||||
</Box>
|
||||
<Box $justify="center">
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import Image from 'next/image';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { css } from 'styled-components';
|
||||
|
||||
import IconDocs from '@/assets/icons/icon-docs.svg';
|
||||
import { default as IconDocs } from '@/assets/icons/icon-docs.svg?url';
|
||||
import { Box, StyledLink } from '@/components/';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { ButtonLogin } from '@/features/auth';
|
||||
@@ -50,7 +51,7 @@ export const Header = () => {
|
||||
$height="fit-content"
|
||||
$margin={{ top: 'auto' }}
|
||||
>
|
||||
<IconDocs aria-label={t('Docs Logo')} width={25} />
|
||||
<Image priority src={IconDocs} alt={t('Docs Logo')} width={25} />
|
||||
<Title />
|
||||
</Box>
|
||||
</StyledLink>
|
||||
|
||||
|
Before Width: | Height: | Size: 401 KiB After Width: | Height: | Size: 342 KiB |
|
Before Width: | Height: | Size: 410 KiB After Width: | Height: | Size: 336 KiB |
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 112 KiB |
|
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 114 KiB |
|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 407 KiB After Width: | Height: | Size: 185 KiB |
@@ -1,26 +0,0 @@
|
||||
<svg
|
||||
width="24"
|
||||
height="25"
|
||||
viewBox="0 0 24 25"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g clip-path="url(#clip0_7060_4428)">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M12 0.0153809C5.37 0.0153809 0 5.38538 0 12.0154C0 17.3254 3.435 21.8104 8.205 23.4004C8.805 23.5054 9.03 23.1454 9.03 22.8304C9.03 22.5454 9.015 21.6004 9.015 20.5954C6 21.1504 5.22 19.8604 4.98 19.1854C4.845 18.8404 4.26 17.7754 3.75 17.4904C3.33 17.2654 2.73 16.7104 3.735 16.6954C4.68 16.6804 5.355 17.5654 5.58 17.9254C6.66 19.7404 8.385 19.2304 9.075 18.9154C9.18 18.1354 9.495 17.6104 9.84 17.3104C7.17 17.0104 4.38 15.9754 4.38 11.3854C4.38 10.0804 4.845 9.00038 5.61 8.16038C5.49 7.86038 5.07 6.63038 5.73 4.98038C5.73 4.98038 6.735 4.66538 9.03 6.21038C9.99 5.94038 11.01 5.80538 12.03 5.80538C13.05 5.80538 14.07 5.94038 15.03 6.21038C17.325 4.65038 18.33 4.98038 18.33 4.98038C18.99 6.63038 18.57 7.86038 18.45 8.16038C19.215 9.00038 19.68 10.0654 19.68 11.3854C19.68 15.9904 16.875 17.0104 14.205 17.3104C14.64 17.6854 15.015 18.4054 15.015 19.5304C15.015 21.1354 15 22.4254 15 22.8304C15 23.1454 15.225 23.5204 15.825 23.4004C20.565 21.8104 24 17.3104 24 12.0154C24 5.38538 18.63 0.0153809 12 0.0153809Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_7060_4428">
|
||||
<rect
|
||||
width="24"
|
||||
height="24"
|
||||
fill="white"
|
||||
transform="translate(0 0.0153809)"
|
||||
/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -1,4 +1,3 @@
|
||||
import { Button } from '@openfun/cunningham-react';
|
||||
import Image from 'next/image';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { css } from 'styled-components';
|
||||
@@ -11,7 +10,6 @@ import { Title } from '@/features/header';
|
||||
import { useResponsiveStore } from '@/stores';
|
||||
|
||||
import SC5 from '../assets/SC5.png';
|
||||
import GithubIcon from '../assets/github.svg';
|
||||
|
||||
import { HomeSection } from './HomeSection';
|
||||
|
||||
@@ -74,7 +72,7 @@ function HomeOpenSource() {
|
||||
</Text>
|
||||
<Text as="p" $display="inline">
|
||||
<Trans t={t} i18nKey="home-content-open-source-part2">
|
||||
You can easily self-hosted Docs (check our installation{' '}
|
||||
You can easily self-host Docs (check our installation{' '}
|
||||
<a
|
||||
href="https://github.com/suitenumerique/docs/tree/main/docs"
|
||||
target="_blank"
|
||||
@@ -116,27 +114,6 @@ function HomeOpenSource() {
|
||||
are interested in using or contributing to docs.
|
||||
</Trans>
|
||||
</Text>
|
||||
<Box $direction="row" $gap="1rem" $margin={{ top: 'small' }}>
|
||||
<Button
|
||||
icon={
|
||||
<Text $isMaterialIcon $color="white">
|
||||
chat
|
||||
</Text>
|
||||
}
|
||||
href="https://matrix.to/#/#docs-official:matrix.org"
|
||||
target="_blank"
|
||||
>
|
||||
<Text $color="white">Matrix</Text>
|
||||
</Button>
|
||||
<Button
|
||||
color="secondary"
|
||||
icon={<GithubIcon />}
|
||||
href="https://github.com/suitenumerique/docs"
|
||||
target="_blank"
|
||||
>
|
||||
Github
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Image from 'next/image';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import IconDocs from '@/assets/icons/icon-docs.svg';
|
||||
import { default as IconDocs } from '@/assets/icons/icon-docs.svg?url';
|
||||
import { Box } from '@/components';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { ButtonTogglePanel, Title } from '@/features/header/';
|
||||
@@ -61,7 +61,7 @@ export const HomeHeader = () => {
|
||||
$position="relative"
|
||||
$height="fit-content"
|
||||
>
|
||||
<IconDocs aria-label={t('Docs Logo')} width={32} />
|
||||
<Image priority src={IconDocs} alt={t('Docs Logo')} width={32} />
|
||||
<Title />
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@@ -175,7 +175,7 @@ export const HomeSection = ({
|
||||
height: 'fit-content',
|
||||
margin: 'auto',
|
||||
overflow: 'auto',
|
||||
flexBasis: direction === 'column' ? 'fit-content' : '50%',
|
||||
flexBasis: direction === 'column' ? '100%' : '50%',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -54,7 +54,6 @@ export const LanguagePicker = () => {
|
||||
$theme="primary"
|
||||
$weight="bold"
|
||||
$variation="800"
|
||||
aria-hidden="true"
|
||||
>
|
||||
translate
|
||||
</Text>
|
||||
|
||||
@@ -52,7 +52,6 @@ export const LeftPanelTargetFilters = () => {
|
||||
|
||||
return (
|
||||
<Box
|
||||
role="tablist"
|
||||
$justify="center"
|
||||
$padding={{ horizontal: 'sm' }}
|
||||
$gap={spacing['2xs']}
|
||||
@@ -62,7 +61,7 @@ export const LeftPanelTargetFilters = () => {
|
||||
|
||||
return (
|
||||
<BoxButton
|
||||
role="tab"
|
||||
aria-label={query.label}
|
||||
key={query.label}
|
||||
onClick={() => onSelectQuery(query.targetQuery)}
|
||||
$direction="row"
|
||||
@@ -86,7 +85,6 @@ export const LeftPanelTargetFilters = () => {
|
||||
<Icon
|
||||
$variation={isActive ? '1000' : '700'}
|
||||
iconName={query.icon}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<Text $variation={isActive ? '1000' : '700'} $size="sm">
|
||||
{query.label}
|
||||
|
||||
@@ -50,11 +50,8 @@ export const LeftPanelHeader = ({ children }: PropsWithChildren) => {
|
||||
onClick={goToHome}
|
||||
size="medium"
|
||||
color="tertiary-text"
|
||||
aria-label={t('Back to home page')}
|
||||
icon={
|
||||
<span aria-hidden="true">
|
||||
<Icon $variation="800" $theme="primary" iconName="house" />
|
||||
</span>
|
||||
<Icon $variation="800" $theme="primary" iconName="house" />
|
||||
}
|
||||
/>
|
||||
{authenticated && (
|
||||
@@ -62,15 +59,8 @@ export const LeftPanelHeader = ({ children }: PropsWithChildren) => {
|
||||
onClick={searchModal.open}
|
||||
size="medium"
|
||||
color="tertiary-text"
|
||||
aria-label={t('Search')}
|
||||
icon={
|
||||
<span aria-hidden="true">
|
||||
<Icon
|
||||
$variation="800"
|
||||
$theme="primary"
|
||||
iconName="search"
|
||||
/>
|
||||
</span>
|
||||
<Icon $variation="800" $theme="primary" iconName="search" />
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -195,20 +195,10 @@ export class ApiPlugin implements WorkboxPlugin {
|
||||
abilities: {
|
||||
accesses_manage: true,
|
||||
accesses_view: true,
|
||||
ai_transform: true,
|
||||
ai_translate: true,
|
||||
attachment_upload: true,
|
||||
children_create: true,
|
||||
children_list: true,
|
||||
collaboration_auth: true,
|
||||
destroy: true,
|
||||
favorite: true,
|
||||
invite_owner: true,
|
||||
link_configuration: true,
|
||||
media_auth: true,
|
||||
move: true,
|
||||
partial_update: true,
|
||||
restore: true,
|
||||
retrieve: true,
|
||||
update: true,
|
||||
versions_destroy: true,
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
"AI seems busy! Please try again.": "KI scheint beschäftigt! Bitte versuchen Sie es erneut.",
|
||||
"Accessibility": "Barrierefreiheit",
|
||||
"Accessibility statement": "Erklärung zur Barrierefreiheit",
|
||||
"Accessible to anyone": "Für jeden zugänglich",
|
||||
"Accessible to authenticated users": "Für authentifizierte Benutzer zugänglich",
|
||||
"Add": "Hinzufügen",
|
||||
"Address:": "Anschrift:",
|
||||
"All docs": "Alle Dokumente",
|
||||
@@ -94,7 +92,6 @@
|
||||
"Pending invitations": "Ausstehende Einladungen",
|
||||
"Personal data and cookies": "Personenbezogene Daten und Cookies",
|
||||
"Pin": "Anheften",
|
||||
"Pinned document.": "Angeheftetes Dokument",
|
||||
"Pinned documents": "Angepinnte Dokumente",
|
||||
"Private": "Privat",
|
||||
"Public": "Öffentlich",
|
||||
@@ -121,7 +118,6 @@
|
||||
"Share with {{count}} users_many": "Teilen mit {{count}} Benutzern",
|
||||
"Share with {{count}} users_one": "Teilen mit {{count}} Benutzern",
|
||||
"Share with {{count}} users_other": "Teilen mit {{count}} Benutzern",
|
||||
"Shared with {{count}} users": "Mit {{count}} Benutzern geteilt",
|
||||
"Shared with me": "Mit mir geteilt",
|
||||
"Something bad happens, please retry.": "Etwas ist schiefgelaufen, bitte versuchen Sie es erneut.",
|
||||
"Stéphanie Schaer: Interministerial Digital Director (DINUM).": "Stéphanie Schaer: Interministerielle Digitaldirektorin (DINUM).",
|
||||
@@ -137,7 +133,6 @@
|
||||
"This site places a small text file (a \"cookie\") on your computer when you visit it.": "Diese Website platziert beim Besuch auf Ihrem Computer eine kleine Textdatei (ein \"Cookie\").",
|
||||
"This will protect your privacy, but will also prevent the owner from learning from your actions and creating a better experience for you and other users.": "Dies schützt Ihre Privatsphäre, verhindert jedoch auch, dass der Eigentümer aus Ihren Aktionen lernt und eine bessere Erfahrung für Sie und andere Benutzer schafft.",
|
||||
"Too many requests. Please wait 60 seconds.": "Zu viele Anfragen. Bitte warten Sie 60 Sekunden.",
|
||||
"Translate": "Übersetzen",
|
||||
"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",
|
||||
"Unless otherwise stated, all content on this site is under": "Sofern nicht anders angegeben, steht der gesamte Inhalt dieser Website unter",
|
||||
@@ -172,7 +167,6 @@
|
||||
"translation": {
|
||||
"\"{{email}}\" is already invited to the document.": "\"{{email}}\" est déjà invité à accéder au document.",
|
||||
"\"{{email}}\" is already member of the document.": "\"{{email}}\" est déjà membre du document.",
|
||||
"A new way to organize knowledge.": "Une nouvelle façon d’organiser les connaissances.",
|
||||
"AI Actions": "Actions IA",
|
||||
"AI seems busy! Please try again.": "L'IA semble occupée ! Veuillez réessayer.",
|
||||
"Accessibility": "Accessibilité",
|
||||
@@ -183,22 +177,16 @@
|
||||
"Address:": "Adresse :",
|
||||
"Administrator": "Administrateur",
|
||||
"All docs": "Tous les documents",
|
||||
"An uncompromising writing experience.": "Une expérience d'écriture sans compromis.",
|
||||
"Anonymous": "Anonyme",
|
||||
"Anyone with the link can edit the document": "N'importe qui avec le lien peut éditer le document",
|
||||
"Anyone with the link can edit the document if they are logged in": "N'importe qui avec le lien peut éditer le document à condition qu'il soit connecté",
|
||||
"Anyone with the link can see the document": "N'importe qui avec le lien peut voir le document",
|
||||
"Anyone with the link can view the document if they are logged in": "N'importe qui avec le lien peut voir le document à condition qu'il soit connecté",
|
||||
"Are you sure you want to delete the document \"{{title}}\"?": "Êtes-vous sûr de vouloir supprimer le document \"{{title}}\" ?",
|
||||
"Available soon": "Disponible prochainement",
|
||||
"Back to home page": "Retour à l'accueil",
|
||||
"Banner image": "Image de la bannière",
|
||||
"Can't load this page, please check your internet connection.": "Impossible de charger cette page, veuillez vérifier votre connexion Internet.",
|
||||
"Cancel": "Annuler",
|
||||
"Close the modal": "Fermer la modale",
|
||||
"Collaborate": "Collaborer",
|
||||
"Collaborate and write in real time, without layout constraints.": "Collaborez et rédigez en temps réel, sans contrainte de mise en page.",
|
||||
"Collaborative writing, Simplified.": "L'écriture collaborative simplifiée.",
|
||||
"Compliance status": "État de conformité",
|
||||
"Confirm deletion": "Confirmer la suppression",
|
||||
"Connected": "Connecté",
|
||||
@@ -218,10 +206,6 @@
|
||||
"Doc visibility card": "Carte de visibilité du doc",
|
||||
"Docs": "Docs",
|
||||
"Docs Logo": "Logo Docs",
|
||||
"Docs is already available, log in to use it now.": "Docs est déjà disponible, connectez-vous pour l’utiliser dès maintenant.",
|
||||
"Docs makes real-time collaboration simple. Invite collaborators - public officials or external partners - with one click to see their changes live, while maintaining precise access control for data security.": "Docs simplifie la collaboration en temps réel. Invitez des collaborateurs - agents publics ou partenaires externes - d'un clic pour voir leurs modifications en direct, tout en gardant un contrôle précis des accès pour la sécurité des données.",
|
||||
"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 propose une expérience d'écriture intuitive. Son interface minimaliste privilégie le contenu sur la mise en page, tout en offrant l'essentiel : import de médias, mode hors-ligne et raccourcis clavier pour plus d'efficacité.",
|
||||
"Docs transforms your documents into knowledge bases thanks to subpages, powerful search and the ability to pin your important documents.": "Docs transforme vos documents en bases de connaissances grâce aux sous-pages, une recherche performante et la possibilité d'épingler vos documents importants.",
|
||||
"Docs: Your new companion to collaborate on documents efficiently, intuitively, and securely.": "Docs : Votre nouveau compagnon pour collaborer sur des documents efficacement, intuitivement et en toute sécurité.",
|
||||
"Document owner": "Propriétaire du document",
|
||||
"Document title updated successfully": "Titre du document mis à jour avec succès",
|
||||
@@ -243,14 +227,11 @@
|
||||
"Failed to copy link": "Échec de la copie du lien",
|
||||
"Failed to copy to clipboard": "Échec de la copie dans le presse-papier",
|
||||
"Failed to create the invitation for {{email}}.": "Impossible de créer l'invitation pour {{email}}.",
|
||||
"Flexible export.": "Un export flexible.",
|
||||
"Format": "Format",
|
||||
"French Interministerial Directorate for Digital Affairs (DINUM), 20 avenue de Ségur 75007 Paris.": "Direction interministérielle des affaires numériques (DINUM), 20 avenue de Segur 75007 Paris.",
|
||||
"Govs ❤️ Open Source.": "Gouvs ❤️ Open Source.",
|
||||
"History": "Historique",
|
||||
"If a member is editing, his works can be lost.": "Si un membre est en train d'éditer, ses travaux peuvent être perdus.",
|
||||
"If you are unable to access a content or a service, you can contact the person responsible for https://lasuite.numerique.gouv.fr to be directed to an accessible alternative or to obtain the content in another form.": "Si vous ne pouvez pas accéder à un contenu ou à un service, vous pouvez contacter la personne responsable de https://lasuite. umerique.gouv.fr pour être dirigé vers une alternative accessible ou pour obtenir le contenu sous une autre forme.",
|
||||
"Illustration": "Image",
|
||||
"Illustration:": "Illustration :",
|
||||
"Improvement and contact": "Amélioration et contact",
|
||||
"Invite": "Inviter",
|
||||
@@ -260,7 +241,7 @@
|
||||
"It's true, you didn't have to click on a block that covers half the page to say you agree to the placement of cookies — even if you don't know what it means!": "C'est vrai, vous n'avez pas à cliquer sur un bloc qui couvre la moitié de la page pour dire que vous acceptez le placement de cookies — même si vous ne savez pas ce que cela signifie !",
|
||||
"Language": "Langue",
|
||||
"Last update: {{update}}": "Dernière mise à jour : {{update}}",
|
||||
"Legal Notice": "Mentions Légales",
|
||||
"Legal Notice": "Mentions Legales",
|
||||
"Legal notice": "Mention légale",
|
||||
"Link Copied !": "Lien copié !",
|
||||
"Link parameters": "Paramètres du lien",
|
||||
@@ -283,10 +264,8 @@
|
||||
"OK": "OK",
|
||||
"Offline ?!": "Hors-ligne ?!",
|
||||
"Only invited people can access": "Seules les personnes invitées peuvent accéder",
|
||||
"Open Source": "Open Source",
|
||||
"Open the document options": "Ouvrir les options du document",
|
||||
"Open the header menu": "Ouvrir le menu d'en-tête",
|
||||
"Organize": "Organiser",
|
||||
"Ouch !": "Aïe !",
|
||||
"Owner": "Propriétaire",
|
||||
"PDF": "PDF",
|
||||
@@ -294,18 +273,15 @@
|
||||
"Personal data and cookies": "Données personnelles et cookies",
|
||||
"Pin": "Épingler",
|
||||
"Pin document icon": "Icône épingler un document",
|
||||
"Pinned document.": "Document épinglé",
|
||||
"Pinned documents": "Documents épinglés",
|
||||
"Private": "Privé",
|
||||
"ProConnect Image": "Image ProConnect",
|
||||
"Proconnect Login": "Login Proconnect",
|
||||
"Public": "Public",
|
||||
"Public document": "Document public",
|
||||
"Publication Director": "Directeur de la publication",
|
||||
"Publisher": "Éditeur",
|
||||
"Quick search input": "Saisie de recherche rapide",
|
||||
"Reader": "Lecteur",
|
||||
"Reading": "Lecture seule",
|
||||
"Reading": "Lecture seul",
|
||||
"Remedies": "Voie de recours",
|
||||
"Remove": "Supprimer",
|
||||
"Rename": "Renommer",
|
||||
@@ -323,16 +299,12 @@
|
||||
"Share with {{count}} users_many": "Partager avec {{count}} utilisateurs",
|
||||
"Share with {{count}} users_one": "Partager avec {{count}} utilisateur",
|
||||
"Share with {{count}} users_other": "Partager avec {{count}} utilisateurs",
|
||||
"Shared with {{count}} users": "Partagé avec {{count}} utilisateurs",
|
||||
"Shared with me": "Partagés avec moi",
|
||||
"Shared with {{count}} users_many": "Partager avec {{count}} utilisateurs",
|
||||
"Shared with {{count}} users_one": "Partager avec {{count}} utilisateur",
|
||||
"Shared with {{count}} users_other": "Partager avec {{count}} utilisateurs",
|
||||
"Show more": "Voir plus",
|
||||
"Simple and secure collaboration.": "Une collaboration simple et sécurisée.",
|
||||
"Simple document icon": "Icône simple du document",
|
||||
"Something bad happens, please retry.": "Une erreur inattendue s'est produite, veuillez réessayer.",
|
||||
"Start Writing": "Commencer à écrire",
|
||||
"Stéphanie Schaer: Interministerial Digital Director (DINUM).": "Stéphanie Schaer: Directrice numérique interministériel (DINUM).",
|
||||
"Summarize": "Résumer",
|
||||
"Summary": "Sommaire",
|
||||
@@ -347,9 +319,7 @@
|
||||
"This site does not display a cookie consent banner, why?": "Ce site n'affiche pas de bannière de consentement des cookies, pourquoi?",
|
||||
"This site places a small text file (a \"cookie\") on your computer when you visit it.": "Ce site place un petit fichier texte (un « cookie ») sur votre ordinateur lorsque vous le visitez.",
|
||||
"This will protect your privacy, but will also prevent the owner from learning from your actions and creating a better experience for you and other users.": "Cela protégera votre vie privée, mais empêchera également le propriétaire d'apprendre de vos actions et de créer une meilleure expérience pour vous et les autres utilisateurs.",
|
||||
"To facilitate the circulation of documents, Docs allows you to export your content to the most common formats: PDF, Word or OpenDocument.": "Pour faciliter la circulation des documents, Docs permet d'exporter vos contenus vers les formats les plus courants : PDF, Word ou OpenDocument.",
|
||||
"Too many requests. Please wait 60 seconds.": "Trop de demandes. Veuillez patienter 60 secondes.",
|
||||
"Translate": "Traduire",
|
||||
"Type a name or email": "Tapez un nom ou un email",
|
||||
"Type the name of a document": "Tapez le nom d'un document",
|
||||
"Unless otherwise stated, all content on this site is under": "Sauf mention contraire, tout le contenu de ce site est sous",
|
||||
@@ -364,7 +334,6 @@
|
||||
"Warning": "Attention",
|
||||
"We simply comply with the law, which states that certain audience measurement tools, properly configured to respect privacy, are exempt from prior authorization.": "Nous nous conformons simplement à la loi, qui stipule que certains outils de mesure d’audience, correctement configurés pour respecter la vie privée, sont exemptés de toute autorisation préalable.",
|
||||
"We try to respond within 2 working days.": "Nous essayons de répondre dans les 2 jours ouvrables.",
|
||||
"Write": "Écrire",
|
||||
"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.": "Vous êtes le seul propriétaire de ce groupe, faites d'un autre membre le propriétaire du groupe, avant de pouvoir modifier votre propre rôle ou vous supprimer du document.",
|
||||
"You can oppose the tracking of your browsing on this website.": "Vous pouvez vous opposer au suivi de votre navigation sur ce site.",
|
||||
"You can:": "Vous pouvez:",
|
||||
@@ -376,9 +345,6 @@
|
||||
"accessibility-dinum-services": "<strong>DINUM</strong> s'engage à rendre accessibles ses services numériques, conformément à l'article 47 de la loi n° 2005-102 du 11 février 2005.",
|
||||
"accessibility-form-defenseurdesdroits": "Écrire un message au<1>Défenseur des droits</1>",
|
||||
"accessibility-not-audit": "<strong>docs.numerique.gouv.fr</strong> n'est pas en conformité avec le RGAA 4.1. Le site n'a <strong>pas encore été audité.</strong>",
|
||||
"home-content-open-source-part1": "Docs est construit sur <2>Django Rest Framework</2>, <5>Next.js</5>, et <8>MinIO</8>. Nous utilisons également <11>Yjs</11> et <15>BlockNote.js</15> dont nous sommes fiers sponsors.",
|
||||
"home-content-open-source-part2": "Vous pouvez facilement auto-héberger Docs (consultez notre <2>documentation</2> d'installation avec des exemples prêts pour la production).<br/>Docs utilise une <8>licence</8> adaptée à l'innovation et aux entreprises.<br/>Les contributions sont les bienvenues (consultez notre feuille de route <13>ici</13>).",
|
||||
"home-content-open-source-part3": "Docs est le résultat d'un effort conjoint mené par les gouvernements français 🇫🇷🥖 <1>(DINUM)</1> et allemand 🇩🇪🥨 <5>(ZenDiS)</5>. Nous sommes toujours à la recherche de nouveaux partenaires publics (nous embarquons actuellement les Pays-Bas 🇳🇱🧀). N'hésitez pas à nous contacter si vous souhaitez utiliser ou contribuer à Docs.",
|
||||
"you have reported to the website manager a lack of accessibility that prevents you from accessing content or one of the services of the portal and you have not received a satisfactory response.": "vous avez signalé au responsable du site internet un défaut d'accessibilité qui vous empêche d'accéder à un contenu ou à un des services du portail et vous n'avez pas obtenu de réponse satisfaisante."
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "impress",
|
||||
"version": "2.2.0",
|
||||
"version": "2.1.0",
|
||||
"private": true,
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "eslint-config-impress",
|
||||
"version": "2.2.0",
|
||||
"version": "2.1.0",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"lint": "eslint --ext .js ."
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "packages-i18n",
|
||||
"version": "2.2.0",
|
||||
"version": "2.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"extract-translation": "yarn extract-translation:impress",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "server-y-provider",
|
||||
"version": "2.2.0",
|
||||
"version": "2.1.0",
|
||||
"description": "Y.js provider for docs",
|
||||
"repository": "https://github.com/numerique-gouv/impress",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -3357,6 +3357,13 @@
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.20.13"
|
||||
|
||||
"@react-pdf/fns@3.1.0":
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-pdf/fns/-/fns-3.1.0.tgz#cc1130b35e21b173d1d0fa1729db3285d209a9ea"
|
||||
integrity sha512-BjT7C/IeYlrF4Pevlrlo+fILhSxsWSm6Ka/rQrQzYsyQuOsqI6bmBzsTW+T6ghqrD5HLRKr1n8vjAaE9g4rFhA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.20.13"
|
||||
|
||||
"@react-pdf/font@^3.0.1":
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@react-pdf/font/-/font-3.0.1.tgz#ea831f272e3b1418ffd2d9f70c835236e6564354"
|
||||
@@ -3367,6 +3374,16 @@
|
||||
fontkit "^2.0.2"
|
||||
is-url "^1.2.4"
|
||||
|
||||
"@react-pdf/font@^3.0.2":
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@react-pdf/font/-/font-3.0.2.tgz#b29b5e2e83c5ce515148b8f150ae3795492ff8e1"
|
||||
integrity sha512-5fGlAc8uC1ls+Atdc1J4EGcProH72lcE47TL2+EX54OgChl5m5H1+yrw/VufLd3Ua1e4YSvr53rYXVD2PUFzWA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.20.13"
|
||||
"@react-pdf/types" "^2.7.1"
|
||||
fontkit "^2.0.2"
|
||||
is-url "^1.2.4"
|
||||
|
||||
"@react-pdf/image@^3.0.1":
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@react-pdf/image/-/image-3.0.1.tgz#5c08a7ddf5d07c53ea3377348e7bb07d17efe7c2"
|
||||
@@ -3393,6 +3410,23 @@
|
||||
queue "^6.0.1"
|
||||
yoga-layout "^3.1.0"
|
||||
|
||||
"@react-pdf/layout@^4.2.2":
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/@react-pdf/layout/-/layout-4.2.2.tgz#19dd4fae3264801f943a15404d90c9cdebce2645"
|
||||
integrity sha512-PHX1yiRXF1nxtKtRgT7rKmA1D6QHaAaWfSQcCKumolsdD/KZnAX2jIRR6s8Sss03ak342K8gGs/udbZio17zhA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.20.13"
|
||||
"@react-pdf/fns" "3.1.0"
|
||||
"@react-pdf/image" "^3.0.1"
|
||||
"@react-pdf/pdfkit" "^4.0.1"
|
||||
"@react-pdf/primitives" "^4.1.0"
|
||||
"@react-pdf/stylesheet" "^5.2.2"
|
||||
"@react-pdf/textkit" "^5.0.2"
|
||||
"@react-pdf/types" "^2.7.1"
|
||||
emoji-regex "^10.3.0"
|
||||
queue "^6.0.1"
|
||||
yoga-layout "^3.2.1"
|
||||
|
||||
"@react-pdf/pdfkit@^4.0.0":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-pdf/pdfkit/-/pdfkit-4.0.0.tgz#8dbbfc8e546ebd0b76e88bd525fd6bec43c19df4"
|
||||
@@ -3406,6 +3440,20 @@
|
||||
jay-peg "^1.1.0"
|
||||
vite-compatible-readable-stream "^3.6.1"
|
||||
|
||||
"@react-pdf/pdfkit@^4.0.1":
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@react-pdf/pdfkit/-/pdfkit-4.0.1.tgz#ef7f20790a31ddc7a8e1a9104f5676e5456b2e26"
|
||||
integrity sha512-p76g0DQOG5t3yDymQYL4EHgbhTKvADTaK5J8DHNqhQGxwOi0qrkKbtfe21tgdzBm6xrTauoBp+teKtUn+jr/zA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.20.13"
|
||||
"@react-pdf/png-js" "^3.0.0"
|
||||
browserify-zlib "^0.2.0"
|
||||
crypto-js "^4.2.0"
|
||||
fontkit "^2.0.2"
|
||||
jay-peg "^1.1.1"
|
||||
linebreak "^1.1.0"
|
||||
vite-compatible-readable-stream "^3.6.1"
|
||||
|
||||
"@react-pdf/png-js@^3.0.0":
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-pdf/png-js/-/png-js-3.0.0.tgz#c0b7dc7c77e36f0830e9b7bccca7ddd64ada1c5e"
|
||||
@@ -3418,6 +3466,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@react-pdf/primitives/-/primitives-4.0.0.tgz#0a710664923547c315386e82a643e58008612844"
|
||||
integrity sha512-yp4E0rDL03NaUp/CnDBz3HQNfH2Mzdlgku57yhTMGNzetwB0NJusXcjYg5XsTGIXnR7Tv80JKI4O4ajj+oaLeQ==
|
||||
|
||||
"@react-pdf/primitives@^4.1.0":
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-pdf/primitives/-/primitives-4.1.0.tgz#85f389d40612b6bfa5e70d50eec0a7c09f0948f1"
|
||||
integrity sha512-ijzkIBdazFFiZFLWLPOK3wIqfJt276ZqvXgDkz+HTgT4hsRo+wOc8ykBoYfKUlAGnFVb/SOZaN3D2mSi4AM2AA==
|
||||
|
||||
"@react-pdf/reconciler@^1.1.3":
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/@react-pdf/reconciler/-/reconciler-1.1.3.tgz#6fbd0f601fcb4f7ff1ff7c4dcc4df6afbccd9129"
|
||||
@@ -3442,7 +3495,41 @@
|
||||
parse-svg-path "^0.1.2"
|
||||
svg-arc-to-cubic-bezier "^3.2.0"
|
||||
|
||||
"@react-pdf/renderer@4.1.6", "@react-pdf/renderer@^4.0.0":
|
||||
"@react-pdf/render@^4.1.1":
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@react-pdf/render/-/render-4.1.1.tgz#fd4152d8760146466ea0dd43a12e0e877744027f"
|
||||
integrity sha512-F20HpVxgd666yKenH0sfMD2VbH8A7PT7iFZsMseY9/PDWB+u4eEDOYwo/j1qfxKwLybKMsGKdNv7ohc0APkHaw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.20.13"
|
||||
"@react-pdf/fns" "3.1.0"
|
||||
"@react-pdf/primitives" "^4.1.0"
|
||||
"@react-pdf/textkit" "^5.0.2"
|
||||
"@react-pdf/types" "^2.7.1"
|
||||
abs-svg-path "^0.1.1"
|
||||
color-string "^1.9.1"
|
||||
normalize-svg-path "^1.1.0"
|
||||
parse-svg-path "^0.1.2"
|
||||
svg-arc-to-cubic-bezier "^3.2.0"
|
||||
|
||||
"@react-pdf/renderer@4.2.1":
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@react-pdf/renderer/-/renderer-4.2.1.tgz#9211d531579ff58965442abe452b3ffe84ddc46d"
|
||||
integrity sha512-rkwJSvkXGhDCkjWgomwsQZdLhIll1p2MBDwPdaqcprH+eZ4JVXoeJCw4rhDyY4NgyP+LaJuVzDTnFYlrIhs47A==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.20.13"
|
||||
"@react-pdf/font" "^3.0.2"
|
||||
"@react-pdf/layout" "^4.2.2"
|
||||
"@react-pdf/pdfkit" "^4.0.1"
|
||||
"@react-pdf/primitives" "^4.1.0"
|
||||
"@react-pdf/reconciler" "^1.1.3"
|
||||
"@react-pdf/render" "^4.1.1"
|
||||
"@react-pdf/types" "^2.7.1"
|
||||
events "^3.3.0"
|
||||
object-assign "^4.1.1"
|
||||
prop-types "^15.6.2"
|
||||
queue "^6.0.1"
|
||||
|
||||
"@react-pdf/renderer@^4.0.0":
|
||||
version "4.1.6"
|
||||
resolved "https://registry.yarnpkg.com/@react-pdf/renderer/-/renderer-4.1.6.tgz#257d4871192edb4d1716bc6399b5a7cf73ee3db3"
|
||||
integrity sha512-hfQ0PsuVqfoYxkYgmkj+HFkylbB1QTpXY1rnlgnzJlrlSoNXjzPrCa/ty8jcHOwYA2lNoazIAoDatBIsc8K5pw==
|
||||
@@ -3473,6 +3560,19 @@
|
||||
media-engine "^1.0.3"
|
||||
postcss-value-parser "^4.1.0"
|
||||
|
||||
"@react-pdf/stylesheet@^5.2.2":
|
||||
version "5.2.2"
|
||||
resolved "https://registry.yarnpkg.com/@react-pdf/stylesheet/-/stylesheet-5.2.2.tgz#6d5d2e0ea476bc508469eb4682d7f20b790b2b62"
|
||||
integrity sha512-oHP+hZakETrecnZCSRPqNvFhSyBgoZSDOkonY9WJOxRkUb6P6A+mAVSOWBaNt2eM4FHMDpYDeR9stx+gAWn6gg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.20.13"
|
||||
"@react-pdf/fns" "3.1.0"
|
||||
"@react-pdf/types" "^2.7.1"
|
||||
color-string "^1.9.1"
|
||||
hsl-to-hex "^1.0.0"
|
||||
media-engine "^1.0.3"
|
||||
postcss-value-parser "^4.1.0"
|
||||
|
||||
"@react-pdf/textkit@^5.0.1":
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@react-pdf/textkit/-/textkit-5.0.1.tgz#284e55ff016f46c8bf364aa1d7bcef772c913662"
|
||||
@@ -3484,11 +3584,27 @@
|
||||
hyphen "^1.6.4"
|
||||
unicode-properties "^1.4.1"
|
||||
|
||||
"@react-pdf/textkit@^5.0.2":
|
||||
version "5.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@react-pdf/textkit/-/textkit-5.0.2.tgz#ff8ee086bc81ef4c706e51f3eeb1219228c8266c"
|
||||
integrity sha512-vZoXznaZTQ/6ISpbCwAatZ6UNieUp12ByY4hlEXQ108VA3WDmcYm2usqk63LhZJiwE6ag+VyEus7R3CgDcxoMw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.20.13"
|
||||
"@react-pdf/fns" "3.1.0"
|
||||
bidi-js "^1.0.2"
|
||||
hyphen "^1.6.4"
|
||||
unicode-properties "^1.4.1"
|
||||
|
||||
"@react-pdf/types@^2.7.0":
|
||||
version "2.7.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-pdf/types/-/types-2.7.0.tgz#56a0232ce420c313fe67cef193cbf57870a01477"
|
||||
integrity sha512-7KrPPCpgRPKR+g+T127PE4bpw9Q84ZiY07EYRwXKVtTEVW9wJ5BZiF9smT9IvH19s+MQaDLmYRgjESsnqlyH0Q==
|
||||
|
||||
"@react-pdf/types@^2.7.1":
|
||||
version "2.7.1"
|
||||
resolved "https://registry.yarnpkg.com/@react-pdf/types/-/types-2.7.1.tgz#eb9f70be66b42c47f60c5afcc0af044ac48b98bf"
|
||||
integrity sha512-MyjR1u+6SclQ/Tx6NP3/yoYZw7reXgC4OHFOrdMh/zeZ+ezfdGyovB+jdmVQuMe7Fsh64v7PUkO5tnsXHyCFWQ==
|
||||
|
||||
"@react-stately/autocomplete@3.0.0-alpha.0":
|
||||
version "3.0.0-alpha.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-stately/autocomplete/-/autocomplete-3.0.0-alpha.0.tgz#3b80c82ba50d682dbbdd2f1f2c8b6ecc059f8afc"
|
||||
@@ -5993,6 +6109,11 @@ bare-events@^2.2.0:
|
||||
resolved "https://registry.yarnpkg.com/bare-events/-/bare-events-2.5.4.tgz#16143d435e1ed9eafd1ab85f12b89b3357a41745"
|
||||
integrity sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==
|
||||
|
||||
base64-js@0.0.8:
|
||||
version "0.0.8"
|
||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.8.tgz#1101e9544f4a76b1bc3b26d452ca96d7a35e7978"
|
||||
integrity sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==
|
||||
|
||||
base64-js@^1.1.2, base64-js@^1.3.0, base64-js@^1.3.1:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
||||
@@ -9266,7 +9387,7 @@ jake@^10.8.5:
|
||||
filelist "^1.0.4"
|
||||
minimatch "^3.1.2"
|
||||
|
||||
jay-peg@^1.1.0:
|
||||
jay-peg@^1.1.0, jay-peg@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/jay-peg/-/jay-peg-1.1.1.tgz#fdf410b89fa7a295bf74424ffe4c9083dbe7c363"
|
||||
integrity sha512-D62KEuBxz/ip2gQKOEhk/mx14o7eiFRaU+VNNSP4MOiIkwb/D6B3G1Mfas7C/Fit8EsSV2/IWjZElx/Gs6A4ww==
|
||||
@@ -9909,6 +10030,14 @@ lilconfig@^3.1.2:
|
||||
resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.3.tgz#a1bcfd6257f9585bf5ae14ceeebb7b559025e4c4"
|
||||
integrity sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==
|
||||
|
||||
linebreak@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/linebreak/-/linebreak-1.1.0.tgz#831cf378d98bced381d8ab118f852bd50d81e46b"
|
||||
integrity sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==
|
||||
dependencies:
|
||||
base64-js "0.0.8"
|
||||
unicode-trie "^2.0.0"
|
||||
|
||||
lines-and-columns@^1.1.6:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
|
||||
@@ -14650,7 +14779,7 @@ yocto-queue@^0.1.0:
|
||||
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
|
||||
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
|
||||
|
||||
yoga-layout@^3.1.0:
|
||||
yoga-layout@^3.1.0, yoga-layout@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/yoga-layout/-/yoga-layout-3.2.1.tgz#d2d1ba06f0e81c2eb650c3e5ad8b0b4adde1e843"
|
||||
integrity sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==
|
||||
|
||||
@@ -93,4 +93,4 @@ releases:
|
||||
environments:
|
||||
dev:
|
||||
values:
|
||||
- version: 2.2.0
|
||||
- version: 2.1.0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
apiVersion: v2
|
||||
type: application
|
||||
name: docs
|
||||
version: 2.2.0-beta.1
|
||||
version: 2.1.0
|
||||
appVersion: latest
|
||||
|
||||
@@ -131,7 +131,6 @@
|
||||
| `backend.persistence.volume-name.mountPath` | Path where the volume should be mounted to | |
|
||||
| `backend.extraVolumeMounts` | Additional volumes to mount on the backend. | `[]` |
|
||||
| `backend.extraVolumes` | Additional volumes to mount on the backend. | `[]` |
|
||||
| `backend.pdb.enabled` | Enable pdb on backend | `true` |
|
||||
|
||||
### frontend
|
||||
|
||||
@@ -181,7 +180,6 @@
|
||||
| `frontend.persistence.volume-name.mountPath` | Path where the volume should be mounted to | |
|
||||
| `frontend.extraVolumeMounts` | Additional volumes to mount on the frontend. | `[]` |
|
||||
| `frontend.extraVolumes` | Additional volumes to mount on the frontend. | `[]` |
|
||||
| `frontend.pdb.enabled` | Enable pdb on frontend | `true` |
|
||||
|
||||
### posthog
|
||||
|
||||
@@ -263,4 +261,3 @@
|
||||
| `yProvider.persistence.volume-name.mountPath` | Path where the volume should be mounted to | |
|
||||
| `yProvider.extraVolumeMounts` | Additional volumes to mount on the yProvider. | `[]` |
|
||||
| `yProvider.extraVolumes` | Additional volumes to mount on the yProvider. | `[]` |
|
||||
| `yProvider.pdb.enabled` | Enable pdb on yProvider | `true` |
|
||||
|
||||
2
src/helm/impress/generate-readme.sh
Executable file → Normal file
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/bin/bash
|
||||
|
||||
docker image ls | grep readme-generator-for-helm
|
||||
if [ "$?" -ne "0" ]; then
|
||||
|
||||
@@ -138,16 +138,3 @@ spec:
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
---
|
||||
{{ if .Values.backend.pdb.enabled }}
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
spec:
|
||||
maxUnavailable: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "impress.common.selectorLabels" (list . $component) | nindent 6 }}
|
||||
{{ end }}
|
||||
|
||||
@@ -138,16 +138,3 @@ spec:
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
---
|
||||
{{ if .Values.frontend.pdb.enabled }}
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
spec:
|
||||
maxUnavailable: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "impress.common.selectorLabels" (list . $component) | nindent 6 }}
|
||||
{{ end }}
|
||||
|
||||
@@ -138,16 +138,3 @@ spec:
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
---
|
||||
{{ if .Values.yProvider.pdb.enabled }}
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
spec:
|
||||
maxUnavailable: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "impress.common.selectorLabels" (list . $component) | nindent 6 }}
|
||||
{{ end }}
|
||||
|
||||
@@ -308,9 +308,6 @@ backend:
|
||||
## @param backend.extraVolumes Additional volumes to mount on the backend.
|
||||
extraVolumes: []
|
||||
|
||||
## @param backend.pdb.enabled Enable pdb on backend
|
||||
pdb:
|
||||
enabled: true
|
||||
|
||||
## @section frontend
|
||||
|
||||
@@ -406,10 +403,6 @@ frontend:
|
||||
## @param frontend.extraVolumes Additional volumes to mount on the frontend.
|
||||
extraVolumes: []
|
||||
|
||||
## @param frontend.pdb.enabled Enable pdb on frontend
|
||||
pdb:
|
||||
enabled: true
|
||||
|
||||
## @section posthog
|
||||
|
||||
posthog:
|
||||
@@ -578,7 +571,3 @@ yProvider:
|
||||
|
||||
## @param yProvider.extraVolumes Additional volumes to mount on the yProvider.
|
||||
extraVolumes: []
|
||||
|
||||
## @param yProvider.pdb.enabled Enable pdb on yProvider
|
||||
pdb:
|
||||
enabled: true
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<mj-include path="./partial/header.mjml" />
|
||||
|
||||
<mj-body mj-class="bg--blue-100">
|
||||
<mj-wrapper css-class="wrapper" padding="5px 25px 0px 25px">
|
||||
<mj-wrapper css-class="wrapper" padding="0 25px 0px 25px">
|
||||
<mj-section css-class="wrapper-logo">
|
||||
<mj-column>
|
||||
<mj-image
|
||||
@@ -14,7 +14,7 @@
|
||||
/>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
<mj-section mj-class="bg--white-100" padding="0px 20px 60px 20px">
|
||||
<mj-section mj-class="bg--white-100" padding="30px 20px 60px 20px">
|
||||
<mj-column>
|
||||
<mj-text align="center">
|
||||
<h1>{{title|capfirst}}</h1>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<mj-all
|
||||
font-family="Roboto, -apple-system, BlinkMacSystemFont, 'Segoe UI', Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif"
|
||||
font-size="16px"
|
||||
line-height="normal"
|
||||
line-height="1.3em"
|
||||
color="#3A3A3A"
|
||||
/>
|
||||
</mj-attributes>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mail_mjml",
|
||||
"version": "2.2.0",
|
||||
"version": "2.1.0",
|
||||
"description": "An util to generate html and text django's templates from mjml templates",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
||||