mirror of
https://github.com/suitenumerique/docs.git
synced 2026-04-26 01:25:05 +02:00
Compare commits
2 Commits
fix/link-p
...
feat/leave
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e4e557173 | ||
|
|
11dfc9ff03 |
@@ -15,6 +15,7 @@ and this project adheres to
|
||||
- ✨(frontend) subdocs can manage link reach #1190
|
||||
- ✨(frontend) add duplicate action to doc tree #1175
|
||||
- ✨(frontend) add multi columns support for editor #1219
|
||||
- ✨(frontend) Can mask a document from the list view #1233
|
||||
|
||||
### Changed
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ class ListDocumentSerializer(serializers.ModelSerializer):
|
||||
"""Serialize documents with limited fields for display in lists."""
|
||||
|
||||
is_favorite = serializers.BooleanField(read_only=True)
|
||||
is_masked = serializers.BooleanField(read_only=True)
|
||||
nb_accesses_ancestors = serializers.IntegerField(read_only=True)
|
||||
nb_accesses_direct = serializers.IntegerField(read_only=True)
|
||||
user_role = serializers.SerializerMethodField(read_only=True)
|
||||
@@ -85,6 +86,7 @@ class ListDocumentSerializer(serializers.ModelSerializer):
|
||||
"depth",
|
||||
"excerpt",
|
||||
"is_favorite",
|
||||
"is_masked",
|
||||
"link_role",
|
||||
"link_reach",
|
||||
"nb_accesses_ancestors",
|
||||
@@ -107,6 +109,7 @@ class ListDocumentSerializer(serializers.ModelSerializer):
|
||||
"depth",
|
||||
"excerpt",
|
||||
"is_favorite",
|
||||
"is_masked",
|
||||
"link_role",
|
||||
"link_reach",
|
||||
"nb_accesses_ancestors",
|
||||
@@ -176,6 +179,7 @@ class DocumentSerializer(ListDocumentSerializer):
|
||||
"depth",
|
||||
"excerpt",
|
||||
"is_favorite",
|
||||
"is_masked",
|
||||
"link_role",
|
||||
"link_reach",
|
||||
"nb_accesses_ancestors",
|
||||
|
||||
@@ -405,6 +405,7 @@ class DocumentViewSet(
|
||||
queryset = super().filter_queryset(queryset)
|
||||
user = self.request.user
|
||||
queryset = queryset.annotate_is_favorite(user)
|
||||
queryset = queryset.annotate_is_masked(user)
|
||||
queryset = queryset.annotate_user_roles(user)
|
||||
return queryset
|
||||
|
||||
@@ -453,8 +454,9 @@ class DocumentViewSet(
|
||||
)
|
||||
queryset = queryset.filter(path__in=root_paths)
|
||||
|
||||
# Annotate favorite status and filter if applicable as late as possible
|
||||
# Annotate favorite and masked status and filter if applicable as late as possible
|
||||
queryset = queryset.annotate_is_favorite(user)
|
||||
queryset = queryset.annotate_is_masked(user)
|
||||
for field in ["is_favorite", "is_masked"]:
|
||||
queryset = filterset.filters[field].filter(queryset, filter_data[field])
|
||||
|
||||
|
||||
@@ -326,6 +326,18 @@ class DocumentQuerySet(MP_NodeQuerySet):
|
||||
|
||||
return self.annotate(is_favorite=models.Value(False))
|
||||
|
||||
def annotate_is_masked(self, user):
|
||||
"""
|
||||
Annotate document queryset with the masked status for the current user.
|
||||
"""
|
||||
if user.is_authenticated:
|
||||
masked_exists_subquery = LinkTrace.objects.filter(
|
||||
document_id=models.OuterRef("pk"), user=user, is_masked=True
|
||||
)
|
||||
return self.annotate(is_masked=models.Exists(masked_exists_subquery))
|
||||
|
||||
return self.annotate(is_masked=models.Value(False))
|
||||
|
||||
def annotate_user_roles(self, user):
|
||||
"""
|
||||
Annotate document queryset with the roles of the current user
|
||||
|
||||
@@ -45,6 +45,7 @@ def test_api_documents_children_list_anonymous_public_standalone(
|
||||
"excerpt": child1.excerpt,
|
||||
"id": str(child1.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": child1.link_reach,
|
||||
"link_role": child1.link_role,
|
||||
"numchild": 0,
|
||||
@@ -67,6 +68,7 @@ def test_api_documents_children_list_anonymous_public_standalone(
|
||||
"excerpt": child2.excerpt,
|
||||
"id": str(child2.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": child2.link_reach,
|
||||
"link_role": child2.link_role,
|
||||
"numchild": 0,
|
||||
@@ -119,6 +121,7 @@ def test_api_documents_children_list_anonymous_public_parent(django_assert_num_q
|
||||
"excerpt": child1.excerpt,
|
||||
"id": str(child1.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": child1.link_reach,
|
||||
"link_role": child1.link_role,
|
||||
"numchild": 0,
|
||||
@@ -141,6 +144,7 @@ def test_api_documents_children_list_anonymous_public_parent(django_assert_num_q
|
||||
"excerpt": child2.excerpt,
|
||||
"id": str(child2.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": child2.link_reach,
|
||||
"link_role": child2.link_role,
|
||||
"numchild": 0,
|
||||
@@ -212,6 +216,7 @@ def test_api_documents_children_list_authenticated_unrelated_public_or_authentic
|
||||
"excerpt": child1.excerpt,
|
||||
"id": str(child1.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": child1.link_reach,
|
||||
"link_role": child1.link_role,
|
||||
"numchild": 0,
|
||||
@@ -234,6 +239,7 @@ def test_api_documents_children_list_authenticated_unrelated_public_or_authentic
|
||||
"excerpt": child2.excerpt,
|
||||
"id": str(child2.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": child2.link_reach,
|
||||
"link_role": child2.link_role,
|
||||
"numchild": 0,
|
||||
@@ -291,6 +297,7 @@ def test_api_documents_children_list_authenticated_public_or_authenticated_paren
|
||||
"excerpt": child1.excerpt,
|
||||
"id": str(child1.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": child1.link_reach,
|
||||
"link_role": child1.link_role,
|
||||
"numchild": 0,
|
||||
@@ -313,6 +320,7 @@ def test_api_documents_children_list_authenticated_public_or_authenticated_paren
|
||||
"excerpt": child2.excerpt,
|
||||
"id": str(child2.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": child2.link_reach,
|
||||
"link_role": child2.link_role,
|
||||
"numchild": 0,
|
||||
@@ -397,6 +405,7 @@ def test_api_documents_children_list_authenticated_related_direct(
|
||||
"excerpt": child1.excerpt,
|
||||
"id": str(child1.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": child1.link_reach,
|
||||
"link_role": child1.link_role,
|
||||
"numchild": 0,
|
||||
@@ -419,6 +428,7 @@ def test_api_documents_children_list_authenticated_related_direct(
|
||||
"excerpt": child2.excerpt,
|
||||
"id": str(child2.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": child2.link_reach,
|
||||
"link_role": child2.link_role,
|
||||
"numchild": 0,
|
||||
@@ -479,6 +489,7 @@ def test_api_documents_children_list_authenticated_related_parent(
|
||||
"excerpt": child1.excerpt,
|
||||
"id": str(child1.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": child1.link_reach,
|
||||
"link_role": child1.link_role,
|
||||
"numchild": 0,
|
||||
@@ -501,6 +512,7 @@ def test_api_documents_children_list_authenticated_related_parent(
|
||||
"excerpt": child2.excerpt,
|
||||
"id": str(child2.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": child2.link_reach,
|
||||
"link_role": child2.link_role,
|
||||
"numchild": 0,
|
||||
@@ -613,6 +625,7 @@ def test_api_documents_children_list_authenticated_related_team_members(
|
||||
"excerpt": child1.excerpt,
|
||||
"id": str(child1.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": child1.link_reach,
|
||||
"link_role": child1.link_role,
|
||||
"numchild": 0,
|
||||
@@ -635,6 +648,7 @@ def test_api_documents_children_list_authenticated_related_team_members(
|
||||
"excerpt": child2.excerpt,
|
||||
"id": str(child2.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": child2.link_reach,
|
||||
"link_role": child2.link_role,
|
||||
"numchild": 0,
|
||||
|
||||
@@ -42,6 +42,7 @@ def test_api_documents_descendants_list_anonymous_public_standalone():
|
||||
"excerpt": child1.excerpt,
|
||||
"id": str(child1.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": child1.link_reach,
|
||||
"link_role": child1.link_role,
|
||||
"numchild": 1,
|
||||
@@ -66,6 +67,7 @@ def test_api_documents_descendants_list_anonymous_public_standalone():
|
||||
"excerpt": grand_child.excerpt,
|
||||
"id": str(grand_child.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": grand_child.link_reach,
|
||||
"link_role": grand_child.link_role,
|
||||
"numchild": 0,
|
||||
@@ -88,6 +90,7 @@ def test_api_documents_descendants_list_anonymous_public_standalone():
|
||||
"excerpt": child2.excerpt,
|
||||
"id": str(child2.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": child2.link_reach,
|
||||
"link_role": child2.link_role,
|
||||
"numchild": 0,
|
||||
@@ -139,6 +142,7 @@ def test_api_documents_descendants_list_anonymous_public_parent():
|
||||
"excerpt": child1.excerpt,
|
||||
"id": str(child1.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": child1.link_reach,
|
||||
"link_role": child1.link_role,
|
||||
"numchild": 1,
|
||||
@@ -161,6 +165,7 @@ def test_api_documents_descendants_list_anonymous_public_parent():
|
||||
"excerpt": grand_child.excerpt,
|
||||
"id": str(grand_child.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": grand_child.link_reach,
|
||||
"link_role": grand_child.link_role,
|
||||
"numchild": 0,
|
||||
@@ -183,6 +188,7 @@ def test_api_documents_descendants_list_anonymous_public_parent():
|
||||
"excerpt": child2.excerpt,
|
||||
"id": str(child2.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": child2.link_reach,
|
||||
"link_role": child2.link_role,
|
||||
"numchild": 0,
|
||||
@@ -255,6 +261,7 @@ def test_api_documents_descendants_list_authenticated_unrelated_public_or_authen
|
||||
"excerpt": child1.excerpt,
|
||||
"id": str(child1.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": child1.link_reach,
|
||||
"link_role": child1.link_role,
|
||||
"numchild": 1,
|
||||
@@ -277,6 +284,7 @@ def test_api_documents_descendants_list_authenticated_unrelated_public_or_authen
|
||||
"excerpt": grand_child.excerpt,
|
||||
"id": str(grand_child.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": grand_child.link_reach,
|
||||
"link_role": grand_child.link_role,
|
||||
"numchild": 0,
|
||||
@@ -299,6 +307,7 @@ def test_api_documents_descendants_list_authenticated_unrelated_public_or_authen
|
||||
"excerpt": child2.excerpt,
|
||||
"id": str(child2.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": child2.link_reach,
|
||||
"link_role": child2.link_role,
|
||||
"numchild": 0,
|
||||
@@ -356,6 +365,7 @@ def test_api_documents_descendants_list_authenticated_public_or_authenticated_pa
|
||||
"excerpt": child1.excerpt,
|
||||
"id": str(child1.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": child1.link_reach,
|
||||
"link_role": child1.link_role,
|
||||
"numchild": 1,
|
||||
@@ -378,6 +388,7 @@ def test_api_documents_descendants_list_authenticated_public_or_authenticated_pa
|
||||
"excerpt": grand_child.excerpt,
|
||||
"id": str(grand_child.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": grand_child.link_reach,
|
||||
"link_role": grand_child.link_role,
|
||||
"numchild": 0,
|
||||
@@ -400,6 +411,7 @@ def test_api_documents_descendants_list_authenticated_public_or_authenticated_pa
|
||||
"excerpt": child2.excerpt,
|
||||
"id": str(child2.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": child2.link_reach,
|
||||
"link_role": child2.link_role,
|
||||
"numchild": 0,
|
||||
@@ -478,6 +490,7 @@ def test_api_documents_descendants_list_authenticated_related_direct():
|
||||
"excerpt": child1.excerpt,
|
||||
"id": str(child1.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": child1.link_reach,
|
||||
"link_role": child1.link_role,
|
||||
"numchild": 1,
|
||||
@@ -500,6 +513,7 @@ def test_api_documents_descendants_list_authenticated_related_direct():
|
||||
"excerpt": grand_child.excerpt,
|
||||
"id": str(grand_child.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": grand_child.link_reach,
|
||||
"link_role": grand_child.link_role,
|
||||
"numchild": 0,
|
||||
@@ -522,6 +536,7 @@ def test_api_documents_descendants_list_authenticated_related_direct():
|
||||
"excerpt": child2.excerpt,
|
||||
"id": str(child2.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": child2.link_reach,
|
||||
"link_role": child2.link_role,
|
||||
"numchild": 0,
|
||||
@@ -580,6 +595,7 @@ def test_api_documents_descendants_list_authenticated_related_parent():
|
||||
"excerpt": child1.excerpt,
|
||||
"id": str(child1.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": child1.link_reach,
|
||||
"link_role": child1.link_role,
|
||||
"numchild": 1,
|
||||
@@ -602,6 +618,7 @@ def test_api_documents_descendants_list_authenticated_related_parent():
|
||||
"excerpt": grand_child.excerpt,
|
||||
"id": str(grand_child.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": grand_child.link_reach,
|
||||
"link_role": grand_child.link_role,
|
||||
"numchild": 0,
|
||||
@@ -624,6 +641,7 @@ def test_api_documents_descendants_list_authenticated_related_parent():
|
||||
"excerpt": child2.excerpt,
|
||||
"id": str(child2.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": child2.link_reach,
|
||||
"link_role": child2.link_role,
|
||||
"numchild": 0,
|
||||
@@ -728,6 +746,7 @@ def test_api_documents_descendants_list_authenticated_related_team_members(
|
||||
"excerpt": child1.excerpt,
|
||||
"id": str(child1.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": child1.link_reach,
|
||||
"link_role": child1.link_role,
|
||||
"numchild": 1,
|
||||
@@ -750,6 +769,7 @@ def test_api_documents_descendants_list_authenticated_related_team_members(
|
||||
"excerpt": grand_child.excerpt,
|
||||
"id": str(grand_child.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": grand_child.link_reach,
|
||||
"link_role": grand_child.link_role,
|
||||
"numchild": 0,
|
||||
@@ -772,6 +792,7 @@ def test_api_documents_descendants_list_authenticated_related_team_members(
|
||||
"excerpt": child2.excerpt,
|
||||
"id": str(child2.id),
|
||||
"is_favorite": False,
|
||||
"is_masked": False,
|
||||
"link_reach": child2.link_reach,
|
||||
"link_role": child2.link_role,
|
||||
"numchild": 0,
|
||||
|
||||
@@ -72,6 +72,7 @@ def test_api_documents_list_format():
|
||||
"depth": 1,
|
||||
"excerpt": document.excerpt,
|
||||
"is_favorite": True,
|
||||
"is_masked": False,
|
||||
"link_reach": document.link_reach,
|
||||
"link_role": document.link_role,
|
||||
"nb_accesses_ancestors": 3,
|
||||
@@ -408,6 +409,7 @@ def test_api_documents_list_favorites_no_extra_queries(django_assert_num_queries
|
||||
assert len(results) == 5
|
||||
|
||||
assert all(result["is_favorite"] is False for result in results)
|
||||
assert all(result["is_masked"] is False for result in results)
|
||||
|
||||
# Mark documents as favorite and check results again
|
||||
for document in special_documents:
|
||||
@@ -427,3 +429,5 @@ def test_api_documents_list_favorites_no_extra_queries(django_assert_num_queries
|
||||
assert result["is_favorite"] is True
|
||||
else:
|
||||
assert result["is_favorite"] is False
|
||||
# All documents should be unmasked in this test
|
||||
assert result["is_masked"] is False
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
useCreateFavoriteDoc,
|
||||
useDeleteFavoriteDoc,
|
||||
useDuplicateDoc,
|
||||
useMaskDocOption,
|
||||
} from '@/docs/doc-management';
|
||||
import { DocShareModal } from '@/docs/doc-share';
|
||||
import {
|
||||
@@ -81,6 +82,7 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
|
||||
const makeFavoriteDoc = useCreateFavoriteDoc({
|
||||
listInvalideQueries: [KEY_LIST_DOC, KEY_DOC],
|
||||
});
|
||||
const maskDocOption = useMaskDocOption(doc);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectHistoryModal.isOpen) {
|
||||
@@ -126,6 +128,7 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
|
||||
}
|
||||
},
|
||||
testId: `docs-actions-${doc.is_favorite ? 'unpin' : 'pin'}-${doc.id}`,
|
||||
showSeparator: true,
|
||||
},
|
||||
{
|
||||
label: t('Version history'),
|
||||
@@ -162,17 +165,23 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
|
||||
canSave: doc.abilities.partial_update,
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
label: t('Delete document'),
|
||||
icon: 'delete',
|
||||
disabled: !doc.abilities.destroy,
|
||||
callback: () => {
|
||||
setIsModalRemoveOpen(true);
|
||||
},
|
||||
showSeparator: true,
|
||||
},
|
||||
];
|
||||
|
||||
const leaveDocOption: DropdownMenuOption = doc.abilities.destroy
|
||||
? {
|
||||
label: t('Delete document'),
|
||||
icon: 'delete',
|
||||
disabled: !doc.abilities.destroy,
|
||||
callback: () => {
|
||||
setIsModalRemoveOpen(true);
|
||||
},
|
||||
}
|
||||
: maskDocOption;
|
||||
|
||||
options.push(leaveDocOption);
|
||||
|
||||
const copyCurrentEditorToClipboard = useCopyCurrentEditorToClipboard();
|
||||
|
||||
return (
|
||||
|
||||
@@ -4,7 +4,8 @@ export * from './useDeleteFavoriteDoc';
|
||||
export * from './useDoc';
|
||||
export * from './useDocOptions';
|
||||
export * from './useDocs';
|
||||
export * from './useSubDocs';
|
||||
export * from './useDuplicateDoc';
|
||||
export * from './useMaskDoc';
|
||||
export * from './useSubDocs';
|
||||
export * from './useUpdateDoc';
|
||||
export * from './useUpdateDocLink';
|
||||
|
||||
@@ -16,6 +16,7 @@ export type DocsParams = {
|
||||
is_creator_me?: boolean;
|
||||
title?: string;
|
||||
is_favorite?: boolean;
|
||||
is_masked?: boolean;
|
||||
};
|
||||
|
||||
export const constructParams = (params: DocsParams): URLSearchParams => {
|
||||
@@ -36,6 +37,9 @@ export const constructParams = (params: DocsParams): URLSearchParams => {
|
||||
if (params.is_favorite !== undefined) {
|
||||
searchParams.set('is_favorite', params.is_favorite.toString());
|
||||
}
|
||||
if (params.is_masked !== undefined) {
|
||||
searchParams.set('is_masked', params.is_masked.toString());
|
||||
}
|
||||
|
||||
return searchParams;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
import { APIError, errorCauses, fetchAPI } from '@/api';
|
||||
import { Doc } from '@/docs/doc-management';
|
||||
|
||||
export type MaskDocParams = Pick<Doc, 'id'>;
|
||||
|
||||
export const maskDoc = async ({ id }: MaskDocParams) => {
|
||||
const response = await fetchAPI(`documents/${id}/mask/`, {
|
||||
method: 'POST',
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new APIError(
|
||||
'Failed to make the doc as masked',
|
||||
await errorCauses(response),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
interface MaskDocProps {
|
||||
onSuccess?: () => void;
|
||||
listInvalideQueries?: string[];
|
||||
}
|
||||
|
||||
export function useMaskDoc({ onSuccess, listInvalideQueries }: MaskDocProps) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<void, APIError, MaskDocParams>({
|
||||
mutationFn: maskDoc,
|
||||
onSuccess: () => {
|
||||
listInvalideQueries?.forEach((queryKey) => {
|
||||
void queryClient.invalidateQueries({
|
||||
queryKey: [queryKey],
|
||||
});
|
||||
});
|
||||
onSuccess?.();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export type DeleteMaskDocParams = Pick<Doc, 'id'>;
|
||||
|
||||
export const deleteMaskDoc = async ({ id }: DeleteMaskDocParams) => {
|
||||
const response = await fetchAPI(`documents/${id}/mask/`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new APIError(
|
||||
'Failed to remove the doc as masked',
|
||||
await errorCauses(response),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
interface DeleteMaskDocProps {
|
||||
onSuccess?: () => void;
|
||||
listInvalideQueries?: string[];
|
||||
}
|
||||
|
||||
export function useDeleteMaskDoc({
|
||||
onSuccess,
|
||||
listInvalideQueries,
|
||||
}: DeleteMaskDocProps) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<void, APIError, DeleteMaskDocParams>({
|
||||
mutationFn: deleteMaskDoc,
|
||||
onSuccess: () => {
|
||||
listInvalideQueries?.forEach((queryKey) => {
|
||||
void queryClient.invalidateQueries({
|
||||
queryKey: [queryKey],
|
||||
});
|
||||
});
|
||||
onSuccess?.();
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -2,4 +2,5 @@ export * from './useCollaboration';
|
||||
export * from './useCopyDocLink';
|
||||
export * from './useDocUtils';
|
||||
export * from './useIsCollaborativeEditable';
|
||||
export * from './useMaskDocOption';
|
||||
export * from './useTrans';
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { DropdownMenuOption } from '@/components';
|
||||
|
||||
import { KEY_DOC, KEY_LIST_DOC, useDeleteMaskDoc, useMaskDoc } from '../api';
|
||||
import { Doc } from '../types';
|
||||
|
||||
export const useMaskDocOption = (doc: Doc) => {
|
||||
const { t } = useTranslation();
|
||||
const maskDoc = useMaskDoc({
|
||||
listInvalideQueries: [KEY_LIST_DOC, KEY_DOC],
|
||||
});
|
||||
const deleteMaskDoc = useDeleteMaskDoc({
|
||||
listInvalideQueries: [KEY_LIST_DOC, KEY_DOC],
|
||||
});
|
||||
|
||||
const leaveDocOption: DropdownMenuOption = doc.is_masked
|
||||
? {
|
||||
label: t('Join the doc'),
|
||||
icon: 'login',
|
||||
callback: () => {
|
||||
deleteMaskDoc.mutate({
|
||||
id: doc.id,
|
||||
});
|
||||
},
|
||||
disabled: !doc.abilities.mask,
|
||||
testId: `docs-grid-actions-mask-${doc.id}`,
|
||||
}
|
||||
: {
|
||||
label: t('Leave doc'),
|
||||
icon: 'logout',
|
||||
callback: () => {
|
||||
maskDoc.mutate({
|
||||
id: doc.id,
|
||||
});
|
||||
},
|
||||
disabled: !doc.abilities.mask,
|
||||
testId: `docs-grid-actions-mask-${doc.id}`,
|
||||
};
|
||||
|
||||
return leaveDocOption;
|
||||
};
|
||||
@@ -59,6 +59,7 @@ export interface Doc {
|
||||
depth: number;
|
||||
path: string;
|
||||
is_favorite: boolean;
|
||||
is_masked: boolean;
|
||||
link_reach: LinkReach;
|
||||
link_role: LinkRole;
|
||||
nb_accesses_direct: number;
|
||||
@@ -84,6 +85,7 @@ export interface Doc {
|
||||
favorite: boolean;
|
||||
invite_owner: boolean;
|
||||
link_configuration: boolean;
|
||||
mask: boolean;
|
||||
media_auth: boolean;
|
||||
move: boolean;
|
||||
partial_update: boolean;
|
||||
|
||||
@@ -32,10 +32,14 @@ export const DocsGrid = ({
|
||||
hasNextPage,
|
||||
} = useInfiniteDocs({
|
||||
page: 1,
|
||||
...(target &&
|
||||
target !== DocDefaultFilter.ALL_DOCS && {
|
||||
is_creator_me: target === DocDefaultFilter.MY_DOCS,
|
||||
}),
|
||||
is_masked:
|
||||
!target || target === DocDefaultFilter.ALL_DOCS ? false : undefined,
|
||||
is_creator_me:
|
||||
target === DocDefaultFilter.MY_DOCS
|
||||
? true
|
||||
: target === DocDefaultFilter.SHARED_WITH_ME
|
||||
? false
|
||||
: undefined,
|
||||
});
|
||||
|
||||
const docs = data?.pages.flatMap((page) => page.results) ?? [];
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
useCreateFavoriteDoc,
|
||||
useDeleteFavoriteDoc,
|
||||
useDuplicateDoc,
|
||||
useMaskDocOption,
|
||||
} from '@/docs/doc-management';
|
||||
|
||||
interface DocsGridActionsProps {
|
||||
@@ -31,6 +32,7 @@ export const DocsGridActions = ({
|
||||
const makeFavoriteDoc = useCreateFavoriteDoc({
|
||||
listInvalideQueries: [KEY_LIST_DOC],
|
||||
});
|
||||
const maskDocOption = useMaskDocOption(doc);
|
||||
|
||||
const options: DropdownMenuOption[] = [
|
||||
{
|
||||
@@ -44,6 +46,7 @@ export const DocsGridActions = ({
|
||||
}
|
||||
},
|
||||
testId: `docs-grid-actions-${doc.is_favorite ? 'unpin' : 'pin'}-${doc.id}`,
|
||||
showSeparator: true,
|
||||
},
|
||||
{
|
||||
label: t('Share'),
|
||||
@@ -65,16 +68,22 @@ export const DocsGridActions = ({
|
||||
canSave: false,
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
label: t('Remove'),
|
||||
icon: 'delete',
|
||||
callback: () => deleteModal.open(),
|
||||
disabled: !doc.abilities.destroy,
|
||||
testId: `docs-grid-actions-remove-${doc.id}`,
|
||||
showSeparator: true,
|
||||
},
|
||||
];
|
||||
|
||||
const leaveDocOption: DropdownMenuOption = doc.abilities.destroy
|
||||
? {
|
||||
label: t('Delete document'),
|
||||
icon: 'delete',
|
||||
callback: () => deleteModal.open(),
|
||||
disabled: !doc.abilities.destroy,
|
||||
testId: `docs-grid-actions-remove-${doc.id}`,
|
||||
}
|
||||
: maskDocOption;
|
||||
|
||||
options.push(leaveDocOption);
|
||||
|
||||
return (
|
||||
<>
|
||||
<DropdownMenu options={options}>
|
||||
|
||||
@@ -174,6 +174,7 @@ export class ApiPlugin implements WorkboxPlugin {
|
||||
creator: 'dummy-id',
|
||||
depth: 1,
|
||||
is_favorite: false,
|
||||
is_masked: false,
|
||||
nb_accesses_direct: 1,
|
||||
nb_accesses_ancestors: 1,
|
||||
numchild: 0,
|
||||
@@ -192,6 +193,7 @@ export class ApiPlugin implements WorkboxPlugin {
|
||||
favorite: true,
|
||||
invite_owner: true,
|
||||
link_configuration: true,
|
||||
mask: true,
|
||||
media_auth: true,
|
||||
move: true,
|
||||
partial_update: true,
|
||||
|
||||
Reference in New Issue
Block a user