️(frontend) improve tree stability

Improve tree stability by limiting the requests,
we now only load the tree request one time then
we let the treeContext handle the state without
mutating it directly.
We do not do the doc subpage request anymore,
the treeContext has already the data we need,
we just need to update the tree node when needed.
This commit is contained in:
Anthony LC
2025-07-22 17:53:41 +02:00
parent b28ff8f632
commit bbf48f088f
15 changed files with 191 additions and 247 deletions

View File

@@ -16,6 +16,7 @@ and this project adheres to
- ♻️(frontend) redirect to doc after duplicate #1175
- 🔧(project) change env.d system by using local files #1200
- ⚡️(frontend) improve tree stability #1207
### Fixed

View File

@@ -1,7 +1,7 @@
/* eslint-disable jsx-a11y/click-events-have-key-events */
/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */
import { useTreeContext } from '@gouvfr-lasuite/ui-kit';
import { Tooltip } from '@openfun/cunningham-react';
import { useQueryClient } from '@tanstack/react-query';
import React, { useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { css } from 'styled-components';
@@ -12,7 +12,6 @@ import {
Doc,
KEY_DOC,
KEY_LIST_DOC,
KEY_SUB_PAGE,
useDocStore,
useTrans,
useUpdateDoc,
@@ -50,10 +49,10 @@ export const DocTitleText = () => {
const DocTitleInput = ({ doc }: DocTitleProps) => {
const { isDesktop } = useResponsiveStore();
const queryClient = useQueryClient();
const { t } = useTranslation();
const { colorsTokens } = useCunninghamTheme();
const [titleDisplay, setTitleDisplay] = useState(doc.title);
const treeContext = useTreeContext<Doc>();
const { untitledDocument } = useTrans();
@@ -64,10 +63,16 @@ const DocTitleInput = ({ doc }: DocTitleProps) => {
onSuccess(updatedDoc) {
// Broadcast to every user connected to the document
broadcast(`${KEY_DOC}-${updatedDoc.id}`);
queryClient.setQueryData(
[KEY_SUB_PAGE, { id: updatedDoc.id }],
updatedDoc,
);
if (!treeContext) {
return;
}
if (treeContext.root?.id === updatedDoc.id) {
treeContext?.setRoot(updatedDoc);
} else {
treeContext?.treeData.updateNode(updatedDoc.id, updatedDoc);
}
},
});

View File

@@ -19,7 +19,6 @@ export const getDoc = async ({ id }: DocParams): Promise<Doc> => {
};
export const KEY_DOC = 'doc';
export const KEY_SUB_PAGE = 'sub-page';
export const KEY_DOC_VISIBILITY = 'doc-visibility';
export function useDoc(

View File

@@ -1,17 +1,10 @@
import { VariantType, useToastProvider } from '@openfun/cunningham-react';
import { useQueryClient } from '@tanstack/react-query';
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { css } from 'styled-components';
import { DropdownMenu, DropdownMenuOption, Text } from '@/components';
import {
Access,
Doc,
KEY_SUB_PAGE,
Role,
useTrans,
} from '@/docs/doc-management/';
import { Access, Doc, Role, useTrans } from '@/docs/doc-management/';
import { useDeleteDocAccess, useDeleteDocInvitation } from '../api';
import { Invitation, isInvitation } from '../types';
@@ -39,19 +32,9 @@ export const DocRoleDropdown = ({
}: DocRoleDropdownProps) => {
const { t } = useTranslation();
const { transRole, translatedRoles } = useTrans();
const queryClient = useQueryClient();
const { toast } = useToastProvider();
const { mutate: removeDocInvitation } = useDeleteDocInvitation({
onSuccess: () => {
if (!doc) {
return;
}
void queryClient.invalidateQueries({
queryKey: [KEY_SUB_PAGE, { id: doc.id }],
});
},
onError: (error) => {
toast(
error?.data?.role?.[0] ?? t('Error during delete invitation'),
@@ -64,14 +47,6 @@ export const DocRoleDropdown = ({
});
const { mutate: removeDocAccess } = useDeleteDocAccess({
onSuccess: () => {
if (!doc) {
return;
}
void queryClient.invalidateQueries({
queryKey: [KEY_SUB_PAGE, { id: doc.id }],
});
},
onError: () => {
toast(t('Error while deleting invitation'), VariantType.ERROR, {
duration: 4000,

View File

@@ -3,7 +3,6 @@ import {
VariantType,
useToastProvider,
} from '@openfun/cunningham-react';
import { useQueryClient } from '@tanstack/react-query';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { css } from 'styled-components';
@@ -11,7 +10,7 @@ import { css } from 'styled-components';
import { APIError } from '@/api';
import { Box } from '@/components';
import { useCunninghamTheme } from '@/cunningham';
import { Doc, KEY_SUB_PAGE, Role } from '@/docs/doc-management';
import { Doc, Role } from '@/docs/doc-management';
import { User } from '@/features/auth';
import { useCreateDocAccess, useCreateDocInvitation } from '../api';
@@ -45,7 +44,6 @@ export const DocShareAddMemberList = ({
const { spacingsTokens, colorsTokens } = useCunninghamTheme();
const [invitationRole, setInvitationRole] = useState<Role>(Role.EDITOR);
const canShare = doc.abilities.accesses_manage;
const queryClient = useQueryClient();
const { mutateAsync: createInvitation } = useCreateDocInvitation();
const { mutateAsync: createDocAccess } = useCreateDocAccess();
@@ -91,32 +89,14 @@ export const DocShareAddMemberList = ({
};
return isInvitationMode
? createInvitation(
{
...payload,
email: user.email,
},
{
onSuccess: () => {
void queryClient.invalidateQueries({
queryKey: [KEY_SUB_PAGE, { id: doc.id }],
});
},
},
)
: createDocAccess(
{
...payload,
memberId: user.id,
},
{
onSuccess: () => {
void queryClient.invalidateQueries({
queryKey: [KEY_SUB_PAGE, { id: doc.id }],
});
},
},
);
? createInvitation({
...payload,
email: user.email,
})
: createDocAccess({
...payload,
memberId: user.id,
});
});
const settledPromises = await Promise.allSettled(promises);

View File

@@ -1,5 +1,4 @@
import { VariantType, useToastProvider } from '@openfun/cunningham-react';
import { useQueryClient } from '@tanstack/react-query';
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { css } from 'styled-components';
@@ -15,7 +14,7 @@ import {
} from '@/components';
import { QuickSearchData, QuickSearchGroup } from '@/components/quick-search';
import { useCunninghamTheme } from '@/cunningham';
import { Doc, KEY_SUB_PAGE, Role } from '@/docs/doc-management';
import { Doc, Role } from '@/docs/doc-management';
import { User } from '@/features/auth';
import {
@@ -38,7 +37,6 @@ export const DocShareInvitationItem = ({
invitation,
}: DocShareInvitationItemProps) => {
const { t } = useTranslation();
const queryClient = useQueryClient();
const { spacingsTokens } = useCunninghamTheme();
const invitedUser: User = {
id: invitation.email,
@@ -52,11 +50,6 @@ export const DocShareInvitationItem = ({
const canUpdate = doc.abilities.accesses_manage;
const { mutate: updateDocInvitation } = useUpdateDocInvitation({
onSuccess: () => {
void queryClient.invalidateQueries({
queryKey: [KEY_SUB_PAGE, { id: doc.id }],
});
},
onError: (error) => {
toast(
error?.data?.role?.[0] ?? t('Error during update invitation'),
@@ -69,11 +62,6 @@ export const DocShareInvitationItem = ({
});
const { mutate: removeDocInvitation } = useDeleteDocInvitation({
onSuccess: () => {
void queryClient.invalidateQueries({
queryKey: [KEY_SUB_PAGE, { id: doc.id }],
});
},
onError: (error) => {
toast(
error?.data?.role?.[0] ?? t('Error during delete invitation'),

View File

@@ -1,5 +1,4 @@
import { VariantType, useToastProvider } from '@openfun/cunningham-react';
import { useQueryClient } from '@tanstack/react-query';
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
@@ -7,7 +6,7 @@ import { Box } from '@/components';
import { QuickSearchData } from '@/components/quick-search';
import { QuickSearchGroup } from '@/components/quick-search/QuickSearchGroup';
import { useCunninghamTheme } from '@/cunningham';
import { Access, Doc, KEY_SUB_PAGE, Role } from '@/docs/doc-management/';
import { Access, Doc, Role } from '@/docs/doc-management/';
import { useDocAccesses, useUpdateDocAccess } from '../api';
import { useWhoAmI } from '../hooks/';
@@ -26,7 +25,6 @@ export const DocShareMemberItem = ({
isInherited = false,
}: Props) => {
const { t } = useTranslation();
const queryClient = useQueryClient();
const { isLastOwner } = useWhoAmI(access);
const { toast } = useToastProvider();
@@ -39,14 +37,6 @@ export const DocShareMemberItem = ({
: undefined;
const { mutate: updateDocAccess } = useUpdateDocAccess({
onSuccess: () => {
if (!doc) {
return;
}
void queryClient.invalidateQueries({
queryKey: [KEY_SUB_PAGE, { id: doc.id }],
});
},
onError: () => {
toast(t('Error while updating the member role.'), VariantType.ERROR, {
duration: 4000,

View File

@@ -9,11 +9,7 @@ export type DocsTreeParams = {
};
export const getDocTree = async ({ docId }: DocsTreeParams): Promise<Doc> => {
const searchParams = new URLSearchParams();
const response = await fetchAPI(
`documents/${docId}/tree/?${searchParams.toString()}`,
);
const response = await fetchAPI(`documents/${docId}/tree/`);
if (!response.ok) {
throw new APIError(
@@ -29,10 +25,7 @@ export const KEY_DOC_TREE = 'doc-tree';
export function useDocTree(
params: DocsTreeParams,
queryConfig?: Omit<
UseQueryOptions<Doc, APIError, Doc>,
'queryKey' | 'queryFn'
>,
queryConfig?: UseQueryOptions<Doc, APIError, Doc>,
) {
return useQuery<Doc, APIError, Doc>({
queryKey: [KEY_DOC_TREE, params],

View File

@@ -4,17 +4,12 @@ import {
useTreeContext,
} from '@gouvfr-lasuite/ui-kit';
import { useRouter } from 'next/navigation';
import { useEffect, useRef, useState } from 'react';
import { useState } from 'react';
import { css } from 'styled-components';
import { Box, Icon, Text } from '@/components';
import { useCunninghamTheme } from '@/cunningham';
import {
Doc,
KEY_SUB_PAGE,
useDoc,
useTrans,
} from '@/features/docs/doc-management';
import { Doc, useTrans } from '@/features/docs/doc-management';
import { useLeftPanelStore } from '@/features/left-panel';
import { useResponsiveStore } from '@/stores';
@@ -31,8 +26,7 @@ const ItemTextCss = css`
-webkit-box-orient: vertical;
`;
type Props = TreeViewNodeProps<Doc>;
export const DocSubPageItem = (props: Props) => {
export const DocSubPageItem = (props: TreeViewNodeProps<Doc>) => {
const doc = props.node.data.value as Doc;
const treeContext = useTreeContext<Doc>();
const { untitledDocument } = useTrans();
@@ -44,28 +38,6 @@ export const DocSubPageItem = (props: Props) => {
const router = useRouter();
const { togglePanel } = useLeftPanelStore();
const isInitialLoad = useRef(false);
const { data: docQuery } = useDoc(
{ id: doc.id },
{
initialData: doc,
queryKey: [KEY_SUB_PAGE, { id: doc.id }],
refetchOnMount: false,
refetchOnWindowFocus: false,
},
);
useEffect(() => {
if (docQuery && isInitialLoad.current === true) {
treeContext?.treeData.updateNode(docQuery.id, docQuery);
}
if (docQuery) {
isInitialLoad.current = true;
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [docQuery]);
const afterCreate = (createdDoc: Doc) => {
const actualChildren = node.data.children ?? [];

View File

@@ -5,52 +5,46 @@ import {
useTreeContext,
} from '@gouvfr-lasuite/ui-kit';
import { useRouter } from 'next/navigation';
import { useEffect, useRef, useState } from 'react';
import { useCallback, useEffect, useState } from 'react';
import { css } from 'styled-components';
import { Box, StyledLink } from '@/components';
import { useCunninghamTheme } from '@/cunningham';
import { Doc, KEY_SUB_PAGE, useDoc, useDocStore } from '@/docs/doc-management';
import { Doc } from '@/docs/doc-management';
import { SimpleDocItem } from '@/docs/docs-grid';
import { useDocTree } from '../api/useDocTree';
import { KEY_DOC_TREE, useDocTree } from '../api/useDocTree';
import { useMoveDoc } from '../api/useMove';
import { findIndexInTree } from '../utils';
import { DocSubPageItem } from './DocSubPageItem';
import { DocTreeItemActions } from './DocTreeItemActions';
type DocTreeProps = {
initialTargetId: string;
currentDoc: Doc;
};
export const DocTree = ({ initialTargetId }: DocTreeProps) => {
export const DocTree = ({ currentDoc }: DocTreeProps) => {
const { spacingsTokens } = useCunninghamTheme();
const [rootActionsOpen, setRootActionsOpen] = useState(false);
const treeContext = useTreeContext<Doc>();
const { currentDoc } = useDocStore();
const treeContext = useTreeContext<Doc | null>();
const router = useRouter();
const previousDocId = useRef<string | null>(initialTargetId);
const { data: rootNode } = useDoc(
{ id: treeContext?.root?.id ?? '' },
{
enabled: !!treeContext?.root?.id,
initialData: treeContext?.root ?? undefined,
queryKey: [KEY_SUB_PAGE, { id: treeContext?.root?.id ?? '' }],
refetchOnMount: false,
refetchOnWindowFocus: false,
},
);
const [initialOpenState, setInitialOpenState] = useState<OpenMap | undefined>(
undefined,
);
const { mutate: moveDoc } = useMoveDoc();
const { data } = useDocTree({
docId: initialTargetId,
});
const { data: tree, isFetching } = useDocTree(
{
docId: currentDoc.id,
},
{
enabled: !!!treeContext?.root?.id,
queryKey: [KEY_DOC_TREE, { id: currentDoc.id }],
},
);
const handleMove = (result: TreeViewMoveResult) => {
moveDoc({
@@ -61,12 +55,55 @@ export const DocTree = ({ initialTargetId }: DocTreeProps) => {
treeContext?.treeData.handleMove(result);
};
useEffect(() => {
if (!data) {
/**
* This function resets the tree states.
*/
const resetStateTree = useCallback(() => {
if (!treeContext?.root?.id) {
return;
}
const { children: rootChildren, ...root } = data;
treeContext?.setRoot(null);
setInitialOpenState(undefined);
}, [treeContext]);
/**
* This effect is used to reset the tree when a new document
* that is not part of the current tree is loaded.
*/
useEffect(() => {
if (!treeContext?.root?.id) {
return;
}
const index = findIndexInTree(treeContext.treeData.nodes, currentDoc.id);
if (index === -1 && currentDoc.id !== treeContext.root?.id) {
resetStateTree();
return;
}
}, [currentDoc, resetStateTree, treeContext]);
/**
* This effect is used to reset the tree when the component is unmounted.
*/
useEffect(() => {
return () => {
resetStateTree();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
/**
* This effect is used to set the initial open state of the tree when the tree is loaded.
* If the treeContext is already set, we do not need to set it again.
*/
useEffect(() => {
if (!tree || treeContext?.root?.id || isFetching) {
return;
}
const { children: rootChildren, ...root } = tree;
const children = rootChildren ?? [];
treeContext?.setRoot(root);
const initialOpenState: OpenMap = {};
@@ -84,50 +121,30 @@ export const DocTree = ({ initialTargetId }: DocTreeProps) => {
treeContext?.treeData.resetTree(children);
setInitialOpenState(initialOpenState);
if (initialTargetId === root.id) {
treeContext?.treeData.setSelectedNode(root);
} else {
treeContext?.treeData.selectNodeById(initialTargetId);
}
// Because treeData change in the treeContext, we have a infinite loop
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [data, initialTargetId]);
}, [tree, treeContext, isFetching]);
/**
* This effect is used to select the current document in the tree
*/
useEffect(() => {
if (
!currentDoc ||
(previousDocId.current && previousDocId.current === currentDoc.id)
) {
if (!treeContext || !treeContext.root?.id) {
return;
}
const item = treeContext?.treeData.getNode(currentDoc?.id ?? '');
if (!item && currentDoc.id !== rootNode?.id) {
treeContext?.treeData.resetTree([]);
treeContext?.setRoot(currentDoc);
treeContext?.setInitialTargetId(currentDoc.id);
} else if (item) {
const { children: _children, ...leftDoc } = currentDoc;
treeContext?.treeData.updateNode(currentDoc.id, {
...leftDoc,
childrenCount: leftDoc.numchild,
});
}
if (currentDoc?.id && currentDoc?.id !== previousDocId.current) {
previousDocId.current = currentDoc?.id;
if (currentDoc.id === treeContext?.root?.id) {
treeContext?.treeData.setSelectedNode(treeContext?.root);
} else {
treeContext?.treeData.selectNodeById(currentDoc.id);
}
}, [currentDoc, treeContext]);
treeContext?.treeData.setSelectedNode(currentDoc);
}, [currentDoc, rootNode?.id, treeContext]);
const rootIsSelected =
treeContext?.treeData.selectedNode?.id === treeContext?.root?.id;
if (!initialTargetId || !treeContext) {
if (!treeContext || !treeContext.root) {
return null;
}
const rootIsSelected =
treeContext.treeData.selectedNode?.id === treeContext.root.id;
return (
<Box
data-testid="doc-tree"
@@ -178,42 +195,38 @@ export const DocTree = ({ initialTargetId }: DocTreeProps) => {
}
`}
>
{treeContext.root !== null && rootNode && (
<StyledLink
$css={css`
width: 100%;
`}
href={`/docs/${treeContext.root.id}`}
onClick={(e) => {
e.stopPropagation();
e.preventDefault();
treeContext.treeData.setSelectedNode(
treeContext.root ?? undefined,
);
router.push(`/docs/${treeContext?.root?.id}`);
}}
>
<Box $direction="row" $align="center" $width="100%">
<SimpleDocItem doc={rootNode} showAccesses={true} />
<div className="doc-tree-root-item-actions">
<DocTreeItemActions
doc={rootNode}
onCreateSuccess={(createdDoc) => {
const newDoc = {
...createdDoc,
children: [],
childrenCount: 0,
parentId: treeContext.root?.id ?? undefined,
};
treeContext?.treeData.addChild(null, newDoc);
}}
isOpen={rootActionsOpen}
onOpenChange={setRootActionsOpen}
/>
</div>
</Box>
</StyledLink>
)}
<StyledLink
$css={css`
width: 100%;
`}
href={`/docs/${treeContext.root.id}`}
onClick={(e) => {
e.stopPropagation();
e.preventDefault();
treeContext.treeData.setSelectedNode(
treeContext.root ?? undefined,
);
router.push(`/docs/${treeContext?.root?.id}`);
}}
>
<Box $direction="row" $align="center" $width="100%">
<SimpleDocItem doc={treeContext.root} showAccesses={true} />
<DocTreeItemActions
doc={treeContext.root}
onCreateSuccess={(createdDoc) => {
const newDoc = {
...createdDoc,
children: [],
childrenCount: 0,
parentId: treeContext.root?.id ?? undefined,
};
treeContext?.treeData.addChild(null, newDoc);
}}
isOpen={rootActionsOpen}
onOpenChange={setRootActionsOpen}
/>
</Box>
</StyledLink>
</Box>
</Box>
@@ -227,20 +240,17 @@ export const DocTree = ({ initialTargetId }: DocTreeProps) => {
undefined
}
canDrop={({ parentNode }) => {
if (!rootNode) {
return false;
}
const parentDoc = parentNode?.data.value as Doc;
if (!parentDoc) {
return rootNode?.abilities.move;
return currentDoc.abilities.move;
}
return parentDoc?.abilities.move;
return parentDoc.abilities.move;
}}
canDrag={(node) => {
const doc = node.value as Doc;
return doc.abilities.move;
}}
rootNodeId={treeContext.root?.id ?? ''}
rootNodeId={treeContext.root.id}
renderNode={DocSubPageItem}
/>
)}

View File

@@ -5,7 +5,6 @@ import {
} from '@gouvfr-lasuite/ui-kit';
import { useModal } from '@openfun/cunningham-react';
import { useRouter } from 'next/router';
import { Fragment } from 'react';
import { useTranslation } from 'react-i18next';
import { css } from 'styled-components';
@@ -25,9 +24,9 @@ import { useTreeUtils } from '../hooks';
type DocTreeItemActionsProps = {
doc: Doc;
isOpen?: boolean;
parentId?: string | null;
onCreateSuccess?: (newDoc: Doc) => void;
isOpen?: boolean;
onOpenChange?: (isOpen: boolean) => void;
};
@@ -45,10 +44,12 @@ export const DocTreeItemActions = ({
const copyLink = useCopyDocLink(doc.id);
const { isCurrentParent } = useTreeUtils(doc);
const { mutate: detachDoc } = useDetachDoc();
const treeContext = useTreeContext<Doc>();
const treeContext = useTreeContext<Doc | null>();
const { mutate: duplicateDoc } = useDuplicateDoc({
onSuccess: (data) => {
void router.push(`/docs/${data.id}`);
onSuccess: (duplicatedDoc) => {
// Reset the tree context root will reset the full tree view.
treeContext?.setRoot(null);
void router.push(`/docs/${duplicatedDoc.id}`);
},
});
@@ -61,10 +62,13 @@ export const DocTreeItemActions = ({
{ documentId: doc.id, rootId: treeContext.root.id },
{
onSuccess: () => {
treeContext.treeData.deleteNode(doc.id);
if (treeContext.root) {
treeContext.treeData.setSelectedNode(treeContext.root);
void router.push(`/docs/${treeContext.root.id}`);
void router.push(`/docs/${treeContext.root.id}`).then(() => {
setTimeout(() => {
treeContext?.treeData.deleteNode(doc.id);
}, 100);
});
}
},
},
@@ -124,18 +128,24 @@ export const DocTreeItemActions = ({
const afterDelete = () => {
if (parentId) {
treeContext?.treeData.deleteNode(doc.id);
void router.push(`/docs/${parentId}`);
void router.push(`/docs/${parentId}`).then(() => {
setTimeout(() => {
treeContext?.treeData.deleteNode(doc.id);
}, 100);
});
} else if (doc.id === treeContext?.root?.id && !parentId) {
void router.push(`/docs/`);
} else if (treeContext && treeContext.root) {
treeContext?.treeData.deleteNode(doc.id);
void router.push(`/docs/${treeContext.root.id}`);
void router.push(`/docs/${treeContext.root.id}`).then(() => {
setTimeout(() => {
treeContext?.treeData.deleteNode(doc.id);
}, 100);
});
}
};
return (
<Fragment>
<Box className="doc-tree-root-item-actions">
<Box
$direction="row"
$align="center"
@@ -187,6 +197,6 @@ export const DocTreeItemActions = ({
afterDelete={afterDelete}
/>
)}
</Fragment>
</Box>
);
};

View File

@@ -0,0 +1 @@
export * from './DocTree';

View File

@@ -1,3 +1,4 @@
export * from './api';
export * from './components';
export * from './hooks';
export * from './utils';

View File

@@ -1,4 +1,4 @@
import { TreeViewDataType } from '@gouvfr-lasuite/ui-kit';
import { TreeDataItem, TreeViewDataType } from '@gouvfr-lasuite/ui-kit';
import { Doc } from '../doc-management';
@@ -9,3 +9,24 @@ export const subPageToTree = (children: Doc[]): TreeViewDataType<Doc>[] => {
});
return children;
};
export const findIndexInTree = (
nodes: TreeDataItem<TreeViewDataType<Doc>>[],
key: string,
) => {
for (let i = 0; i < nodes.length; i++) {
if (nodes[i].key === key) {
return i;
}
if (nodes[i].children?.length ?? 0 > 0) {
const childIndex: number = nodes[i].children
? findIndexInTree(nodes[i].children ?? [], key)
: -1;
if (childIndex !== -1) {
return childIndex;
}
}
}
return -1;
};

View File

@@ -2,7 +2,7 @@ import { useTreeContext } from '@gouvfr-lasuite/ui-kit';
import { Box } from '@/components';
import { Doc, useDocStore } from '@/docs/doc-management';
import { DocTree } from '@/features/docs/doc-tree/components/DocTree';
import { DocTree } from '@/docs/doc-tree/';
export const LeftPanelDocContent = () => {
const { currentDoc } = useDocStore();
@@ -20,9 +20,7 @@ export const LeftPanelDocContent = () => {
$css="width: 100%; overflow-y: auto; overflow-x: hidden;"
className="--docs--left-panel-doc-content"
>
{tree.initialTargetId && (
<DocTree initialTargetId={tree.initialTargetId} />
)}
<DocTree currentDoc={currentDoc} />
</Box>
);
};