diff --git a/CHANGELOG.md b/CHANGELOG.md
index 08aa34d88..1771d6c72 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,7 @@ and this project adheres to
- ♿️(frontend) use semantic `
` structure in document info card #2379
- 🚸(frontend) print from document options menu #2550
+- 🚚(frontend) add doc move to doc options #2555
### Fixed
diff --git a/src/frontend/apps/impress/src/assets/icons/ui-kit/doc-move-out.svg b/src/frontend/apps/impress/src/assets/icons/ui-kit/doc-move-out.svg
index 2a2055079..3f23292b2 100644
--- a/src/frontend/apps/impress/src/assets/icons/ui-kit/doc-move-out.svg
+++ b/src/frontend/apps/impress/src/assets/icons/ui-kit/doc-move-out.svg
@@ -1,6 +1,18 @@
-
-
-
-
-
+
+
+
+
+
diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/api/useMoveDoc.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/api/useMoveDoc.tsx
index c0e732259..3a2c2d412 100644
--- a/src/frontend/apps/impress/src/features/docs/doc-management/api/useMoveDoc.tsx
+++ b/src/frontend/apps/impress/src/features/docs/doc-management/api/useMoveDoc.tsx
@@ -2,7 +2,9 @@ import { TreeViewMoveModeEnum } from '@gouvfr-lasuite/ui-kit';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { APIError, errorCauses, fetchAPI } from '@/api';
+import { KEY_DOC_TREE } from '@/docs/doc-tree/api/useDocTree';
+import { KEY_DOC } from './useDoc';
import { KEY_LIST_DOC } from './useDocs';
export type MoveDocParam = {
@@ -37,9 +39,9 @@ export function useMoveDoc() {
return useMutation({
mutationFn: moveDoc,
onSuccess() {
- void queryClient.invalidateQueries({
- queryKey: [KEY_LIST_DOC],
- });
+ void queryClient.invalidateQueries({ queryKey: [KEY_LIST_DOC] });
+ void queryClient.invalidateQueries({ queryKey: [KEY_DOC] });
+ void queryClient.invalidateQueries({ queryKey: [KEY_DOC_TREE] });
},
});
}
diff --git a/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocMoveModal.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/components/DocMoveModal.tsx
similarity index 98%
rename from src/frontend/apps/impress/src/features/docs/docs-grid/components/DocMoveModal.tsx
rename to src/frontend/apps/impress/src/features/docs/doc-management/components/DocMoveModal.tsx
index f43aff36f..ab57f46dc 100644
--- a/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocMoveModal.tsx
+++ b/src/frontend/apps/impress/src/features/docs/doc-management/components/DocMoveModal.tsx
@@ -17,10 +17,12 @@ import { Box, ButtonCloseModal, Text } from '@/components';
import { QuickSearch } from '@/components/quick-search';
import { Doc, useMoveDoc, useTrans } from '@/docs/doc-management';
import { DocSearchContent } from '@/docs/doc-search';
+import {
+ DocsGridItemDate,
+ DocsGridItemTitle,
+} from '@/docs/docs-grid/components/DocsGridItem';
import { useResponsiveStore } from '@/stores';
-import { DocsGridItemDate, DocsGridItemTitle } from './DocsGridItem';
-
const AlertModalRequestAccess = dynamic(
() =>
import('@/docs/doc-share/components/AlertModalRequestAccess').then(
@@ -83,12 +85,14 @@ type DocMoveModalGlobalProps = {
doc: Doc;
isOpen: boolean;
onClose: () => void;
+ onAfterMove?: () => void;
};
export const DocMoveModal = ({
doc,
isOpen,
onClose,
+ onAfterMove,
}: DocMoveModalGlobalProps) => {
const { t } = useTranslation();
const [loading, setLoading] = useState(false);
@@ -120,10 +124,8 @@ export const DocMoveModal = ({
position: TreeViewMoveModeEnum.FIRST_CHILD,
})
.then(() => {
- toast(
- t(`The document has been moved successfully.`),
- VariantType.SUCCESS,
- );
+ onClose();
+ onAfterMove?.();
})
.catch(() => {
toast(
diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/components/DocToolBox.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/components/DocToolBox.tsx
index 9546ae400..0796a68de 100644
--- a/src/frontend/apps/impress/src/features/docs/doc-management/components/DocToolBox.tsx
+++ b/src/frontend/apps/impress/src/features/docs/doc-management/components/DocToolBox.tsx
@@ -21,11 +21,15 @@ import MoreSVG from '@/assets/icons/ui-kit/more_horiz.svg';
import PrintIcon from '@/assets/icons/ui-kit/print.svg';
import SharedIcon from '@/assets/icons/ui-kit/shared.svg';
import DeleteIcon from '@/assets/icons/ui-kit/trash.svg';
+import { printDocumentWithStyles } from '@/docs/doc-export/utils_print';
+import { DocMoveModal } from '@/docs/doc-management/components/DocMoveModal';
import { usePresenterStore } from '@/docs/doc-presenter/stores';
+import { useDetachDoc } from '@/docs/doc-tree/api/useDetach';
import { useAuth } from '@/features/auth';
+import DocMoveInIcon from '@/icons/doc-move-in.svg';
+import DocMoveOutIcon from '@/icons/doc-move-out.svg';
import { useFocusStore, useResponsiveStore } from '@/stores';
-import { printDocumentWithStyles } from '../../doc-export/utils_print';
import {
KEY_DOC,
KEY_LIST_DOC,
@@ -35,7 +39,7 @@ import {
useDuplicateDoc,
} from '../api';
import { useCopyDocLink } from '../hooks';
-import { Doc } from '../types';
+import { Doc, Role } from '../types';
const ModalRemoveDoc = dynamic(
() =>
@@ -88,7 +92,7 @@ interface DocToolBoxProps {
export const DocToolBox = ({ doc }: DocToolBoxProps) => {
const { t } = useTranslation();
- const treeContext = useTreeContext();
+ const treeContext = useTreeContext();
const router = useRouter();
const isTopParent = doc.id === treeContext?.root?.id; // it can be a child but not for the current user
const { authenticated } = useAuth();
@@ -98,6 +102,8 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
const [isModalShareOpen, setIsModalShareOpen] = useState(false);
const [isModalHistoryOpen, setIsModalHistoryOpen] = useState(false);
const [isModalLeaveOpen, setIsModalLeaveOpen] = useState(false);
+ const [isModalMoveOpen, setIsModalMoveOpen] = useState(false);
+ const { mutate: detachDoc } = useDetachDoc();
const { restoreFocus, addLastFocus } = useFocusStore();
const { isMobile } = useResponsiveStore();
@@ -198,6 +204,40 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
},
isHidden: !doc.abilities.duplicate,
},
+ {
+ label: t('Move to my docs'),
+ isHidden: isTopParent || doc.user_role !== Role.OWNER,
+ icon: ,
+ callback: () => {
+ if (!treeContext?.root) {
+ return;
+ }
+
+ detachDoc(
+ { documentId: doc.id, rootId: treeContext.root.id },
+ {
+ onSuccess: () => {
+ if (treeContext.root) {
+ treeContext.treeData.setSelectedNode(treeContext.root);
+ void router.push(`/docs/${treeContext.root.id}`).then(() => {
+ setTimeout(() => {
+ treeContext?.treeData.deleteNode(doc.id);
+ }, 100);
+ });
+ }
+ },
+ },
+ );
+ },
+ },
+ {
+ label: t('Move into a doc'),
+ icon: ,
+ callback: () => {
+ setIsModalMoveOpen(true);
+ },
+ isHidden: !doc.abilities.move,
+ },
{ type: 'separator' },
{
label: t('History', {
@@ -322,6 +362,17 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
doc={doc}
/>
)}
+ {isModalMoveOpen && (
+ {
+ setIsModalMoveOpen(false);
+ restoreFocus();
+ }}
+ isOpen={isModalMoveOpen}
+ onAfterMove={() => treeContext?.setRoot(null)}
+ />
+ )}
>
);
};
diff --git a/src/frontend/apps/impress/src/features/docs/docs-grid/components/ModalConfimationMoveDoc.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/components/ModalConfimationMoveDoc.tsx
similarity index 100%
rename from src/frontend/apps/impress/src/features/docs/docs-grid/components/ModalConfimationMoveDoc.tsx
rename to src/frontend/apps/impress/src/features/docs/doc-management/components/ModalConfimationMoveDoc.tsx
diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/assets/doc-extract-bold.svg b/src/frontend/apps/impress/src/features/docs/doc-tree/assets/doc-extract-bold.svg
deleted file mode 100644
index 47d4fa1a9..000000000
--- a/src/frontend/apps/impress/src/features/docs/doc-tree/assets/doc-extract-bold.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocSubPageItem.tsx b/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocSubPageItem.tsx
index b85ceeb0f..17d3e0398 100644
--- a/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocSubPageItem.tsx
+++ b/src/frontend/apps/impress/src/features/docs/doc-tree/components/DocSubPageItem.tsx
@@ -11,7 +11,7 @@ import { useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { css } from 'styled-components';
-import { Box, Icon, StyledLink, Text } from '@/components';
+import { Box, StyledLink, Text } from '@/components';
import {
Doc,
DocIcon,
@@ -294,14 +294,6 @@ const DocSubPageItemContent = (props: TreeViewNodeProps) => {
{displayTitle}
- {doc.nb_accesses_direct >= 1 && (
-
- )}
-
-
+
),
callback: handleDetachDoc,
},
diff --git a/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocGridContentList.tsx b/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocGridContentList.tsx
index 03fea5ac0..78b90c1c3 100644
--- a/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocGridContentList.tsx
+++ b/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocGridContentList.tsx
@@ -23,9 +23,11 @@ import { Droppable } from './Droppable';
const ModalConfirmationMoveDoc = dynamic(
() =>
- import('./ModalConfimationMoveDoc').then((mod) => ({
- default: mod.ModalConfirmationMoveDoc,
- })),
+ import('@/docs/doc-management/components/ModalConfimationMoveDoc').then(
+ (mod) => ({
+ default: mod.ModalConfirmationMoveDoc,
+ }),
+ ),
{ ssr: false },
);
diff --git a/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGridActions.tsx b/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGridActions.tsx
index 430df4711..6bd5fc709 100644
--- a/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGridActions.tsx
+++ b/src/frontend/apps/impress/src/features/docs/docs-grid/components/DocsGridActions.tsx
@@ -13,7 +13,7 @@ import KeepOffSVG from '@/assets/icons/ui-kit/keep_off.svg';
import LeaveSVG from '@/assets/icons/ui-kit/leave.svg';
import MoreSVG from '@/assets/icons/ui-kit/more_horiz.svg';
import {
- Doc,
+ type Doc,
KEY_LIST_DOC,
KEY_LIST_FAVORITE_DOC,
useCreateFavoriteDoc,
@@ -21,11 +21,10 @@ import {
useDuplicateDoc,
useTrans,
} from '@/docs/doc-management';
+import { DocMoveModal } from '@/docs/doc-management/components/DocMoveModal';
import { focusMainContentStart } from '@/layouts/utils';
import { useFocusStore } from '@/stores';
-import { DocMoveModal } from './DocMoveModal';
-
const DocShareModal = dynamic(
() =>
import('@/docs/doc-share/components/DocShareModal').then((mod) => ({