Compare commits

..

3 Commits

Author SHA1 Message Date
Anthony LC
ac86a4e7f7 🔖(minor) release 1.4.0
Added:
- (backend) Add link public/authenticated/restricted
access with read/editor roles
- (frontend) add copy link button
- 🛂(frontend) access public docs without being logged

Changed:
- ♻️(backend) Allow null titles on documents
for easier creation
- 🛂(backend) stop to list public doc to everyone
- 🚚(frontend) change visibility in share modal
- ️(frontend) Improve summary

Fixed:
- 🐛(backend) Fix forcing ID when creating a
document via API endpoint
- 🐛 Rebuild frontend dev container from makefile
2024-09-18 12:01:52 +02:00
Anthony LC
bbe5501297 🌐(frontend) translate last features
Translate:
- doc visibility
- doc table of contents
2024-09-18 11:18:29 +02:00
Anthony LC
b37acf3138 💄(frontend) improve ui table of contents
- keep correctly the text on the left side
- improve accuracy highlightment heading when scrolling
- display full heading text when text transform is applied
- fix typo
2024-09-18 11:18:29 +02:00
19 changed files with 82 additions and 78 deletions

View File

@@ -9,23 +9,25 @@ and this project adheres to
## [Unreleased]
## [1.4.0] - 2024-09-17
## Added
- ✨Add link public/authenticated/restricted access with read/editor roles #234
- ✨(frontend) add copy link button #235
- 🛂(frontend) access public docs without being logged #235
- 🌐(frontend) add localization to editor #268
## Changed
- ♻️ Allow null titles on documents for easier creation #234
- ♻️(backend) Allow null titles on documents for easier creation #234
- 🛂(backend) stop to list public doc to everyone #234
- 🚚(frontend) change visibility in share modal #235
- ⚡️(frontend) Improve summary #244
## Fixed
- 🐛 Fix forcing ID when creating a document via API endpoint #234
- 🐛(backend) Fix forcing ID when creating a document via API endpoint #234
- 🐛 Rebuild frontend dev container from makefile #248
@@ -151,7 +153,8 @@ and this project adheres to
- 🚀 Impress, project to manage your documents easily and collaboratively.
[unreleased]: https://github.com/numerique-gouv/impress/compare/v1.3.0...main
[unreleased]: https://github.com/numerique-gouv/impress/compare/v1.4.0...main
[1.4.0]: https://github.com/numerique-gouv/impress/releases/v1.4.0
[1.3.0]: https://github.com/numerique-gouv/impress/releases/v1.3.0
[1.2.1]: https://github.com/numerique-gouv/impress/releases/v1.2.1
[1.2.0]: https://github.com/numerique-gouv/impress/releases/v1.2.0

View File

