🛂(frontend) button request access only on parent

The children reflect the parent access. So we can
request access only on the parent document.
This commit is contained in:
Anthony LC
2025-07-08 12:43:14 +02:00
parent 95838e332c
commit 7abe1c9eb4
6 changed files with 153 additions and 18 deletions

View File

@@ -7,6 +7,7 @@ import {
randomName,
verifyDocName,
} from './common';
import { createRootSubPage } from './sub-pages-utils';
test.describe('Document create member', () => {
test.beforeEach(async ({ page }) => {
@@ -272,7 +273,9 @@ test.describe('Document create member: Multiple login', () => {
await expect(
page.getByRole('link', { name: 'Docs Logo Docs' }),
).toBeVisible();
).toBeVisible({
timeout: 10000,
});
await page.goto(urlDoc);
@@ -294,4 +297,61 @@ test.describe('Document create member: Multiple login', () => {
await expect(page.getByText('Share with 2 users')).toBeVisible();
await expect(page.getByText(`E2E ${otherBrowser}`)).toBeVisible();
});
test('It cannot request member access on child doc on a 403 page', async ({
page,
browserName,
}) => {
test.slow();
await page.goto('/');
await keyCloakSignIn(page, browserName);
const [docParent] = await createDoc(
page,
'Block Member access request on child doc - parent',
browserName,
1,
);
await verifyDocName(page, docParent);
await createRootSubPage(
page,
browserName,
'Block Member access request on child doc - child',
);
const urlDoc = page.url();
await page
.getByRole('button', {
name: 'Logout',
})
.click();
const otherBrowser = BROWSERS.find((b) => b !== browserName);
await keyCloakSignIn(page, otherBrowser!);
await expect(
page.getByRole('link', { name: 'Docs Logo Docs' }),
).toBeVisible({
timeout: 10000,
});
await page.goto(urlDoc);
await expect(
page.getByText(
"You're currently viewing a sub-document. To gain access, please request permission from the main document.",
),
).toBeVisible({
timeout: 10000,
});
await expect(
page.getByRole('button', { name: 'Request access' }),
).toBeHidden();
});
});

View File

@@ -7,6 +7,7 @@ import {
keyCloakSignIn,
verifyDocName,
} from './common';
import { createRootSubPage } from './sub-pages-utils';
test.describe('Doc Visibility', () => {
test.beforeEach(async ({ page }) => {
@@ -271,7 +272,7 @@ test.describe('Doc Visibility: Public', () => {
await page.getByRole('button', { name: 'Share' }).click();
await expect(
page.getByText(
'You do not have permission to view users sharing this document or modify link settings.',
'You can view this document but need additional access to see its members or modify settings.',
),
).toBeVisible();
@@ -398,6 +399,8 @@ test.describe('Doc Visibility: Authenticated', () => {
page,
browserName,
}) => {
test.slow();
await page.goto('/');
await keyCloakSignIn(page, browserName);
@@ -435,6 +438,14 @@ test.describe('Doc Visibility: Authenticated', () => {
const urlDoc = page.url();
const { name: childTitle } = await createRootSubPage(
page,
browserName,
'Authenticated read onlyc - child',
);
const urlChildDoc = page.url();
await page
.getByRole('button', {
name: 'Logout',
@@ -446,7 +457,9 @@ test.describe('Doc Visibility: Authenticated', () => {
await expect(
page.getByRole('link', { name: 'Docs Logo Docs' }),
).toBeVisible();
).toBeVisible({
timeout: 10000,
});
await page.goto(urlDoc);
@@ -457,7 +470,7 @@ test.describe('Doc Visibility: Authenticated', () => {
await expect(
page.getByText(
'You do not have permission to view users sharing this document or modify link settings.',
'You can view this document but need additional access to see its members or modify settings.',
),
).toBeVisible();
@@ -466,6 +479,22 @@ test.describe('Doc Visibility: Authenticated', () => {
await expect(
page.getByRole('button', { name: 'Request access' }),
).toBeDisabled();
await page.goto(urlChildDoc);
await expect(page.locator('h2').getByText(childTitle)).toBeVisible();
await page.getByRole('button', { name: 'Share' }).click();
await expect(
page.getByText(
'As this is a sub-document, please request access to the parent document to enable these features.',
),
).toBeVisible();
await expect(
page.getByRole('button', { name: 'Request access' }),
).toBeHidden();
});
test('It checks a authenticated doc in editable mode', async ({

View File

@@ -1,7 +1,7 @@
import { Loader } from '@openfun/cunningham-react';
import { useTranslation } from 'react-i18next';
import { Box } from './Box';
import { Box, BoxProps } from './Box';
import { Icon } from './Icon';
import { Text } from './Text';
@@ -36,8 +36,8 @@ export const LoadMoreText = ({
);
};
export const Loading = () => (
<Box $align="center" $justify="center" $height="100%">
export const Loading = (props: BoxProps) => (
<Box $align="center" $justify="center" $height="100%" {...props}>
<Loader />
</Box>
);

View File

@@ -8,7 +8,14 @@ import { useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { createGlobalStyle } from 'styled-components';
import { Box, BoxButton, Icon, LoadMoreText } from '@/components';
import {
Box,
BoxButton,
Icon,
LoadMoreText,
Loading,
Text,
} from '@/components';
import { QuickSearchData, QuickSearchGroup } from '@/components/quick-search';
import { useCunninghamTheme } from '@/cunningham';
import { AccessRequest, Doc } from '@/docs/doc-management/';
@@ -161,7 +168,11 @@ export const ButtonAccessRequest = ({
...buttonProps
}: ButtonAccessRequestProps) => {
const { authenticated } = useAuth();
const { data: requests } = useDocAccessRequests({
const {
data: requests,
error: docAccessError,
isLoading,
} = useDocAccessRequests({
docId,
page: 1,
});
@@ -175,14 +186,28 @@ export const ButtonAccessRequest = ({
},
});
const hasRequested = !!(
requests && requests?.results.find((request) => request.document === docId)
);
if (!authenticated) {
return null;
}
if (docAccessError?.status === 404) {
return (
<Text $maxWidth="320px" $textAlign="center" $variation="600" $size="sm">
{t(
'As this is a sub-document, please request access to the parent document to enable these features.',
)}
</Text>
);
}
if (isLoading) {
return <Loading $height="auto" />;
}
const hasRequested = !!(
requests && requests?.results.find((request) => request.document === docId)
);
return (
<Button
onClick={() => createRequest({ docId })}

View File

@@ -179,7 +179,7 @@ export const DocShareModal = ({ doc, onClose, isRootDoc = true }: Props) => {
$size="sm"
>
{t(
'You do not have permission to view users sharing this document or modify link settings.',
'You can view this document but need additional access to see its members or modify settings.',
)}
</Text>
<ButtonAccessRequest

View File

@@ -46,7 +46,11 @@ interface DocProps {
const DocPage403 = ({ id }: DocProps) => {
const { t } = useTranslation();
const { data: requests, isLoading: isLoadingRequest } = useDocAccessRequests({
const {
data: requests,
isLoading: isLoadingRequest,
error: docAccessError,
} = useDocAccessRequests({
docId: id,
page: 1,
});
@@ -56,7 +60,7 @@ const DocPage403 = ({ id }: DocProps) => {
(request) => request.document === id,
);
const { error, isLoading: isLoadingDoc } = useDoc(
const { error: docError, isLoading: isLoadingDoc } = useDoc(
{ id },
{
staleTime: 0,
@@ -71,7 +75,7 @@ const DocPage403 = ({ id }: DocProps) => {
},
);
if (!isLoadingDoc && error?.status !== 403) {
if (!isLoadingDoc && docError?.status !== 403) {
void replace(`/docs/${id}`);
return <Loading />;
}
@@ -115,6 +119,21 @@ const DocPage403 = ({ id }: DocProps) => {
: t('Insufficient access rights to view the document.')}
</Text>
{docAccessError?.status === 404 && (
<Text
as="p"
$maxWidth="320px"
$textAlign="center"
$variation="600"
$size="sm"
$margin={{ top: '0' }}
>
{t(
"You're currently viewing a sub-document. To gain access, please request permission from the main document.",
)}
</Text>
)}
<Box $direction="row" $gap="0.7rem">
<StyledLink href="/">
<StyledButton
@@ -124,7 +143,9 @@ const DocPage403 = ({ id }: DocProps) => {
{t('Home')}
</StyledButton>
</StyledLink>
<ButtonAccessRequest docId={id} />
{docAccessError?.status !== 404 && (
<ButtonAccessRequest docId={id} />
)}
</Box>
</Box>
</Box>