diff --git a/CHANGELOG.md b/CHANGELOG.md
index b7ce8322..a2dc2524 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,7 @@ and this project adheres to
### Changed
+- ♻️(frontend) search on all docs if no children #1184
- ♻️(frontend) redirect to doc after duplicate #1175
- 🔧(project) change env.d system by using local files #1200
- ⚡️(frontend) improve tree stability #1207
diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-search.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-search.spec.ts
index 1d55a07f..c8c09942 100644
--- a/src/frontend/apps/e2e/__tests__/app-impress/doc-search.spec.ts
+++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-search.spec.ts
@@ -1,6 +1,7 @@
import { expect, test } from '@playwright/test';
import { createDoc, randomName, verifyDocName } from './utils-common';
+import { createRootSubPage } from './utils-sub-pages';
test.beforeEach(async ({ page }) => {
await page.goto('/');
@@ -98,39 +99,46 @@ test.describe('Document search', () => {
).toBeHidden();
});
- test("it checks we don't see filters in search modal", async ({ page }) => {
- const searchButton = page
- .getByTestId('left-panel-desktop')
- .getByRole('button', { name: 'search' });
-
- await expect(searchButton).toBeVisible();
- await page.getByRole('button', { name: 'search', exact: true }).click();
- await expect(
- page.getByRole('combobox', { name: 'Quick search input' }),
- ).toBeVisible();
- await expect(page.getByTestId('doc-search-filters')).toBeHidden();
- });
-});
-
-test.describe('Sub page search', () => {
test('it check the presence of filters in search modal', async ({
page,
browserName,
}) => {
- await page.goto('/');
- const [doc1Title] = await createDoc(
- page,
- 'My sub page search',
- browserName,
- 1,
- );
- await verifyDocName(page, doc1Title);
+ // Doc grid filters are not visible
const searchButton = page
.getByTestId('left-panel-desktop')
- .getByRole('button', { name: 'search' });
- await searchButton.click();
+ .getByRole('button', { name: 'search', exact: true });
+
const filters = page.getByTestId('doc-search-filters');
+
+ await searchButton.click();
+ await expect(
+ page.getByRole('combobox', { name: 'Quick search input' }),
+ ).toBeVisible();
+ await expect(filters).toBeHidden();
+
+ await page.getByRole('button', { name: 'close' }).click();
+
+ // Create a doc without children for the moment
+ // and check that filters are not visible
+ const [doc1Title] = await createDoc(page, 'My page search', browserName, 1);
+ await verifyDocName(page, doc1Title);
+
+ await searchButton.click();
+ await expect(
+ page.getByRole('combobox', { name: 'Quick search input' }),
+ ).toBeVisible();
+ await expect(filters).toBeHidden();
+
+ await page.getByRole('button', { name: 'close' }).click();
+
+ // Create a sub page
+ // and check that filters are visible
+ await createRootSubPage(page, browserName, 'My sub page search');
+
+ await searchButton.click();
+
await expect(filters).toBeVisible();
+
await filters.click();
await filters.getByRole('button', { name: 'Current doc' }).click();
await expect(
@@ -139,43 +147,70 @@ test.describe('Sub page search', () => {
await expect(
page.getByRole('menuitem', { name: 'Current doc' }),
).toBeVisible();
- await page.getByRole('menuitem', { name: 'Current doc' }).click();
+ await page.getByRole('menuitem', { name: 'All docs' }).click();
await expect(page.getByRole('button', { name: 'Reset' })).toBeVisible();
});
test('it searches sub pages', async ({ page, browserName }) => {
- await page.goto('/');
-
- const [doc1Title] = await createDoc(
+ // First doc
+ const [firstDocTitle] = await createDoc(
page,
- 'My sub page search',
+ 'My first sub page search',
browserName,
1,
);
- await verifyDocName(page, doc1Title);
+ await verifyDocName(page, firstDocTitle);
+
+ // Create a new doc - for the moment without children
await page.getByRole('button', { name: 'New doc' }).click();
await verifyDocName(page, '');
await page.getByRole('textbox', { name: 'doc title input' }).click();
await page
.getByRole('textbox', { name: 'doc title input' })
.press('ControlOrMeta+a');
- const [randomDocName] = randomName('doc-sub-page', browserName, 1);
+ const [secondDocTitle] = randomName(
+ 'My second sub page search',
+ browserName,
+ 1,
+ );
await page
.getByRole('textbox', { name: 'doc title input' })
- .fill(randomDocName);
+ .fill(secondDocTitle);
+
const searchButton = page
.getByTestId('left-panel-desktop')
.getByRole('button', { name: 'search' });
await searchButton.click();
- await expect(
- page.getByRole('button', { name: 'Current doc' }),
- ).toBeVisible();
await page.getByRole('combobox', { name: 'Quick search input' }).click();
await page
.getByRole('combobox', { name: 'Quick search input' })
- .fill('sub');
- await expect(page.getByLabel(randomDocName)).toBeVisible();
+ .fill('sub page search');
+
+ // Expect to find the first doc
+ await expect(
+ page.getByRole('presentation').getByLabel(firstDocTitle),
+ ).toBeVisible();
+ await expect(
+ page.getByRole('presentation').getByLabel(secondDocTitle),
+ ).toBeVisible();
+
+ await page.getByRole('button', { name: 'close' }).click();
+
+ // Create a sub page
+ await createRootSubPage(page, browserName, secondDocTitle);
+ await searchButton.click();
+ await page
+ .getByRole('combobox', { name: 'Quick search input' })
+ .fill('sub page search');
+
+ // Now there is a sub page - expect to have the focus on the current doc
+ await expect(
+ page.getByRole('presentation').getByLabel(secondDocTitle),
+ ).toBeVisible();
+ await expect(
+ page.getByRole('presentation').getByLabel(firstDocTitle),
+ ).toBeHidden();
});
});
diff --git a/src/frontend/apps/impress/src/features/docs/doc-management/hooks/index.ts b/src/frontend/apps/impress/src/features/docs/doc-management/hooks/index.ts
index 96968e38..adf2d777 100644
--- a/src/frontend/apps/impress/src/features/docs/doc-management/hooks/index.ts
+++ b/src/frontend/apps/impress/src/features/docs/doc-management/hooks/index.ts
@@ -1,4 +1,5 @@
export * from './useCollaboration';
export * from './useCopyDocLink';
+export * from './useDocUtils';
export * from './useIsCollaborativeEditable';
export * from './useTrans';
diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/hooks/useTreeUtils.tsx b/src/frontend/apps/impress/src/features/docs/doc-management/hooks/useDocUtils.tsx
similarity index 80%
rename from src/frontend/apps/impress/src/features/docs/doc-tree/hooks/useTreeUtils.tsx
rename to src/frontend/apps/impress/src/features/docs/doc-management/hooks/useDocUtils.tsx
index 34f4d02c..3e954d9b 100644
--- a/src/frontend/apps/impress/src/features/docs/doc-tree/hooks/useTreeUtils.tsx
+++ b/src/frontend/apps/impress/src/features/docs/doc-management/hooks/useDocUtils.tsx
@@ -1,9 +1,10 @@
import { Doc } from '@/docs/doc-management';
-export const useTreeUtils = (doc: Doc) => {
+export const useDocUtils = (doc: Doc) => {
return {
isTopRoot: doc.depth === 1,
isChild: doc.depth > 1,
+ hasChildren: doc.numchild > 0,
isDesynchronized: !!(
doc.ancestors_link_reach &&
(doc.computed_link_reach !== doc.ancestors_link_reach ||
diff --git a/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchModal.tsx b/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchModal.tsx
index c8f1dbd1..b0137082 100644
--- a/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchModal.tsx
+++ b/src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchModal.tsx
@@ -7,9 +7,9 @@ import { useDebouncedCallback } from 'use-debounce';
import { Box } from '@/components';
import { QuickSearch } from '@/components/quick-search';
+import { Doc, useDocUtils } from '@/docs/doc-management';
import { useResponsiveStore } from '@/stores';
-import { Doc } from '../../doc-management';
import EmptySearchIcon from '../assets/illustration-docs-empty.png';
import { DocSearchContent } from './DocSearchContent';
@@ -20,18 +20,18 @@ import {
} from './DocSearchFilters';
import { DocSearchSubPageContent } from './DocSearchSubPageContent';
-type DocSearchModalProps = {
+type DocSearchModalGlobalProps = {
onClose: () => void;
isOpen: boolean;
showFilters?: boolean;
defaultFilters?: DocSearchFiltersValues;
};
-export const DocSearchModal = ({
+const DocSearchModalGlobal = ({
showFilters = false,
defaultFilters,
...modalProps
-}: DocSearchModalProps) => {
+}: DocSearchModalGlobalProps) => {
const { t } = useTranslation();
const [loading, setLoading] = useState(false);
@@ -126,3 +126,42 @@ export const DocSearchModal = ({
);
};
+
+type DocSearchModalDetailProps = DocSearchModalGlobalProps & {
+ doc: Doc;
+};
+
+const DocSearchModalDetail = ({
+ doc,
+ ...modalProps
+}: DocSearchModalDetailProps) => {
+ const { hasChildren, isChild } = useDocUtils(doc);
+ const isWithChildren = isChild || hasChildren;
+
+ let defaultFilters = DocSearchTarget.ALL;
+ let showFilters = false;
+ if (isWithChildren) {
+ defaultFilters = DocSearchTarget.CURRENT;
+ showFilters = true;
+ }
+
+ return (
+
+ );
+};
+
+type DocSearchModalProps = DocSearchModalGlobalProps & {
+ doc?: Doc;
+};
+
+export const DocSearchModal = ({ doc, ...modalProps }: DocSearchModalProps) => {
+ if (doc) {
+ return ;
+ }
+
+ return ;
+};
diff --git a/src/frontend/apps/impress/src/features/docs/doc-share/components/DocVisibility.tsx b/src/frontend/apps/impress/src/features/docs/doc-share/components/DocVisibility.tsx
index 3ed24b14..36e97c2e 100644
--- a/src/frontend/apps/impress/src/features/docs/doc-share/components/DocVisibility.tsx
+++ b/src/frontend/apps/impress/src/features/docs/doc-share/components/DocVisibility.tsx
@@ -17,9 +17,9 @@ import {
LinkReach,
LinkRole,
getDocLinkReach,
+ useDocUtils,
useUpdateDocLink,
} from '@/docs/doc-management';
-import { useTreeUtils } from '@/docs/doc-tree';
import { useResponsiveStore } from '@/stores';
import { useTranslatedShareSettings } from '../hooks/';
@@ -37,7 +37,7 @@ export const DocVisibility = ({ doc }: DocVisibilityProps) => {
const canManage = doc.abilities.accesses_manage;
const docLinkReach = getDocLinkReach(doc);
const docLinkRole = doc.computed_link_role ?? LinkRole.READER;
- const { isDesynchronized } = useTreeUtils(doc);
+ const { isDesynchronized } = useDocUtils(doc);
const { linkModeTranslations, linkReachChoices, linkReachTranslations } =
useTranslatedShareSettings();
diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/hooks/index.ts b/src/frontend/apps/impress/src/features/docs/doc-tree/hooks/index.ts
deleted file mode 100644
index 3fb57a34..00000000
--- a/src/frontend/apps/impress/src/features/docs/doc-tree/hooks/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './useTreeUtils';
diff --git a/src/frontend/apps/impress/src/features/docs/doc-tree/index.ts b/src/frontend/apps/impress/src/features/docs/doc-tree/index.ts
index ec8b4043..527c58f0 100644
--- a/src/frontend/apps/impress/src/features/docs/doc-tree/index.ts
+++ b/src/frontend/apps/impress/src/features/docs/doc-tree/index.ts
@@ -1,4 +1,3 @@
export * from './api';
export * from './components';
-export * from './hooks';
export * from './utils';
diff --git a/src/frontend/apps/impress/src/features/left-panel/components/LeftPanelHeader.tsx b/src/frontend/apps/impress/src/features/left-panel/components/LeftPanelHeader.tsx
index 5733b0df..d3621e06 100644
--- a/src/frontend/apps/impress/src/features/left-panel/components/LeftPanelHeader.tsx
+++ b/src/frontend/apps/impress/src/features/left-panel/components/LeftPanelHeader.tsx
@@ -3,7 +3,8 @@ import { useRouter } from 'next/router';
import { PropsWithChildren, useCallback, useState } from 'react';
import { Box, Icon, SeparatedSection } from '@/components';
-import { DocSearchModal, DocSearchTarget } from '@/docs/doc-search/';
+import { useDocStore } from '@/docs/doc-management';
+import { DocSearchModal } from '@/docs/doc-search/';
import { useAuth } from '@/features/auth';
import { useCmdK } from '@/hook/useCmdK';
@@ -12,10 +13,9 @@ import { useLeftPanelStore } from '../stores';
import { LeftPanelHeaderButton } from './LeftPanelHeaderButton';
export const LeftPanelHeader = ({ children }: PropsWithChildren) => {
+ const { currentDoc } = useDocStore();
const router = useRouter();
const { authenticated } = useAuth();
- const isDoc = router.pathname === '/docs/[id]';
-
const [isSearchModalOpen, setIsSearchModalOpen] = useState(false);
const openSearchModal = useCallback(() => {
@@ -81,10 +81,7 @@ export const LeftPanelHeader = ({ children }: PropsWithChildren) => {
)}
>