diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e5c21bb..7f191fc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to - ✨(frontend) Can print a doc #1832 - ✨(backend) manage reconciliation requests for user accounts #1878 - 👷(CI) add GHCR workflow for forked repo testing #1851 +- ✨(frontend) Move doc modal #1886 - ⚡️(backend) remove content from Document serializer when asked #1910 - ✨(backend) allow the duplication of subpages #1893 - ✨(backend) Onboarding docs for new users #1891 diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-grid-dnd.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-grid-move.spec.ts similarity index 83% rename from src/frontend/apps/e2e/__tests__/app-impress/doc-grid-dnd.spec.ts rename to src/frontend/apps/e2e/__tests__/app-impress/doc-grid-move.spec.ts index 17cfa815..ba61f4f6 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-grid-dnd.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-grid-move.spec.ts @@ -1,10 +1,19 @@ import { expect, test } from '@playwright/test'; -import { createDoc, mockedListDocs, toggleHeaderMenu } from './utils-common'; +import { + createDoc, + getGridRow, + mockedListDocs, + toggleHeaderMenu, + verifyDocName, +} from './utils-common'; import { createRootSubPage } from './utils-sub-pages'; -test.describe('Doc grid dnd', () => { - test('it creates a doc', async ({ page, browserName }) => { +test.describe('Doc grid move', () => { + test('it checks drag and drop functionality', async ({ + page, + browserName, + }) => { await page.goto('/'); const header = page.locator('header').first(); await createDoc(page, 'Draggable doc', browserName, 1); @@ -29,7 +38,7 @@ test.describe('Doc grid dnd', () => { await expect(draggableElement).toBeVisible(); await expect(dropZone).toBeVisible(); - // Obtenir les positions des éléments + // Get the position of the elements const draggableBoundingBox = await draggableElement.boundingBox(); const dropZoneBoundingBox = await dropZone.boundingBox(); @@ -46,7 +55,7 @@ test.describe('Doc grid dnd', () => { ); await page.mouse.down(); - // Déplacer vers la zone cible + // Move to the target zone await page.mouse.move( dropZoneBoundingBox.x + dropZoneBoundingBox.width / 2, dropZoneBoundingBox.y + dropZoneBoundingBox.height / 2, @@ -161,6 +170,55 @@ test.describe('Doc grid dnd', () => { await page.mouse.up(); }); + + test('it moves a doc from the doc search modal', async ({ + page, + browserName, + }) => { + await page.goto('/'); + + const [titleDoc1] = await createDoc(page, 'Draggable doc', browserName, 1); + await page.getByRole('button', { name: 'Back to homepage' }).click(); + + const [titleDoc2] = await createDoc(page, 'Droppable doc', browserName, 1); + await page.getByRole('button', { name: 'Back to homepage' }).click(); + + const docsGrid = page.getByTestId('docs-grid'); + await expect(docsGrid.getByText(titleDoc1)).toBeVisible(); + await expect(docsGrid.getByText(titleDoc2)).toBeVisible(); + + const row = await getGridRow(page, titleDoc1); + await row.getByText(`more_horiz`).click(); + + await page.getByRole('menuitem', { name: 'Move into a doc' }).click(); + + await expect( + page.getByRole('dialog').getByRole('heading', { name: 'Move' }), + ).toBeVisible(); + + const input = page.getByRole('combobox', { name: 'Quick search input' }); + await input.click(); + await input.fill(titleDoc2); + + await expect(page.getByRole('option').getByText(titleDoc2)).toBeVisible(); + + // Select the first result + await page.keyboard.press('Enter'); + // The CTA should get the focus + await page.keyboard.press('Tab'); + // Validate the move action + await page.keyboard.press('Enter'); + + await expect(docsGrid.getByText(titleDoc1)).toBeHidden(); + await docsGrid + .getByRole('link', { name: `Open document ${titleDoc2}` }) + .click(); + + await verifyDocName(page, titleDoc2); + + const docTree = page.getByTestId('doc-tree'); + await expect(docTree.getByText(titleDoc1)).toBeVisible(); + }); }); test.describe('Doc grid dnd mobile', () => { diff --git a/src/frontend/apps/impress/src/components/quick-search/QuickSearch.tsx b/src/frontend/apps/impress/src/components/quick-search/QuickSearch.tsx index 16cbb826..441e3e44 100644 --- a/src/frontend/apps/impress/src/components/quick-search/QuickSearch.tsx +++ b/src/frontend/apps/impress/src/components/quick-search/QuickSearch.tsx @@ -15,6 +15,7 @@ export type QuickSearchAction = { export type QuickSearchData = { groupName: string; + groupKey?: string; elements: T[]; emptyString?: string; startActions?: QuickSearchAction[]; @@ -30,13 +31,13 @@ export type QuickSearchProps = { loading?: boolean; label?: string; placeholder?: string; + groupKey?: string; }; export const QuickSearch = ({ onFilter, inputContent, inputValue, - loading, showInput = true, label, placeholder, @@ -72,10 +73,10 @@ export const QuickSearch = ({ tabIndex={-1} value={selectedValue} onValueChange={handleValueChange} + disablePointerSelection > {showInput && ( ({ {group.startActions?.map((action, index) => { return ( {action.content} @@ -38,8 +38,8 @@ export const QuickSearchGroup = ({ {group.elements.map((groupElement, index) => { return ( { onSelect?.(groupElement); }} @@ -51,7 +51,7 @@ export const QuickSearchGroup = ({ {group.endActions?.map((action, index) => { return ( {action.content} diff --git a/src/frontend/apps/impress/src/components/quick-search/QuickSearchInput.tsx b/src/frontend/apps/impress/src/components/quick-search/QuickSearchInput.tsx index e1fcdcf0..803ab4c4 100644 --- a/src/frontend/apps/impress/src/components/quick-search/QuickSearchInput.tsx +++ b/src/frontend/apps/impress/src/components/quick-search/QuickSearchInput.tsx @@ -1,6 +1,5 @@ -import { Loader } from '@gouvfr-lasuite/cunningham-react'; import { Command } from 'cmdk'; -import { ReactNode } from 'react'; +import { PropsWithChildren } from 'react'; import { useTranslation } from 'react-i18next'; import { HorizontalSeparator } from '@/components'; @@ -9,19 +8,16 @@ import { useCunninghamTheme } from '@/cunningham'; import { Box } from '../Box'; import { Icon } from '../Icon'; -type Props = { - loading?: boolean; +type QuickSearchInputProps = { inputValue?: string; onFilter?: (str: string) => void; placeholder?: string; - children?: ReactNode; withSeparator?: boolean; listId?: string; onUserInteract?: () => void; isExpanded?: boolean; }; export const QuickSearchInput = ({ - loading, inputValue, onFilter, placeholder, @@ -30,7 +26,7 @@ export const QuickSearchInput = ({ listId, onUserInteract, isExpanded, -}: Props) => { +}: PropsWithChildren) => { const { t } = useTranslation(); const { spacingsTokens } = useCunninghamTheme(); @@ -52,14 +48,7 @@ export const QuickSearchInput = ({ $gap={spacingsTokens['2xs']} $padding={{ horizontal: 'base', vertical: 'sm' }} > - {!loading && ( -