Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0815af4977 | |||
| bf0b1591b3 | |||
| a1bca9c436 | |||
| d02fa1ddd4 | |||
| 1fd66d3081 | |||
| bae8c4c563 | |||
| 0dae35dab1 | |||
| 929a50b573 | |||
| 83dfd26d1c | |||
| addc6a331f |
@@ -9,6 +9,13 @@ and this project adheres to
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## Added
|
||||
- 📝(doc) Add security.md and codeofconduct.md #604
|
||||
- ✨(frontend) add Alert, Quote, and Divider blocks to the editor #566
|
||||
|
||||
|
||||
## [2.1.0] - 2025-01-29
|
||||
|
||||
## Added
|
||||
|
||||
- ✨(backend) add soft delete and restore API endpoints to documents #516
|
||||
@@ -23,15 +30,18 @@ and this project adheres to
|
||||
|
||||
- 💄(frontend) add abilities on doc row #581
|
||||
- 💄(frontend) improve DocsGridItem responsive padding #582
|
||||
- 🔧(backend) Bump maximum page size to 200 #516
|
||||
- 📝(doc) Improve Read me #558
|
||||
|
||||
## Changed
|
||||
## Fixed
|
||||
|
||||
- 🔧(backend) Bump page size to 200 #516
|
||||
- 🐛Fix invitations #575
|
||||
|
||||
## Removed
|
||||
|
||||
- 🔥(backend) remove "content" field from list serializer # 516
|
||||
|
||||
|
||||
## [2.0.1] - 2025-01-17
|
||||
|
||||
## Fixed
|
||||
@@ -51,7 +61,6 @@ and this project adheres to
|
||||
- ✨(frontend) add favorite feature #515
|
||||
- 📝(documentation) Documentation about self-hosted installation #530
|
||||
- ✨(helm) helm versioning #530
|
||||
- ✨(frontend) add home page #553
|
||||
|
||||
## Changed
|
||||
|
||||
@@ -387,7 +396,8 @@ and this project adheres to
|
||||
- 🚀 Impress, project to manage your documents easily and collaboratively.
|
||||
|
||||
|
||||
[unreleased]: https://github.com/numerique-gouv/impress/compare/v2.0.1...main
|
||||
[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
|
||||
[v1.10.0]: https://github.com/numerique-gouv/impress/releases/v1.10.0
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our community include:
|
||||
|
||||
- Demonstrating empathy and kindness toward other people
|
||||
- Being respectful of differing opinions, viewpoints, and experiences
|
||||
- Giving and gracefully accepting constructive feedback
|
||||
- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
|
||||
- Focusing on what is best not just for us as individuals, but for the overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
- The use of sexualized language or imagery, and sexual attention or advances of any kind
|
||||
- Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information, such as a physical or email address, without their explicit permission
|
||||
- Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
- Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
|
||||
- Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
- This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
- Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at docs@numerique.gouv.fr.
|
||||
|
||||
- All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
- All community leaders are obligated to respect the privacy and security of the reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
- Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this
|
||||
|
||||
## Code of Conduct:
|
||||
|
||||
1. Correction
|
||||
|
||||
Community Impact: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
|
||||
|
||||
Consequence: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
|
||||
2. Warning
|
||||
|
||||
Community Impact: A violation through a single incident or series of actions.
|
||||
|
||||
Consequence: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
|
||||
3. Temporary Ban
|
||||
|
||||
Community Impact: A serious violation of community standards, including sustained inappropriate behavior.
|
||||
|
||||
Consequence: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
|
||||
4. Permanent Ban
|
||||
|
||||
Community Impact: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
Consequence: A permanent ban from any sort of public interaction within the community.
|
||||
Attribution
|
||||
|
||||
This Code of Conduct is adapted from the Contributor Covenant, version 2.1, available at https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.
|
||||
|
||||
Community Impact Guidelines were inspired by Mozilla's code of conduct enforcement ladder.
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations.
|
||||
@@ -13,8 +13,10 @@ Welcome to Docs! The open source document editor where your notes can become kno
|
||||
Chat on Matrix
|
||||
</a> - <a href="/docs/">
|
||||
Documentation
|
||||
</a> - <a href="#getting-started">
|
||||
</a> - <a href="#getting-started-">
|
||||
Getting started
|
||||
</a> - <a href="mailto:docs@numerique.gouv.fr">
|
||||
Reach out
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -60,7 +62,7 @@ $ docker compose -v
|
||||
docker compose version 1.27.4, build 40524192
|
||||
```
|
||||
|
||||
> ⚠️ You may need to run the following commands with sudo but this can be avoided by assigning your user to the `docker` group.
|
||||
> ⚠️ You may need to run the following commands with sudo but this can be avoided by adding your user to the `docker` group.
|
||||
|
||||
**Project bootstrap**
|
||||
The easiest way to start working on the project is to use GNU Make:
|
||||
@@ -71,7 +73,7 @@ $ make bootstrap FLUSH_ARGS='--no-input'
|
||||
|
||||
This command builds the `app` container, installs dependencies, performs database migrations and compile translations. It's a good idea to use this
|
||||
|
||||
command each time you are pulling code from the project repository to avoid dependency-releated or migration-releated issues.
|
||||
command each time you are pulling code from the project repository to avoid dependency-related or migration-related issues.
|
||||
|
||||
Your Docker services should now be up and running 🎉
|
||||
|
||||
@@ -79,9 +81,8 @@ You can access to the project by going to <http://localhost:3000>.
|
||||
|
||||
You will be prompted to log in, the default credentials are:
|
||||
|
||||
```shellscript
|
||||
```
|
||||
username: impress
|
||||
|
||||
password: impress
|
||||
```
|
||||
|
||||
@@ -172,11 +173,11 @@ docs
|
||||
Docs is built on top of [Django Rest Framework](https://www.django-rest-framework.org/), [Next.js](https://nextjs.org/), [MinIO](https://min.io/), [BlockNote.js](https://www.blocknotejs.org/), [HocusPocus](https://tiptap.dev/docs/hocuspocus/introduction) and [Yjs](https://yjs.dev/)
|
||||
|
||||
### Gov ❤️ open source
|
||||
Docs is the result of a joint effort lead by the French 🇫🇷🥖 ([DINUM](https://www.numerique.gouv.fr/dinum/)) and German 🇩🇪🥨 governments ([ZenDiS](https://zendis.de/)).
|
||||
Docs is the result of a joint effort led by the French 🇫🇷🥖 ([DINUM](https://www.numerique.gouv.fr/dinum/)) and German 🇩🇪🥨 governments ([ZenDiS](https://zendis.de/)).
|
||||
|
||||
We are proud sponsors of [BlockNotejs](https://www.blocknotejs.org/) and [Yjs](https://yjs.dev/).
|
||||
|
||||
We are always looking for new public partners (we are currently onboarding the Netherlands 🇳🇱🧀), feel free to [reach out](https://matrix.to/#/#docs-official:matrix.org) if you are interested in using or contributing to Docs.
|
||||
We are always looking for new public partners (we are currently onboarding the Netherlands 🇳🇱🧀), feel free to [reach out](mailto:docs@numerique.gouv.fr) if you are interested in using or contributing to Docs.
|
||||
|
||||
<p align="center">
|
||||
<img src="/docs/assets/europe_opensource.png" width="50%"/>
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# Security Policy
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Security is very important to us.
|
||||
|
||||
If you have any issue regarding security, please disclose the information responsibly submiting [this form](https://vdp.numerique.gouv.fr/p/Send-a-report?lang=en) and not by creating an issue on the repository. You can also email us at docs@numerique.gouv.fr
|
||||
|
||||
We appreciate your effort to make Docs more secure.
|
||||
|
||||
## Vulnerability disclosure policy
|
||||
|
||||
Working with security issues in an open source project can be challenging, as we are required to disclose potential problems that could be exploited by attackers. With this in mind, our security fix policy is as follows:
|
||||
|
||||
1. The Maintainers team will handle the fix as usual (Pull Request,
|
||||
release).
|
||||
2. In the release notes, we will include the identification numbers from the
|
||||
GitHub Advisory Database (GHSA) and, if applicable, the Common Vulnerabilities
|
||||
and Exposures (CVE) identifier for the vulnerability.
|
||||
3. Once this grace period has passed, we will publish the vulnerability.
|
||||
|
||||
By adhering to this security policy, we aim to address security concerns
|
||||
effectively and responsibly in our open source software project.
|
||||
@@ -14,10 +14,15 @@
|
||||
"groupName": "ignored js dependencies",
|
||||
"matchManagers": ["npm"],
|
||||
"matchPackageNames": [
|
||||
"@openfun/cunningham-react",
|
||||
"@types/react",
|
||||
"@types/react-dom",
|
||||
"eslint",
|
||||
"fetch-mock",
|
||||
"node",
|
||||
"node-fetch",
|
||||
"eslint",
|
||||
"react",
|
||||
"react-dom",
|
||||
"workbox-webpack-plugin"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-01-15 21:00+0000\n"
|
||||
"PO-Revision-Date: 2025-01-27 09:27\n"
|
||||
"POT-Creation-Date: 2025-01-29 13:43+0000\n"
|
||||
"PO-Revision-Date: 2025-01-30 10:24\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: German\n"
|
||||
"Language: de_DE\n"
|
||||
@@ -17,18 +17,23 @@ msgstr ""
|
||||
"X-Crowdin-File: backend-impress.pot\n"
|
||||
"X-Crowdin-File-ID: 18\n"
|
||||
|
||||
#: build/lib/core/admin.py:33 core/admin.py:33
|
||||
#: build/lib/core/admin.py:37 core/admin.py:37
|
||||
msgid "Personal info"
|
||||
msgstr "Persönliche Daten"
|
||||
|
||||
#: build/lib/core/admin.py:46 core/admin.py:46
|
||||
#: build/lib/core/admin.py:50 build/lib/core/admin.py:138 core/admin.py:50
|
||||
#: core/admin.py:138
|
||||
msgid "Permissions"
|
||||
msgstr "Berechtigungen"
|
||||
|
||||
#: build/lib/core/admin.py:58 core/admin.py:58
|
||||
#: build/lib/core/admin.py:62 core/admin.py:62
|
||||
msgid "Important dates"
|
||||
msgstr "Wichtige Daten"
|
||||
|
||||
#: build/lib/core/admin.py:148 core/admin.py:148
|
||||
msgid "Tree structure"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/api/filters.py:16 core/api/filters.py:16
|
||||
msgid "Creator is me"
|
||||
msgstr "Ersteller bin ich"
|
||||
@@ -41,23 +46,23 @@ msgstr "Favorit"
|
||||
msgid "Title"
|
||||
msgstr "Titel"
|
||||
|
||||
#: build/lib/core/api/serializers.py:317 core/api/serializers.py:317
|
||||
#: build/lib/core/api/serializers.py:346 core/api/serializers.py:346
|
||||
msgid "A new document was created on your behalf!"
|
||||
msgstr "Ein neues Dokument wurde in Ihrem Namen erstellt!"
|
||||
|
||||
#: build/lib/core/api/serializers.py:321 core/api/serializers.py:321
|
||||
#: build/lib/core/api/serializers.py:350 core/api/serializers.py:350
|
||||
msgid "You have been granted ownership of a new document:"
|
||||
msgstr "Sie sind Besitzer eines neuen Dokuments:"
|
||||
|
||||
#: build/lib/core/api/serializers.py:422 core/api/serializers.py:422
|
||||
#: build/lib/core/api/serializers.py:453 core/api/serializers.py:453
|
||||
msgid "Body"
|
||||
msgstr "Inhalt"
|
||||
|
||||
#: build/lib/core/api/serializers.py:425 core/api/serializers.py:425
|
||||
#: build/lib/core/api/serializers.py:456 core/api/serializers.py:456
|
||||
msgid "Body type"
|
||||
msgstr "Typ"
|
||||
|
||||
#: build/lib/core/api/serializers.py:431 core/api/serializers.py:431
|
||||
#: build/lib/core/api/serializers.py:462 core/api/serializers.py:462
|
||||
msgid "Format"
|
||||
msgstr ""
|
||||
|
||||
@@ -71,270 +76,306 @@ msgstr "Ungültiges Antwortformat oder Token-Verifizierung fehlgeschlagen"
|
||||
msgid "User account is disabled"
|
||||
msgstr "Benutzerkonto ist deaktiviert"
|
||||
|
||||
#: build/lib/core/models.py:63 build/lib/core/models.py:70 core/models.py:63
|
||||
#: core/models.py:70
|
||||
#: build/lib/core/enums.py:19 core/enums.py:19
|
||||
msgid "First child"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:20 core/enums.py:20
|
||||
msgid "Last child"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:21 core/enums.py:21
|
||||
msgid "First sibling"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:22 core/enums.py:22
|
||||
msgid "Last sibling"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:23 core/enums.py:23
|
||||
msgid "Left"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:24 core/enums.py:24
|
||||
msgid "Right"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:54 build/lib/core/models.py:61 core/models.py:54
|
||||
#: core/models.py:61
|
||||
msgid "Reader"
|
||||
msgstr "Lesen"
|
||||
|
||||
#: build/lib/core/models.py:64 build/lib/core/models.py:71 core/models.py:64
|
||||
#: core/models.py:71
|
||||
#: build/lib/core/models.py:55 build/lib/core/models.py:62 core/models.py:55
|
||||
#: core/models.py:62
|
||||
msgid "Editor"
|
||||
msgstr "Bearbeiten"
|
||||
|
||||
#: build/lib/core/models.py:72 core/models.py:72
|
||||
#: build/lib/core/models.py:63 core/models.py:63
|
||||
msgid "Administrator"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:73 core/models.py:73
|
||||
#: build/lib/core/models.py:64 core/models.py:64
|
||||
msgid "Owner"
|
||||
msgstr "Besitzer"
|
||||
|
||||
#: build/lib/core/models.py:84 core/models.py:84
|
||||
#: build/lib/core/models.py:75 core/models.py:75
|
||||
msgid "Restricted"
|
||||
msgstr "Beschränkt"
|
||||
|
||||
#: build/lib/core/models.py:88 core/models.py:88
|
||||
#: build/lib/core/models.py:79 core/models.py:79
|
||||
msgid "Authenticated"
|
||||
msgstr "Authentifiziert"
|
||||
|
||||
#: build/lib/core/models.py:90 core/models.py:90
|
||||
#: build/lib/core/models.py:81 core/models.py:81
|
||||
msgid "Public"
|
||||
msgstr "Öffentlich"
|
||||
|
||||
#: build/lib/core/models.py:112 core/models.py:112
|
||||
#: build/lib/core/models.py:103 core/models.py:103
|
||||
msgid "id"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:113 core/models.py:113
|
||||
#: build/lib/core/models.py:104 core/models.py:104
|
||||
msgid "primary key for the record as UUID"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:119 core/models.py:119
|
||||
#: build/lib/core/models.py:110 core/models.py:110
|
||||
msgid "created on"
|
||||
msgstr "Erstellt"
|
||||
|
||||
#: build/lib/core/models.py:120 core/models.py:120
|
||||
#: build/lib/core/models.py:111 core/models.py:111
|
||||
msgid "date and time at which a record was created"
|
||||
msgstr "Datum und Uhrzeit, an dem ein Datensatz erstellt wurde"
|
||||
|
||||
#: build/lib/core/models.py:125 core/models.py:125
|
||||
#: build/lib/core/models.py:116 core/models.py:116
|
||||
msgid "updated on"
|
||||
msgstr "Aktualisiert"
|
||||
|
||||
#: build/lib/core/models.py:126 core/models.py:126
|
||||
#: build/lib/core/models.py:117 core/models.py:117
|
||||
msgid "date and time at which a record was last updated"
|
||||
msgstr "Datum und Uhrzeit, an dem zuletzt aktualisiert wurde"
|
||||
|
||||
#: build/lib/core/models.py:162 core/models.py:162
|
||||
#: build/lib/core/models.py:153 core/models.py:153
|
||||
msgid "We couldn't find a user with this sub but the email is already associated with a registered user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:175 core/models.py:175
|
||||
#: build/lib/core/models.py:166 core/models.py:166
|
||||
msgid "Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/_/: characters."
|
||||
msgstr "Geben Sie eine gültige Unterseite ein. Dieser Wert darf nur Buchstaben, Zahlen und die @/./+/-/_/: Zeichen enthalten."
|
||||
|
||||
#: build/lib/core/models.py:181 core/models.py:181
|
||||
#: build/lib/core/models.py:172 core/models.py:172
|
||||
msgid "sub"
|
||||
msgstr "unter"
|
||||
|
||||
#: build/lib/core/models.py:183 core/models.py:183
|
||||
#: build/lib/core/models.py:174 core/models.py:174
|
||||
msgid "Required. 255 characters or fewer. Letters, numbers, and @/./+/-/_/: characters only."
|
||||
msgstr "Erforderlich. 255 Zeichen oder weniger. Buchstaben, Zahlen und die Zeichen @/./+/-/_/:"
|
||||
|
||||
#: build/lib/core/models.py:192 core/models.py:192
|
||||
#: build/lib/core/models.py:183 core/models.py:183
|
||||
msgid "full name"
|
||||
msgstr "Name"
|
||||
|
||||
#: build/lib/core/models.py:193 core/models.py:193
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
msgid "short name"
|
||||
msgstr "Kurzbezeichnung"
|
||||
|
||||
#: build/lib/core/models.py:195 core/models.py:195
|
||||
#: build/lib/core/models.py:186 core/models.py:186
|
||||
msgid "identity email address"
|
||||
msgstr "Identitäts-E-Mail-Adresse"
|
||||
|
||||
#: build/lib/core/models.py:200 core/models.py:200
|
||||
#: build/lib/core/models.py:191 core/models.py:191
|
||||
msgid "admin email address"
|
||||
msgstr "Admin E-Mail-Adresse"
|
||||
|
||||
#: build/lib/core/models.py:207 core/models.py:207
|
||||
#: build/lib/core/models.py:198 core/models.py:198
|
||||
msgid "language"
|
||||
msgstr "Sprache"
|
||||
|
||||
#: build/lib/core/models.py:208 core/models.py:208
|
||||
#: build/lib/core/models.py:199 core/models.py:199
|
||||
msgid "The language in which the user wants to see the interface."
|
||||
msgstr "Die Sprache, in der der Benutzer die Benutzeroberfläche sehen möchte."
|
||||
|
||||
#: build/lib/core/models.py:214 core/models.py:214
|
||||
#: build/lib/core/models.py:205 core/models.py:205
|
||||
msgid "The timezone in which the user wants to see times."
|
||||
msgstr "Die Zeitzone, in der der Nutzer Zeiten sehen möchte."
|
||||
|
||||
#: build/lib/core/models.py:217 core/models.py:217
|
||||
#: build/lib/core/models.py:208 core/models.py:208
|
||||
msgid "device"
|
||||
msgstr "Gerät"
|
||||
|
||||
#: build/lib/core/models.py:219 core/models.py:219
|
||||
#: build/lib/core/models.py:210 core/models.py:210
|
||||
msgid "Whether the user is a device or a real user."
|
||||
msgstr "Ob der Benutzer ein Gerät oder ein echter Benutzer ist."
|
||||
|
||||
#: build/lib/core/models.py:222 core/models.py:222
|
||||
#: build/lib/core/models.py:213 core/models.py:213
|
||||
msgid "staff status"
|
||||
msgstr "Status des Teammitgliedes"
|
||||
|
||||
#: build/lib/core/models.py:224 core/models.py:224
|
||||
#: build/lib/core/models.py:215 core/models.py:215
|
||||
msgid "Whether the user can log into this admin site."
|
||||
msgstr "Gibt an, ob der Benutzer sich in diese Admin-Seite einloggen kann."
|
||||
|
||||
#: build/lib/core/models.py:227 core/models.py:227
|
||||
#: build/lib/core/models.py:218 core/models.py:218
|
||||
msgid "active"
|
||||
msgstr "aktiviert"
|
||||
|
||||
#: build/lib/core/models.py:230 core/models.py:230
|
||||
#: build/lib/core/models.py:221 core/models.py:221
|
||||
msgid "Whether this user should be treated as active. Unselect this instead of deleting accounts."
|
||||
msgstr "Ob dieser Benutzer als aktiviert behandelt werden soll. Deaktivieren Sie diese Option, anstatt Konten zu löschen."
|
||||
|
||||
#: build/lib/core/models.py:242 core/models.py:242
|
||||
#: build/lib/core/models.py:233 core/models.py:233
|
||||
msgid "user"
|
||||
msgstr "Benutzer"
|
||||
|
||||
#: build/lib/core/models.py:243 core/models.py:243
|
||||
#: build/lib/core/models.py:234 core/models.py:234
|
||||
msgid "users"
|
||||
msgstr "Benutzer"
|
||||
|
||||
#: build/lib/core/models.py:382 build/lib/core/models.py:758 core/models.py:382
|
||||
#: core/models.py:758
|
||||
#: build/lib/core/models.py:373 build/lib/core/models.py:925 core/models.py:373
|
||||
#: core/models.py:925
|
||||
msgid "title"
|
||||
msgstr "Titel"
|
||||
|
||||
#: build/lib/core/models.py:404 core/models.py:404
|
||||
#: build/lib/core/models.py:374 core/models.py:374
|
||||
msgid "excerpt"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:405 core/models.py:405
|
||||
msgid "Document"
|
||||
msgstr "Dokument"
|
||||
|
||||
#: build/lib/core/models.py:405 core/models.py:405
|
||||
#: build/lib/core/models.py:406 core/models.py:406
|
||||
msgid "Documents"
|
||||
msgstr "Dokumente"
|
||||
|
||||
#: build/lib/core/models.py:408 core/models.py:408
|
||||
#: build/lib/core/models.py:418 core/models.py:418
|
||||
msgid "Untitled Document"
|
||||
msgstr "Unbenanntes Dokument"
|
||||
|
||||
#: build/lib/core/models.py:633 core/models.py:633
|
||||
#: build/lib/core/models.py:719 core/models.py:719
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr "{name} hat ein Dokument mit Ihnen geteilt!"
|
||||
|
||||
#: build/lib/core/models.py:637 core/models.py:637
|
||||
#: build/lib/core/models.py:723 core/models.py:723
|
||||
#, python-brace-format
|
||||
msgid "{name} invited you with the role \"{role}\" on the following document:"
|
||||
msgstr "{name} hat Sie mit der Rolle \"{role}\" zu folgendem Dokument eingeladen:"
|
||||
|
||||
#: build/lib/core/models.py:640 core/models.py:640
|
||||
#: build/lib/core/models.py:726 core/models.py:726
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you: {title}"
|
||||
msgstr "{name} hat ein Dokument mit Ihnen geteilt: {title}"
|
||||
|
||||
#: build/lib/core/models.py:663 core/models.py:663
|
||||
#: build/lib/core/models.py:762 core/models.py:762
|
||||
msgid "This document is not deleted."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:769 core/models.py:769
|
||||
msgid "This document was permanently deleted and cannot be restored."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:820 core/models.py:820
|
||||
msgid "Document/user link trace"
|
||||
msgstr "Dokument/Benutzer Linkverfolgung"
|
||||
|
||||
#: build/lib/core/models.py:664 core/models.py:664
|
||||
#: build/lib/core/models.py:821 core/models.py:821
|
||||
msgid "Document/user link traces"
|
||||
msgstr "Dokument/Benutzer Linkverfolgung"
|
||||
|
||||
#: build/lib/core/models.py:670 core/models.py:670
|
||||
#: build/lib/core/models.py:827 core/models.py:827
|
||||
msgid "A link trace already exists for this document/user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:693 core/models.py:693
|
||||
#: build/lib/core/models.py:850 core/models.py:850
|
||||
msgid "Document favorite"
|
||||
msgstr "Dokumentenfavorit"
|
||||
|
||||
#: build/lib/core/models.py:694 core/models.py:694
|
||||
#: build/lib/core/models.py:851 core/models.py:851
|
||||
msgid "Document favorites"
|
||||
msgstr "Dokumentfavoriten"
|
||||
|
||||
#: build/lib/core/models.py:700 core/models.py:700
|
||||
#: build/lib/core/models.py:857 core/models.py:857
|
||||
msgid "This document is already targeted by a favorite relation instance for the same user."
|
||||
msgstr "Dieses Dokument ist bereits durch den gleichen Benutzer favorisiert worden."
|
||||
|
||||
#: build/lib/core/models.py:722 core/models.py:722
|
||||
#: build/lib/core/models.py:879 core/models.py:879
|
||||
msgid "Document/user relation"
|
||||
msgstr "Dokument/Benutzerbeziehung"
|
||||
|
||||
#: build/lib/core/models.py:723 core/models.py:723
|
||||
#: build/lib/core/models.py:880 core/models.py:880
|
||||
msgid "Document/user relations"
|
||||
msgstr "Dokument/Benutzerbeziehungen"
|
||||
|
||||
#: build/lib/core/models.py:729 core/models.py:729
|
||||
#: build/lib/core/models.py:886 core/models.py:886
|
||||
msgid "This user is already in this document."
|
||||
msgstr "Dieser Benutzer befindet sich bereits in diesem Dokument."
|
||||
|
||||
#: build/lib/core/models.py:735 core/models.py:735
|
||||
#: build/lib/core/models.py:892 core/models.py:892
|
||||
msgid "This team is already in this document."
|
||||
msgstr "Dieses Team befindet sich bereits in diesem Dokument."
|
||||
|
||||
#: build/lib/core/models.py:741 build/lib/core/models.py:930 core/models.py:741
|
||||
#: core/models.py:930
|
||||
#: build/lib/core/models.py:898 build/lib/core/models.py:1012
|
||||
#: core/models.py:898 core/models.py:1012
|
||||
msgid "Either user or team must be set, not both."
|
||||
msgstr "Benutzer oder Team müssen gesetzt werden, nicht beides."
|
||||
|
||||
#: build/lib/core/models.py:759 core/models.py:759
|
||||
#: build/lib/core/models.py:926 core/models.py:926
|
||||
msgid "description"
|
||||
msgstr "Beschreibung"
|
||||
|
||||
#: build/lib/core/models.py:760 core/models.py:760
|
||||
#: build/lib/core/models.py:927 core/models.py:927
|
||||
msgid "code"
|
||||
msgstr "Code"
|
||||
|
||||
#: build/lib/core/models.py:761 core/models.py:761
|
||||
#: build/lib/core/models.py:928 core/models.py:928
|
||||
msgid "css"
|
||||
msgstr "CSS"
|
||||
|
||||
#: build/lib/core/models.py:763 core/models.py:763
|
||||
#: build/lib/core/models.py:930 core/models.py:930
|
||||
msgid "public"
|
||||
msgstr "öffentlich"
|
||||
|
||||
#: build/lib/core/models.py:765 core/models.py:765
|
||||
#: build/lib/core/models.py:932 core/models.py:932
|
||||
msgid "Whether this template is public for anyone to use."
|
||||
msgstr "Ob diese Vorlage für jedermann öffentlich ist."
|
||||
|
||||
#: build/lib/core/models.py:771 core/models.py:771
|
||||
#: build/lib/core/models.py:938 core/models.py:938
|
||||
msgid "Template"
|
||||
msgstr "Vorlage"
|
||||
|
||||
#: build/lib/core/models.py:772 core/models.py:772
|
||||
#: build/lib/core/models.py:939 core/models.py:939
|
||||
msgid "Templates"
|
||||
msgstr "Vorlagen"
|
||||
|
||||
#: build/lib/core/models.py:911 core/models.py:911
|
||||
#: build/lib/core/models.py:993 core/models.py:993
|
||||
msgid "Template/user relation"
|
||||
msgstr "Vorlage/Benutzer-Beziehung"
|
||||
|
||||
#: build/lib/core/models.py:912 core/models.py:912
|
||||
#: build/lib/core/models.py:994 core/models.py:994
|
||||
msgid "Template/user relations"
|
||||
msgstr "Vorlage/Benutzerbeziehungen"
|
||||
|
||||
#: build/lib/core/models.py:918 core/models.py:918
|
||||
#: build/lib/core/models.py:1000 core/models.py:1000
|
||||
msgid "This user is already in this template."
|
||||
msgstr "Dieser Benutzer ist bereits in dieser Vorlage."
|
||||
|
||||
#: build/lib/core/models.py:924 core/models.py:924
|
||||
#: build/lib/core/models.py:1006 core/models.py:1006
|
||||
msgid "This team is already in this template."
|
||||
msgstr "Dieses Team ist bereits in diesem Template."
|
||||
|
||||
#: build/lib/core/models.py:947 core/models.py:947
|
||||
#: build/lib/core/models.py:1029 core/models.py:1029
|
||||
msgid "email address"
|
||||
msgstr "E-Mail-Adresse"
|
||||
|
||||
#: build/lib/core/models.py:966 core/models.py:966
|
||||
#: build/lib/core/models.py:1048 core/models.py:1048
|
||||
msgid "Document invitation"
|
||||
msgstr "Einladung zum Dokument"
|
||||
|
||||
#: build/lib/core/models.py:967 core/models.py:967
|
||||
#: build/lib/core/models.py:1049 core/models.py:1049
|
||||
msgid "Document invitations"
|
||||
msgstr "Dokumenteinladungen"
|
||||
|
||||
#: build/lib/core/models.py:987 core/models.py:987
|
||||
#: build/lib/core/models.py:1069 core/models.py:1069
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr "Diese E-Mail ist bereits einem registrierten Benutzer zugeordnet."
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-01-15 21:00+0000\n"
|
||||
"PO-Revision-Date: 2025-01-27 09:27\n"
|
||||
"POT-Creation-Date: 2025-01-29 13:43+0000\n"
|
||||
"PO-Revision-Date: 2025-01-30 10:24\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: English\n"
|
||||
"Language: en_US\n"
|
||||
@@ -17,18 +17,23 @@ msgstr ""
|
||||
"X-Crowdin-File: backend-impress.pot\n"
|
||||
"X-Crowdin-File-ID: 18\n"
|
||||
|
||||
#: build/lib/core/admin.py:33 core/admin.py:33
|
||||
#: build/lib/core/admin.py:37 core/admin.py:37
|
||||
msgid "Personal info"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/admin.py:46 core/admin.py:46
|
||||
#: build/lib/core/admin.py:50 build/lib/core/admin.py:138 core/admin.py:50
|
||||
#: core/admin.py:138
|
||||
msgid "Permissions"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/admin.py:58 core/admin.py:58
|
||||
#: build/lib/core/admin.py:62 core/admin.py:62
|
||||
msgid "Important dates"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/admin.py:148 core/admin.py:148
|
||||
msgid "Tree structure"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/api/filters.py:16 core/api/filters.py:16
|
||||
msgid "Creator is me"
|
||||
msgstr ""
|
||||
@@ -41,23 +46,23 @@ msgstr ""
|
||||
msgid "Title"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/api/serializers.py:317 core/api/serializers.py:317
|
||||
#: build/lib/core/api/serializers.py:346 core/api/serializers.py:346
|
||||
msgid "A new document was created on your behalf!"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/api/serializers.py:321 core/api/serializers.py:321
|
||||
#: build/lib/core/api/serializers.py:350 core/api/serializers.py:350
|
||||
msgid "You have been granted ownership of a new document:"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/api/serializers.py:422 core/api/serializers.py:422
|
||||
#: build/lib/core/api/serializers.py:453 core/api/serializers.py:453
|
||||
msgid "Body"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/api/serializers.py:425 core/api/serializers.py:425
|
||||
#: build/lib/core/api/serializers.py:456 core/api/serializers.py:456
|
||||
msgid "Body type"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/api/serializers.py:431 core/api/serializers.py:431
|
||||
#: build/lib/core/api/serializers.py:462 core/api/serializers.py:462
|
||||
msgid "Format"
|
||||
msgstr ""
|
||||
|
||||
@@ -71,270 +76,306 @@ msgstr ""
|
||||
msgid "User account is disabled"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:63 build/lib/core/models.py:70 core/models.py:63
|
||||
#: core/models.py:70
|
||||
#: build/lib/core/enums.py:19 core/enums.py:19
|
||||
msgid "First child"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:20 core/enums.py:20
|
||||
msgid "Last child"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:21 core/enums.py:21
|
||||
msgid "First sibling"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:22 core/enums.py:22
|
||||
msgid "Last sibling"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:23 core/enums.py:23
|
||||
msgid "Left"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:24 core/enums.py:24
|
||||
msgid "Right"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:54 build/lib/core/models.py:61 core/models.py:54
|
||||
#: core/models.py:61
|
||||
msgid "Reader"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:64 build/lib/core/models.py:71 core/models.py:64
|
||||
#: core/models.py:71
|
||||
#: build/lib/core/models.py:55 build/lib/core/models.py:62 core/models.py:55
|
||||
#: core/models.py:62
|
||||
msgid "Editor"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:72 core/models.py:72
|
||||
#: build/lib/core/models.py:63 core/models.py:63
|
||||
msgid "Administrator"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:73 core/models.py:73
|
||||
#: build/lib/core/models.py:64 core/models.py:64
|
||||
msgid "Owner"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:84 core/models.py:84
|
||||
#: build/lib/core/models.py:75 core/models.py:75
|
||||
msgid "Restricted"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:88 core/models.py:88
|
||||
#: build/lib/core/models.py:79 core/models.py:79
|
||||
msgid "Authenticated"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:90 core/models.py:90
|
||||
#: build/lib/core/models.py:81 core/models.py:81
|
||||
msgid "Public"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:112 core/models.py:112
|
||||
#: build/lib/core/models.py:103 core/models.py:103
|
||||
msgid "id"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:113 core/models.py:113
|
||||
#: build/lib/core/models.py:104 core/models.py:104
|
||||
msgid "primary key for the record as UUID"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:119 core/models.py:119
|
||||
#: build/lib/core/models.py:110 core/models.py:110
|
||||
msgid "created on"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:120 core/models.py:120
|
||||
#: build/lib/core/models.py:111 core/models.py:111
|
||||
msgid "date and time at which a record was created"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:125 core/models.py:125
|
||||
#: build/lib/core/models.py:116 core/models.py:116
|
||||
msgid "updated on"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:126 core/models.py:126
|
||||
#: build/lib/core/models.py:117 core/models.py:117
|
||||
msgid "date and time at which a record was last updated"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:162 core/models.py:162
|
||||
#: build/lib/core/models.py:153 core/models.py:153
|
||||
msgid "We couldn't find a user with this sub but the email is already associated with a registered user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:175 core/models.py:175
|
||||
#: build/lib/core/models.py:166 core/models.py:166
|
||||
msgid "Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/_/: characters."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:181 core/models.py:181
|
||||
#: build/lib/core/models.py:172 core/models.py:172
|
||||
msgid "sub"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:183 core/models.py:183
|
||||
#: build/lib/core/models.py:174 core/models.py:174
|
||||
msgid "Required. 255 characters or fewer. Letters, numbers, and @/./+/-/_/: characters only."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:192 core/models.py:192
|
||||
#: build/lib/core/models.py:183 core/models.py:183
|
||||
msgid "full name"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:193 core/models.py:193
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
msgid "short name"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:195 core/models.py:195
|
||||
#: build/lib/core/models.py:186 core/models.py:186
|
||||
msgid "identity email address"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:200 core/models.py:200
|
||||
#: build/lib/core/models.py:191 core/models.py:191
|
||||
msgid "admin email address"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:207 core/models.py:207
|
||||
#: build/lib/core/models.py:198 core/models.py:198
|
||||
msgid "language"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:208 core/models.py:208
|
||||
#: build/lib/core/models.py:199 core/models.py:199
|
||||
msgid "The language in which the user wants to see the interface."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:214 core/models.py:214
|
||||
#: build/lib/core/models.py:205 core/models.py:205
|
||||
msgid "The timezone in which the user wants to see times."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:217 core/models.py:217
|
||||
#: build/lib/core/models.py:208 core/models.py:208
|
||||
msgid "device"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:219 core/models.py:219
|
||||
#: build/lib/core/models.py:210 core/models.py:210
|
||||
msgid "Whether the user is a device or a real user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:222 core/models.py:222
|
||||
#: build/lib/core/models.py:213 core/models.py:213
|
||||
msgid "staff status"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:224 core/models.py:224
|
||||
#: build/lib/core/models.py:215 core/models.py:215
|
||||
msgid "Whether the user can log into this admin site."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:227 core/models.py:227
|
||||
#: build/lib/core/models.py:218 core/models.py:218
|
||||
msgid "active"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:230 core/models.py:230
|
||||
#: build/lib/core/models.py:221 core/models.py:221
|
||||
msgid "Whether this user should be treated as active. Unselect this instead of deleting accounts."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:242 core/models.py:242
|
||||
#: build/lib/core/models.py:233 core/models.py:233
|
||||
msgid "user"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:243 core/models.py:243
|
||||
#: build/lib/core/models.py:234 core/models.py:234
|
||||
msgid "users"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:382 build/lib/core/models.py:758 core/models.py:382
|
||||
#: core/models.py:758
|
||||
#: build/lib/core/models.py:373 build/lib/core/models.py:925 core/models.py:373
|
||||
#: core/models.py:925
|
||||
msgid "title"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:404 core/models.py:404
|
||||
msgid "Document"
|
||||
#: build/lib/core/models.py:374 core/models.py:374
|
||||
msgid "excerpt"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:405 core/models.py:405
|
||||
msgid "Document"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:406 core/models.py:406
|
||||
msgid "Documents"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:408 core/models.py:408
|
||||
#: build/lib/core/models.py:418 core/models.py:418
|
||||
msgid "Untitled Document"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:633 core/models.py:633
|
||||
#: build/lib/core/models.py:719 core/models.py:719
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:637 core/models.py:637
|
||||
#: build/lib/core/models.py:723 core/models.py:723
|
||||
#, python-brace-format
|
||||
msgid "{name} invited you with the role \"{role}\" on the following document:"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:640 core/models.py:640
|
||||
#: build/lib/core/models.py:726 core/models.py:726
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you: {title}"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:663 core/models.py:663
|
||||
#: build/lib/core/models.py:762 core/models.py:762
|
||||
msgid "This document is not deleted."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:769 core/models.py:769
|
||||
msgid "This document was permanently deleted and cannot be restored."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:820 core/models.py:820
|
||||
msgid "Document/user link trace"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:664 core/models.py:664
|
||||
#: build/lib/core/models.py:821 core/models.py:821
|
||||
msgid "Document/user link traces"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:670 core/models.py:670
|
||||
#: build/lib/core/models.py:827 core/models.py:827
|
||||
msgid "A link trace already exists for this document/user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:693 core/models.py:693
|
||||
#: build/lib/core/models.py:850 core/models.py:850
|
||||
msgid "Document favorite"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:694 core/models.py:694
|
||||
#: build/lib/core/models.py:851 core/models.py:851
|
||||
msgid "Document favorites"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:700 core/models.py:700
|
||||
#: build/lib/core/models.py:857 core/models.py:857
|
||||
msgid "This document is already targeted by a favorite relation instance for the same user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:722 core/models.py:722
|
||||
#: build/lib/core/models.py:879 core/models.py:879
|
||||
msgid "Document/user relation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:723 core/models.py:723
|
||||
#: build/lib/core/models.py:880 core/models.py:880
|
||||
msgid "Document/user relations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:729 core/models.py:729
|
||||
#: build/lib/core/models.py:886 core/models.py:886
|
||||
msgid "This user is already in this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:735 core/models.py:735
|
||||
#: build/lib/core/models.py:892 core/models.py:892
|
||||
msgid "This team is already in this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:741 build/lib/core/models.py:930 core/models.py:741
|
||||
#: core/models.py:930
|
||||
#: build/lib/core/models.py:898 build/lib/core/models.py:1012
|
||||
#: core/models.py:898 core/models.py:1012
|
||||
msgid "Either user or team must be set, not both."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:759 core/models.py:759
|
||||
#: build/lib/core/models.py:926 core/models.py:926
|
||||
msgid "description"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:760 core/models.py:760
|
||||
#: build/lib/core/models.py:927 core/models.py:927
|
||||
msgid "code"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:761 core/models.py:761
|
||||
#: build/lib/core/models.py:928 core/models.py:928
|
||||
msgid "css"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:763 core/models.py:763
|
||||
#: build/lib/core/models.py:930 core/models.py:930
|
||||
msgid "public"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:765 core/models.py:765
|
||||
#: build/lib/core/models.py:932 core/models.py:932
|
||||
msgid "Whether this template is public for anyone to use."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:771 core/models.py:771
|
||||
#: build/lib/core/models.py:938 core/models.py:938
|
||||
msgid "Template"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:772 core/models.py:772
|
||||
#: build/lib/core/models.py:939 core/models.py:939
|
||||
msgid "Templates"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:911 core/models.py:911
|
||||
#: build/lib/core/models.py:993 core/models.py:993
|
||||
msgid "Template/user relation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:912 core/models.py:912
|
||||
#: build/lib/core/models.py:994 core/models.py:994
|
||||
msgid "Template/user relations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:918 core/models.py:918
|
||||
#: build/lib/core/models.py:1000 core/models.py:1000
|
||||
msgid "This user is already in this template."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:924 core/models.py:924
|
||||
#: build/lib/core/models.py:1006 core/models.py:1006
|
||||
msgid "This team is already in this template."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:947 core/models.py:947
|
||||
#: build/lib/core/models.py:1029 core/models.py:1029
|
||||
msgid "email address"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:966 core/models.py:966
|
||||
#: build/lib/core/models.py:1048 core/models.py:1048
|
||||
msgid "Document invitation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:967 core/models.py:967
|
||||
#: build/lib/core/models.py:1049 core/models.py:1049
|
||||
msgid "Document invitations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:987 core/models.py:987
|
||||
#: build/lib/core/models.py:1069 core/models.py:1069
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr ""
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-01-15 21:00+0000\n"
|
||||
"PO-Revision-Date: 2025-01-27 09:27\n"
|
||||
"POT-Creation-Date: 2025-01-29 13:43+0000\n"
|
||||
"PO-Revision-Date: 2025-01-30 10:24\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: French\n"
|
||||
"Language: fr_FR\n"
|
||||
@@ -17,18 +17,23 @@ msgstr ""
|
||||
"X-Crowdin-File: backend-impress.pot\n"
|
||||
"X-Crowdin-File-ID: 18\n"
|
||||
|
||||
#: build/lib/core/admin.py:33 core/admin.py:33
|
||||
#: build/lib/core/admin.py:37 core/admin.py:37
|
||||
msgid "Personal info"
|
||||
msgstr "Infos Personnelles"
|
||||
|
||||
#: build/lib/core/admin.py:46 core/admin.py:46
|
||||
#: build/lib/core/admin.py:50 build/lib/core/admin.py:138 core/admin.py:50
|
||||
#: core/admin.py:138
|
||||
msgid "Permissions"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/admin.py:58 core/admin.py:58
|
||||
#: build/lib/core/admin.py:62 core/admin.py:62
|
||||
msgid "Important dates"
|
||||
msgstr "Dates importantes"
|
||||
|
||||
#: build/lib/core/admin.py:148 core/admin.py:148
|
||||
msgid "Tree structure"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/api/filters.py:16 core/api/filters.py:16
|
||||
msgid "Creator is me"
|
||||
msgstr ""
|
||||
@@ -41,23 +46,23 @@ msgstr ""
|
||||
msgid "Title"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/api/serializers.py:317 core/api/serializers.py:317
|
||||
#: build/lib/core/api/serializers.py:346 core/api/serializers.py:346
|
||||
msgid "A new document was created on your behalf!"
|
||||
msgstr "Un nouveau document a été créé pour vous !"
|
||||
|
||||
#: build/lib/core/api/serializers.py:321 core/api/serializers.py:321
|
||||
#: build/lib/core/api/serializers.py:350 core/api/serializers.py:350
|
||||
msgid "You have been granted ownership of a new document:"
|
||||
msgstr "Vous avez été déclaré propriétaire d'un nouveau document :"
|
||||
|
||||
#: build/lib/core/api/serializers.py:422 core/api/serializers.py:422
|
||||
#: build/lib/core/api/serializers.py:453 core/api/serializers.py:453
|
||||
msgid "Body"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/api/serializers.py:425 core/api/serializers.py:425
|
||||
#: build/lib/core/api/serializers.py:456 core/api/serializers.py:456
|
||||
msgid "Body type"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/api/serializers.py:431 core/api/serializers.py:431
|
||||
#: build/lib/core/api/serializers.py:462 core/api/serializers.py:462
|
||||
msgid "Format"
|
||||
msgstr ""
|
||||
|
||||
@@ -71,270 +76,306 @@ msgstr ""
|
||||
msgid "User account is disabled"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:63 build/lib/core/models.py:70 core/models.py:63
|
||||
#: core/models.py:70
|
||||
#: build/lib/core/enums.py:19 core/enums.py:19
|
||||
msgid "First child"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:20 core/enums.py:20
|
||||
msgid "Last child"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:21 core/enums.py:21
|
||||
msgid "First sibling"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:22 core/enums.py:22
|
||||
msgid "Last sibling"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:23 core/enums.py:23
|
||||
msgid "Left"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:24 core/enums.py:24
|
||||
msgid "Right"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:54 build/lib/core/models.py:61 core/models.py:54
|
||||
#: core/models.py:61
|
||||
msgid "Reader"
|
||||
msgstr "Lecteur"
|
||||
|
||||
#: build/lib/core/models.py:64 build/lib/core/models.py:71 core/models.py:64
|
||||
#: core/models.py:71
|
||||
#: build/lib/core/models.py:55 build/lib/core/models.py:62 core/models.py:55
|
||||
#: core/models.py:62
|
||||
msgid "Editor"
|
||||
msgstr "Éditeur"
|
||||
|
||||
#: build/lib/core/models.py:72 core/models.py:72
|
||||
#: build/lib/core/models.py:63 core/models.py:63
|
||||
msgid "Administrator"
|
||||
msgstr "Administrateur"
|
||||
|
||||
#: build/lib/core/models.py:73 core/models.py:73
|
||||
#: build/lib/core/models.py:64 core/models.py:64
|
||||
msgid "Owner"
|
||||
msgstr "Propriétaire"
|
||||
|
||||
#: build/lib/core/models.py:84 core/models.py:84
|
||||
#: build/lib/core/models.py:75 core/models.py:75
|
||||
msgid "Restricted"
|
||||
msgstr "Restreint"
|
||||
|
||||
#: build/lib/core/models.py:88 core/models.py:88
|
||||
#: build/lib/core/models.py:79 core/models.py:79
|
||||
msgid "Authenticated"
|
||||
msgstr "Authentifié"
|
||||
|
||||
#: build/lib/core/models.py:90 core/models.py:90
|
||||
#: build/lib/core/models.py:81 core/models.py:81
|
||||
msgid "Public"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:112 core/models.py:112
|
||||
#: build/lib/core/models.py:103 core/models.py:103
|
||||
msgid "id"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:113 core/models.py:113
|
||||
#: build/lib/core/models.py:104 core/models.py:104
|
||||
msgid "primary key for the record as UUID"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:119 core/models.py:119
|
||||
#: build/lib/core/models.py:110 core/models.py:110
|
||||
msgid "created on"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:120 core/models.py:120
|
||||
#: build/lib/core/models.py:111 core/models.py:111
|
||||
msgid "date and time at which a record was created"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:125 core/models.py:125
|
||||
#: build/lib/core/models.py:116 core/models.py:116
|
||||
msgid "updated on"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:126 core/models.py:126
|
||||
#: build/lib/core/models.py:117 core/models.py:117
|
||||
msgid "date and time at which a record was last updated"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:162 core/models.py:162
|
||||
#: build/lib/core/models.py:153 core/models.py:153
|
||||
msgid "We couldn't find a user with this sub but the email is already associated with a registered user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:175 core/models.py:175
|
||||
#: build/lib/core/models.py:166 core/models.py:166
|
||||
msgid "Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/_/: characters."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:181 core/models.py:181
|
||||
#: build/lib/core/models.py:172 core/models.py:172
|
||||
msgid "sub"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:183 core/models.py:183
|
||||
#: build/lib/core/models.py:174 core/models.py:174
|
||||
msgid "Required. 255 characters or fewer. Letters, numbers, and @/./+/-/_/: characters only."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:192 core/models.py:192
|
||||
#: build/lib/core/models.py:183 core/models.py:183
|
||||
msgid "full name"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:193 core/models.py:193
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
msgid "short name"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:195 core/models.py:195
|
||||
#: build/lib/core/models.py:186 core/models.py:186
|
||||
msgid "identity email address"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:200 core/models.py:200
|
||||
#: build/lib/core/models.py:191 core/models.py:191
|
||||
msgid "admin email address"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:207 core/models.py:207
|
||||
#: build/lib/core/models.py:198 core/models.py:198
|
||||
msgid "language"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:208 core/models.py:208
|
||||
#: build/lib/core/models.py:199 core/models.py:199
|
||||
msgid "The language in which the user wants to see the interface."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:214 core/models.py:214
|
||||
#: build/lib/core/models.py:205 core/models.py:205
|
||||
msgid "The timezone in which the user wants to see times."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:217 core/models.py:217
|
||||
#: build/lib/core/models.py:208 core/models.py:208
|
||||
msgid "device"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:219 core/models.py:219
|
||||
#: build/lib/core/models.py:210 core/models.py:210
|
||||
msgid "Whether the user is a device or a real user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:222 core/models.py:222
|
||||
#: build/lib/core/models.py:213 core/models.py:213
|
||||
msgid "staff status"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:224 core/models.py:224
|
||||
#: build/lib/core/models.py:215 core/models.py:215
|
||||
msgid "Whether the user can log into this admin site."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:227 core/models.py:227
|
||||
#: build/lib/core/models.py:218 core/models.py:218
|
||||
msgid "active"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:230 core/models.py:230
|
||||
#: build/lib/core/models.py:221 core/models.py:221
|
||||
msgid "Whether this user should be treated as active. Unselect this instead of deleting accounts."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:242 core/models.py:242
|
||||
#: build/lib/core/models.py:233 core/models.py:233
|
||||
msgid "user"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:243 core/models.py:243
|
||||
#: build/lib/core/models.py:234 core/models.py:234
|
||||
msgid "users"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:382 build/lib/core/models.py:758 core/models.py:382
|
||||
#: core/models.py:758
|
||||
#: build/lib/core/models.py:373 build/lib/core/models.py:925 core/models.py:373
|
||||
#: core/models.py:925
|
||||
msgid "title"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:404 core/models.py:404
|
||||
msgid "Document"
|
||||
#: build/lib/core/models.py:374 core/models.py:374
|
||||
msgid "excerpt"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:405 core/models.py:405
|
||||
msgid "Document"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:406 core/models.py:406
|
||||
msgid "Documents"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:408 core/models.py:408
|
||||
#: build/lib/core/models.py:418 core/models.py:418
|
||||
msgid "Untitled Document"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:633 core/models.py:633
|
||||
#: build/lib/core/models.py:719 core/models.py:719
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr "{name} a partagé un document avec vous!"
|
||||
|
||||
#: build/lib/core/models.py:637 core/models.py:637
|
||||
#: build/lib/core/models.py:723 core/models.py:723
|
||||
#, python-brace-format
|
||||
msgid "{name} invited you with the role \"{role}\" on the following document:"
|
||||
msgstr "{name} vous a invité avec le rôle \"{role}\" sur le document suivant:"
|
||||
|
||||
#: build/lib/core/models.py:640 core/models.py:640
|
||||
#: build/lib/core/models.py:726 core/models.py:726
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you: {title}"
|
||||
msgstr "{name} a partagé un document avec vous: {title}"
|
||||
|
||||
#: build/lib/core/models.py:663 core/models.py:663
|
||||
#: build/lib/core/models.py:762 core/models.py:762
|
||||
msgid "This document is not deleted."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:769 core/models.py:769
|
||||
msgid "This document was permanently deleted and cannot be restored."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:820 core/models.py:820
|
||||
msgid "Document/user link trace"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:664 core/models.py:664
|
||||
#: build/lib/core/models.py:821 core/models.py:821
|
||||
msgid "Document/user link traces"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:670 core/models.py:670
|
||||
#: build/lib/core/models.py:827 core/models.py:827
|
||||
msgid "A link trace already exists for this document/user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:693 core/models.py:693
|
||||
#: build/lib/core/models.py:850 core/models.py:850
|
||||
msgid "Document favorite"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:694 core/models.py:694
|
||||
#: build/lib/core/models.py:851 core/models.py:851
|
||||
msgid "Document favorites"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:700 core/models.py:700
|
||||
#: build/lib/core/models.py:857 core/models.py:857
|
||||
msgid "This document is already targeted by a favorite relation instance for the same user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:722 core/models.py:722
|
||||
#: build/lib/core/models.py:879 core/models.py:879
|
||||
msgid "Document/user relation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:723 core/models.py:723
|
||||
#: build/lib/core/models.py:880 core/models.py:880
|
||||
msgid "Document/user relations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:729 core/models.py:729
|
||||
#: build/lib/core/models.py:886 core/models.py:886
|
||||
msgid "This user is already in this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:735 core/models.py:735
|
||||
#: build/lib/core/models.py:892 core/models.py:892
|
||||
msgid "This team is already in this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:741 build/lib/core/models.py:930 core/models.py:741
|
||||
#: core/models.py:930
|
||||
#: build/lib/core/models.py:898 build/lib/core/models.py:1012
|
||||
#: core/models.py:898 core/models.py:1012
|
||||
msgid "Either user or team must be set, not both."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:759 core/models.py:759
|
||||
#: build/lib/core/models.py:926 core/models.py:926
|
||||
msgid "description"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:760 core/models.py:760
|
||||
#: build/lib/core/models.py:927 core/models.py:927
|
||||
msgid "code"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:761 core/models.py:761
|
||||
#: build/lib/core/models.py:928 core/models.py:928
|
||||
msgid "css"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:763 core/models.py:763
|
||||
#: build/lib/core/models.py:930 core/models.py:930
|
||||
msgid "public"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:765 core/models.py:765
|
||||
#: build/lib/core/models.py:932 core/models.py:932
|
||||
msgid "Whether this template is public for anyone to use."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:771 core/models.py:771
|
||||
#: build/lib/core/models.py:938 core/models.py:938
|
||||
msgid "Template"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:772 core/models.py:772
|
||||
#: build/lib/core/models.py:939 core/models.py:939
|
||||
msgid "Templates"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:911 core/models.py:911
|
||||
#: build/lib/core/models.py:993 core/models.py:993
|
||||
msgid "Template/user relation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:912 core/models.py:912
|
||||
#: build/lib/core/models.py:994 core/models.py:994
|
||||
msgid "Template/user relations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:918 core/models.py:918
|
||||
#: build/lib/core/models.py:1000 core/models.py:1000
|
||||
msgid "This user is already in this template."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:924 core/models.py:924
|
||||
#: build/lib/core/models.py:1006 core/models.py:1006
|
||||
msgid "This team is already in this template."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:947 core/models.py:947
|
||||
#: build/lib/core/models.py:1029 core/models.py:1029
|
||||
msgid "email address"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:966 core/models.py:966
|
||||
#: build/lib/core/models.py:1048 core/models.py:1048
|
||||
msgid "Document invitation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:967 core/models.py:967
|
||||
#: build/lib/core/models.py:1049 core/models.py:1049
|
||||
msgid "Document invitations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:987 core/models.py:987
|
||||
#: build/lib/core/models.py:1069 core/models.py:1069
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr ""
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-01-15 21:00+0000\n"
|
||||
"PO-Revision-Date: 2025-01-27 09:27\n"
|
||||
"POT-Creation-Date: 2025-01-29 13:43+0000\n"
|
||||
"PO-Revision-Date: 2025-01-30 10:24\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Dutch\n"
|
||||
"Language: nl_NL\n"
|
||||
@@ -17,18 +17,23 @@ msgstr ""
|
||||
"X-Crowdin-File: backend-impress.pot\n"
|
||||
"X-Crowdin-File-ID: 18\n"
|
||||
|
||||
#: build/lib/core/admin.py:33 core/admin.py:33
|
||||
#: build/lib/core/admin.py:37 core/admin.py:37
|
||||
msgid "Personal info"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/admin.py:46 core/admin.py:46
|
||||
#: build/lib/core/admin.py:50 build/lib/core/admin.py:138 core/admin.py:50
|
||||
#: core/admin.py:138
|
||||
msgid "Permissions"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/admin.py:58 core/admin.py:58
|
||||
#: build/lib/core/admin.py:62 core/admin.py:62
|
||||
msgid "Important dates"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/admin.py:148 core/admin.py:148
|
||||
msgid "Tree structure"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/api/filters.py:16 core/api/filters.py:16
|
||||
msgid "Creator is me"
|
||||
msgstr ""
|
||||
@@ -41,23 +46,23 @@ msgstr ""
|
||||
msgid "Title"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/api/serializers.py:317 core/api/serializers.py:317
|
||||
#: build/lib/core/api/serializers.py:346 core/api/serializers.py:346
|
||||
msgid "A new document was created on your behalf!"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/api/serializers.py:321 core/api/serializers.py:321
|
||||
#: build/lib/core/api/serializers.py:350 core/api/serializers.py:350
|
||||
msgid "You have been granted ownership of a new document:"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/api/serializers.py:422 core/api/serializers.py:422
|
||||
#: build/lib/core/api/serializers.py:453 core/api/serializers.py:453
|
||||
msgid "Body"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/api/serializers.py:425 core/api/serializers.py:425
|
||||
#: build/lib/core/api/serializers.py:456 core/api/serializers.py:456
|
||||
msgid "Body type"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/api/serializers.py:431 core/api/serializers.py:431
|
||||
#: build/lib/core/api/serializers.py:462 core/api/serializers.py:462
|
||||
msgid "Format"
|
||||
msgstr ""
|
||||
|
||||
@@ -71,270 +76,306 @@ msgstr ""
|
||||
msgid "User account is disabled"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:63 build/lib/core/models.py:70 core/models.py:63
|
||||
#: core/models.py:70
|
||||
#: build/lib/core/enums.py:19 core/enums.py:19
|
||||
msgid "First child"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:20 core/enums.py:20
|
||||
msgid "Last child"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:21 core/enums.py:21
|
||||
msgid "First sibling"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:22 core/enums.py:22
|
||||
msgid "Last sibling"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:23 core/enums.py:23
|
||||
msgid "Left"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:24 core/enums.py:24
|
||||
msgid "Right"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:54 build/lib/core/models.py:61 core/models.py:54
|
||||
#: core/models.py:61
|
||||
msgid "Reader"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:64 build/lib/core/models.py:71 core/models.py:64
|
||||
#: core/models.py:71
|
||||
#: build/lib/core/models.py:55 build/lib/core/models.py:62 core/models.py:55
|
||||
#: core/models.py:62
|
||||
msgid "Editor"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:72 core/models.py:72
|
||||
#: build/lib/core/models.py:63 core/models.py:63
|
||||
msgid "Administrator"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:73 core/models.py:73
|
||||
#: build/lib/core/models.py:64 core/models.py:64
|
||||
msgid "Owner"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:84 core/models.py:84
|
||||
#: build/lib/core/models.py:75 core/models.py:75
|
||||
msgid "Restricted"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:88 core/models.py:88
|
||||
#: build/lib/core/models.py:79 core/models.py:79
|
||||
msgid "Authenticated"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:90 core/models.py:90
|
||||
#: build/lib/core/models.py:81 core/models.py:81
|
||||
msgid "Public"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:112 core/models.py:112
|
||||
#: build/lib/core/models.py:103 core/models.py:103
|
||||
msgid "id"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:113 core/models.py:113
|
||||
#: build/lib/core/models.py:104 core/models.py:104
|
||||
msgid "primary key for the record as UUID"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:119 core/models.py:119
|
||||
#: build/lib/core/models.py:110 core/models.py:110
|
||||
msgid "created on"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:120 core/models.py:120
|
||||
#: build/lib/core/models.py:111 core/models.py:111
|
||||
msgid "date and time at which a record was created"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:125 core/models.py:125
|
||||
#: build/lib/core/models.py:116 core/models.py:116
|
||||
msgid "updated on"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:126 core/models.py:126
|
||||
#: build/lib/core/models.py:117 core/models.py:117
|
||||
msgid "date and time at which a record was last updated"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:162 core/models.py:162
|
||||
#: build/lib/core/models.py:153 core/models.py:153
|
||||
msgid "We couldn't find a user with this sub but the email is already associated with a registered user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:175 core/models.py:175
|
||||
#: build/lib/core/models.py:166 core/models.py:166
|
||||
msgid "Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/_/: characters."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:181 core/models.py:181
|
||||
#: build/lib/core/models.py:172 core/models.py:172
|
||||
msgid "sub"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:183 core/models.py:183
|
||||
#: build/lib/core/models.py:174 core/models.py:174
|
||||
msgid "Required. 255 characters or fewer. Letters, numbers, and @/./+/-/_/: characters only."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:192 core/models.py:192
|
||||
#: build/lib/core/models.py:183 core/models.py:183
|
||||
msgid "full name"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:193 core/models.py:193
|
||||
#: build/lib/core/models.py:184 core/models.py:184
|
||||
msgid "short name"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:195 core/models.py:195
|
||||
#: build/lib/core/models.py:186 core/models.py:186
|
||||
msgid "identity email address"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:200 core/models.py:200
|
||||
#: build/lib/core/models.py:191 core/models.py:191
|
||||
msgid "admin email address"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:207 core/models.py:207
|
||||
#: build/lib/core/models.py:198 core/models.py:198
|
||||
msgid "language"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:208 core/models.py:208
|
||||
#: build/lib/core/models.py:199 core/models.py:199
|
||||
msgid "The language in which the user wants to see the interface."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:214 core/models.py:214
|
||||
#: build/lib/core/models.py:205 core/models.py:205
|
||||
msgid "The timezone in which the user wants to see times."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:217 core/models.py:217
|
||||
#: build/lib/core/models.py:208 core/models.py:208
|
||||
msgid "device"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:219 core/models.py:219
|
||||
#: build/lib/core/models.py:210 core/models.py:210
|
||||
msgid "Whether the user is a device or a real user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:222 core/models.py:222
|
||||
#: build/lib/core/models.py:213 core/models.py:213
|
||||
msgid "staff status"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:224 core/models.py:224
|
||||
#: build/lib/core/models.py:215 core/models.py:215
|
||||
msgid "Whether the user can log into this admin site."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:227 core/models.py:227
|
||||
#: build/lib/core/models.py:218 core/models.py:218
|
||||
msgid "active"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:230 core/models.py:230
|
||||
#: build/lib/core/models.py:221 core/models.py:221
|
||||
msgid "Whether this user should be treated as active. Unselect this instead of deleting accounts."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:242 core/models.py:242
|
||||
#: build/lib/core/models.py:233 core/models.py:233
|
||||
msgid "user"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:243 core/models.py:243
|
||||
#: build/lib/core/models.py:234 core/models.py:234
|
||||
msgid "users"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:382 build/lib/core/models.py:758 core/models.py:382
|
||||
#: core/models.py:758
|
||||
#: build/lib/core/models.py:373 build/lib/core/models.py:925 core/models.py:373
|
||||
#: core/models.py:925
|
||||
msgid "title"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:404 core/models.py:404
|
||||
msgid "Document"
|
||||
#: build/lib/core/models.py:374 core/models.py:374
|
||||
msgid "excerpt"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:405 core/models.py:405
|
||||
msgid "Document"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:406 core/models.py:406
|
||||
msgid "Documents"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:408 core/models.py:408
|
||||
#: build/lib/core/models.py:418 core/models.py:418
|
||||
msgid "Untitled Document"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:633 core/models.py:633
|
||||
#: build/lib/core/models.py:719 core/models.py:719
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:637 core/models.py:637
|
||||
#: build/lib/core/models.py:723 core/models.py:723
|
||||
#, python-brace-format
|
||||
msgid "{name} invited you with the role \"{role}\" on the following document:"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:640 core/models.py:640
|
||||
#: build/lib/core/models.py:726 core/models.py:726
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you: {title}"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:663 core/models.py:663
|
||||
#: build/lib/core/models.py:762 core/models.py:762
|
||||
msgid "This document is not deleted."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:769 core/models.py:769
|
||||
msgid "This document was permanently deleted and cannot be restored."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:820 core/models.py:820
|
||||
msgid "Document/user link trace"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:664 core/models.py:664
|
||||
#: build/lib/core/models.py:821 core/models.py:821
|
||||
msgid "Document/user link traces"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:670 core/models.py:670
|
||||
#: build/lib/core/models.py:827 core/models.py:827
|
||||
msgid "A link trace already exists for this document/user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:693 core/models.py:693
|
||||
#: build/lib/core/models.py:850 core/models.py:850
|
||||
msgid "Document favorite"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:694 core/models.py:694
|
||||
#: build/lib/core/models.py:851 core/models.py:851
|
||||
msgid "Document favorites"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:700 core/models.py:700
|
||||
#: build/lib/core/models.py:857 core/models.py:857
|
||||
msgid "This document is already targeted by a favorite relation instance for the same user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:722 core/models.py:722
|
||||
#: build/lib/core/models.py:879 core/models.py:879
|
||||
msgid "Document/user relation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:723 core/models.py:723
|
||||
#: build/lib/core/models.py:880 core/models.py:880
|
||||
msgid "Document/user relations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:729 core/models.py:729
|
||||
#: build/lib/core/models.py:886 core/models.py:886
|
||||
msgid "This user is already in this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:735 core/models.py:735
|
||||
#: build/lib/core/models.py:892 core/models.py:892
|
||||
msgid "This team is already in this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:741 build/lib/core/models.py:930 core/models.py:741
|
||||
#: core/models.py:930
|
||||
#: build/lib/core/models.py:898 build/lib/core/models.py:1012
|
||||
#: core/models.py:898 core/models.py:1012
|
||||
msgid "Either user or team must be set, not both."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:759 core/models.py:759
|
||||
#: build/lib/core/models.py:926 core/models.py:926
|
||||
msgid "description"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:760 core/models.py:760
|
||||
#: build/lib/core/models.py:927 core/models.py:927
|
||||
msgid "code"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:761 core/models.py:761
|
||||
#: build/lib/core/models.py:928 core/models.py:928
|
||||
msgid "css"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:763 core/models.py:763
|
||||
#: build/lib/core/models.py:930 core/models.py:930
|
||||
msgid "public"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:765 core/models.py:765
|
||||
#: build/lib/core/models.py:932 core/models.py:932
|
||||
msgid "Whether this template is public for anyone to use."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:771 core/models.py:771
|
||||
#: build/lib/core/models.py:938 core/models.py:938
|
||||
msgid "Template"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:772 core/models.py:772
|
||||
#: build/lib/core/models.py:939 core/models.py:939
|
||||
msgid "Templates"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:911 core/models.py:911
|
||||
#: build/lib/core/models.py:993 core/models.py:993
|
||||
msgid "Template/user relation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:912 core/models.py:912
|
||||
#: build/lib/core/models.py:994 core/models.py:994
|
||||
msgid "Template/user relations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:918 core/models.py:918
|
||||
#: build/lib/core/models.py:1000 core/models.py:1000
|
||||
msgid "This user is already in this template."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:924 core/models.py:924
|
||||
#: build/lib/core/models.py:1006 core/models.py:1006
|
||||
msgid "This team is already in this template."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:947 core/models.py:947
|
||||
#: build/lib/core/models.py:1029 core/models.py:1029
|
||||
msgid "email address"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:966 core/models.py:966
|
||||
#: build/lib/core/models.py:1048 core/models.py:1048
|
||||
msgid "Document invitation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:967 core/models.py:967
|
||||
#: build/lib/core/models.py:1049 core/models.py:1049
|
||||
msgid "Document invitations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:987 core/models.py:987
|
||||
#: build/lib/core/models.py:1069 core/models.py:1069
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr ""
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "impress"
|
||||
version = "2.0.1"
|
||||
version = "2.1.0"
|
||||
authors = [{ "name" = "DINUM", "email" = "dev@mail.numerique.gouv.fr" }]
|
||||
classifiers = [
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
await expect(
|
||||
page.locator('header').first().locator('h2').getByText('Docs'),
|
||||
).toBeVisible();
|
||||
@@ -24,6 +24,6 @@ test.describe('404', () => {
|
||||
page,
|
||||
}) => {
|
||||
await page.getByText('Back to home page').click();
|
||||
await expect(page).toHaveURL('/docs/');
|
||||
await expect(page).toHaveURL('/');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,8 +3,7 @@ import { test as setup } from '@playwright/test';
|
||||
import { keyCloakSignIn } from './common';
|
||||
|
||||
setup('authenticate-chromium', async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
await page.getByTestId('proconnect-button').first().click();
|
||||
await page.goto('/');
|
||||
await keyCloakSignIn(page, 'chromium');
|
||||
await page
|
||||
.context()
|
||||
@@ -12,8 +11,7 @@ setup('authenticate-chromium', async ({ page }) => {
|
||||
});
|
||||
|
||||
setup('authenticate-webkit', async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
await page.getByTestId('proconnect-button').first().click();
|
||||
await page.goto('/');
|
||||
await keyCloakSignIn(page, 'webkit');
|
||||
await page
|
||||
.context()
|
||||
@@ -21,8 +19,7 @@ setup('authenticate-webkit', async ({ page }) => {
|
||||
});
|
||||
|
||||
setup('authenticate-firefox', async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
await page.getByTestId('proconnect-button').first().click();
|
||||
await page.goto('/');
|
||||
await keyCloakSignIn(page, 'firefox');
|
||||
await page
|
||||
.context()
|
||||
|
||||
@@ -21,43 +21,13 @@ const config = {
|
||||
};
|
||||
|
||||
test.describe('Config', () => {
|
||||
test('it checks that media server is configured from config endpoint', async ({
|
||||
page,
|
||||
browserName,
|
||||
}) => {
|
||||
await page.goto('/docs/');
|
||||
|
||||
await createDoc(page, 'doc-media', browserName, 1);
|
||||
|
||||
const fileChooserPromise = page.waitForEvent('filechooser');
|
||||
|
||||
await page.locator('.bn-block-outer').last().fill('Anything');
|
||||
await page.locator('.bn-block-outer').last().fill('/');
|
||||
await page.getByText('Resizable image with caption').click();
|
||||
await page.getByText('Upload image').click();
|
||||
|
||||
const fileChooser = await fileChooserPromise;
|
||||
await fileChooser.setFiles(
|
||||
path.join(__dirname, 'assets/logo-suite-numerique.png'),
|
||||
);
|
||||
|
||||
const image = page.getByRole('img', { name: 'logo-suite-numerique.png' });
|
||||
|
||||
await expect(image).toBeVisible();
|
||||
|
||||
// Check src of image
|
||||
expect(await image.getAttribute('src')).toMatch(
|
||||
/http:\/\/localhost:8083\/media\/.*\/attachments\/.*.png/,
|
||||
);
|
||||
});
|
||||
|
||||
test('it checks the config api is called', async ({ page }) => {
|
||||
const responsePromise = page.waitForResponse(
|
||||
(response) =>
|
||||
response.url().includes('/config/') && response.status() === 200,
|
||||
);
|
||||
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
|
||||
const response = await responsePromise;
|
||||
expect(response.ok()).toBeTruthy();
|
||||
@@ -88,11 +58,62 @@ test.describe('Config', () => {
|
||||
predicate: (msg) => msg.text().includes(invalidMsg),
|
||||
});
|
||||
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
|
||||
expect((await consoleMessage).text()).toContain(invalidMsg);
|
||||
});
|
||||
|
||||
test('it checks that theme is configured from config endpoint', async ({
|
||||
page,
|
||||
}) => {
|
||||
const responsePromise = page.waitForResponse(
|
||||
(response) =>
|
||||
response.url().includes('/config/') && response.status() === 200,
|
||||
);
|
||||
|
||||
await page.goto('/');
|
||||
|
||||
const response = await responsePromise;
|
||||
expect(response.ok()).toBeTruthy();
|
||||
|
||||
const jsonResponse = await response.json();
|
||||
expect(jsonResponse.FRONTEND_THEME).toStrictEqual('dsfr');
|
||||
|
||||
const footer = page.locator('footer').first();
|
||||
// alt 'Gouvernement Logo' comes from the theme
|
||||
await expect(footer.getByAltText('Gouvernement Logo')).toBeVisible();
|
||||
});
|
||||
|
||||
test('it checks that media server is configured from config endpoint', async ({
|
||||
page,
|
||||
browserName,
|
||||
}) => {
|
||||
await page.goto('/');
|
||||
|
||||
await createDoc(page, 'doc-media', browserName, 1);
|
||||
|
||||
const fileChooserPromise = page.waitForEvent('filechooser');
|
||||
|
||||
await page.locator('.bn-block-outer').last().fill('Anything');
|
||||
await page.locator('.bn-block-outer').last().fill('/');
|
||||
await page.getByText('Resizable image with caption').click();
|
||||
await page.getByText('Upload image').click();
|
||||
|
||||
const fileChooser = await fileChooserPromise;
|
||||
await fileChooser.setFiles(
|
||||
path.join(__dirname, 'assets/logo-suite-numerique.png'),
|
||||
);
|
||||
|
||||
const image = page.getByRole('img', { name: 'logo-suite-numerique.png' });
|
||||
|
||||
await expect(image).toBeVisible();
|
||||
|
||||
// Check src of image
|
||||
expect(await image.getAttribute('src')).toMatch(
|
||||
/http:\/\/localhost:8083\/media\/.*\/attachments\/.*.png/,
|
||||
);
|
||||
});
|
||||
|
||||
test('it checks that collaboration server is configured from config endpoint', async ({
|
||||
page,
|
||||
browserName,
|
||||
@@ -101,7 +122,7 @@ test.describe('Config', () => {
|
||||
return webSocket.url().includes('ws://localhost:8083/collaboration/ws/');
|
||||
});
|
||||
|
||||
await page.goto('/docs');
|
||||
await page.goto('/');
|
||||
|
||||
const randomDoc = await createDoc(
|
||||
page,
|
||||
@@ -133,29 +154,10 @@ test.describe('Config', () => {
|
||||
}
|
||||
});
|
||||
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
|
||||
await expect(
|
||||
page.locator('#crisp-chatbox').getByText('Invalid website'),
|
||||
).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Config footer logo', () => {
|
||||
test('it checks that theme is configured from config endpoint', async ({
|
||||
page,
|
||||
}) => {
|
||||
const responsePromise = page.waitForResponse(
|
||||
(response) =>
|
||||
response.url().includes('/config/') && response.status() === 200,
|
||||
);
|
||||
|
||||
await page.goto('/docs/');
|
||||
|
||||
const response = await responsePromise;
|
||||
expect(response.ok()).toBeTruthy();
|
||||
|
||||
const jsonResponse = await response.json();
|
||||
expect(jsonResponse.FRONTEND_THEME).toStrictEqual('dsfr');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
} from './common';
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
});
|
||||
|
||||
test.describe('Doc Create', () => {
|
||||
@@ -62,7 +62,7 @@ test.describe('Doc Create: Not loggued', () => {
|
||||
);
|
||||
|
||||
expect(newDoc.ok()).toBeTruthy();
|
||||
await page.getByTestId('proconnect-button').first().click();
|
||||
|
||||
await keyCloakSignIn(page, browserName);
|
||||
|
||||
await goToGridDoc(page, { title });
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
} from './common';
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
});
|
||||
|
||||
test.describe('Doc Editor', () => {
|
||||
@@ -257,7 +257,7 @@ test.describe('Doc Editor', () => {
|
||||
await editor.fill('Hello World Doc persisted 2');
|
||||
await expect(editor.getByText('Hello World Doc persisted 2')).toBeVisible();
|
||||
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
|
||||
await goToGridDoc(page, {
|
||||
title: doc,
|
||||
@@ -368,4 +368,84 @@ test.describe('Doc Editor', () => {
|
||||
|
||||
await expect(editor.getByText('Bonjour le monde')).toBeVisible();
|
||||
});
|
||||
|
||||
test('it checks the divider block', async ({ page, browserName }) => {
|
||||
await createDoc(page, 'divider-block', browserName, 1);
|
||||
|
||||
const editor = page.locator('.ProseMirror');
|
||||
// Trigger slash menu to show menu
|
||||
await editor.click();
|
||||
await editor.fill('/');
|
||||
await page.getByText('Divider', { exact: true }).click();
|
||||
|
||||
await expect(
|
||||
editor.locator('.bn-block-content[data-content-type="divider"]'),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test('it checks the quote block', async ({ page, browserName }) => {
|
||||
await createDoc(page, 'divider-block', browserName, 1);
|
||||
|
||||
const editor = page.locator('.ProseMirror');
|
||||
// Trigger slash menu to show menu
|
||||
await editor.click();
|
||||
await editor.fill('/');
|
||||
await page.getByText('Quote', { exact: true }).click();
|
||||
|
||||
await expect(
|
||||
editor.locator('.bn-block-content[data-content-type="quote"]'),
|
||||
).toBeVisible();
|
||||
|
||||
await editor.fill('Hello World');
|
||||
|
||||
await expect(editor.getByText('Hello World')).toHaveCSS(
|
||||
'font-style',
|
||||
'italic',
|
||||
);
|
||||
});
|
||||
|
||||
test('it checks the alert block', async ({ page, browserName }) => {
|
||||
await createDoc(page, 'divider-block', browserName, 1);
|
||||
|
||||
const editor = page.locator('.ProseMirror');
|
||||
// Trigger slash menu to show menu
|
||||
await editor.click();
|
||||
await editor.fill('/');
|
||||
await page.getByText('Alert', { exact: true }).click();
|
||||
|
||||
const alertBlock = editor.locator(
|
||||
'.bn-block-content[data-content-type="alert"]',
|
||||
);
|
||||
await expect(
|
||||
alertBlock.locator('div[data-alert-type="warning"]'),
|
||||
).toBeVisible();
|
||||
await editor.fill('My alert');
|
||||
await expect(alertBlock.getByText('My alert')).toBeVisible();
|
||||
|
||||
await alertBlock.getByText('warning').click();
|
||||
|
||||
await expect(
|
||||
alertBlock.getByRole('menuitem', { name: 'warning Warning' }),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(
|
||||
alertBlock.getByRole('menuitem', { name: 'error Error' }),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(
|
||||
alertBlock.getByRole('menuitem', { name: 'info Info' }),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(
|
||||
alertBlock.getByRole('menuitem', { name: 'check_circle Success' }),
|
||||
).toBeVisible();
|
||||
|
||||
await alertBlock
|
||||
.getByRole('menuitem', { name: 'check_circle Success' })
|
||||
.click();
|
||||
|
||||
await expect(
|
||||
alertBlock.locator('div[data-alert-type="success"]'),
|
||||
).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@ import pdf from 'pdf-parse';
|
||||
import { createDoc, verifyDocName } from './common';
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
});
|
||||
|
||||
test.describe('Doc Export', () => {
|
||||
@@ -29,9 +29,7 @@ test.describe('Doc Export', () => {
|
||||
.first(),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page.getByText(
|
||||
'Upload your docs to a Microsoft Word, Open Office or PDF document',
|
||||
),
|
||||
page.getByText('Download your document in a .docx or .pdf format.'),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page.getByRole('combobox', { name: 'Template' }),
|
||||
@@ -95,7 +93,7 @@ test.describe('Doc Export', () => {
|
||||
.click();
|
||||
|
||||
await page.getByRole('combobox', { name: 'Format' }).click();
|
||||
await page.getByRole('option', { name: 'Word / Open Office' }).click();
|
||||
await page.getByRole('option', { name: 'Docx' }).click();
|
||||
|
||||
await page
|
||||
.getByRole('button', {
|
||||
|
||||
@@ -8,14 +8,14 @@ type SmallDoc = {
|
||||
};
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
});
|
||||
|
||||
test.describe('Documents Grid mobile', () => {
|
||||
test.use({ viewport: { width: 500, height: 1200 } });
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
});
|
||||
|
||||
test('it checks the grid when mobile', async ({ page }) => {
|
||||
@@ -76,7 +76,7 @@ test.describe('Documents Grid mobile', () => {
|
||||
}
|
||||
});
|
||||
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
|
||||
const docsGrid = page.getByTestId('docs-grid');
|
||||
await expect(docsGrid).toBeVisible();
|
||||
@@ -195,7 +195,7 @@ test.describe('Document grid item options', () => {
|
||||
},
|
||||
});
|
||||
});
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
|
||||
const button = page.getByTestId(
|
||||
`docs-grid-actions-button-mocked-document-id`,
|
||||
@@ -286,7 +286,7 @@ test.describe('Documents filters', () => {
|
||||
|
||||
test.describe('Documents Grid', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
});
|
||||
|
||||
test('checks all the elements are visible', async ({ page }) => {
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
} from './common';
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
});
|
||||
|
||||
test.describe('Doc Header', () => {
|
||||
@@ -434,7 +434,7 @@ test.describe('Documents Header mobile', () => {
|
||||
test.use({ viewport: { width: 500, height: 1200 } });
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
});
|
||||
|
||||
test('it checks the copy link button', async ({ page, browserName }) => {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { expect, test } from '@playwright/test';
|
||||
import { createDoc, randomName } from './common';
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
});
|
||||
|
||||
test.describe('Document create member', () => {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { expect, test } from '@playwright/test';
|
||||
import { addNewMember, createDoc, goToGridDoc, verifyDocName } from './common';
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
});
|
||||
|
||||
test.describe('Document list members', () => {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { keyCloakSignIn, mockedDocument } from './common';
|
||||
|
||||
test.describe('Doc Routing', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
});
|
||||
|
||||
test('Check the presence of the meta tag noindex', async ({ page }) => {
|
||||
@@ -24,7 +24,7 @@ test.describe('Doc Routing', () => {
|
||||
});
|
||||
|
||||
test('checks alias docs url with homepage', async ({ page }) => {
|
||||
await expect(page).toHaveURL('/docs/');
|
||||
await expect(page).toHaveURL('/');
|
||||
|
||||
const buttonCreateHomepage = page.getByRole('button', {
|
||||
name: 'New doc',
|
||||
@@ -62,18 +62,17 @@ test.describe('Doc Routing: Not loggued', () => {
|
||||
await mockedDocument(page, { link_reach: 'public' });
|
||||
await page.goto('/docs/mocked-document-id/');
|
||||
await expect(page.locator('h2').getByText('Mocked document')).toBeVisible();
|
||||
|
||||
await page.getByRole('button', { name: 'Login' }).click();
|
||||
|
||||
await keyCloakSignIn(page, browserName);
|
||||
await expect(page.locator('h2').getByText('Mocked document')).toBeVisible();
|
||||
});
|
||||
|
||||
test('Check is redirected to home page if user is not logged', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto('/docs/');
|
||||
|
||||
await expect(page.getByTestId('proconnect-button').first()).toBeVisible();
|
||||
test('The homepage redirects to login.', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await expect(
|
||||
page.getByRole('button', {
|
||||
name: 'Sign In',
|
||||
}),
|
||||
).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@ import { expect, test } from '@playwright/test';
|
||||
import { createDoc, verifyDocName } from './common';
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
});
|
||||
|
||||
test.describe('Document search', () => {
|
||||
@@ -15,7 +15,7 @@ test.describe('Document search', () => {
|
||||
1,
|
||||
);
|
||||
await verifyDocName(page, doc1Title);
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
|
||||
const [doc2Title] = await createDoc(
|
||||
page,
|
||||
@@ -24,7 +24,7 @@ test.describe('Document search', () => {
|
||||
1,
|
||||
);
|
||||
await verifyDocName(page, doc2Title);
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
await page.getByRole('button', { name: 'search' }).click();
|
||||
|
||||
await expect(
|
||||
|
||||
@@ -3,7 +3,7 @@ import { expect, test } from '@playwright/test';
|
||||
import { createDoc, verifyDocName } from './common';
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
});
|
||||
|
||||
test.describe('Doc Table Content', () => {
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
} from './common';
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
});
|
||||
|
||||
test.describe('Doc Version', () => {
|
||||
|
||||
@@ -6,7 +6,7 @@ const browsersName = ['chromium', 'webkit', 'firefox'];
|
||||
|
||||
test.describe('Doc Visibility', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
});
|
||||
|
||||
test('It checks the copy link button', async ({ page, browserName }) => {
|
||||
@@ -71,8 +71,7 @@ test.describe('Doc Visibility: Restricted', () => {
|
||||
page,
|
||||
browserName,
|
||||
}) => {
|
||||
await page.goto('/docs/');
|
||||
await page.getByTestId('proconnect-button').first().click();
|
||||
await page.goto('/');
|
||||
await keyCloakSignIn(page, browserName);
|
||||
|
||||
const [docTitle] = await createDoc(
|
||||
@@ -92,9 +91,9 @@ test.describe('Doc Visibility: Restricted', () => {
|
||||
})
|
||||
.click();
|
||||
|
||||
await expect(page.getByTestId('proconnect-button').first()).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: 'Sign in' })).toBeVisible();
|
||||
|
||||
await page.goto(urlDoc);
|
||||
await page.getByTestId('proconnect-button').first().click();
|
||||
|
||||
await expect(page.getByRole('textbox', { name: 'password' })).toBeVisible();
|
||||
});
|
||||
@@ -103,8 +102,7 @@ test.describe('Doc Visibility: Restricted', () => {
|
||||
page,
|
||||
browserName,
|
||||
}) => {
|
||||
await page.goto('/docs/');
|
||||
await page.getByTestId('proconnect-button').first().click();
|
||||
await page.goto('/');
|
||||
await keyCloakSignIn(page, browserName);
|
||||
|
||||
const [docTitle] = await createDoc(page, 'Restricted auth', browserName, 1);
|
||||
@@ -121,7 +119,6 @@ test.describe('Doc Visibility: Restricted', () => {
|
||||
|
||||
const otherBrowser = browsersName.find((b) => b !== browserName);
|
||||
|
||||
await page.getByTestId('proconnect-button').first().click();
|
||||
await keyCloakSignIn(page, otherBrowser!);
|
||||
|
||||
await page.goto(urlDoc);
|
||||
@@ -133,8 +130,7 @@ test.describe('Doc Visibility: Restricted', () => {
|
||||
|
||||
test('A doc is accessible when member.', async ({ page, browserName }) => {
|
||||
test.slow();
|
||||
await page.goto('/docs/');
|
||||
await page.getByTestId('proconnect-button').first().click();
|
||||
await page.goto('/');
|
||||
await keyCloakSignIn(page, browserName);
|
||||
|
||||
const [docTitle] = await createDoc(page, 'Restricted auth', browserName, 1);
|
||||
@@ -171,7 +167,6 @@ test.describe('Doc Visibility: Restricted', () => {
|
||||
})
|
||||
.click();
|
||||
|
||||
await page.getByTestId('proconnect-button').first().click();
|
||||
await keyCloakSignIn(page, otherBrowser!);
|
||||
|
||||
await page.goto(urlDoc);
|
||||
@@ -191,8 +186,7 @@ test.describe('Doc Visibility: Public', () => {
|
||||
page,
|
||||
browserName,
|
||||
}) => {
|
||||
await page.goto('/docs/');
|
||||
await page.getByTestId('proconnect-button').first().click();
|
||||
await page.goto('/');
|
||||
await keyCloakSignIn(page, browserName);
|
||||
|
||||
const [docTitle] = await createDoc(
|
||||
@@ -253,7 +247,7 @@ test.describe('Doc Visibility: Public', () => {
|
||||
})
|
||||
.click();
|
||||
|
||||
await expect(page.getByTestId('proconnect-button').first()).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: 'Sign in' })).toBeVisible();
|
||||
|
||||
await page.goto(urlDoc);
|
||||
|
||||
@@ -271,8 +265,7 @@ test.describe('Doc Visibility: Public', () => {
|
||||
page,
|
||||
browserName,
|
||||
}) => {
|
||||
await page.goto('/docs/');
|
||||
await page.getByTestId('proconnect-button').first().click();
|
||||
await page.goto('/');
|
||||
await keyCloakSignIn(page, browserName);
|
||||
|
||||
const [docTitle] = await createDoc(page, 'Public editable', browserName, 1);
|
||||
@@ -320,7 +313,7 @@ test.describe('Doc Visibility: Public', () => {
|
||||
})
|
||||
.click();
|
||||
|
||||
await expect(page.getByTestId('proconnect-button').first()).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: 'Sign in' })).toBeVisible();
|
||||
|
||||
await page.goto(urlDoc);
|
||||
|
||||
@@ -336,8 +329,7 @@ test.describe('Doc Visibility: Authenticated', () => {
|
||||
page,
|
||||
browserName,
|
||||
}) => {
|
||||
await page.goto('/docs/');
|
||||
await page.getByTestId('proconnect-button').first().click();
|
||||
await page.goto('/');
|
||||
await keyCloakSignIn(page, browserName);
|
||||
|
||||
const [docTitle] = await createDoc(
|
||||
@@ -372,12 +364,11 @@ test.describe('Doc Visibility: Authenticated', () => {
|
||||
})
|
||||
.click();
|
||||
|
||||
await expect(page.getByTestId('proconnect-button').first()).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: 'Sign in' })).toBeVisible();
|
||||
|
||||
await page.goto(urlDoc);
|
||||
|
||||
await expect(page.locator('h2').getByText(docTitle)).toBeHidden();
|
||||
await page.getByTestId('proconnect-button').first().click();
|
||||
await expect(page.getByRole('textbox', { name: 'password' })).toBeVisible();
|
||||
});
|
||||
|
||||
@@ -385,8 +376,7 @@ test.describe('Doc Visibility: Authenticated', () => {
|
||||
page,
|
||||
browserName,
|
||||
}) => {
|
||||
await page.goto('/docs/');
|
||||
await page.getByTestId('proconnect-button').first().click();
|
||||
await page.goto('/');
|
||||
await keyCloakSignIn(page, browserName);
|
||||
|
||||
const [docTitle] = await createDoc(
|
||||
@@ -422,7 +412,6 @@ test.describe('Doc Visibility: Authenticated', () => {
|
||||
.click();
|
||||
|
||||
const otherBrowser = browsersName.find((b) => b !== browserName);
|
||||
await page.getByTestId('proconnect-button').first().click();
|
||||
await keyCloakSignIn(page, otherBrowser!);
|
||||
|
||||
await page.goto(urlDoc);
|
||||
@@ -437,8 +426,7 @@ test.describe('Doc Visibility: Authenticated', () => {
|
||||
page,
|
||||
browserName,
|
||||
}) => {
|
||||
await page.goto('/docs/');
|
||||
await page.getByTestId('proconnect-button').first().click();
|
||||
await page.goto('/');
|
||||
await keyCloakSignIn(page, browserName);
|
||||
|
||||
const [docTitle] = await createDoc(
|
||||
@@ -480,7 +468,6 @@ test.describe('Doc Visibility: Authenticated', () => {
|
||||
.click();
|
||||
|
||||
const otherBrowser = browsersName.find((b) => b !== browserName);
|
||||
await page.getByTestId('proconnect-button').first().click();
|
||||
await keyCloakSignIn(page, otherBrowser!);
|
||||
|
||||
await page.goto(urlDoc);
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
import { keyCloakSignIn } from './common';
|
||||
import { goToGridDoc } from './common';
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
});
|
||||
|
||||
test.describe('Footer', () => {
|
||||
test.use({ storageState: { cookies: [], origins: [] } });
|
||||
test('checks all the elements are visible', async ({ page }) => {
|
||||
const footer = page.locator('footer').first();
|
||||
|
||||
@@ -48,14 +47,9 @@ test.describe('Footer', () => {
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test('checks footer is not visible on doc editor', async ({
|
||||
page,
|
||||
browserName,
|
||||
}) => {
|
||||
await page.getByTestId('proconnect-button').first().click();
|
||||
await keyCloakSignIn(page, browserName);
|
||||
await page.goto('/docs/');
|
||||
|
||||
test('checks footer is not visible on doc editor', async ({ page }) => {
|
||||
await expect(page.locator('footer')).toBeVisible();
|
||||
await goToGridDoc(page);
|
||||
await expect(page.locator('footer')).toBeHidden();
|
||||
});
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { keyCloakSignIn } from './common';
|
||||
|
||||
test.describe('Header', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
});
|
||||
|
||||
test('checks all the elements are visible', async ({ page }) => {
|
||||
@@ -69,7 +69,7 @@ test.describe('Header mobile', () => {
|
||||
test.use({ viewport: { width: 500, height: 1200 } });
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
});
|
||||
|
||||
test('it checks the header when mobile', async ({ page }) => {
|
||||
@@ -89,8 +89,7 @@ test.describe('Header: Log out', () => {
|
||||
test.use({ storageState: { cookies: [], origins: [] } });
|
||||
|
||||
test('checks logout button', async ({ page, browserName }) => {
|
||||
await page.goto('/docs/');
|
||||
await page.getByTestId('proconnect-button').first().click();
|
||||
await page.goto('/');
|
||||
await keyCloakSignIn(page, browserName);
|
||||
|
||||
await page
|
||||
@@ -99,6 +98,6 @@ test.describe('Header: Log out', () => {
|
||||
})
|
||||
.click();
|
||||
|
||||
await expect(page.getByTestId('proconnect-button')).toHaveCount(2);
|
||||
await expect(page.getByRole('button', { name: 'Sign in' })).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
});
|
||||
|
||||
test.describe('Home page', () => {
|
||||
test.use({ storageState: { cookies: [], origins: [] } });
|
||||
test('checks all the elements are visible', async ({ page }) => {
|
||||
// Check header content
|
||||
const header = page.locator('header').first();
|
||||
const footer = page.locator('footer').first();
|
||||
await expect(header).toBeVisible();
|
||||
await expect(
|
||||
header.getByRole('combobox', { name: 'Language' }),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
header.getByRole('button', { name: 'Les services de La Suite numé' }),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
header.getByRole('img', { name: 'Gouvernement Logo' }),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
header.getByRole('img', { name: 'Docs app logo' }),
|
||||
).toBeVisible();
|
||||
await expect(header.getByRole('heading', { name: 'Docs' })).toBeVisible();
|
||||
await expect(header.getByText('BETA')).toBeVisible();
|
||||
|
||||
// Check the ttile and subtitle are visible
|
||||
await expect(page.getByText('Collaborative writing made')).toBeVisible();
|
||||
await expect(page.getByText('Collaborate and write in real')).toBeVisible();
|
||||
await expect(page.getByText('An uncompromising writing')).toBeVisible();
|
||||
await expect(page.getByText('Docs offers an intuitive')).toBeVisible();
|
||||
await expect(page.getByText('Simple and secure')).toBeVisible();
|
||||
await expect(page.getByText('Docs makes real-time')).toBeVisible();
|
||||
await expect(page.getByText('Flexible export.')).toBeVisible();
|
||||
await expect(page.getByText('To facilitate the circulation')).toBeVisible();
|
||||
await expect(page.getByText('A new way to organize')).toBeVisible();
|
||||
await expect(page.getByText('Docs transforms your')).toBeVisible();
|
||||
|
||||
await expect(page.getByTestId('proconnect-button')).toHaveCount(2);
|
||||
|
||||
// Footer - The footer is already tested in its entirety in the footer.spec.ts file
|
||||
await expect(footer).toBeVisible();
|
||||
await expect(
|
||||
page.getByRole('link', { name: 'expand_more See more' }),
|
||||
).toBeVisible();
|
||||
});
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
});
|
||||
|
||||
test.describe('Language', () => {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { expect, test } from '@playwright/test';
|
||||
|
||||
test.describe('Left panel desktop', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
});
|
||||
|
||||
test('checks all the elements are visible', async ({ page }) => {
|
||||
@@ -17,7 +17,7 @@ test.describe('Left panel mobile', () => {
|
||||
test.use({ viewport: { width: 500, height: 1200 } });
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
await page.goto('/');
|
||||
});
|
||||
|
||||
test('checks all the desktop elements are hidden and all mobile elements are visible', async ({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "app-e2e",
|
||||
"version": "2.0.1",
|
||||
"version": "2.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"lint": "eslint . --ext .ts",
|
||||
@@ -12,7 +12,7 @@
|
||||
"test:ui::chromium": "yarn test:ui --project=chromium"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "1.49.1",
|
||||
"@playwright/test": "1.50.0",
|
||||
"@types/node": "*",
|
||||
"@types/pdf-parse": "1.1.4",
|
||||
"eslint-config-impress": "*",
|
||||
|
||||
@@ -5,7 +5,6 @@ const config = {
|
||||
colors: {
|
||||
'card-border': '#ededed',
|
||||
'primary-bg': '#FAFAFA',
|
||||
'primary-action': '#1212FF',
|
||||
'primary-050': '#F5F5FE',
|
||||
'primary-100': '#EDF5FA',
|
||||
'primary-150': '#E5EEFA',
|
||||
@@ -60,11 +59,6 @@ const config = {
|
||||
h4: '1.375rem',
|
||||
h5: '1.25rem',
|
||||
h6: '1.125rem',
|
||||
'xl-alt': '5rem',
|
||||
'lg-alt': '4.5rem',
|
||||
'md-alt': '4rem',
|
||||
'sm-alt': '3.5rem',
|
||||
'xs-alt': '3rem',
|
||||
},
|
||||
weights: {
|
||||
thin: 100,
|
||||
@@ -230,7 +224,7 @@ const config = {
|
||||
'color-hover': 'var(--c--theme--colors--primary-700)',
|
||||
},
|
||||
border: {
|
||||
color: 'var(--c--theme--colors--greyscale-300)',
|
||||
color: 'var(--c--theme--colors--primary-200)',
|
||||
},
|
||||
},
|
||||
tertiary: {
|
||||
@@ -385,8 +379,8 @@ const config = {
|
||||
'color-active': '#EDEDED',
|
||||
},
|
||||
border: {
|
||||
color: 'var(--c--theme--colors--greyscale-300)',
|
||||
'color-hover': 'var(--c--theme--colors--greyscale-300)',
|
||||
color: 'var(--c--theme--colors--primary-600)',
|
||||
'color-hover': 'var(--c--theme--colors--primary-600)',
|
||||
},
|
||||
color: 'var(--c--theme--colors--primary-text)',
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "app-impress",
|
||||
"version": "2.0.1",
|
||||
"version": "2.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
@@ -21,42 +21,42 @@
|
||||
"@blocknote/xl-docx-exporter": "0.21.0",
|
||||
"@blocknote/xl-pdf-exporter": "0.21.0",
|
||||
"@gouvfr-lasuite/integration": "1.0.2",
|
||||
"@hocuspocus/provider": "2.15.0",
|
||||
"@hocuspocus/provider": "2.15.1",
|
||||
"@openfun/cunningham-react": "2.9.4",
|
||||
"@react-pdf/renderer": "4.1.6",
|
||||
"@sentry/nextjs": "8.47.0",
|
||||
"@tanstack/react-query": "5.62.11",
|
||||
"@sentry/nextjs": "8.52.0",
|
||||
"@tanstack/react-query": "5.65.1",
|
||||
"cmdk": "1.0.4",
|
||||
"crisp-sdk-web": "1.0.25",
|
||||
"docx": "9.1.0",
|
||||
"i18next": "24.2.0",
|
||||
"docx": "9.1.1",
|
||||
"i18next": "24.2.2",
|
||||
"i18next-browser-languagedetector": "8.0.2",
|
||||
"idb": "8.0.1",
|
||||
"lodash": "4.17.21",
|
||||
"luxon": "3.5.0",
|
||||
"next": "15.1.3",
|
||||
"posthog-js": "1.204.0",
|
||||
"next": "15.1.6",
|
||||
"posthog-js": "1.211.3",
|
||||
"react": "*",
|
||||
"react-aria-components": "1.5.0",
|
||||
"react-aria-components": "1.6.0",
|
||||
"react-dom": "*",
|
||||
"react-i18next": "15.4.0",
|
||||
"react-intersection-observer": "9.13.1",
|
||||
"react-select": "5.9.0",
|
||||
"styled-components": "6.1.13",
|
||||
"react-intersection-observer": "9.15.1",
|
||||
"react-select": "5.10.0",
|
||||
"styled-components": "6.1.14",
|
||||
"use-debounce": "10.0.4",
|
||||
"y-protocols": "1.0.6",
|
||||
"yjs": "13.6.21",
|
||||
"zustand": "5.0.2"
|
||||
"yjs": "13.6.23",
|
||||
"zustand": "5.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@svgr/webpack": "8.1.0",
|
||||
"@tanstack/react-query-devtools": "5.62.11",
|
||||
"@tanstack/react-query-devtools": "5.65.1",
|
||||
"@testing-library/dom": "10.4.0",
|
||||
"@testing-library/jest-dom": "6.6.3",
|
||||
"@testing-library/react": "16.1.0",
|
||||
"@testing-library/user-event": "14.5.2",
|
||||
"@testing-library/react": "16.2.0",
|
||||
"@testing-library/user-event": "14.6.1",
|
||||
"@types/jest": "29.5.14",
|
||||
"@types/lodash": "4.17.13",
|
||||
"@types/lodash": "4.17.15",
|
||||
"@types/luxon": "3.4.2",
|
||||
"@types/node": "*",
|
||||
"@types/react": "18.3.12",
|
||||
@@ -69,9 +69,9 @@
|
||||
"jest-environment-jsdom": "29.7.0",
|
||||
"node-fetch": "2.7.0",
|
||||
"prettier": "3.4.2",
|
||||
"stylelint": "16.12.0",
|
||||
"stylelint-config-standard": "36.0.1",
|
||||
"stylelint-prettier": "5.0.2",
|
||||
"stylelint": "16.14.1",
|
||||
"stylelint-config-standard": "37.0.0",
|
||||
"stylelint-prettier": "5.0.3",
|
||||
"typescript": "*",
|
||||
"webpack": "5.97.1",
|
||||
"workbox-webpack-plugin": "7.1.0"
|
||||
|
||||
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 743 B |
@@ -1,4 +0,0 @@
|
||||
<svg width="70" height="70" viewBox="0 0 70 70" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M47.2515 62.7264C49.7721 62.0196 52.1861 60.7298 53.7701 58.4505C55.3337 56.2187 55.774 53.3875 55.774 50.6632V10.749C55.774 10.0423 55.7356 9.33431 55.6503 8.63477C56.9023 9.12719 57.8672 9.94087 58.5451 11.0758C59.3448 12.3663 59.7447 14.0657 59.7447 16.1741V56.7153C59.7447 59.5689 59.0449 61.7046 57.6454 63.1223C56.2458 64.54 54.1374 65.2489 51.3202 65.2489H36.0065C36.3692 65.1854 36.7328 65.12 37.0972 65.0528C40.2928 64.4817 43.6701 63.7067 47.2256 62.7336L47.2515 62.7264Z" fill="#C9191E"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.4521 55.8703V15.2746C10.4521 12.8027 11.1156 10.9306 12.4424 9.65832C13.7874 8.38601 15.5686 7.68624 17.7861 7.55901C21.0577 7.35908 24.1567 7.08644 27.083 6.7411C30.0093 6.37758 32.8084 5.95954 35.4803 5.48697C38.1703 5.01439 40.7876 4.48729 43.3322 3.90567C45.9495 3.28769 47.958 3.59668 49.3575 4.83264C50.757 6.06859 51.4568 8.04067 51.4568 10.7489V50.663C51.4568 53.044 51.0479 54.8161 50.2299 55.9794C49.412 57.1608 48.0307 58.0242 46.0859 58.5695C42.6324 59.5146 39.379 60.2598 36.3254 60.8051C33.2719 61.3685 30.2911 61.7957 27.3829 62.0865C24.4748 62.3773 21.494 62.6045 18.4404 62.7681C15.914 62.9135 13.951 62.3864 12.5515 61.1868C11.1519 60.0053 10.4521 58.2332 10.4521 55.8703ZM20.4387 22.6454C24.4424 22.3905 28.1112 21.9992 31.4447 21.4709C32.2535 21.339 33.0611 21.2017 33.8657 21.0592C34.7076 20.9101 35.3165 20.1764 35.3165 19.3233C35.3165 18.2185 34.3166 17.3865 33.2308 17.5717C32.6071 17.6781 31.9801 17.7815 31.3497 17.8819C28.0496 18.4078 24.4029 18.7979 20.4098 19.052C19.8118 19.0906 19.336 19.2769 19.0302 19.6482C18.741 19.9994 18.5993 20.4218 18.5993 20.9033C18.5993 21.3928 18.7644 21.8188 19.0941 22.1691L19.0987 22.1737C19.456 22.531 19.91 22.6857 20.4387 22.6454ZM20.4374 31.6973C24.4416 31.4424 28.1108 31.051 31.4447 30.5227C34.7931 29.9768 38.1061 29.3397 41.3818 28.6117C42.0465 28.464 42.5444 28.2314 42.7935 27.8701C43.0383 27.5228 43.1594 27.1247 43.1594 26.6834C43.1594 26.1857 42.9698 25.757 42.601 25.4087C42.2038 25.0336 41.6486 24.9462 40.9915 25.0815L40.9873 25.0825C37.8658 25.7902 34.6533 26.4074 31.3497 26.9337C28.0496 27.4596 24.4029 27.8497 20.4098 28.1038C19.8118 28.1424 19.336 28.3287 19.0302 28.7C18.7424 29.0495 18.5993 29.4621 18.5993 29.9278C18.5993 30.4329 18.7625 30.8691 19.0939 31.2211L19.1034 31.2301C19.4595 31.5653 19.9088 31.7177 20.432 31.6976L20.4374 31.6973ZM20.4383 40.7488C24.4422 40.4758 28.111 40.0753 31.4446 39.547C34.7933 39.0192 38.1057 38.3913 41.3818 37.6633C42.0481 37.5152 42.5464 37.2729 42.7951 36.892C43.0376 36.5471 43.1594 36.1594 43.1594 35.735C43.1594 35.2373 42.9698 34.8086 42.601 34.4602C42.2038 34.0852 41.6486 33.9978 40.9915 34.1331L40.9885 34.1338C37.8666 34.8235 34.6537 35.4316 31.3497 35.958C28.0493 36.4839 24.4025 36.8832 20.4092 37.1554C19.8115 37.1941 19.3359 37.3804 19.0302 37.7516C18.7424 38.1011 18.5993 38.5137 18.5993 38.9794C18.5993 39.4845 18.7625 39.9206 19.0939 40.2727L19.1034 40.2816C19.4595 40.6168 19.9088 40.7693 20.432 40.7492L20.4383 40.7488ZM31.4447 48.5358C28.1112 49.0641 24.4424 49.4555 20.4388 49.7103C19.91 49.7506 19.456 49.596 19.0987 49.2386L19.0941 49.2339C18.7645 48.8837 18.5993 48.4577 18.5993 47.9682C18.5993 47.4867 18.741 47.0644 19.0302 46.7132C19.336 46.3418 19.812 46.1555 20.41 46.117C24.4031 45.8629 28.0496 45.4727 31.3497 44.9469C31.9801 44.8464 32.6071 44.743 33.2308 44.6366C34.3166 44.4514 35.3165 45.2834 35.3165 46.3882C35.3165 47.2413 34.7076 47.975 33.8657 48.1241C33.0611 48.2666 32.2535 48.404 31.4447 48.5358Z" fill="#000091"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.6 KiB |
@@ -14,11 +14,12 @@ import { useAuthStore } from './useAuthStore';
|
||||
* When we will have a homepage design for non-authenticated users, we will remove this restriction to have
|
||||
* the full website accessible without authentication.
|
||||
*/
|
||||
const regexpUrlsAuth = [/\/docs\/$/g];
|
||||
const regexpUrlsAuth = [/\/docs\/$/g, /^\/$/g];
|
||||
|
||||
export const Auth = ({ children }: PropsWithChildren) => {
|
||||
const { initAuth, initiated, authenticated, login } = useAuthStore();
|
||||
const { asPath } = useRouter();
|
||||
const { initAuth, initiated, authenticated, login, getAuthUrl } =
|
||||
useAuthStore();
|
||||
const { asPath, replace } = useRouter();
|
||||
|
||||
const [pathAllowed, setPathAllowed] = useState<boolean>(
|
||||
!regexpUrlsAuth.some((regexp) => !!asPath.match(regexp)),
|
||||
@@ -41,6 +42,18 @@ export const Auth = ({ children }: PropsWithChildren) => {
|
||||
login();
|
||||
}, [authenticated, pathAllowed, login, initiated]);
|
||||
|
||||
// Redirect to the path before login
|
||||
useEffect(() => {
|
||||
if (!authenticated) {
|
||||
return;
|
||||
}
|
||||
|
||||
const authUrl = getAuthUrl();
|
||||
if (authUrl) {
|
||||
void replace(authUrl);
|
||||
}
|
||||
}, [authenticated, getAuthUrl, replace]);
|
||||
|
||||
if ((!initiated && pathAllowed) || (!authenticated && !pathAllowed)) {
|
||||
return (
|
||||
<Box $height="100vh" $width="100vw" $align="center" $justify="center">
|
||||
|
||||
@@ -9,11 +9,7 @@ export const ButtonLogin = () => {
|
||||
|
||||
if (!authenticated) {
|
||||
return (
|
||||
<Button
|
||||
onClick={() => login(true)}
|
||||
color="primary-text"
|
||||
aria-label={t('Login')}
|
||||
>
|
||||
<Button onClick={login} color="primary-text" aria-label={t('Login')}>
|
||||
{t('Login')}
|
||||
</Button>
|
||||
);
|
||||
|
||||
@@ -11,7 +11,7 @@ interface AuthStore {
|
||||
authenticated: boolean;
|
||||
initAuth: () => void;
|
||||
logout: () => void;
|
||||
login: (directLogin?: boolean) => void;
|
||||
login: () => void;
|
||||
setAuthUrl: (url: string) => void;
|
||||
getAuthUrl: () => string | undefined;
|
||||
userData?: User;
|
||||
@@ -37,18 +37,10 @@ export const useAuthStore = create<AuthStore>((set, get) => ({
|
||||
set({ initiated: true });
|
||||
});
|
||||
},
|
||||
login: (directLogin?: boolean) => {
|
||||
if (directLogin) {
|
||||
get().setAuthUrl(window.location.pathname);
|
||||
window.location.replace(`${baseApiUrl()}authenticate/`);
|
||||
return;
|
||||
}
|
||||
login: () => {
|
||||
get().setAuthUrl(window.location.pathname);
|
||||
|
||||
if (window.location.pathname !== '/') {
|
||||
get().setAuthUrl(window.location.pathname);
|
||||
window.location.replace(`/`);
|
||||
return;
|
||||
}
|
||||
window.location.replace(`${baseApiUrl()}authenticate/`);
|
||||
},
|
||||
logout: () => {
|
||||
terminateCrispSession();
|
||||
|
||||
@@ -71,7 +71,6 @@
|
||||
--c--theme--colors--danger-text: var(--c--theme--colors--greyscale-000);
|
||||
--c--theme--colors--card-border: #ededed;
|
||||
--c--theme--colors--primary-bg: #fafafa;
|
||||
--c--theme--colors--primary-action: #1212ff;
|
||||
--c--theme--colors--primary-050: #f5f5fe;
|
||||
--c--theme--colors--primary-150: #e5eefa;
|
||||
--c--theme--colors--primary-950: #1b1b35;
|
||||
@@ -123,11 +122,6 @@
|
||||
--c--theme--font--sizes--ml: 0.938rem;
|
||||
--c--theme--font--sizes--xl: 1.25rem;
|
||||
--c--theme--font--sizes--t: 0.6875rem;
|
||||
--c--theme--font--sizes--xl-alt: 5rem;
|
||||
--c--theme--font--sizes--lg-alt: 4.5rem;
|
||||
--c--theme--font--sizes--md-alt: 4rem;
|
||||
--c--theme--font--sizes--sm-alt: 3.5rem;
|
||||
--c--theme--font--sizes--xs-alt: 3rem;
|
||||
--c--theme--font--weights--thin: 100;
|
||||
--c--theme--font--weights--light: 300;
|
||||
--c--theme--font--weights--regular: 400;
|
||||
@@ -322,7 +316,7 @@
|
||||
--c--theme--colors--primary-700
|
||||
);
|
||||
--c--components--button--secondary--border--color: var(
|
||||
--c--theme--colors--greyscale-300
|
||||
--c--theme--colors--primary-200
|
||||
);
|
||||
--c--components--button--tertiary--color: var(
|
||||
--c--theme--colors--primary-text
|
||||
@@ -507,10 +501,10 @@
|
||||
--c--components--button--secondary--background--color-hover: #f6f6f6;
|
||||
--c--components--button--secondary--background--color-active: #ededed;
|
||||
--c--components--button--secondary--border--color: var(
|
||||
--c--theme--colors--greyscale-300
|
||||
--c--theme--colors--primary-600
|
||||
);
|
||||
--c--components--button--secondary--border--color-hover: var(
|
||||
--c--theme--colors--greyscale-300
|
||||
--c--theme--colors--primary-600
|
||||
);
|
||||
--c--components--button--secondary--color: var(
|
||||
--c--theme--colors--primary-text
|
||||
@@ -880,10 +874,6 @@
|
||||
color: var(--c--theme--colors--primary-bg);
|
||||
}
|
||||
|
||||
.clr-primary-action {
|
||||
color: var(--c--theme--colors--primary-action);
|
||||
}
|
||||
|
||||
.clr-primary-050 {
|
||||
color: var(--c--theme--colors--primary-050);
|
||||
}
|
||||
@@ -1312,10 +1302,6 @@
|
||||
background-color: var(--c--theme--colors--primary-bg);
|
||||
}
|
||||
|
||||
.bg-primary-action {
|
||||
background-color: var(--c--theme--colors--primary-action);
|
||||
}
|
||||
|
||||
.bg-primary-050 {
|
||||
background-color: var(--c--theme--colors--primary-050);
|
||||
}
|
||||
@@ -1564,31 +1550,6 @@
|
||||
letter-spacing: var(--c--theme--font--letterspacings--t);
|
||||
}
|
||||
|
||||
.fs-xl-alt {
|
||||
font-size: var(--c--theme--font--sizes--xl-alt);
|
||||
letter-spacing: var(--c--theme--font--letterspacings--xl-alt);
|
||||
}
|
||||
|
||||
.fs-lg-alt {
|
||||
font-size: var(--c--theme--font--sizes--lg-alt);
|
||||
letter-spacing: var(--c--theme--font--letterspacings--lg-alt);
|
||||
}
|
||||
|
||||
.fs-md-alt {
|
||||
font-size: var(--c--theme--font--sizes--md-alt);
|
||||
letter-spacing: var(--c--theme--font--letterspacings--md-alt);
|
||||
}
|
||||
|
||||
.fs-sm-alt {
|
||||
font-size: var(--c--theme--font--sizes--sm-alt);
|
||||
letter-spacing: var(--c--theme--font--letterspacings--sm-alt);
|
||||
}
|
||||
|
||||
.fs-xs-alt {
|
||||
font-size: var(--c--theme--font--sizes--xs-alt);
|
||||
letter-spacing: var(--c--theme--font--letterspacings--xs-alt);
|
||||
}
|
||||
|
||||
.f-base {
|
||||
font-family: var(--c--theme--font--families--base);
|
||||
}
|
||||
|
||||
@@ -75,7 +75,6 @@ export const tokens = {
|
||||
'danger-text': '#fff',
|
||||
'card-border': '#ededed',
|
||||
'primary-bg': '#FAFAFA',
|
||||
'primary-action': '#1212FF',
|
||||
'primary-050': '#F5F5FE',
|
||||
'primary-150': '#E5EEFA',
|
||||
'primary-950': '#1B1B35',
|
||||
@@ -130,11 +129,6 @@ export const tokens = {
|
||||
ml: '0.938rem',
|
||||
xl: '1.25rem',
|
||||
t: '0.6875rem',
|
||||
'xl-alt': '5rem',
|
||||
'lg-alt': '4.5rem',
|
||||
'md-alt': '4rem',
|
||||
'sm-alt': '3.5rem',
|
||||
'xs-alt': '3rem',
|
||||
},
|
||||
weights: {
|
||||
thin: 100,
|
||||
@@ -321,7 +315,7 @@ export const tokens = {
|
||||
color: 'white',
|
||||
'color-hover': 'var(--c--theme--colors--primary-700)',
|
||||
},
|
||||
border: { color: 'var(--c--theme--colors--greyscale-300)' },
|
||||
border: { color: 'var(--c--theme--colors--primary-200)' },
|
||||
},
|
||||
tertiary: {
|
||||
color: 'var(--c--theme--colors--primary-text)',
|
||||
@@ -508,8 +502,8 @@ export const tokens = {
|
||||
secondary: {
|
||||
background: { 'color-hover': '#F6F6F6', 'color-active': '#EDEDED' },
|
||||
border: {
|
||||
color: 'var(--c--theme--colors--greyscale-300)',
|
||||
'color-hover': 'var(--c--theme--colors--greyscale-300)',
|
||||
color: 'var(--c--theme--colors--primary-600)',
|
||||
'color-hover': 'var(--c--theme--colors--primary-600)',
|
||||
},
|
||||
color: 'var(--c--theme--colors--primary-text)',
|
||||
},
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import { Dictionary, locales } from '@blocknote/core';
|
||||
import {
|
||||
BlockNoteEditor as BlockNoteEditorCore,
|
||||
BlockNoteSchema,
|
||||
Dictionary,
|
||||
defaultBlockSpecs,
|
||||
locales,
|
||||
} from '@blocknote/core';
|
||||
import '@blocknote/core/fonts/inter.css';
|
||||
import { BlockNoteView } from '@blocknote/mantine';
|
||||
import '@blocknote/mantine/style.css';
|
||||
@@ -6,7 +12,6 @@ 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';
|
||||
@@ -17,95 +22,27 @@ 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';
|
||||
import { AlertBlock, DividerBlock, QuoteBlock } from './custom-blocks';
|
||||
|
||||
const cssEditor = (readonly: boolean) => css`
|
||||
&,
|
||||
& > .bn-container,
|
||||
& .ProseMirror {
|
||||
height: 100%;
|
||||
export const schema = BlockNoteSchema.create({
|
||||
blockSpecs: {
|
||||
...defaultBlockSpecs,
|
||||
alert: AlertBlock,
|
||||
quote: QuoteBlock,
|
||||
divider: DividerBlock,
|
||||
},
|
||||
});
|
||||
|
||||
.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;
|
||||
}
|
||||
}
|
||||
`;
|
||||
export type DocsBlockNoteEditor = BlockNoteEditorCore<
|
||||
typeof schema.blockSchema,
|
||||
typeof schema.inlineContentSchema,
|
||||
typeof schema.styleSchema
|
||||
>;
|
||||
|
||||
interface BlockNoteEditorProps {
|
||||
doc: Doc;
|
||||
@@ -164,6 +101,7 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
|
||||
},
|
||||
},
|
||||
dictionary: locales[lang as keyof typeof locales] as Dictionary,
|
||||
schema,
|
||||
uploadFile,
|
||||
},
|
||||
[collabName, lang, provider, uploadFile],
|
||||
@@ -198,8 +136,10 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
|
||||
editor={editor}
|
||||
formattingToolbar={false}
|
||||
editable={!readOnly}
|
||||
slashMenu={false}
|
||||
theme="light"
|
||||
>
|
||||
<BlockNoteSuggestionMenu />
|
||||
<BlockNoteToolbar />
|
||||
</BlockNoteView>
|
||||
</Box>
|
||||
@@ -225,6 +165,7 @@ export const BlockNoteEditorVersion = ({
|
||||
},
|
||||
provider: undefined,
|
||||
},
|
||||
schema,
|
||||
},
|
||||
[initialContent],
|
||||
);
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import { combineByGroup, filterSuggestionItems } from '@blocknote/core';
|
||||
import '@blocknote/mantine/style.css';
|
||||
import {
|
||||
SuggestionMenuController,
|
||||
getDefaultReactSlashMenuItems,
|
||||
useBlockNoteEditor,
|
||||
} from '@blocknote/react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { DocsBlockNoteEditor } from './BlockNoteEditor';
|
||||
import { insertAlert, insertDivider, insertQuote } from './custom-blocks';
|
||||
|
||||
export const BlockNoteSuggestionMenu = () => {
|
||||
const editor = useBlockNoteEditor() as DocsBlockNoteEditor;
|
||||
const { t } = useTranslation();
|
||||
|
||||
const getSlashMenuItems = useMemo(() => {
|
||||
return async (query: string) =>
|
||||
Promise.resolve(
|
||||
filterSuggestionItems(
|
||||
combineByGroup(
|
||||
getDefaultReactSlashMenuItems(editor),
|
||||
[insertAlert(editor, t)],
|
||||
[insertQuote(editor, t)],
|
||||
[insertDivider(editor, t)],
|
||||
),
|
||||
query,
|
||||
),
|
||||
);
|
||||
}, [editor, t]);
|
||||
|
||||
return (
|
||||
<SuggestionMenuController
|
||||
triggerCharacter="/"
|
||||
getItems={getSlashMenuItems}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,179 @@
|
||||
/* eslint-disable react-hooks/rules-of-hooks */
|
||||
import { defaultProps, insertOrUpdateBlock } from '@blocknote/core';
|
||||
import { createReactBlockSpec } from '@blocknote/react';
|
||||
import { Menu } from '@mantine/core';
|
||||
import { TFunction } from 'i18next';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { css } from 'styled-components';
|
||||
|
||||
import { Box, Text } from '@/components';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
|
||||
import { DocsBlockNoteEditor } from '../BlockNoteEditor';
|
||||
|
||||
// The types of alerts that users can choose from.
|
||||
export const alertTypes = [
|
||||
{
|
||||
title: 'Warning',
|
||||
value: 'warning',
|
||||
icon: 'warning',
|
||||
color: 'warning-500',
|
||||
backgroundColor: 'warning-300',
|
||||
},
|
||||
{
|
||||
title: 'Error',
|
||||
value: 'danger',
|
||||
icon: 'error',
|
||||
color: 'danger-500',
|
||||
backgroundColor: 'danger-300',
|
||||
},
|
||||
{
|
||||
title: 'Info',
|
||||
value: 'info',
|
||||
icon: 'info',
|
||||
color: 'info-500',
|
||||
backgroundColor: 'info-300',
|
||||
},
|
||||
{
|
||||
title: 'Success',
|
||||
value: 'success',
|
||||
icon: 'check_circle',
|
||||
color: 'success-500',
|
||||
backgroundColor: 'success-100',
|
||||
},
|
||||
] as const;
|
||||
|
||||
// The Alert block.
|
||||
export const AlertBlock = createReactBlockSpec(
|
||||
{
|
||||
type: 'alert',
|
||||
propSchema: {
|
||||
textAlignment: defaultProps.textAlignment,
|
||||
textColor: defaultProps.textColor,
|
||||
type: {
|
||||
default: 'warning',
|
||||
values: ['warning', 'danger', 'info', 'success'],
|
||||
},
|
||||
},
|
||||
content: 'inline',
|
||||
},
|
||||
{
|
||||
render: (props) => {
|
||||
const { colorsTokens } = useCunninghamTheme();
|
||||
const { t } = useTranslation();
|
||||
let alertType = alertTypes.find(
|
||||
(a) => a.value === props.block.props.type,
|
||||
);
|
||||
|
||||
if (!alertType) {
|
||||
alertType = alertTypes[0];
|
||||
}
|
||||
|
||||
return (
|
||||
<Box
|
||||
className="alert"
|
||||
data-alert-type={props.block.props.type}
|
||||
$direction="row"
|
||||
$justify="center"
|
||||
$align="center"
|
||||
$radius="4px"
|
||||
$padding="4px"
|
||||
$background={colorsTokens()[alertType.backgroundColor]}
|
||||
$minHeight="48px"
|
||||
$css={css`
|
||||
flex-grow: 1;
|
||||
`}
|
||||
>
|
||||
<Menu withinPortal={false}>
|
||||
<Menu.Target>
|
||||
<Box
|
||||
className="alert-icon-wrapper"
|
||||
$margin={{ horizontal: '12px' }}
|
||||
$radius="16px"
|
||||
$justify="center"
|
||||
$align="center"
|
||||
$height="24px"
|
||||
$width="24px"
|
||||
contentEditable={false}
|
||||
$css="user-select: none; cursor: pointer;"
|
||||
>
|
||||
<Text
|
||||
$isMaterialIcon
|
||||
$theme={alertType.value}
|
||||
$variation="500"
|
||||
$size="20px"
|
||||
>
|
||||
{alertType.icon}
|
||||
</Text>
|
||||
</Box>
|
||||
</Menu.Target>
|
||||
<Menu.Dropdown style={{ zIndex: 9999 }}>
|
||||
<Menu.Label>{t('Alert Type')}</Menu.Label>
|
||||
<Menu.Divider />
|
||||
{alertTypes.map((type) => (
|
||||
<Menu.Item
|
||||
key={type.value}
|
||||
leftSection={
|
||||
<Text
|
||||
$isMaterialIcon
|
||||
$color={colorsTokens()[type.color]}
|
||||
$size="16px"
|
||||
>
|
||||
{type.icon}
|
||||
</Text>
|
||||
}
|
||||
onClick={() =>
|
||||
props.editor.updateBlock(props.block, {
|
||||
type: 'alert',
|
||||
props: { type: type.value },
|
||||
})
|
||||
}
|
||||
>
|
||||
{t(type.title)}
|
||||
</Menu.Item>
|
||||
))}
|
||||
</Menu.Dropdown>
|
||||
</Menu>
|
||||
<Box
|
||||
className="inline-content"
|
||||
$css={css`
|
||||
flex-grow: 1;
|
||||
& * {
|
||||
color: ${colorsTokens()[alertType.color]};
|
||||
}
|
||||
`}
|
||||
ref={props.contentRef}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
export const insertAlert = (
|
||||
editor: DocsBlockNoteEditor,
|
||||
t: TFunction<'translation', undefined>,
|
||||
) => ({
|
||||
title: t('Alert'),
|
||||
onItemClick: () => {
|
||||
insertOrUpdateBlock(editor, {
|
||||
type: 'alert',
|
||||
});
|
||||
},
|
||||
aliases: [
|
||||
'alert',
|
||||
'notification',
|
||||
'emphasize',
|
||||
'warning',
|
||||
'error',
|
||||
'info',
|
||||
'success',
|
||||
],
|
||||
group: t('Others'),
|
||||
icon: (
|
||||
<Text $isMaterialIcon $size="18px">
|
||||
warning
|
||||
</Text>
|
||||
),
|
||||
subtext: t('Add a colored alert box'),
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
import { defaultProps, insertOrUpdateBlock } from '@blocknote/core';
|
||||
import { createReactBlockSpec } from '@blocknote/react';
|
||||
import { TFunction } from 'i18next';
|
||||
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
|
||||
import { DocsBlockNoteEditor } from '../BlockNoteEditor';
|
||||
|
||||
export const DividerBlock = createReactBlockSpec(
|
||||
{
|
||||
type: 'divider',
|
||||
propSchema: {
|
||||
textAlignment: defaultProps.textAlignment,
|
||||
textColor: defaultProps.textColor,
|
||||
},
|
||||
content: 'none',
|
||||
},
|
||||
{
|
||||
render: () => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
const { colorsTokens } = useCunninghamTheme();
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '2px',
|
||||
backgroundColor: colorsTokens()['greyscale-300'],
|
||||
margin: '1rem 0',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
export const insertDivider = (
|
||||
editor: DocsBlockNoteEditor,
|
||||
t: TFunction<'translation', undefined>,
|
||||
) => ({
|
||||
title: t('Divider'),
|
||||
onItemClick: () => {
|
||||
insertOrUpdateBlock(editor, {
|
||||
type: 'divider',
|
||||
});
|
||||
},
|
||||
aliases: ['divider', 'hr', 'horizontal rule', 'line', 'separator'],
|
||||
group: t('Others'),
|
||||
icon: (
|
||||
<span className="material-icons" style={{ fontSize: '18px' }}>
|
||||
remove
|
||||
</span>
|
||||
),
|
||||
subtext: t('Add a horizontal line'),
|
||||
});
|
||||
@@ -0,0 +1,63 @@
|
||||
import { defaultProps, insertOrUpdateBlock } from '@blocknote/core';
|
||||
import { createReactBlockSpec } from '@blocknote/react';
|
||||
import { TFunction } from 'i18next';
|
||||
import React from 'react';
|
||||
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
|
||||
import { DocsBlockNoteEditor } from '../BlockNoteEditor';
|
||||
|
||||
export const QuoteBlock = createReactBlockSpec(
|
||||
{
|
||||
type: 'quote',
|
||||
propSchema: {
|
||||
textAlignment: defaultProps.textAlignment,
|
||||
textColor: defaultProps.textColor,
|
||||
},
|
||||
content: 'inline',
|
||||
},
|
||||
{
|
||||
render: (props) => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
const { colorsTokens } = useCunninghamTheme();
|
||||
|
||||
return (
|
||||
<div
|
||||
className="inline-content"
|
||||
style={{
|
||||
borderLeft: `4px solid ${colorsTokens()['greyscale-300']}`,
|
||||
margin: '0 0 1rem 0',
|
||||
padding: '0.5rem 1rem',
|
||||
color: colorsTokens()['greyscale-600'],
|
||||
fontStyle: 'italic',
|
||||
flexGrow: 1,
|
||||
}}
|
||||
ref={props.contentRef}
|
||||
/>
|
||||
);
|
||||
},
|
||||
parse: () => {
|
||||
return undefined;
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
export const insertQuote = (
|
||||
editor: DocsBlockNoteEditor,
|
||||
t: TFunction<'translation', undefined>,
|
||||
) => ({
|
||||
title: t('Quote'),
|
||||
onItemClick: () => {
|
||||
insertOrUpdateBlock(editor, {
|
||||
type: 'quote',
|
||||
});
|
||||
},
|
||||
aliases: ['quote', 'blockquote', 'citation'],
|
||||
group: t('Others'),
|
||||
icon: (
|
||||
<span className="material-icons" style={{ fontSize: '18px' }}>
|
||||
format_quote
|
||||
</span>
|
||||
),
|
||||
subtext: t('Add a quote block'),
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from './AlertBlock';
|
||||
export * from './DividerBlock';
|
||||
export * from './QuoteBlock';
|
||||
@@ -1,9 +1,9 @@
|
||||
import { BlockNoteEditor } from '@blocknote/core';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { DocsBlockNoteEditor } from '../components/BlockNoteEditor';
|
||||
import { useHeadingStore } from '../stores';
|
||||
|
||||
export const useHeadings = (editor: BlockNoteEditor) => {
|
||||
export const useHeadings = (editor: DocsBlockNoteEditor) => {
|
||||
const { setHeadings, resetHeadings } = useHeadingStore();
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { BlockNoteEditor } from '@blocknote/core';
|
||||
import { create } from 'zustand';
|
||||
|
||||
import { DocsBlockNoteEditor } from '../components/BlockNoteEditor';
|
||||
|
||||
export interface UseEditorstore {
|
||||
editor?: BlockNoteEditor;
|
||||
setEditor: (editor: BlockNoteEditor | undefined) => void;
|
||||
editor?: DocsBlockNoteEditor;
|
||||
setEditor: (editor: DocsBlockNoteEditor | undefined) => void;
|
||||
}
|
||||
|
||||
export const useEditorStore = create<UseEditorstore>((set) => ({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { BlockNoteEditor } from '@blocknote/core';
|
||||
import { create } from 'zustand';
|
||||
|
||||
import { DocsBlockNoteEditor } from '../components/BlockNoteEditor';
|
||||
import { HeadingBlock } from '../types';
|
||||
|
||||
const recursiveTextContent = (content: HeadingBlock['content']): string => {
|
||||
@@ -21,7 +21,7 @@ const recursiveTextContent = (content: HeadingBlock['content']): string => {
|
||||
|
||||
export interface UseHeadingStore {
|
||||
headings: HeadingBlock[];
|
||||
setHeadings: (editor: BlockNoteEditor) => void;
|
||||
setHeadings: (editor: DocsBlockNoteEditor) => void;
|
||||
resetHeadings: () => void;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
import { css } from 'styled-components';
|
||||
|
||||
export const cssEditor = (readonly: boolean) => css`
|
||||
&,
|
||||
& > .bn-container,
|
||||
& .ProseMirror {
|
||||
height: 100%;
|
||||
|
||||
.bn-side-menu[data-block-type='alert'] {
|
||||
height: 55px;
|
||||
}
|
||||
.bn-side-menu[data-block-type='divider'] {
|
||||
height: 40px;
|
||||
}
|
||||
.bn-side-menu[data-block-type='quote'] {
|
||||
height: 46px;
|
||||
}
|
||||
.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;
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -179,9 +179,7 @@ export const ModalExport = ({ onClose, doc }: ModalExportProps) => {
|
||||
$gap="1rem"
|
||||
>
|
||||
<Text $variation="600" $size="sm">
|
||||
{t(
|
||||
'Upload your docs to a Microsoft Word, Open Office or PDF document.',
|
||||
)}
|
||||
{t('Download your document in a .docx or .pdf format.')}
|
||||
</Text>
|
||||
<Select
|
||||
clearable={false}
|
||||
@@ -197,7 +195,7 @@ export const ModalExport = ({ onClose, doc }: ModalExportProps) => {
|
||||
fullWidth
|
||||
label={t('Format')}
|
||||
options={[
|
||||
{ label: t('Word / Open Office'), value: DocDownloadFormat.DOCX },
|
||||
{ label: t('Docx'), value: DocDownloadFormat.DOCX },
|
||||
{ label: t('PDF'), value: DocDownloadFormat.PDF },
|
||||
]}
|
||||
value={format}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { BlockNoteEditor } from '@blocknote/core';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { BoxButton, Text } from '@/components';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { useResponsiveStore } from '@/stores';
|
||||
|
||||
import { DocsBlockNoteEditor } from '../../doc-editor/components/BlockNoteEditor';
|
||||
|
||||
const leftPaddingMap: { [key: number]: string } = {
|
||||
3: '1.5rem',
|
||||
2: '0.9rem',
|
||||
@@ -17,7 +18,7 @@ export type HeadingsHighlight = {
|
||||
}[];
|
||||
|
||||
interface HeadingProps {
|
||||
editor: BlockNoteEditor;
|
||||
editor: DocsBlockNoteEditor;
|
||||
level: number;
|
||||
text: string;
|
||||
headingId: string;
|
||||
|
||||
@@ -60,13 +60,14 @@ export const Header = () => {
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<StyledLink href="/docs">
|
||||
<StyledLink href="/">
|
||||
<Box
|
||||
$align="center"
|
||||
$gap={spacings['3xs']}
|
||||
$direction="row"
|
||||
$position="relative"
|
||||
$height="fit-content"
|
||||
$margin={{ top: 'auto' }}
|
||||
>
|
||||
<Image priority src={IconDocs} alt={t('Docs Logo')} width={25} />
|
||||
<Title />
|
||||
|
||||
@@ -1,47 +1,26 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { css } from 'styled-components';
|
||||
|
||||
import { Box, Text } from '@/components/';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
|
||||
type TitleProps = {
|
||||
size?: 'sm' | 'md';
|
||||
};
|
||||
|
||||
const Title = ({ size = 'sm' }: TitleProps) => {
|
||||
const Title = () => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useCunninghamTheme();
|
||||
const spacings = theme.spacingsTokens();
|
||||
const colors = theme.colorsTokens();
|
||||
|
||||
return (
|
||||
<Box
|
||||
$direction="row"
|
||||
$align="center"
|
||||
$gap={size === 'sm' ? spacings['2xs'] : '1.125rem'}
|
||||
>
|
||||
<Text
|
||||
$margin="none"
|
||||
as="h2"
|
||||
$color="#000091"
|
||||
$zIndex={1}
|
||||
$size={size === 'sm' ? '1.3rem' : spacings['xxl']}
|
||||
>
|
||||
<Box $direction="row" $align="center" $gap={spacings['2xs']}>
|
||||
<Text $margin="none" as="h2" $color="#000091" $zIndex={1} $size="1.30rem">
|
||||
{t('Docs')}
|
||||
</Text>
|
||||
<Text
|
||||
$padding={{
|
||||
horizontal: size === 'sm' ? '2xs' : 'sm',
|
||||
vertical: size === 'sm' ? '3xs' : 'xs',
|
||||
}}
|
||||
$size={size === 'sm' ? '0.68rem' : spacings['md']}
|
||||
$padding={{ horizontal: 'xs', vertical: '1px' }}
|
||||
$size="11px"
|
||||
$theme="primary"
|
||||
$variation="500"
|
||||
$weight="bold"
|
||||
$radius={size === 'sm' ? '0.75rem' : '1.5rem'}
|
||||
$css={css`
|
||||
line-height: ${size === 'sm' ? '1rem' : '1.25rem'};
|
||||
`}
|
||||
$radius="12px"
|
||||
$background={colors['primary-200']}
|
||||
>
|
||||
BETA
|
||||
|
||||
|
Before Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 284 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 919 B |
@@ -1,84 +0,0 @@
|
||||
import { Button } from '@openfun/cunningham-react';
|
||||
import Image from 'next/image';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { css } from 'styled-components';
|
||||
|
||||
import { Box, Icon, Text } from '@/components';
|
||||
import { ProConnectButton } from '@/components/ProConnectButton';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { useResponsiveStore } from '@/stores';
|
||||
|
||||
import firstImage from '../assets/banner.png';
|
||||
import DocLogo from '../assets/logo-docs.png';
|
||||
|
||||
export default function HomeBanner() {
|
||||
const { t } = useTranslation();
|
||||
const { spacingsTokens } = useCunninghamTheme();
|
||||
const spacings = spacingsTokens();
|
||||
const { isDesktop } = useResponsiveStore();
|
||||
|
||||
return (
|
||||
<Box $maxWidth="78rem" $width="100%" $justify="center" $align="center">
|
||||
<Box
|
||||
$width="100%"
|
||||
$padding={{ top: 'xxxl', bottom: 'calc(3.5rem + 94px)' }}
|
||||
$justify="space-between"
|
||||
$align="center"
|
||||
$height="calc(100dvh - 94px)"
|
||||
$position="relative"
|
||||
$direction={isDesktop ? 'row' : 'column'}
|
||||
>
|
||||
<Box
|
||||
$width="100%"
|
||||
$justify="center"
|
||||
$align="center"
|
||||
$padding={{ horizontal: '10px' }}
|
||||
$gap={spacings['sm']}
|
||||
>
|
||||
<Image src={DocLogo} alt="DocLogo" />
|
||||
<Text
|
||||
$size={isDesktop ? 'xs-alt' : '2.3rem'}
|
||||
$variation="800"
|
||||
$weight="bold"
|
||||
$textAlign="center"
|
||||
$css={css`
|
||||
line-height: 56px;
|
||||
`}
|
||||
>
|
||||
{t('Collaborative writing made simple')}
|
||||
</Text>
|
||||
<Text $size="lg" $variation="700" $textAlign="center">
|
||||
{t(
|
||||
'Collaborate and write in real time, without layout constraints.',
|
||||
)}
|
||||
</Text>
|
||||
<ProConnectButton />
|
||||
</Box>
|
||||
{isDesktop && (
|
||||
<Image src={firstImage} alt="first" style={{ maxWidth: '50%' }} />
|
||||
)}
|
||||
<Box
|
||||
$position="absolute"
|
||||
$padding="base"
|
||||
$justify="center"
|
||||
$align="center"
|
||||
$css={css`
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
`}
|
||||
>
|
||||
<Button
|
||||
href="#docs-app-info"
|
||||
color="secondary"
|
||||
icon={
|
||||
<Icon $theme="primary" $variation="800" iconName="expand_more" />
|
||||
}
|
||||
>
|
||||
{t('See more')}
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { createGlobalStyle } from 'styled-components';
|
||||
|
||||
import IconDocs from '@/assets/common/logo-docs.svg';
|
||||
import { Box, Text } from '@/components';
|
||||
import { ProConnectButton } from '@/components/ProConnectButton';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { Footer } from '@/features/footer';
|
||||
import Title from '@/features/header/components/Title/Title';
|
||||
import { useLanguage } from '@/i18n/hooks/useLanguage';
|
||||
import { useResponsiveStore } from '@/stores';
|
||||
|
||||
import SC1Responsive from '../assets/SC1-responsive.png';
|
||||
import SC2 from '../assets/SC2.png';
|
||||
import SC3 from '../assets/SC3.png';
|
||||
import SC4Responsive from '../assets/SC4-responsive.png';
|
||||
import SC4 from '../assets/SC4.png';
|
||||
|
||||
import HomeBanner from './HomeBanner';
|
||||
import { HomeHeader } from './HomeHeader';
|
||||
import { HomeSection } from './HomeSection';
|
||||
|
||||
const GlobalHomePageStyle = createGlobalStyle`
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
`;
|
||||
|
||||
export default function HomeContent() {
|
||||
const { t } = useTranslation();
|
||||
const { isDesktop } = useResponsiveStore();
|
||||
const { spacingsTokens } = useCunninghamTheme();
|
||||
const spacings = spacingsTokens();
|
||||
const lang = useLanguage();
|
||||
|
||||
return (
|
||||
<>
|
||||
<GlobalHomePageStyle />
|
||||
<Box $background="white">
|
||||
<HomeHeader />
|
||||
<Box $align="center" $justify="center">
|
||||
<Box
|
||||
$maxWidth="78rem"
|
||||
$width="100%"
|
||||
$justify="center"
|
||||
$align="center"
|
||||
>
|
||||
<HomeBanner />
|
||||
<Box
|
||||
id="docs-app-info"
|
||||
$gap={isDesktop ? '230px' : '115px'}
|
||||
$padding={{
|
||||
vertical: spacings['6xl'],
|
||||
}}
|
||||
>
|
||||
<HomeSection
|
||||
isColumn={true}
|
||||
illustration={isDesktop ? undefined : SC1Responsive}
|
||||
video={
|
||||
isDesktop ? `assets/SC1-${lang.language}.webm` : undefined
|
||||
}
|
||||
title={t('An uncompromising writing experience.')}
|
||||
tag={t('Write')}
|
||||
description={t(
|
||||
'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.',
|
||||
)}
|
||||
/>
|
||||
<HomeSection
|
||||
isColumn={false}
|
||||
illustration={SC2}
|
||||
title={t('Simple and secure collaboration.')}
|
||||
tag={t('Collaborate')}
|
||||
description={t(
|
||||
'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.',
|
||||
)}
|
||||
/>
|
||||
<HomeSection
|
||||
isColumn={false}
|
||||
reverse={true}
|
||||
illustration={SC3}
|
||||
title={t('Flexible export.')}
|
||||
tag={t('Export')}
|
||||
description={t(
|
||||
'To facilitate the circulation of documents, Docs allows you to export your content to the most common formats: PDF, Word or OpenDocument.',
|
||||
)}
|
||||
/>
|
||||
|
||||
<HomeSection
|
||||
illustration={isDesktop ? SC4 : SC4Responsive}
|
||||
title={t('A new way to organize knowledge.')}
|
||||
tag={t('Organize')}
|
||||
availableSoon={true}
|
||||
description={t(
|
||||
'Docs transforms your documents into knowledge bases thanks to subpages, powerful search and the ability to pin your important documents.',
|
||||
)}
|
||||
/>
|
||||
<Box
|
||||
$gap={spacings['md']}
|
||||
$justify="center"
|
||||
$align="center"
|
||||
$padding={{ vertical: '140px' }}
|
||||
>
|
||||
<Box
|
||||
$align="center"
|
||||
$gap={spacings['3xs']}
|
||||
$direction="row"
|
||||
$position="relative"
|
||||
$height="fit-content"
|
||||
>
|
||||
<IconDocs />
|
||||
<Title size="md" />
|
||||
</Box>
|
||||
<Text $size="md" $variation="1000" $textAlign="center">
|
||||
{t('Docs is already available, log in to use it now.')}
|
||||
</Text>
|
||||
<ProConnectButton />
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
<Footer />
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
import Image from 'next/image';
|
||||
|
||||
import IconDocs from '@/assets/common/logo-docs-sm.png';
|
||||
import { Box } from '@/components';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { LaGaufre } from '@/features/header/components/LaGaufre';
|
||||
import Title from '@/features/header/components/Title/Title';
|
||||
import { LanguagePicker } from '@/features/language';
|
||||
import { useResponsiveStore } from '@/stores';
|
||||
|
||||
export const HomeHeader = () => {
|
||||
const { isDesktop } = useResponsiveStore();
|
||||
const { themeTokens, spacingsTokens } = useCunninghamTheme();
|
||||
const logo = themeTokens().logo;
|
||||
const spacings = spacingsTokens();
|
||||
return (
|
||||
<Box
|
||||
$direction="row"
|
||||
$justify="space-between"
|
||||
as="header"
|
||||
$align="center"
|
||||
$width="100%"
|
||||
$padding={{ horizontal: '18px', vertical: 'base' }}
|
||||
>
|
||||
<Box $align="center" $gap="3rem" $direction="row">
|
||||
{logo && (
|
||||
<Image
|
||||
priority
|
||||
src={logo.src}
|
||||
alt={logo.alt}
|
||||
width={0}
|
||||
height={0}
|
||||
style={{ width: 109, height: 'auto' }}
|
||||
/>
|
||||
)}
|
||||
|
||||
{isDesktop && (
|
||||
<Box
|
||||
$align="center"
|
||||
$gap={spacings['3xs']}
|
||||
$direction="row"
|
||||
$position="relative"
|
||||
$height="fit-content"
|
||||
>
|
||||
<Image src={IconDocs} alt="Docs app logo" />
|
||||
<Title />
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
<Box $direction="row" $gap="1rem" $align="center">
|
||||
<LanguagePicker />
|
||||
<LaGaufre />
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -1,143 +0,0 @@
|
||||
import Image, { ImageProps } from 'next/image';
|
||||
import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { css } from 'styled-components';
|
||||
|
||||
import { Box, Text } from '@/components';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { useResponsiveStore } from '@/stores';
|
||||
|
||||
export type HomeSectionProps = {
|
||||
illustration?: ImageProps['src'];
|
||||
title: string;
|
||||
description: string;
|
||||
tag: string;
|
||||
availableSoon?: boolean;
|
||||
|
||||
isColumn?: boolean;
|
||||
video?: string;
|
||||
reverse?: boolean;
|
||||
};
|
||||
export const HomeSection = ({
|
||||
illustration,
|
||||
title,
|
||||
description,
|
||||
tag,
|
||||
reverse = false,
|
||||
isColumn = true,
|
||||
availableSoon = false,
|
||||
|
||||
video,
|
||||
}: HomeSectionProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { spacingsTokens } = useCunninghamTheme();
|
||||
const spacings = spacingsTokens();
|
||||
|
||||
const { isDesktop } = useResponsiveStore();
|
||||
|
||||
const direction = useMemo(() => {
|
||||
if (!isDesktop) {
|
||||
return 'column';
|
||||
} else if (isColumn) {
|
||||
return reverse ? 'column-reverse' : 'column';
|
||||
}
|
||||
|
||||
return reverse ? 'row-reverse' : 'row';
|
||||
}, [isColumn, isDesktop, reverse]);
|
||||
|
||||
return (
|
||||
<Box
|
||||
$direction={direction}
|
||||
$gap={spacings['lg']}
|
||||
$padding={{
|
||||
horizontal: isDesktop ? '6xl' : spacings['md'],
|
||||
}}
|
||||
$align={isDesktop ? 'flex-start' : 'center'}
|
||||
$justify={isDesktop ? 'flex-start' : 'center'}
|
||||
>
|
||||
<Box $gap={spacings['sm']} $maxWidth="850px" $width="100%">
|
||||
<Box $direction="row" $gap={spacings['sm']} $wrap="wrap">
|
||||
<SectionTag tag={tag} />
|
||||
{availableSoon && (
|
||||
<SectionTag tag={t('Available soon')} availableSoon />
|
||||
)}
|
||||
</Box>
|
||||
<Text
|
||||
$css={css`
|
||||
line-height: 50px;
|
||||
`}
|
||||
$variation="1000"
|
||||
$weight="bold"
|
||||
$size={isDesktop ? 'xs-alt' : 'h1'}
|
||||
>
|
||||
{title}
|
||||
</Text>
|
||||
<Text $variation="700" $weight="400" $size="md">
|
||||
{description}
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
{video && (
|
||||
<video
|
||||
preload="none"
|
||||
loop
|
||||
muted
|
||||
autoPlay
|
||||
src={video}
|
||||
style={{
|
||||
width: '100%',
|
||||
maxWidth: !isDesktop ? 'calc(100dvw - 50px)' : '1200px',
|
||||
height: 'auto',
|
||||
}}
|
||||
>
|
||||
<source src={video} type="video/webm" />
|
||||
</video>
|
||||
)}
|
||||
|
||||
{illustration && (
|
||||
<Image
|
||||
src={illustration}
|
||||
alt="SC4Illustration"
|
||||
style={{
|
||||
width: '100%',
|
||||
maxWidth: !isDesktop ? 'calc(100dvw - 50px)' : '1200px',
|
||||
height: 'auto',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
const SectionTag = ({
|
||||
tag,
|
||||
availableSoon,
|
||||
}: {
|
||||
tag: string;
|
||||
availableSoon?: boolean;
|
||||
}) => {
|
||||
const { colorsTokens, spacingsTokens } = useCunninghamTheme();
|
||||
const spacings = spacingsTokens();
|
||||
const colors = colorsTokens();
|
||||
return (
|
||||
<Box
|
||||
$background={
|
||||
!availableSoon ? colors['primary-100'] : colors['warning-100']
|
||||
}
|
||||
$padding={{ horizontal: spacings['sm'], vertical: '6px' }}
|
||||
$css={css`
|
||||
align-self: flex-start;
|
||||
border-radius: 4px;
|
||||
`}
|
||||
>
|
||||
<Text
|
||||
$size="md"
|
||||
$variation={availableSoon ? '600' : '800'}
|
||||
$weight="bold"
|
||||
$theme={availableSoon ? 'warning' : 'primary'}
|
||||
>
|
||||
{tag}
|
||||
</Text>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -9,7 +9,7 @@ import { LeftPanelFavorites } from './LeftPanelFavorites';
|
||||
|
||||
export const LeftPanelContent = () => {
|
||||
const router = useRouter();
|
||||
const isHome = router.pathname === '/docs';
|
||||
const isHome = router.pathname === '/';
|
||||
const isDoc = router.pathname === '/docs/[id]';
|
||||
|
||||
return (
|
||||
|
||||
@@ -81,7 +81,6 @@
|
||||
"No active search": "Keine aktive Suche",
|
||||
"No document found": "Kein Dokument gefunden",
|
||||
"No documents found": "Keine Dokumente gefunden",
|
||||
"No editor found": "Kein Editor gefunden",
|
||||
"No versions": "Keine Versionen",
|
||||
"Nothing exceptional, no special privileges related to a .gouv.fr.": "Nichts Außergewöhnliches, keine besonderen Privilegien im Zusammenhang mit .gouv.fr.",
|
||||
"Offline ?!": "Offline?!",
|
||||
@@ -140,7 +139,6 @@
|
||||
"Unpin": "Lösen",
|
||||
"Untitled document": "Unbenanntes Dokument",
|
||||
"Updated at": "Aktualisiert am",
|
||||
"Upload your docs to a Microsoft Word, Open Office or PDF document.": "Laden Sie Ihre Dokumente zu einem Microsoft Word, Open Office oder PDF Dokument hoch.",
|
||||
"Use as prompt": "Als Prompt verwenden",
|
||||
"Version history": "Versionsverlauf",
|
||||
"Version restored successfully": "Version erfolgreich wiederhergestellt",
|
||||
@@ -158,7 +156,13 @@
|
||||
"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.": "sie haben dem Website-Manager einen Mangel an Barrierefreiheit gemeldet, der Ihnen den Zugriff auf Inhalte oder einen der Dienste des Portals verwehrt, und Sie haben keine zufriedenstellende Antwort erhalten."
|
||||
}
|
||||
},
|
||||
"en": { "translation": {} },
|
||||
"en": {
|
||||
"translation": {
|
||||
"Shared with {{count}} users_many": "Shared with {{count}} users",
|
||||
"Shared with {{count}} users_one": "Shared with {{count}} user",
|
||||
"Shared with {{count}} users_other": "Shared with {{count}} users"
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"translation": {
|
||||
"\"{{email}}\" is already invited to the document.": "\"{{email}}\" est déjà invité à accéder au document.",
|
||||
@@ -167,6 +171,8 @@
|
||||
"AI seems busy! Please try again.": "L'IA semble occupée ! Veuillez réessayer.",
|
||||
"Accessibility": "Accessibilité",
|
||||
"Accessibility statement": "Déclaration d'accessibilité",
|
||||
"Accessible to anyone": "Accessible à tout le monde",
|
||||
"Accessible to authenticated users": "Accessible aux utilisateurs authentifiés",
|
||||
"Add": "Ajouter",
|
||||
"Address:": "Adresse :",
|
||||
"Administrator": "Administrateur",
|
||||
@@ -203,11 +209,14 @@
|
||||
"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",
|
||||
"Docx": "Docx",
|
||||
"Download": "Télécharger",
|
||||
"Download your document in a .docx or .pdf format.": "Téléchargez votre document au format .docx ou .pdf.",
|
||||
"E-mail:": "E-mail:",
|
||||
"Edition": "Édition",
|
||||
"Editor": "Éditeur",
|
||||
"Editor unavailable": "Éditeur indisponible",
|
||||
"Empty template": "Sans modèle",
|
||||
"Error during delete invitation": "Erreur lors de la suppression de l'invitation",
|
||||
"Error during invitation update": "Erreur lors de la mise à jour de l'invitation",
|
||||
"Error during update invitation": "Erreur lors de la mise à jour de l'invitation",
|
||||
@@ -250,7 +259,6 @@
|
||||
"No active search": "Aucune recherche active",
|
||||
"No document found": "Aucun document trouvé",
|
||||
"No documents found": "Aucun document trouvé",
|
||||
"No editor found": "Pas d'éditeur trouvé",
|
||||
"No versions": "Aucune version",
|
||||
"Nothing exceptional, no special privileges related to a .gouv.fr.": "Rien d'exceptionnel, pas de privilèges spéciaux liés à un .gouv.fr.",
|
||||
"OK": "OK",
|
||||
@@ -264,6 +272,7 @@
|
||||
"Pending invitations": "Invitations en attente",
|
||||
"Personal data and cookies": "Données personnelles et cookies",
|
||||
"Pin": "Épingler",
|
||||
"Pin document icon": "Icône épingler un document",
|
||||
"Pinned documents": "Documents épinglés",
|
||||
"Private": "Privé",
|
||||
"Public": "Public",
|
||||
@@ -291,13 +300,18 @@
|
||||
"Share with {{count}} users_one": "Partager avec {{count}} utilisateur",
|
||||
"Share with {{count}} users_other": "Partager 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",
|
||||
"Simple document icon": "Icône simple du document",
|
||||
"Something bad happens, please retry.": "Une erreur inattendue s'est produite, veuillez réessayer.",
|
||||
"Stéphanie Schaer: Interministerial Digital Director (DINUM).": "Stéphanie Schaer: Directrice numérique interministériel (DINUM).",
|
||||
"Summarize": "Résumer",
|
||||
"Summary": "Sommaire",
|
||||
"Template": "Template",
|
||||
"Template": "Modèle",
|
||||
"The document has been deleted.": "Le document a bien été supprimé.",
|
||||
"The document visibility has been updated.": "La visibilité du document a été mise à jour.",
|
||||
"The export failed": "L’exportation a échoué",
|
||||
"The team in charge of the digital workspace \"La Suite numérique\" can be contacted directly at": "L'équipe responsable de l'espace de travail numérique \"La Suite numérique\" peut être contactée directement à l'adresse",
|
||||
"This accessibility statement applies to the site hosted on": "Cette déclaration d'accessibilité s'applique au site hébergé sur",
|
||||
"This allows us to measure the number of visits and understand which pages are the most viewed.": "Cela nous permet de mesurer le nombre de visites et de comprendre quelles pages sont les plus consultées.",
|
||||
@@ -312,7 +326,6 @@
|
||||
"Unpin": "Désépingler",
|
||||
"Untitled document": "Document sans titre",
|
||||
"Updated at": "Mise à jour le",
|
||||
"Upload your docs to a Microsoft Word, Open Office or PDF document.": "Téléchargez vos documents dans un document Microsoft Word, Open Office ou PDF.",
|
||||
"Use as prompt": "Utiliser comme un prompt",
|
||||
"Version history": "Historique des versions",
|
||||
"Version restored successfully": "Version restaurée avec succès",
|
||||
@@ -321,11 +334,11 @@
|
||||
"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.",
|
||||
"Word / Open Office": "Word / Open Office",
|
||||
"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:",
|
||||
"You cannot update the role or remove other owner.": "Vous ne pouvez pas mettre à jour le rôle ou supprimer un autre propriétaire.",
|
||||
"You do not have permission to view users sharing this document or modify link settings.": "Vous n'avez pas la permission de voir les utilisateurs partageant ce document ou de modifier les paramètres du lien.",
|
||||
"Your current document will revert to this version.": "Votre document actuel va revenir à cette version.",
|
||||
"Your {{format}} was downloaded succesfully": "Votre {{format}} a été téléchargé avec succès",
|
||||
"accessibility-contact-defenseurdesdroits": "Contacter le délégué du<1>Défenseur des droits dans votre région</1>",
|
||||
|
||||
@@ -3,6 +3,7 @@ import { css } from 'styled-components';
|
||||
|
||||
import { Box } from '@/components';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { Footer } from '@/features/footer';
|
||||
import { Header } from '@/features/header';
|
||||
import { HEADER_HEIGHT } from '@/features/header/conf';
|
||||
import { LeftPanel } from '@/features/left-panel';
|
||||
@@ -11,13 +12,13 @@ import { useResponsiveStore } from '@/stores';
|
||||
|
||||
type MainLayoutProps = {
|
||||
backgroundColor?: 'white' | 'grey';
|
||||
|
||||
withoutLeftPanel?: boolean;
|
||||
withoutFooter?: boolean;
|
||||
};
|
||||
|
||||
export function MainLayout({
|
||||
children,
|
||||
backgroundColor = 'white',
|
||||
withoutFooter = false,
|
||||
}: PropsWithChildren<MainLayoutProps>) {
|
||||
const { isDesktop } = useResponsiveStore();
|
||||
const { colorsTokens } = useCunninghamTheme();
|
||||
@@ -56,6 +57,7 @@ export function MainLayout({
|
||||
{children}
|
||||
</Box>
|
||||
</Box>
|
||||
{!withoutFooter && <Footer />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ const Page: NextPageWithLayout = () => {
|
||||
</Text>
|
||||
|
||||
<Box $margin={{ top: 'large' }}>
|
||||
<StyledLink href="/docs/">
|
||||
<StyledLink href="/">
|
||||
<StyledButton>{t('Back to home page')}</StyledButton>
|
||||
</StyledLink>
|
||||
</Box>
|
||||
|
||||
@@ -33,7 +33,7 @@ export function DocLayout() {
|
||||
<meta name="robots" content="noindex" />
|
||||
</Head>
|
||||
|
||||
<MainLayout>
|
||||
<MainLayout withoutFooter>
|
||||
<DocPage id={id} />
|
||||
</MainLayout>
|
||||
</>
|
||||
@@ -46,7 +46,6 @@ interface DocProps {
|
||||
|
||||
const DocPage = ({ id }: DocProps) => {
|
||||
const { login } = useAuthStore();
|
||||
|
||||
const {
|
||||
data: docQuery,
|
||||
isError,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useRouter, useSearchParams } from 'next/navigation';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import type { ReactElement } from 'react';
|
||||
|
||||
import { useAuthStore } from '@/core';
|
||||
import { DocDefaultFilter } from '@/features/docs';
|
||||
import { DocsGrid } from '@/features/docs/docs-grid';
|
||||
import { MainLayout } from '@/layouts';
|
||||
@@ -10,14 +9,6 @@ import { NextPageWithLayout } from '@/types/next';
|
||||
const Page: NextPageWithLayout = () => {
|
||||
const searchParams = useSearchParams();
|
||||
const target = searchParams.get('target');
|
||||
const router = useRouter();
|
||||
const auth = useAuthStore();
|
||||
const url = auth.getAuthUrl();
|
||||
|
||||
if (auth.authenticated && url) {
|
||||
router.replace(url);
|
||||
return null;
|
||||
}
|
||||
|
||||
return <DocsGrid target={target as DocDefaultFilter} />;
|
||||
};
|
||||
|
||||
@@ -1,16 +1,3 @@
|
||||
import { useRouter } from 'next/navigation';
|
||||
import Docs from './docs';
|
||||
|
||||
import { useAuthStore } from '@/core';
|
||||
import HomeContent from '@/features/home/components/HomeContent';
|
||||
|
||||
export default function Index() {
|
||||
const router = useRouter();
|
||||
const auth = useAuthStore();
|
||||
|
||||
if (auth.authenticated) {
|
||||
router.push('/docs/');
|
||||
return null;
|
||||
}
|
||||
|
||||
return <HomeContent />;
|
||||
}
|
||||
export default Docs;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "impress",
|
||||
"version": "2.0.1",
|
||||
"version": "2.1.0",
|
||||
"private": true,
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
@@ -28,13 +28,13 @@
|
||||
"server:test": "yarn COLLABORATION_SERVER run test"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/node": "22.10.3",
|
||||
"@types/node": "22.12.0",
|
||||
"@types/react-dom": "18.3.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.19.0",
|
||||
"@typescript-eslint/parser": "8.19.0",
|
||||
"@typescript-eslint/eslint-plugin": "8.22.0",
|
||||
"@typescript-eslint/parser": "8.22.0",
|
||||
"eslint": "8.57.0",
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1",
|
||||
"typescript": "5.7.2"
|
||||
"typescript": "5.7.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
{
|
||||
"name": "eslint-config-impress",
|
||||
"version": "2.0.1",
|
||||
"version": "2.1.0",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"lint": "eslint --ext .js ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@next/eslint-plugin-next": "15.1.3",
|
||||
"@tanstack/eslint-plugin-query": "5.62.9",
|
||||
"@next/eslint-plugin-next": "15.1.6",
|
||||
"@tanstack/eslint-plugin-query": "5.65.0",
|
||||
"@typescript-eslint/eslint-plugin": "*",
|
||||
"@typescript-eslint/parser": "*",
|
||||
"eslint": "*",
|
||||
"eslint-config-next": "15.1.3",
|
||||
"eslint-config-prettier": "9.1.0",
|
||||
"eslint-config-next": "15.1.6",
|
||||
"eslint-config-prettier": "10.0.1",
|
||||
"eslint-plugin-import": "2.31.0",
|
||||
"eslint-plugin-jest": "28.10.0",
|
||||
"eslint-plugin-jest": "28.11.0",
|
||||
"eslint-plugin-jsx-a11y": "6.10.2",
|
||||
"eslint-plugin-playwright": "2.1.0",
|
||||
"eslint-plugin-prettier": "5.2.1",
|
||||
"eslint-plugin-react": "7.37.3",
|
||||
"eslint-plugin-playwright": "2.2.0",
|
||||
"eslint-plugin-prettier": "5.2.3",
|
||||
"eslint-plugin-react": "7.37.4",
|
||||
"eslint-plugin-testing-library": "7.1.1",
|
||||
"prettier": "3.4.2"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "packages-i18n",
|
||||
"version": "2.0.1",
|
||||
"version": "2.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"extract-translation": "yarn extract-translation:impress",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "server-y-provider",
|
||||
"version": "2.0.1",
|
||||
"version": "2.1.0",
|
||||
"description": "Y.js provider for docs",
|
||||
"repository": "https://github.com/numerique-gouv/impress",
|
||||
"license": "MIT",
|
||||
@@ -16,25 +16,25 @@
|
||||
"node": ">=18"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blocknote/server-util": "0.22.0",
|
||||
"@hocuspocus/server": "2.15.0",
|
||||
"@sentry/node": "8.47.0",
|
||||
"@sentry/profiling-node": "8.47.0",
|
||||
"@blocknote/server-util": "0.21.0",
|
||||
"@hocuspocus/server": "2.15.1",
|
||||
"@sentry/node": "8.52.0",
|
||||
"@sentry/profiling-node": "8.52.0",
|
||||
"cors": "2.8.5",
|
||||
"express": "4.21.2",
|
||||
"express-ws": "5.0.2",
|
||||
"y-protocols": "1.0.6",
|
||||
"yjs": "13.6.21"
|
||||
"yjs": "13.6.23"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@hocuspocus/provider": "2.15.0",
|
||||
"@hocuspocus/provider": "2.15.1",
|
||||
"@types/cors": "2.8.17",
|
||||
"@types/express": "5.0.0",
|
||||
"@types/express-ws": "3.0.5",
|
||||
"@types/jest": "29.5.14",
|
||||
"@types/node": "*",
|
||||
"@types/supertest": "6.0.2",
|
||||
"@types/ws": "8.5.13",
|
||||
"@types/ws": "8.5.14",
|
||||
"cross-env": "7.0.3",
|
||||
"eslint-config-impress": "*",
|
||||
"jest": "29.7.0",
|
||||
|
||||
@@ -93,4 +93,4 @@ releases:
|
||||
environments:
|
||||
dev:
|
||||
values:
|
||||
- version: 2.0.1
|
||||
- version: 2.1.0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
apiVersion: v2
|
||||
type: application
|
||||
name: docs
|
||||
version: 2.0.1-beta.8
|
||||
version: 2.1.0
|
||||
appVersion: latest
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mail_mjml",
|
||||
"version": "2.0.1",
|
||||
"version": "2.1.0",
|
||||
"description": "An util to generate html and text django's templates from mjml templates",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
||||