Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to
### Added

- ✨(frontend) create skeleton component for DocEditor #1491
- ✨(frontend) add an EmojiPicker in the document tree and title #1381

### Changed

Expand Down Expand Up @@ -99,6 +100,9 @@ and this project adheres to
### Added

- ✨(api) add API route to fetch document content #1206
- ✨(frontend) doc emojis improvements #1381
- add an EmojiPicker in the document tree and document title
- remove emoji buttons in menus

### Changed

Expand All @@ -112,6 +116,8 @@ and this project adheres to
- ✨unify tab focus style for better visual consistency #1341
- ♿hide decorative icons, label menus, avoid accessible name… #1362
- ♻️(tilt) use helm dev-backend chart
- 🩹(frontend) on main pages do not display leading emoji as page icon #1381
- 🩹(frontend) handle properly emojis in interlinking #1381

### Removed

Expand Down
54 changes: 36 additions & 18 deletions src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ import {
} from './utils-common';
import { getEditor, openSuggestionMenu, writeInEditor } from './utils-editor';
import { connectOtherUserToDoc, updateShareLink } from './utils-share';
import { createRootSubPage, navigateToPageFromTree } from './utils-sub-pages';
import {
createRootSubPage,
getTreeRow,
navigateToPageFromTree,
} from './utils-sub-pages';

