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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to
### Added

- ✨(backend) allow masking documents from the list view #1171
- ✨(frontend) subdocs can manage link reach #1190
- ✨(frontend) add duplicate action to doc tree #1175

### Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,7 @@ test.describe('Inherited share accesses', () => {

await verifyDocName(page, parentTitle);
});
});

test.describe('Inherited share link', () => {
test('it checks if the link is inherited', async ({ page, browserName }) => {
await page.goto('/');
// Create root doc
Expand All @@ -47,12 +45,50 @@ test.describe('Inherited share link', () => {
// Create sub page
await createRootSubPage(page, browserName, 'sub-page');

// // verify share link is restricted and reader
// Verify share link is like the parent document
await page.getByRole('button', { name: 'Share' }).click();
// await expect(page.getByText('Inherited share')).toBeVisible();
const docVisibilityCard = page.getByLabel('Doc visibility card');
await expect(docVisibilityCard).toBeVisible();

await expect(docVisibilityCard.getByText('Connected')).toBeVisible();
await expect(docVisibilityCard.getByText('Reading')).toBeVisible();

// Verify inherited link
await docVisibilityCard.getByText('Connected').click();
await expect(
page.getByRole('menuitem', { name: 'Private' }),
).toBeDisabled();

// Update child link
await page.getByRole('menuitem', { name: 'Public' }).click();

await docVisibilityCard.getByText('Reading').click();
await page.getByRole('menuitem', { name: 'Editing' }).click();

await expect(docVisibilityCard.getByText('Connected')).toBeHidden();
await expect(docVisibilityCard.getByText('Reading')).toBeHidden();
await expect(
docVisibilityCard.getByText('Public', {
exact: true,
}),
).toBeVisible();
await expect(docVisibilityCard.getByText('Editing')).toBeVisible();
await expect(
docVisibilityCard.getByText(
'The link sharing rules differ from the parent document',
),
).toBeVisible();

// Restore inherited link
await page.getByRole('button', { name: 'Restore' }).click();

await expect(docVisibilityCard.getByText('Connected')).toBeVisible();
await expect(docVisibilityCard.getByText('Reading')).toBeVisible();
await expect(docVisibilityCard.getByText('Public')).toBeHidden();
await expect(docVisibilityCard.getByText('Editing')).toBeHidden();
await expect(
docVisibilityCard.getByText(
'The link sharing rules differ from the parent document',
),
).toBeHidden();
});
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { VariantType, useToastProvider } from '@openfun/cunningham-react';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useTranslation } from 'react-i18next';

import { APIError, errorCauses, fetchAPI } from '@/api';
import { Doc, KEY_DOC } from '@/docs/doc-management';
Expand Down Expand Up @@ -39,6 +41,8 @@ export function useUpdateDocLink({
}: UpdateDocLinkProps = {}) {
const queryClient = useQueryClient();
const { broadcast } = useBroadcastStore();
const { toast } = useToastProvider();
const { t } = useTranslation();

return useMutation<Doc, APIError, UpdateDocLinkParams>({
mutationFn: updateDocLink,
Expand All @@ -52,6 +56,14 @@ export function useUpdateDocLink({
// Broadcast to every user connected to the document
broadcast(`${KEY_DOC}-${variable.id}`);

toast(
t('The document visibility has been updated.'),
VariantType.SUCCESS,
{
duration: 2000,
},
);

onSuccess?.(data);
},
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { Button } from '@openfun/cunningham-react';
import { useTranslation } from 'react-i18next';
import { css } from 'styled-components';

import { Box, Text } from '@/components';
import { useCunninghamTheme } from '@/cunningham';
import {
Doc,
KEY_DOC,
KEY_LIST_DOC,
useUpdateDocLink,
} from '@/docs/doc-management';

import Desync from './../assets/desynchro.svg';
import Undo from './../assets/undo.svg';

interface DocDesynchronizedProps {
doc: Doc;
}

export const DocDesynchronized = ({ doc }: DocDesynchronizedProps) => {
const { t } = useTranslation();
const { spacingsTokens, colorsTokens } = useCunninghamTheme();

const { mutate: updateDocLink } = useUpdateDocLink({
listInvalideQueries: [KEY_LIST_DOC, KEY_DOC],
});

return (
<Box
$background={colorsTokens['primary-100']}
$padding="3xs"
$direction="row"
$align="center"
$justify="space-between"
$gap={spacingsTokens['4xs']}
$color={colorsTokens['primary-800']}
$css={css`
border: 1px solid ${colorsTokens['primary-300']};
border-radius: ${spacingsTokens['2xs']};
`}
>
<Box $direction="row" $align="center" $gap={spacingsTokens['3xs']}>
<Desync />
<Text $size="xs" $theme="primary" $variation="800" $weight="400">
{t('The link sharing rules differ from the parent document')}
</Text>
</Box>
{doc.abilities.accesses_manage && (
<Button
onClick={() =>
updateDocLink({
id: doc.id,
link_reach: doc.ancestors_link_reach,
link_role: doc?.ancestors_link_role || undefined,
})
}
size="small"
color="primary-text"
icon={<Undo />}
>
{t('Restore')}
</Button>
)}
</Box>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,18 @@ export const DocShareModal = ({ doc, onClose, isRootDoc = true }: Props) => {

const { isDesktop } = useResponsiveStore();

/**
* The modal content height is calculated based on the viewport height.
* The formula is:
* 100dvh - 2em - 12px - 34px
* - 34px is the height of the modal title in mobile
* - 2em is the padding of the modal content
* - 12px is the padding of the modal footer
* - 690px is the height of the content in desktop
* This ensures that the modal content is always visible and does not overflow.
*/
const modalContentHeight = isDesktop
? 'min(690px, calc(100dvh - 2em - 12px - 34px))' // 100dvh - 2em - 12px is the max cunningham modal height. 690px is the height of the content in desktop ad 34px is the height of the modal title in mobile
? 'min(690px, calc(100dvh - 2em - 12px - 34px))'
: `calc(100dvh - 34px)`;
const [selectedUsers, setSelectedUsers] = useState<User[]>([]);
const [userQuery, setUserQuery] = useState('');
Expand Down Expand Up @@ -230,13 +240,7 @@ export const DocShareModal = ({ doc, onClose, isRootDoc = true }: Props) => {
</Box>

<Box ref={handleRef}>
{showFooter && (
<DocShareModalFooter
doc={doc}
onClose={onClose}
canEditVisibility={canShare}
/>
)}
{showFooter && <DocShareModalFooter doc={doc} onClose={onClose} />}
</Box>
</Box>
</Modal>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,15 @@ import { Doc, useCopyDocLink } from '@/docs/doc-management';

import { DocVisibility } from './DocVisibility';

type Props = {
type DocShareModalFooterProps = {
doc: Doc;
onClose: () => void;
canEditVisibility?: boolean;
};

export const DocShareModalFooter = ({
doc,
onClose,
canEditVisibility = true,
}: Props) => {
}: DocShareModalFooterProps) => {
const copyDocLink = useCopyDocLink(doc.id);
const { t } = useTranslation();
return (
Expand All @@ -29,7 +27,7 @@ export const DocShareModalFooter = ({
>
<HorizontalSeparator $withPadding={true} customPadding="12px" />

<DocVisibility doc={doc} canEdit={canEditVisibility} />
<DocVisibility doc={doc} />
<HorizontalSeparator customPadding="12px" />

<Box
Expand Down
Loading
Loading