@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "impress"
version = "1.3.0"
version = "1.4.0"
authors = [{ "name" = "DINUM", "email" = "dev@mail.numerique.gouv.fr" }]
classifiers = [
"Development Status :: 5 - Production/Stable",

View File

@@ -20,7 +20,7 @@ test.describe('Doc Table Content', () => {
await page.getByLabel('Open the document options').click();
await page
.getByRole('button', {
name: 'Table of content',
name: 'Table of contents',
})
.click();
@@ -30,6 +30,8 @@ test.describe('Doc Table Content', () => {
await editor.locator('.bn-block-outer').last().fill('/');
await page.getByText('Heading 1').click();
await page.keyboard.type('Hello World');
await editor.getByText('Hello').dblclick();
await page.getByRole('button', { name: 'Strike' }).click();
await page.locator('.bn-block-outer').last().click();
@@ -40,7 +42,7 @@ test.describe('Doc Table Content', () => {
await editor.locator('.bn-block-outer').last().fill('/');
await page.getByText('Heading 2').click();
await page.keyboard.type('Super World');
await page.keyboard.type('Super World', { delay: 100 });
await page.locator('.bn-block-outer').last().click();
@@ -58,15 +60,15 @@ test.describe('Doc Table Content', () => {
const another = panel.getByText('Another World');
await expect(hello).toBeVisible();
await expect(hello).toHaveCSS('font-size', '19.2px');
await expect(hello).toHaveCSS('font-size', /19/);
await expect(hello).toHaveAttribute('aria-selected', 'true');
await expect(superW).toBeVisible();
await expect(superW).toHaveCSS('font-size', '16px');
await expect(superW).toHaveCSS('font-size', /16/);
await expect(superW).toHaveAttribute('aria-selected', 'false');
await expect(another).toBeVisible();
await expect(another).toHaveCSS('font-size', '12.8px');
await expect(another).toHaveCSS('font-size', /12/);
await expect(another).toHaveAttribute('aria-selected', 'false');
await hello.click();

View File

@@ -1,6 +1,6 @@
{
"name": "app-e2e",
"version": "1.3.0",
"version": "1.4.0",
"private": true,
"scripts": {
"lint": "eslint . --ext .ts",

View File

@@ -1,6 +1,6 @@
{
"name": "app-impress",
"version": "1.3.0",
"version": "1.4.0",
"private": true,
"scripts": {
"dev": "next dev",
@@ -33,8 +33,8 @@
"react-i18next": "15.0.2",
"react-select": "5.8.0",
"styled-components": "6.1.13",
"yjs": "*",
"y-protocols": "1.0.6",
"yjs": "*",
"zustand": "4.5.5"
},
"devDependencies": {

View File

@@ -36,10 +36,10 @@ export const Panel = ({
$width="100%"
$maxWidth="20rem"
$position="sticky"
$maxHeight="96vh"
$maxHeight="99vh"
$height="100%"
$css={`
top: 2vh;
top: 0vh;
transition: ${transition};
${
!isOpen &&

View File

@@ -1,7 +1,4 @@
import {
BlockNoteEditor as BlockNoteEditorCore,
locales,
} from '@blocknote/core';
import { BlockNoteEditor as BlockNoteEditorCore } from '@blocknote/core';
import '@blocknote/core/fonts/inter.css';
import { BlockNoteView } from '@blocknote/mantine';
import '@blocknote/mantine/style.css';
@@ -21,8 +18,6 @@ import { randomColor } from '../utils';
import { BlockNoteToolbar } from './BlockNoteToolbar';
import { useTranslation } from 'react-i18next';
const cssEditor = `
&, & > .bn-container, & .ProseMirror {
height:100%
@@ -99,19 +94,6 @@ export const BlockNoteContent = ({
[createDocAttachment, doc.id],
);
const { t, i18n } = useTranslation();
const lang = i18n.language;
const resetStore = () => {
setStore(storeId, { editor: undefined });
};
// Invalidate the stored editor when the language changes
useEffect(() => {
resetStore();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [lang]);
const editor = useMemo(() => {
if (storedEditor) {
return storedEditor;
@@ -126,10 +108,9 @@ export const BlockNoteContent = ({
color: randomColor(),
},
},
dictionary: locales[lang as keyof typeof locales],
uploadFile,
});
}, [provider, storedEditor, uploadFile, userData?.email, lang]);
}, [provider, storedEditor, uploadFile, userData?.email]);
useEffect(() => {
setStore(storeId, { editor });

View File

@@ -15,7 +15,6 @@ import {
} from '@blocknote/react';
import { forEach, isArray } from 'lodash';
import React, { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
export const BlockNoteToolbar = () => {
return (
@@ -94,7 +93,6 @@ export function MarkdownButton() {
const editor = useBlockNoteEditor();
const Components = useComponentsContext();
const selectedBlocks = useSelectedBlocks(editor);
const { t } = useTranslation();
const handleConvertMarkdown = () => {
const blocks = editor.getSelection()?.blocks;
@@ -128,7 +126,7 @@ export function MarkdownButton() {
return (
<Components.FormattingToolbar.Button
mainTooltip={t('Convert Markdown')}
mainTooltip="Convert Markdown"
onClick={handleConvertMarkdown}
>
M

View File

@@ -91,7 +91,7 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
icon={<span className="material-icons">summarize</span>}
size="small"
>
<Text $theme="primary">{t('Table of content')}</Text>
<Text $theme="primary">{t('Table of contents')}</Text>
</Button>
<Button
onClick={() => {

View File

@@ -46,6 +46,7 @@ export const Heading = ({
block: 'start',
});
}}
$css="text-align: left;"
>
<Text
$theme="primary"

View File

@@ -10,11 +10,28 @@ import { useDocTableContentStore } from '../stores';
import { Heading } from './Heading';
const recursiveTextContent = (content: HeadingBlock['content']): string => {
if (!content) {
return '';
}
return content.reduce((acc, content) => {
if (content.type === 'text') {
return acc + content.text;
} else if (content.type === 'link') {
return acc + recursiveTextContent(content.content);
}
return acc;
}, '');
};
type HeadingBlock = {
id: string;
type: string;
text: string;
content: HeadingBlock[];
contentText: string;
props: {
level: number;
};
@@ -31,9 +48,14 @@ export const TableContent = ({ doc }: TableContentProps) => {
const editor = docsStore?.[doc.id]?.editor;
const headingFiltering = useCallback(
() =>
editor?.document.filter(
(block) => block.type === 'heading',
) as unknown as HeadingBlock[],
editor?.document
.filter((block) => block.type === 'heading')
.map((block) => ({
...block,
contentText: recursiveTextContent(
block.content as unknown as HeadingBlock['content'],
),
})) as unknown as HeadingBlock[],
[editor?.document],
);
@@ -71,7 +93,7 @@ export const TableContent = ({ doc }: TableContentProps) => {
for (const heading of headings) {
const elHeading = document.body.querySelector(
`.bn-block-outer[data-id="${heading.id}"]`,
`.bn-block-outer[data-id="${heading.id}"] [data-content-type="heading"]:first-child`,
);
if (!elHeading) {
@@ -121,21 +143,16 @@ export const TableContent = ({ doc }: TableContentProps) => {
<Panel setIsPanelOpen={setClosePanel}>
<Box $padding="small" $maxHeight="95%">
<Box $overflow="auto">
{headings?.map((heading) => {
const content = heading.content?.[0];
const text = content?.type === 'text' ? content.text : '';
return (
<Heading
editor={editor}
headingId={heading.id}
level={heading.props.level}
text={text}
key={heading.id}
isHighlight={headingIdHighlight === heading.id}
/>
);
})}
{headings?.map((heading) => (
<Heading
editor={editor}
headingId={heading.id}
level={heading.props.level}
text={heading.contentText}
key={heading.id}
isHighlight={headingIdHighlight === heading.id}
/>
))}
</Box>
<Box
$height="1px"

View File

@@ -20,6 +20,7 @@
"Content modal to delete document": "Contenu modal pour supprimer le document",
"Content modal to export the document": "Contenu modal pour exporter le document",
"Cookies placed": "Cookies déposés",
"Copy link": "Copier le lien",
"Copyright": "Copyright",
"Create a new document": "Créer un nouveau document",
"Create the document": "Créer le document",
@@ -29,9 +30,10 @@
"Defender of Rights - Free response - 71120 75342 Paris CEDEX 07": "Défenseur des droits - Réponse gratuite - 71120 75342 Paris CEDEX 07",
"Delete document": "Supprimer le document",
"Deleting the document \"{{title}}\"": "Suppression du document \"{{title}}\"",
"Doc visibility card": "Carte de visibilité du doc",
"Docs": "Docs",
"Docs Description": "Description de Docs",
"Docs Logo": "Logo Docs",
"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 icon": "Icône du document",
"Document name": "Nom du document",
"Document panel": "Panneau du document",
@@ -45,6 +47,7 @@
"Export": "Exporter",
"Export your document, it will be inserted in the selected template.": "Exportez votre document, il sera inséré dans le modèle sélectionné.",
"Failed to add the member in the document.": "Impossible d'ajouter le membre dans le document.",
"Failed to copy link": "Échec de la copie du lien",
"Failed to create the invitation for {{email}}.": "Impossible de créer l'invitation pour {{email}}.",
"Find a member to add to the document": "Trouver un membre à ajouter au document",
"French Interministerial Directorate for Digital Affairs (DINUM), 20 avenue de Ségur 75007 Paris.": "Direction interministérielle des affaires numériques (DINUM), 20 avenue de Segur 75007 Paris.",
@@ -56,7 +59,6 @@
"Invitation sent to {{email}}.": "Invitation envoyée à {{email}}.",
"Invite new members to {{title}}": "Invitez de nouveaux membres à rejoindre {{title}}",
"Invited": "Invité",
"Is it public ?": "Est-ce public?",
"It is the card information about the document.": "Il s'agit de la carte d'information du document.",
"It seems that the page you are looking for does not exist or cannot be displayed correctly.": "Il semble que la page que vous cherchez n'existe pas ou ne puisse pas être affichée correctement.",
"It's true, you didn't have to click on a block that covers half the page to say you agree to the placement of cookies — even if you don't know what it means!": "C'est vrai, vous n'avez pas à cliquer sur un bloc qui couvre la moitié de la page pour dire que vous acceptez le placement de cookies — même si vous ne savez pas ce que cela signifie !",
@@ -64,13 +66,14 @@
"Language Icon": "Icône de langue",
"Legal Notice": "Mentions Legales",
"Legal notice": "Mention légale",
"Link Copied !": "Lien copié !",
"List invitation card": "Carte de liste d'invitation",
"List members card": "Carte liste des membres",
"Login": "Connexion",
"Logout": "Se déconnecter",
"Members": "Membres",
"Modal confirmation to restore the version": "Modale de confirmation pour restaurer la version",
"More info?": "Plus d'infos ?",
"My account": "Mon compte",
"No editor found": "Pas d'éditeur trouvé",
"Nothing exceptional, no special privileges related to a .gouv.fr.": "Rien d'exceptionnel, pas de privilèges spéciaux liés à un .gouv.fr.",
"Offline ?!": "Hors-ligne ?!",
@@ -94,16 +97,16 @@
"Restore this version": "Restaurer cette version",
"Restore this version?": "Restaurer cette version?",
"Role": "Rôle",
"SUMMARY": "RÉSUMÉ",
"Search by email": "Recherche par email",
"Send a letter by post (free of charge, no stamp needed):": "Envoyer un courrier par la poste (gratuit, ne pas mettre de timbre):",
"Share": "Partager",
"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).",
"Summary": "Résumé",
"Table of contents": "Table des matières",
"Template": "Template",
"The document has been deleted.": "Le document a bien été supprimé.",
"The document has been updated.": "Le document a été mis à jour.",
"The document visiblitity has been updated.": "La visibilité du document a été mise à jour.",
"The invitation has been removed.": "L'invitation a été supprimée.",
"The member has been removed from the document": "Le membre a été retiré du document",
"The role has been updated": "Le rôle a été mis à jour",
@@ -125,7 +128,7 @@
"Validate the modification": "Valider les modifications",
"Version restored successfully": "Version restaurée avec succès",
"We didn't find a mail matching, try to be more accurate": "Nous n'avons pas trouvé de correspondance par mail, essayez d'être plus précis",
"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 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 daudience, 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.",
"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.",
@@ -140,8 +143,7 @@
"accessibility-dinum-services": "<strong>DINUM</strong> s'engage à rendre accessibles ses services numériques, conformément à l'article 47 de la loi n° 2005-102 du 11 février 2005.",
"accessibility-form-defenseurdesdroits": "Écrire un message au<1>Défenseur des droits</1>",
"accessibility-not-audit": "<strong>docs.numerique.gouv.fr</strong> n'est pas en conformité avec le RGAA 4.1. Le site n'a <strong>pas encore été audité.</strong>",
"you have reported to the website manager a lack of accessibility that prevents you from accessing content or one of the services of the portal and you have not received a satisfactory response.": "vous avez signalé au responsable du site internet un défaut d'accessibilité qui vous empêche d'accéder à un contenu ou à un des services du portail et vous n'avez pas obtenu de réponse satisfaisante.",
"Convert Markdown": "Convertir Markdown"
"you have reported to the website manager a lack of accessibility that prevents you from accessing content or one of the services of the portal and you have not received a satisfactory response.": "vous avez signalé au responsable du site internet un défaut d'accessibilité qui vous empêche d'accéder à un contenu ou à un des services du portail et vous n'avez pas obtenu de réponse satisfaisante."
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "impress",
"version": "1.3.0",
"version": "1.4.0",
"private": true,
"workspaces": {
"packages": [

View File

@@ -1,6 +1,6 @@
{
"name": "eslint-config-impress",
"version": "1.3.0",
"version": "1.4.0",
"license": "MIT",
"scripts": {
"lint": "eslint --ext .js ."

View File

@@ -1,6 +1,6 @@
{
"name": "packages-i18n",
"version": "1.3.0",
"version": "1.4.0",
"private": true,
"scripts": {
"extract-translation": "yarn extract-translation:impress",

View File

@@ -1,6 +1,6 @@
{
"name": "server-y-provider",
"version": "1.3.0",
"version": "1.4.0",
"description": "Y.js provider for docs",
"repository": "https://github.com/numerique-gouv/impress",
"license": "MIT",

View File

@@ -1,7 +1,7 @@
image:
repository: lasuite/impress-backend
pullPolicy: Always
tag: "v1.3.0-preprod"
tag: "v1.4.0-preprod"
backend:
migrateJobAnnotations:
@@ -124,13 +124,13 @@ frontend:
image:
repository: lasuite/impress-frontend
pullPolicy: Always
tag: "v1.3.0-preprod"
tag: "v1.4.0-preprod"
yProvider:
image:
repository: lasuite/impress-y-provider
pullPolicy: Always
tag: "v1.3.0-preprod"
tag: "v1.4.0-preprod"
ingress:
enabled: true

View File

@@ -1,7 +1,7 @@
image:
repository: lasuite/impress-backend
pullPolicy: Always
tag: "v1.3.0"
tag: "v1.4.0"
backend:
migrateJobAnnotations:
@@ -124,13 +124,13 @@ frontend:
image:
repository: lasuite/impress-frontend
pullPolicy: Always
tag: "v1.3.0"
tag: "v1.4.0"
yProvider:
image:
repository: lasuite/impress-y-provider
pullPolicy: Always
tag: "v1.3.0"
tag: "v1.4.0"
ingress:
enabled: true

View File

@@ -1,6 +1,6 @@
{
"name": "mail_mjml",
"version": "1.3.0",
"version": "1.4.0",
"description": "An util to generate html and text django's templates from mjml templates",
"type": "module",
"dependencies": {