test.beforeEach(async ({ page }) => {
await page.goto('/');
Expand Down Expand Up @@ -728,7 +732,13 @@ test.describe('Doc Editor', () => {

await verifyDocName(page, docChild2);

await page.locator('.bn-block-outer').last().fill('/');
const treeRow = await getTreeRow(page, docChild2);
await treeRow.locator('.--docs--doc-icon').click();
await page.getByRole('button', { name: '😀' }).first().click();

await navigateToPageFromTree({ page, title: docChild1 });

await openSuggestionMenu({ page });
await page.getByText('Link a doc').first().click();

const input = page.locator(
Expand All @@ -742,6 +752,16 @@ test.describe('Doc Editor', () => {
await expect(searchContainer.getByText(docChild1)).toBeVisible();
await expect(searchContainer.getByText(docChild2)).toBeVisible();

const searchContainerRow = searchContainer
.getByRole('option')
.filter({
hasText: docChild2,
})
.first();

await expect(searchContainerRow).toContainText('😀');
await expect(searchContainerRow.locator('svg').first()).toBeHidden();

await input.pressSequentially('-child');

await expect(searchContainer.getByText(docChild1)).toBeVisible();
Expand All @@ -756,32 +776,30 @@ test.describe('Doc Editor', () => {
await expect(searchContainer).toBeHidden();

// Wait for the interlink to be created and rendered
const editor = page.locator('.ProseMirror.bn-editor');
const editor = await getEditor({ page });

const interlink = editor.getByRole('button', {
const interlinkChild2 = editor.getByRole('button', {
name: docChild2,
});

await expect(interlink).toBeVisible({ timeout: 10000 });
await interlink.click();
await expect(interlinkChild2).toBeVisible({ timeout: 10000 });
await expect(interlinkChild2).toContainText('😀');
await expect(interlinkChild2.locator('svg').first()).toBeHidden();
await interlinkChild2.click();

await verifyDocName(page, docChild2);
});

test('it checks interlink shortcut @', async ({ page, browserName }) => {
const [randomDoc] = await createDoc(page, 'doc-interlink', browserName, 1);

await verifyDocName(page, randomDoc);

const editor = page.locator('.bn-block-outer').last();
await editor.click();

await page.keyboard.press('@');
await input.fill(docChild1);
await searchContainer.getByText(docChild1).click();

await expect(
page.locator(
"span[data-inline-content-type='interlinkingSearchInline'] input",
),
).toBeVisible();
const interlinkChild1 = editor.getByRole('button', {
name: docChild1,
});
await expect(interlinkChild1).toBeVisible({ timeout: 10000 });
await expect(interlinkChild1.locator('svg').first()).toBeVisible();
});

test('it checks multiple big doc scroll to the top', async ({
Expand Down
43 changes: 27 additions & 16 deletions src/frontend/apps/e2e/__tests__/app-impress/doc-header.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
verifyDocName,
} from './utils-common';
import { mockedAccesses, mockedInvitations } from './utils-share';
import { createRootSubPage } from './utils-sub-pages';
import { createRootSubPage, getTreeRow } from './utils-sub-pages';

test.beforeEach(async ({ page }) => {
await page.goto('/');
Expand Down Expand Up @@ -65,25 +65,36 @@ test.describe('Doc Header', () => {
page,
browserName,
}) => {
await createDoc(page, 'doc-update', browserName, 1);
await createDoc(page, 'doc-update-emoji', browserName, 1);

const emojiPicker = page.locator('.--docs--doc-title').getByRole('button');

// Top parent should not have emoji picker
await expect(emojiPicker).toBeHidden();

const { name: docChild } = await createRootSubPage(
page,
browserName,
'doc-update-emoji-child',
);

await verifyDocName(page, docChild);

await expect(emojiPicker).toBeVisible();
await emojiPicker.click({
delay: 100,
});
await page.getByRole('button', { name: '😀' }).first().click();
await expect(emojiPicker).toHaveText('😀');

const docTitle = page.getByRole('textbox', { name: 'Document title' });
await expect(docTitle).toBeVisible();
await docTitle.fill('👍 Hello Emoji World');
await docTitle.fill('Hello Emoji World');
await docTitle.blur();
await verifyDocName(page, '👍 Hello Emoji World');
await verifyDocName(page, 'Hello Emoji World');

// Check the tree
const docTree = page.getByTestId('doc-tree');
await expect(docTree.getByText('Hello Emoji World')).toBeVisible();
await expect(docTree.getByTestId('doc-emoji-icon')).toBeVisible();
await expect(docTree.getByTestId('doc-simple-icon')).toBeHidden();

await page.getByTestId('home-button').click();

// Check the documents grid
const gridRow = await getGridRow(page, 'Hello Emoji World');
await expect(gridRow.getByTestId('doc-emoji-icon')).toBeVisible();
await expect(gridRow.getByTestId('doc-simple-icon')).toBeHidden();
const row = await getTreeRow(page, 'Hello Emoji World');
await expect(row.getByText('😀')).toBeVisible();
});

test('it deletes the doc', async ({ page, browserName }) => {
Expand Down
58 changes: 57 additions & 1 deletion src/frontend/apps/e2e/__tests__/app-impress/doc-tree.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ import {
verifyDocName,
} from './utils-common';
import { addNewMember } from './utils-share';
import { clickOnAddRootSubPage, createRootSubPage } from './utils-sub-pages';
import {
clickOnAddRootSubPage,
createRootSubPage,
getTreeRow,
} from './utils-sub-pages';

test.describe('Doc Tree', () => {
test.beforeEach(async ({ page }) => {
Expand Down Expand Up @@ -298,6 +302,58 @@ test.describe('Doc Tree', () => {
// Now test keyboard navigation on sub-document
await expect(docTree.getByText(docChild)).toBeVisible();
});

test('it updates the child icon from the tree', async ({
page,
browserName,
}) => {
const [docParent] = await createDoc(
page,
'doc-child-emoji',
browserName,
1,
);
await verifyDocName(page, docParent);

const { name: docChild } = await createRootSubPage(
page,
browserName,
'doc-child-emoji-child',
);

const row = await getTreeRow(page, docChild);

// Check Remove emoji is not present initially
await row.hover();
const menu = row.getByText(`more_horiz`);
await menu.click();
await expect(
page.getByRole('menuitem', { name: 'Remove emoji' }),
).toBeHidden();

// Close the menu
await page.keyboard.press('Escape');

// Update the emoji from the tree
await row.locator('.--docs--doc-icon').click();
await page.getByRole('button', { name: '😀' }).first().click();

// Verify the emoji is updated in the tree and in the document title
await expect(row.getByText('😀')).toBeVisible();

const titleEmojiPicker = page
.locator('.--docs--doc-title')
.getByRole('button');
await expect(titleEmojiPicker).toHaveText('😀');

// Now remove the emoji using the new action
await row.hover();
await menu.click();
await page.getByRole('menuitem', { name: 'Remove emoji' }).click();

await expect(row.getByText('😀')).toBeHidden();
await expect(titleEmojiPicker).not.toHaveText('😀');
});
});

test.describe('Doc Tree: Inheritance', () => {
Expand Down
14 changes: 14 additions & 0 deletions src/frontend/apps/e2e/__tests__/app-impress/utils-sub-pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,20 @@ export const addChild = async ({
return name;
};

export const getTreeRow = async (page: Page, title: string) => {
const docTree = page.getByTestId('doc-tree');
const row = docTree
.getByRole('treeitem')
.filter({
hasText: title,
})
.first();

await expect(row).toBeVisible();

return row;
};

export const navigateToTopParentFromTree = async ({ page }: { page: Page }) => {
await page.getByRole('link', { name: /Open root document/ }).click();
};
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,18 @@ interface EmojiPickerProps {
emojiData: EmojiMartData;
onClickOutside: () => void;
onEmojiSelect: ({ native }: { native: string }) => void;
withOverlay?: boolean;
}

export const EmojiPicker = ({
emojiData,
onClickOutside,
onEmojiSelect,
withOverlay = false,
}: EmojiPickerProps) => {
const { i18n } = useTranslation();

return (
const pickerContent = (
<Box $position="absolute" $zIndex={1000} $margin="2rem 0 0 0">
<Picker
data={emojiData}
Expand All @@ -30,4 +32,27 @@ export const EmojiPicker = ({
/>
</Box>
);

if (withOverlay) {
return (
<>
{/* Overlay transparent pour fermer en cliquant à l'extérieur */}
<div
style={{
position: 'fixed',
top: 0,
left: 0,
width: '100vw',
height: '100vh',
zIndex: 999,
backgroundColor: 'transparent',
}}
onClick={onClickOutside}
/>
{pickerContent}
</>
);
}

return pickerContent;
};
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ const CalloutComponent = ({
emojiData={emojidata}
onClickOutside={onClickOutside}
onEmojiSelect={onEmojiSelect}
withOverlay={true}
/>
)}
<Box as="p" className="inline-content" ref={contentRef} />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './AccessibleImageBlock';
export * from './CalloutBlock';
export { default as emojidata } from './initEmojiCallout';
export * from './PdfBlock';
export * from './UploadLoaderBlock';
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { css } from 'styled-components';
import { BoxButton, Text } from '@/components';
import { useCunninghamTheme } from '@/cunningham';
import SelectedPageIcon from '@/docs/doc-editor/assets/doc-selected.svg';
import { useDoc } from '@/docs/doc-management';
import { getEmojiAndTitle, useDoc } from '@/docs/doc-management';

export const InterlinkingLinkInlineContent = createReactInlineContentSpec(
{
Expand Down Expand Up @@ -52,6 +52,8 @@ interface LinkSelectedProps {
}
const LinkSelected = ({ url, title }: LinkSelectedProps) => {
const { colorsTokens } = useCunninghamTheme();

const { emoji, titleWithoutEmoji } = getEmojiAndTitle(title);
const router = useRouter();

const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
Expand All @@ -78,9 +80,21 @@ const LinkSelected = ({ url, title }: LinkSelectedProps) => {
transition: background-color 0.2s ease-in-out;
`}
>
<SelectedPageIcon width={11.5} color={colorsTokens['primary-400']} />
<Text $weight="500" spellCheck="false" $size="16px" $display="inline">
{title}
{emoji ? (
<Text $size="16px">{emoji}</Text>
) : (
<SelectedPageIcon width={11.5} color={colorsTokens['primary-400']} />
)}
<Text
$weight="500"
spellCheck="false"
$size="16px"
$display="inline"
$css={css`
margin-left: 2px;
`}
>
{titleWithoutEmoji}
</Text>
</BoxButton>
);
Expand Down
Loading
Loading