mirror of
https://github.com/suitenumerique/docs.git
synced 2026-09-27 03:55:01 +02:00
🚩(frontend) add Analytics feature flag on Duplicate with Children
We want to have a fine grained control over the Duplicate with Children feature. By adding the feature flag for Duplicate with Children, we can enable or disable this feature for specific users or groups without deploying new code. This allows us to test the feature in a controlled environment and gather feedback before a full rollout.
This commit is contained in:
@@ -8,6 +8,7 @@ and this project adheres to
|
||||
|
||||
### Added
|
||||
|
||||
- 🚩(setting) add feature flag on Duplicate with Children #2721
|
||||
- 💄(frontend) redesign 404 error standalone page #2696
|
||||
- 💄(frontend) redesign 403 access denied page #2720
|
||||
- ✨(frontend) duplicate with subdocuments #2584
|
||||
|
||||
+8
-1
@@ -39,6 +39,7 @@ import SharedIcon from '@/icons/shared.svg';
|
||||
import StarSlashIcon from '@/icons/star-slash.svg';
|
||||
import StarIcon from '@/icons/star.svg';
|
||||
import DeleteIcon from '@/icons/trash.svg';
|
||||
import { useAnalytics } from '@/libs/Analytics';
|
||||
import { useFocusStore, useResponsiveStore } from '@/stores';
|
||||
import { isMacOS } from '@/utils/userAgent';
|
||||
|
||||
@@ -52,6 +53,8 @@ import {
|
||||
import { useCopyDocLink, useTrans } from '../hooks';
|
||||
import { Doc, Role } from '../types';
|
||||
|
||||
const DUPLICATE_WITH_CHILDREN_FEATURE_FLAG = 'duplicate_with_children';
|
||||
|
||||
const ConfirmationDuplicateModal = dynamic(
|
||||
() =>
|
||||
import('@/docs/doc-management/components/ConfirmationDuplicateModal').then(
|
||||
@@ -154,6 +157,10 @@ const DocToolBoxComponent = ({
|
||||
const [isModalLeaveOpen, setIsModalLeaveOpen] = useState(false);
|
||||
const [isModalMoveOpen, setIsModalMoveOpen] = useState(false);
|
||||
const { onClick: onButtonClick, ...buttonPropsLeft } = buttonProps || {};
|
||||
const { isFeatureFlagActivated } = useAnalytics();
|
||||
const duplicateWithChildrenAllowed = !!(
|
||||
isFeatureFlagActivated(DUPLICATE_WITH_CHILDREN_FEATURE_FLAG) && doc.numchild
|
||||
);
|
||||
|
||||
const editor = useEditorStore((state) => state.editor);
|
||||
const wordCountLabel = useMemo(() => {
|
||||
@@ -301,7 +308,7 @@ const DocToolBoxComponent = ({
|
||||
icon: <ContentCopyIcon width={18} height={18} aria-hidden="true" />,
|
||||
isDisabled: !doc.abilities.duplicate,
|
||||
callback: () => {
|
||||
if (doc.numchild) {
|
||||
if (duplicateWithChildrenAllowed) {
|
||||
setIsModalDuplicateOpen(true);
|
||||
} else {
|
||||
duplicateDoc({
|
||||
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
import { describe, expect, test, vi } from 'vitest';
|
||||
|
||||
import { AppWrapper } from '@/tests/utils';
|
||||
|
||||
import { Doc, LinkReach, Role } from '../../types';
|
||||
import { DocToolBox } from '../DocToolBox';
|
||||
|
||||
vi.mock('next/router', () => ({
|
||||
useRouter: () => ({
|
||||
push: vi.fn(),
|
||||
pathname: '/',
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock('@/features/auth', () => ({
|
||||
useAuth: () => ({ authenticated: true }),
|
||||
}));
|
||||
|
||||
const isFeatureFlagActivatedMock = vi.fn();
|
||||
vi.mock('@/libs/Analytics', () => ({
|
||||
useAnalytics: () => ({
|
||||
isFeatureFlagActivated: isFeatureFlagActivatedMock,
|
||||
trackEvent: vi.fn(),
|
||||
}),
|
||||
}));
|
||||
|
||||
const duplicateDocMock = vi.fn();
|
||||
vi.mock('@/docs/doc-management/components/ConfirmationDuplicateModal', () => ({
|
||||
useDuplicatedDoc: () => ({
|
||||
mutate: duplicateDocMock,
|
||||
isPending: false,
|
||||
}),
|
||||
ConfirmationDuplicateModal: () => (
|
||||
<div data-testid="confirmation-duplicate-modal" />
|
||||
),
|
||||
}));
|
||||
|
||||
const createDoc = (overrides: Partial<Doc> = {}): Doc => ({
|
||||
id: 'doc-id',
|
||||
title: 'My document',
|
||||
created_at: '',
|
||||
creator: '',
|
||||
deleted_at: null,
|
||||
depth: 1,
|
||||
path: '0001',
|
||||
is_favorite: false,
|
||||
link_reach: LinkReach.RESTRICTED,
|
||||
computed_link_reach: LinkReach.RESTRICTED,
|
||||
ancestors_link_reach: LinkReach.RESTRICTED,
|
||||
nb_accesses_direct: 0,
|
||||
nb_accesses_ancestors: 0,
|
||||
numchild: 0,
|
||||
updated_at: '',
|
||||
user_role: Role.OWNER,
|
||||
abilities: {
|
||||
accesses_manage: false,
|
||||
accesses_view: false,
|
||||
ai_proxy: false,
|
||||
ai_transform: false,
|
||||
ai_translate: false,
|
||||
attachment_upload: false,
|
||||
children_create: false,
|
||||
children_list: false,
|
||||
collaboration_auth: false,
|
||||
comment: false,
|
||||
content_patch: false,
|
||||
content_retrieve: false,
|
||||
destroy: false,
|
||||
duplicate: true,
|
||||
favorite: false,
|
||||
formatted_content: false,
|
||||
invite_owner: false,
|
||||
leave: false,
|
||||
link_configuration: false,
|
||||
link_select_options: {},
|
||||
media_auth: false,
|
||||
move: false,
|
||||
partial_update: true,
|
||||
restore: false,
|
||||
retrieve: false,
|
||||
search: false,
|
||||
update: false,
|
||||
versions_list: false,
|
||||
},
|
||||
...overrides,
|
||||
});
|
||||
|
||||
const openDuplicateOption = async () => {
|
||||
const trigger = screen.getByRole('button', {
|
||||
name: /Open the document options/i,
|
||||
});
|
||||
await userEvent.click(trigger);
|
||||
|
||||
const duplicateOption = await screen.findByRole('menuitem', {
|
||||
name: 'Duplicate',
|
||||
});
|
||||
await userEvent.click(duplicateOption);
|
||||
};
|
||||
|
||||
describe('<DocToolBox /> - duplicate with children', () => {
|
||||
test('opens the confirmation modal when the feature flag is active and the doc has children', async () => {
|
||||
isFeatureFlagActivatedMock.mockReturnValue(true);
|
||||
const doc = createDoc({ numchild: 3 });
|
||||
|
||||
render(<DocToolBox doc={doc} isCurrentDoc />, { wrapper: AppWrapper });
|
||||
|
||||
await openDuplicateOption();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.getByTestId('confirmation-duplicate-modal'),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
expect(duplicateDocMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('duplicates directly when the feature flag is inactive, even if the doc has children', async () => {
|
||||
isFeatureFlagActivatedMock.mockReturnValue(false);
|
||||
const doc = createDoc({ numchild: 3 });
|
||||
|
||||
render(<DocToolBox doc={doc} isCurrentDoc />, { wrapper: AppWrapper });
|
||||
|
||||
await openDuplicateOption();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(duplicateDocMock).toHaveBeenCalledWith({
|
||||
docId: doc.id,
|
||||
canSave: doc.abilities.partial_update,
|
||||
});
|
||||
});
|
||||
expect(
|
||||
screen.queryByTestId('confirmation-duplicate-modal'),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('duplicates directly when the feature flag is active but the doc has no children', async () => {
|
||||
isFeatureFlagActivatedMock.mockReturnValue(true);
|
||||
const doc = createDoc({ numchild: 0 });
|
||||
|
||||
render(<DocToolBox doc={doc} isCurrentDoc />, { wrapper: AppWrapper });
|
||||
|
||||
await openDuplicateOption();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(duplicateDocMock).toHaveBeenCalledWith({
|
||||
docId: doc.id,
|
||||
canSave: doc.abilities.partial_update,
|
||||
});
|
||||
});
|
||||
expect(
|
||||
screen.queryByTestId('confirmation-duplicate-modal'),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user