Compare commits

..

1 Commits

Author SHA1 Message Date
Anthony LC 22ef6e0e40 (frontend) add duplicate action to doc tree
We added a duplicate action to the document tree.
2025-07-10 16:54:11 +02:00
18 changed files with 488 additions and 516 deletions
+2 -8
View File
@@ -8,15 +8,10 @@ and this project adheres to
## [Unreleased]
## [3.4.1] - 2025-07-15
### Fixed
- 🌐(frontend) keep simple tag during export #1154
- 🐛(back) manage can-edit endpoint without created room
in the ws #1152
- 🐛(frontend) fix action buttons not clickable #1162
- 🐛(frontend) fix crash share modal on grid options #1174
- 🐛(back) manage can-edit endpoint without created room in the ws
## [3.4.0] - 2025-07-09
@@ -646,8 +641,7 @@ and this project adheres to
- ✨(frontend) Coming Soon page (#67)
- 🚀 Impress, project to manage your documents easily and collaboratively.
[unreleased]: https://github.com/numerique-gouv/impress/compare/v3.4.1...main
[v3.4.1]: https://github.com/numerique-gouv/impress/releases/v3.4.1
[unreleased]: https://github.com/numerique-gouv/impress/compare/v3.4.0...main
[v3.4.0]: https://github.com/numerique-gouv/impress/releases/v3.4.0
[v3.3.0]: https://github.com/numerique-gouv/impress/releases/v3.3.0
[v3.2.1]: https://github.com/numerique-gouv/impress/releases/v3.2.1
+5 -5
View File
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "impress"
version = "3.4.1"
version = "3.4.0"
authors = [{ "name" = "DINUM", "email" = "dev@mail.numerique.gouv.fr" }]
classifiers = [
"Development Status :: 5 - Production/Stable",
@@ -26,7 +26,7 @@ readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"beautifulsoup4==4.13.4",
"boto3==1.39.4",
"boto3==1.39.3",
"Brotli==1.1.0",
"celery[redis]==5.5.3",
"django-configurations==2.5.1",
@@ -34,7 +34,7 @@ dependencies = [
"django-countries==7.6.1",
"django-csp==4.0",
"django-filter==25.1",
"django-lasuite[all]==0.0.11",
"django-lasuite[all]==0.0.10",
"django-parler==2.3",
"django-redis==6.0.0",
"django-storages[s3]==1.14.6",
@@ -52,9 +52,9 @@ dependencies = [
"markdown==3.8.2",
"mozilla-django-oidc==4.0.1",
"nested-multipart-parser==1.5.0",
"openai==1.95.0",
"openai==1.93.0",
"psycopg[binary]==3.2.9",
"pycrdt==0.12.25",
"pycrdt==0.12.23",
"PyJWT==2.10.1",
"python-magic==0.4.27",
"redis<6.0.0",
@@ -91,22 +91,6 @@ test.describe('Document grid item options', () => {
await page.goto('/');
});
test('it checks the share modal', async ({ page, browserName }) => {
const [docTitle] = await createDoc(page, `check share modal`, browserName);
await page.goto('/');
await expect(page.getByText(docTitle)).toBeVisible();
const row = await getGridRow(page, docTitle);
await row.getByText(`more_horiz`).click();
await page.getByRole('menuitem', { name: 'Share' }).click();
await expect(
page.getByRole('dialog').getByText('Share the document'),
).toBeVisible();
});
test('it pins a document', async ({ page, browserName }) => {
const [docTitle] = await createDoc(page, `Favorite doc`, browserName);
@@ -482,6 +482,22 @@ test.describe('Doc Header', () => {
await expect(
page.getByTestId('doc-tree').getByText(duplicateDuplicateTitle),
).toBeVisible();
const docTree = page.getByTestId('doc-tree');
await docTree.getByText(duplicateDuplicateTitle).hover();
await docTree
.getByText(duplicateDuplicateTitle)
.getByRole('button', { name: 'add_box' })
.click();
await page.getByRole('menuitem', { name: 'Duplicate' }).click();
const duplicateDuplicateDuplicateTitle =
'Copy of ' + duplicateDuplicateTitle;
await expect(
page.getByTestId('doc-tree').getByText(duplicateDuplicateDuplicateTitle),
).toBeVisible();
});
});
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "app-e2e",
"version": "3.4.1",
"version": "3.4.0",
"private": true,
"scripts": {
"lint": "eslint . --ext .ts",
@@ -12,7 +12,7 @@
"test:ui::chromium": "yarn test:ui --project=chromium"
},
"devDependencies": {
"@playwright/test": "1.54.1",
"@playwright/test": "1.53.2",
"@types/node": "*",
"@types/pdf-parse": "1.1.5",
"eslint-config-impress": "*",
+11 -11
View File
@@ -1,6 +1,6 @@
{
"name": "app-impress",
"version": "3.4.1",
"version": "3.4.0",
"private": true,
"scripts": {
"dev": "next dev",
@@ -32,27 +32,27 @@
"@hocuspocus/provider": "2.15.2",
"@openfun/cunningham-react": "3.1.0",
"@react-pdf/renderer": "4.3.0",
"@sentry/nextjs": "9.38.0",
"@tanstack/react-query": "5.83.0",
"@sentry/nextjs": "9.35.0",
"@tanstack/react-query": "5.81.5",
"canvg": "4.0.3",
"clsx": "2.1.1",
"cmdk": "1.1.1",
"crisp-sdk-web": "1.0.25",
"docx": "9.5.0",
"emoji-mart": "5.6.0",
"i18next": "25.3.2",
"i18next": "25.3.1",
"i18next-browser-languagedetector": "8.2.0",
"idb": "8.0.3",
"lodash": "4.17.21",
"luxon": "3.7.1",
"next": "15.4.1",
"posthog-js": "1.257.0",
"luxon": "3.6.1",
"next": "15.3.5",
"posthog-js": "1.256.2",
"react": "*",
"react-aria-components": "1.10.1",
"react-dom": "*",
"react-i18next": "15.6.0",
"react-intersection-observer": "9.16.0",
"react-select": "5.10.2",
"react-select": "5.10.1",
"styled-components": "6.1.19",
"use-debounce": "10.0.5",
"y-protocols": "1.0.6",
@@ -61,7 +61,7 @@
},
"devDependencies": {
"@svgr/webpack": "8.1.0",
"@tanstack/react-query-devtools": "5.83.0",
"@tanstack/react-query-devtools": "5.81.5",
"@testing-library/dom": "10.4.0",
"@testing-library/jest-dom": "6.6.3",
"@testing-library/react": "16.3.0",
@@ -73,7 +73,7 @@
"@types/react": "*",
"@types/react-dom": "*",
"cross-env": "7.0.3",
"dotenv": "17.2.0",
"dotenv": "17.1.0",
"eslint-config-impress": "*",
"fetch-mock": "9.11.0",
"jest": "30.0.4",
@@ -84,7 +84,7 @@
"stylelint-config-standard": "38.0.0",
"stylelint-prettier": "5.0.3",
"typescript": "*",
"webpack": "5.100.1",
"webpack": "5.99.9",
"workbox-webpack-plugin": "7.1.0"
}
}
@@ -18,7 +18,7 @@ import {
import { useLeftPanelStore } from '@/features/left-panel';
import { useResponsiveStore } from '@/stores';
import SubPageIcon from './../assets/sub-page-logo.svg';
import Logo from './../assets/sub-page-logo.svg';
import { DocTreeItemActions } from './DocTreeItemActions';
const ItemTextCss = css`
@@ -99,7 +99,6 @@ export const DocSubPageItem = (props: Props) => {
return (
<Box
className="--docs-sub-page-item"
$position="relative"
$css={css`
background-color: ${actionsOpen
? 'var(--c--theme--colors--greyscale-100)'
@@ -107,17 +106,6 @@ export const DocSubPageItem = (props: Props) => {
.light-doc-item-actions {
display: ${actionsOpen || !isDesktop ? 'flex' : 'none'};
position: absolute;
right: 0;
background: ${isDesktop
? 'var(--c--theme--colors--greyscale-100)'
: 'var(--c--theme--colors--greyscale-000)'};
}
.c__tree-view--node.isSelected {
.light-doc-item-actions {
background: var(--c--theme--colors--greyscale-100);
}
}
&:hover {
@@ -126,7 +114,6 @@ export const DocSubPageItem = (props: Props) => {
.light-doc-item-actions {
display: flex;
background: var(--c--theme--colors--greyscale-100);
}
}
`}
@@ -149,7 +136,7 @@ export const DocSubPageItem = (props: Props) => {
$minHeight="24px"
>
<Box $width="16px" $height="16px">
<SubPageIcon />
<Logo />
</Box>
<Box
@@ -136,10 +136,6 @@ export const DocTree = ({ initialTargetId }: DocTreeProps) => {
.c__tree-view--container {
z-index: 1;
margin-top: -10px;
.c__tree-view {
overflow: hidden !important;
}
}
`}
>
@@ -3,7 +3,11 @@ import {
DropdownMenuOption,
useTreeContext,
} from '@gouvfr-lasuite/ui-kit';
import { useModal } from '@openfun/cunningham-react';
import {
VariantType,
useModal,
useToastProvider,
} from '@openfun/cunningham-react';
import { useRouter } from 'next/router';
import { Fragment } from 'react';
import { useTranslation } from 'react-i18next';
@@ -16,6 +20,7 @@ import {
ModalRemoveDoc,
Role,
useCopyDocLink,
useDuplicateDoc,
} from '../../doc-management';
import { useCreateChildrenDoc } from '../api/useCreateChildren';
import { useDetachDoc } from '../api/useDetach';
@@ -45,6 +50,19 @@ export const DocTreeItemActions = ({
const { isCurrentParent } = useTreeUtils(doc);
const { mutate: detachDoc } = useDetachDoc();
const treeContext = useTreeContext<Doc>();
const { toast } = useToastProvider();
const { mutate: duplicateDoc } = useDuplicateDoc({
onSuccess: () => {
toast(t('Document duplicated successfully!'), VariantType.SUCCESS, {
duration: 3000,
});
},
onError: () => {
toast(t('Failed to duplicate the document...'), VariantType.ERROR, {
duration: 3000,
});
},
});
const handleDetachDoc = () => {
if (!treeContext?.root) {
@@ -89,6 +107,18 @@ export const DocTreeItemActions = ({
},
]
: []),
{
label: t('Duplicate'),
icon: <Icon $variation="600" iconName="content_copy" />,
isDisabled: !doc.abilities.duplicate,
callback: () => {
duplicateDoc({
docId: doc.id,
with_accesses: false,
canSave: doc.abilities.partial_update,
});
},
},
{
label: t('Delete'),
isDisabled: !doc.abilities.destroy,
@@ -1,4 +1,3 @@
import { TreeProvider } from '@gouvfr-lasuite/ui-kit';
import { Tooltip, useModal } from '@openfun/cunningham-react';
import { DateTime } from 'luxon';
import { useTranslation } from 'react-i18next';
@@ -144,9 +143,7 @@ export const DocsGridItem = ({ doc, dragMode = false }: DocsGridItemProps) => {
</Box>
</Box>
{shareModal.isOpen && (
<TreeProvider initialNodeId={doc.id}>
<DocShareModal doc={doc} onClose={shareModal.close} />
</TreeProvider>
<DocShareModal doc={doc} onClose={shareModal.close} />
)}
</>
);
+4 -4
View File
@@ -1,6 +1,6 @@
{
"name": "impress",
"version": "3.4.1",
"version": "3.4.0",
"private": true,
"workspaces": {
"packages": [
@@ -28,11 +28,11 @@
"server:test": "yarn COLLABORATION_SERVER run test"
},
"resolutions": {
"@types/node": "22.16.3",
"@types/node": "22.16.0",
"@types/react": "19.1.8",
"@types/react-dom": "19.1.6",
"@typescript-eslint/eslint-plugin": "8.37.0",
"@typescript-eslint/parser": "8.37.0",
"@typescript-eslint/eslint-plugin": "8.36.0",
"@typescript-eslint/parser": "8.36.0",
"eslint": "8.57.0",
"react": "19.1.0",
"react-dom": "19.1.0",
@@ -1,24 +1,24 @@
{
"name": "eslint-config-impress",
"version": "3.4.1",
"version": "3.4.0",
"license": "MIT",
"scripts": {
"lint": "eslint --ext .js ."
},
"dependencies": {
"@next/eslint-plugin-next": "15.4.1",
"@next/eslint-plugin-next": "15.3.5",
"@tanstack/eslint-plugin-query": "5.81.2",
"@typescript-eslint/eslint-plugin": "*",
"@typescript-eslint/parser": "*",
"eslint": "*",
"eslint-config-next": "15.4.1",
"eslint-config-next": "15.3.5",
"eslint-config-prettier": "10.1.5",
"eslint-plugin-import": "2.32.0",
"eslint-plugin-jest": "29.0.1",
"eslint-plugin-jsx-a11y": "6.10.2",
"eslint-plugin-playwright": "2.2.0",
"eslint-plugin-prettier": "5.5.1",
"eslint-plugin-testing-library": "7.6.0",
"eslint-plugin-testing-library": "7.5.3",
"prettier": "3.6.2"
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "packages-i18n",
"version": "3.4.1",
"version": "3.4.0",
"private": true,
"scripts": {
"extract-translation": "yarn extract-translation:impress",
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "server-y-provider",
"version": "3.4.1",
"version": "3.4.0",
"description": "Y.js provider for docs",
"repository": "https://github.com/numerique-gouv/impress",
"license": "MIT",
@@ -18,8 +18,8 @@
"dependencies": {
"@blocknote/server-util": "0.33.0",
"@hocuspocus/server": "2.15.2",
"@sentry/node": "9.38.0",
"@sentry/profiling-node": "9.38.0",
"@sentry/node": "9.35.0",
"@sentry/profiling-node": "9.35.0",
"axios": "1.10.0",
"cors": "2.8.5",
"express": "5.1.0",
+403 -435
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,7 +1,7 @@
environments:
dev:
values:
- version: 3.4.1
- version: 3.4.0
---
repositories:
- name: bitnami
+1 -1
View File
@@ -1,5 +1,5 @@
apiVersion: v2
type: application
name: docs
version: 3.4.1
version: 3.4.0
appVersion: latest
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "mail_mjml",
"version": "3.4.1",
"version": "3.4.0",
"description": "An util to generate html and text django's templates from mjml templates",
"type": "module",
"dependencies": {