Skip to content

Commit 1ae831c

Browse files
committed
♻️(frontend) search on all docs if no children
When searching for documents, if no children are found, the search will now include all documents instead of just those with children.
1 parent f1c2219 commit 1ae831c

File tree

9 files changed

+123
-51
lines changed

9 files changed

+123
-51
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ and this project adheres to
1616

1717
### Changed
1818

19+
- ♻️(frontend) search on all docs if no children #1184
1920
- ♻️(frontend) redirect to doc after duplicate #1175
2021
- 🔧(project) change env.d system by using local files #1200
2122
- ⚡️(frontend) improve tree stability #1207

src/frontend/apps/e2e/__tests__/app-impress/doc-search.spec.ts

Lines changed: 70 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { expect, test } from '@playwright/test';
22

33
import { createDoc, randomName, verifyDocName } from './utils-common';
4+
import { createRootSubPage } from './utils-sub-pages';
45

56
test.beforeEach(async ({ page }) => {
67
await page.goto('/');
@@ -98,39 +99,46 @@ test.describe('Document search', () => {
9899
).toBeHidden();
99100
});
100101

101-
test("it checks we don't see filters in search modal", async ({ page }) => {
102+
test('it check the presence of filters in search modal', async ({
103+
page,
104+
browserName,
105+
}) => {
106+
// Doc grid filters are not visible
102107
const searchButton = page
103108
.getByTestId('left-panel-desktop')
104-
.getByRole('button', { name: 'search' });
109+
.getByRole('button', { name: 'search', exact: true });
110+
111+
const filters = page.getByTestId('doc-search-filters');
105112

106-
await expect(searchButton).toBeVisible();
107-
await page.getByRole('button', { name: 'search', exact: true }).click();
113+
await searchButton.click();
108114
await expect(
109115
page.getByRole('combobox', { name: 'Quick search input' }),
110116
).toBeVisible();
111-
await expect(page.getByTestId('doc-search-filters')).toBeHidden();
112-
});
113-
});
117+
await expect(filters).toBeHidden();
114118

115-
test.describe('Sub page search', () => {
116-
test('it check the presence of filters in search modal', async ({
117-
page,
118-
browserName,
119-
}) => {
120-
await page.goto('/');
121-
const [doc1Title] = await createDoc(
122-
page,
123-
'My sub page search',
124-
browserName,
125-
1,
126-
);
119+
await page.getByRole('button', { name: 'close' }).click();
120+
121+
// Create a doc without children for the moment
122+
// and check that filters are not visible
123+
const [doc1Title] = await createDoc(page, 'My page search', browserName, 1);
127124
await verifyDocName(page, doc1Title);
128-
const searchButton = page
129-
.getByTestId('left-panel-desktop')
130-
.getByRole('button', { name: 'search' });
125+
131126
await searchButton.click();
132-
const filters = page.getByTestId('doc-search-filters');
127+
await expect(
128+
page.getByRole('combobox', { name: 'Quick search input' }),
129+
).toBeVisible();
130+
await expect(filters).toBeHidden();
131+
132+
await page.getByRole('button', { name: 'close' }).click();
133+
134+
// Create a sub page
135+
// and check that filters are visible
136+
await createRootSubPage(page, browserName, 'My sub page search');
137+
138+
await searchButton.click();
139+
133140
await expect(filters).toBeVisible();
141+
134142
await filters.click();
135143
await filters.getByRole('button', { name: 'Current doc' }).click();
136144
await expect(
@@ -139,43 +147,70 @@ test.describe('Sub page search', () => {
139147
await expect(
140148
page.getByRole('menuitem', { name: 'Current doc' }),
141149
).toBeVisible();
142-
await page.getByRole('menuitem', { name: 'Current doc' }).click();
150+
await page.getByRole('menuitem', { name: 'All docs' }).click();
143151

144152
await expect(page.getByRole('button', { name: 'Reset' })).toBeVisible();
145153
});
146154

147155
test('it searches sub pages', async ({ page, browserName }) => {
148-
await page.goto('/');
149-
150-
const [doc1Title] = await createDoc(
156+
// First doc
157+
const [firstDocTitle] = await createDoc(
151158
page,
152-
'My sub page search',
159+
'My first sub page search',
153160
browserName,
154161
1,
155162
);
156-
await verifyDocName(page, doc1Title);
163+
await verifyDocName(page, firstDocTitle);
164+
165+
// Create a new doc - for the moment without children
157166
await page.getByRole('button', { name: 'New doc' }).click();
158167
await verifyDocName(page, '');
159168
await page.getByRole('textbox', { name: 'doc title input' }).click();
160169
await page
161170
.getByRole('textbox', { name: 'doc title input' })
162171
.press('ControlOrMeta+a');
163-
const [randomDocName] = randomName('doc-sub-page', browserName, 1);
172+
const [secondDocTitle] = randomName(
173+
'My second sub page search',
174+
browserName,
175+
1,
176+
);
164177
await page
165178
.getByRole('textbox', { name: 'doc title input' })
166-
.fill(randomDocName);
179+
.fill(secondDocTitle);
180+
167181
const searchButton = page
168182
.getByTestId('left-panel-desktop')
169183
.getByRole('button', { name: 'search' });
170184

171185
await searchButton.click();
186+
await page.getByRole('combobox', { name: 'Quick search input' }).click();
187+
await page
188+
.getByRole('combobox', { name: 'Quick search input' })
189+
.fill('sub page search');
190+
191+
// Expect to find the first doc
172192
await expect(
173-
page.getByRole('button', { name: 'Current doc' }),
193+
page.getByRole('presentation').getByLabel(firstDocTitle),
174194
).toBeVisible();
175-
await page.getByRole('combobox', { name: 'Quick search input' }).click();
195+
await expect(
196+
page.getByRole('presentation').getByLabel(secondDocTitle),
197+
).toBeVisible();
198+
199+
await page.getByRole('button', { name: 'close' }).click();
200+
201+
// Create a sub page
202+
await createRootSubPage(page, browserName, secondDocTitle);
203+
await searchButton.click();
176204
await page
177205
.getByRole('combobox', { name: 'Quick search input' })
178-
.fill('sub');
179-
await expect(page.getByLabel(randomDocName)).toBeVisible();
206+
.fill('sub page search');
207+
208+
// Now there is a sub page - expect to have the focus on the current doc
209+
await expect(
210+
page.getByRole('presentation').getByLabel(secondDocTitle),
211+
).toBeVisible();
212+
await expect(
213+
page.getByRole('presentation').getByLabel(firstDocTitle),
214+
).toBeHidden();
180215
});
181216
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from './useCollaboration';
22
export * from './useCopyDocLink';
3+
export * from './useDocUtils';
34
export * from './useIsCollaborativeEditable';
45
export * from './useTrans';

src/frontend/apps/impress/src/features/docs/doc-tree/hooks/useTreeUtils.tsx renamed to src/frontend/apps/impress/src/features/docs/doc-management/hooks/useDocUtils.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { Doc } from '@/docs/doc-management';
22

3-
export const useTreeUtils = (doc: Doc) => {
3+
export const useDocUtils = (doc: Doc) => {
44
return {
55
isTopRoot: doc.depth === 1,
66
isChild: doc.depth > 1,
7+
hasChildren: doc.numchild > 0,
78
isDesynchronized: !!(
89
doc.ancestors_link_reach &&
910
(doc.computed_link_reach !== doc.ancestors_link_reach ||

src/frontend/apps/impress/src/features/docs/doc-search/components/DocSearchModal.tsx

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ import { useDebouncedCallback } from 'use-debounce';
77

88
import { Box } from '@/components';
99
import { QuickSearch } from '@/components/quick-search';
10+
import { Doc, useDocUtils } from '@/docs/doc-management';
1011
import { useResponsiveStore } from '@/stores';
1112

12-
import { Doc } from '../../doc-management';
1313
import EmptySearchIcon from '../assets/illustration-docs-empty.png';
1414

1515
import { DocSearchContent } from './DocSearchContent';
@@ -20,18 +20,18 @@ import {
2020
} from './DocSearchFilters';
2121
import { DocSearchSubPageContent } from './DocSearchSubPageContent';
2222

23-
type DocSearchModalProps = {
23+
type DocSearchModalGlobalProps = {
2424
onClose: () => void;
2525
isOpen: boolean;
2626
showFilters?: boolean;
2727
defaultFilters?: DocSearchFiltersValues;
2828
};
2929

30-
export const DocSearchModal = ({
30+
const DocSearchModalGlobal = ({
3131
showFilters = false,
3232
defaultFilters,
3333
...modalProps
34-
}: DocSearchModalProps) => {
34+
}: DocSearchModalGlobalProps) => {
3535
const { t } = useTranslation();
3636
const [loading, setLoading] = useState(false);
3737

@@ -126,3 +126,42 @@ export const DocSearchModal = ({
126126
</Modal>
127127
);
128128
};
129+
130+
type DocSearchModalDetailProps = DocSearchModalGlobalProps & {
131+
doc: Doc;
132+
};
133+
134+
const DocSearchModalDetail = ({
135+
doc,
136+
...modalProps
137+
}: DocSearchModalDetailProps) => {
138+
const { hasChildren, isChild } = useDocUtils(doc);
139+
const isWithChildren = isChild || hasChildren;
140+
141+
let defaultFilters = DocSearchTarget.ALL;
142+
let showFilters = false;
143+
if (isWithChildren) {
144+
defaultFilters = DocSearchTarget.CURRENT;
145+
showFilters = true;
146+
}
147+
148+
return (
149+
<DocSearchModalGlobal
150+
{...modalProps}
151+
showFilters={showFilters}
152+
defaultFilters={{ target: defaultFilters }}
153+
/>
154+
);
155+
};
156+
157+
type DocSearchModalProps = DocSearchModalGlobalProps & {
158+
doc?: Doc;
159+
};
160+
161+
export const DocSearchModal = ({ doc, ...modalProps }: DocSearchModalProps) => {
162+
if (doc) {
163+
return <DocSearchModalDetail doc={doc} {...modalProps} />;
164+
}
165+
166+
return <DocSearchModalGlobal {...modalProps} />;
167+
};

src/frontend/apps/impress/src/features/docs/doc-share/components/DocVisibility.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ import {
1717
LinkReach,
1818
LinkRole,
1919
getDocLinkReach,
20+
useDocUtils,
2021
useUpdateDocLink,
2122
} from '@/docs/doc-management';
22-
import { useTreeUtils } from '@/docs/doc-tree';
2323
import { useResponsiveStore } from '@/stores';
2424

2525
import { useTranslatedShareSettings } from '../hooks/';
@@ -37,7 +37,7 @@ export const DocVisibility = ({ doc }: DocVisibilityProps) => {
3737
const canManage = doc.abilities.accesses_manage;
3838
const docLinkReach = getDocLinkReach(doc);
3939
const docLinkRole = doc.computed_link_role ?? LinkRole.READER;
40-
const { isDesynchronized } = useTreeUtils(doc);
40+
const { isDesynchronized } = useDocUtils(doc);
4141
const { linkModeTranslations, linkReachChoices, linkReachTranslations } =
4242
useTranslatedShareSettings();
4343

src/frontend/apps/impress/src/features/docs/doc-tree/hooks/index.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
export * from './api';
22
export * from './components';
3-
export * from './hooks';
43
export * from './utils';

src/frontend/apps/impress/src/features/left-panel/components/LeftPanelHeader.tsx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import { useRouter } from 'next/router';
33
import { PropsWithChildren, useCallback, useState } from 'react';
44

55
import { Box, Icon, SeparatedSection } from '@/components';
6-
import { DocSearchModal, DocSearchTarget } from '@/docs/doc-search/';
6+
import { useDocStore } from '@/docs/doc-management';
7+
import { DocSearchModal } from '@/docs/doc-search/';
78
import { useAuth } from '@/features/auth';
89
import { useCmdK } from '@/hook/useCmdK';
910

@@ -12,10 +13,9 @@ import { useLeftPanelStore } from '../stores';
1213
import { LeftPanelHeaderButton } from './LeftPanelHeaderButton';
1314

1415
export const LeftPanelHeader = ({ children }: PropsWithChildren) => {
16+
const { currentDoc } = useDocStore();
1517
const router = useRouter();
1618
const { authenticated } = useAuth();
17-
const isDoc = router.pathname === '/docs/[id]';
18-
1919
const [isSearchModalOpen, setIsSearchModalOpen] = useState(false);
2020

2121
const openSearchModal = useCallback(() => {
@@ -81,10 +81,7 @@ export const LeftPanelHeader = ({ children }: PropsWithChildren) => {
8181
<DocSearchModal
8282
onClose={closeSearchModal}
8383
isOpen={isSearchModalOpen}
84-
showFilters={isDoc}
85-
defaultFilters={{
86-
target: isDoc ? DocSearchTarget.CURRENT : undefined,
87-
}}
84+
doc={currentDoc}
8885
/>
8986
)}
9087
</>

0 commit comments

Comments
 (0)