wip use a context instead for global usage
This commit is contained in:
@@ -1385,6 +1385,14 @@ class DocumentViewSet(
|
||||
# Check permissions first
|
||||
document = self.get_object()
|
||||
|
||||
if document.is_encrypted:
|
||||
raise drf.exceptions.ValidationError(
|
||||
{
|
||||
"detail": "Visibility cannot be changed for encrypted documents. "
|
||||
"Encrypted documents must remain restricted.",
|
||||
}
|
||||
)
|
||||
|
||||
# Deserialize and validate the data
|
||||
serializer = serializers.LinkDocumentSerializer(
|
||||
document, data=request.data, partial=True
|
||||
|
||||
@@ -9,6 +9,7 @@ import { useEffect } from 'react';
|
||||
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { Auth, KEY_AUTH, setAuthUrl } from '@/features/auth';
|
||||
import { UserEncryptionProvider } from '@/features/docs/doc-collaboration';
|
||||
import { useResponsiveStore } from '@/stores/';
|
||||
|
||||
import { ConfigProvider } from './config/';
|
||||
@@ -74,7 +75,9 @@ export function AppProvider({ children }: { children: React.ReactNode }) {
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<CunninghamProvider theme={theme}>
|
||||
<ConfigProvider>
|
||||
<Auth>{children}</Auth>
|
||||
<Auth>
|
||||
<UserEncryptionProvider>{children}</UserEncryptionProvider>
|
||||
</Auth>
|
||||
</ConfigProvider>
|
||||
</CunninghamProvider>
|
||||
</QueryClientProvider>
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
import { createContext, useContext } from 'react';
|
||||
|
||||
import { useAuth } from '@/features/auth';
|
||||
|
||||
import { EncryptionError, useEncryption } from './hook/useEncryption';
|
||||
|
||||
interface UserEncryptionContextValue {
|
||||
encryptionLoading: boolean;
|
||||
encryptionSettings: {
|
||||
userId: string;
|
||||
userPrivateKey: CryptoKey;
|
||||
userPublicKey: CryptoKey;
|
||||
} | null;
|
||||
encryptionError: EncryptionError;
|
||||
}
|
||||
|
||||
const UserEncryptionContext = createContext<UserEncryptionContextValue>({
|
||||
encryptionLoading: true,
|
||||
encryptionSettings: null,
|
||||
encryptionError: null,
|
||||
});
|
||||
|
||||
export const UserEncryptionProvider = ({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
const { user } = useAuth();
|
||||
const value = useEncryption(user?.id);
|
||||
|
||||
return (
|
||||
<UserEncryptionContext.Provider value={value}>
|
||||
{children}
|
||||
</UserEncryptionContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useUserEncryption = (): UserEncryptionContextValue =>
|
||||
useContext(UserEncryptionContext);
|
||||
+3
-6
@@ -2,18 +2,14 @@ import { useEffect, useState } from 'react';
|
||||
|
||||
import { decryptSymmetricKey } from '@/docs/doc-collaboration/encryption';
|
||||
|
||||
import { useUserEncryption } from '../UserEncryptionProvider';
|
||||
|
||||
export type DocumentEncryptionError =
|
||||
| 'missing_symmetric_key'
|
||||
| 'decryption_failed'
|
||||
| null;
|
||||
|
||||
export function useDocumentEncryption(
|
||||
encryptionLoading: boolean,
|
||||
encryptionSettings: {
|
||||
userId: string;
|
||||
userPrivateKey: CryptoKey;
|
||||
userPublicKey: CryptoKey;
|
||||
} | null,
|
||||
isDocumentEncrypted: boolean | undefined,
|
||||
userEncryptedSymmetricKey: string | undefined,
|
||||
): {
|
||||
@@ -23,6 +19,7 @@ export function useDocumentEncryption(
|
||||
} | null;
|
||||
documentEncryptionError: DocumentEncryptionError;
|
||||
} {
|
||||
const { encryptionLoading, encryptionSettings } = useUserEncryption();
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [settings, setSettings] = useState<{
|
||||
documentSymmetricKey: CryptoKey;
|
||||
|
||||
@@ -16,5 +16,9 @@ export {
|
||||
useEncryption,
|
||||
type EncryptionError,
|
||||
} from './hook/useEncryption';
|
||||
export {
|
||||
UserEncryptionProvider,
|
||||
useUserEncryption,
|
||||
} from './UserEncryptionProvider';
|
||||
export { useKeyFingerprint } from './hook/useKeyFingerprint';
|
||||
export { usePublicKeyRegistry } from './hook/usePublicKeyRegistry';
|
||||
|
||||
@@ -78,7 +78,7 @@ describe('DocEditor', () => {
|
||||
},
|
||||
} as any;
|
||||
|
||||
const { rerender } = render(<DocEditor doc={doc} encryptionSettings={null} documentEncryptionSettings={null} />, {
|
||||
const { rerender } = render(<DocEditor doc={doc} documentEncryptionSettings={null} />, {
|
||||
wrapper: AppWrapper,
|
||||
});
|
||||
|
||||
@@ -90,7 +90,7 @@ describe('DocEditor', () => {
|
||||
|
||||
// Rerender with same doc to check that event is not tracked again
|
||||
rerender(
|
||||
<DocEditor doc={{ ...doc, computed_link_reach: LinkReach.RESTRICTED }} encryptionSettings={null} documentEncryptionSettings={null} />,
|
||||
<DocEditor doc={{ ...doc, computed_link_reach: LinkReach.RESTRICTED }} documentEncryptionSettings={null} />,
|
||||
);
|
||||
|
||||
expect(TrackEventMock).toHaveBeenNthCalledWith(1, {
|
||||
@@ -107,7 +107,6 @@ describe('DocEditor', () => {
|
||||
id: 'test-doc-id-2',
|
||||
computed_link_reach: LinkReach.RESTRICTED,
|
||||
}}
|
||||
encryptionSettings={null}
|
||||
documentEncryptionSettings={null}
|
||||
/>,
|
||||
);
|
||||
|
||||
@@ -76,11 +76,6 @@ export const DocEditorContainer = ({
|
||||
|
||||
interface DocEditorProps {
|
||||
doc: Doc;
|
||||
encryptionSettings: {
|
||||
userId: string;
|
||||
userPrivateKey: CryptoKey;
|
||||
userPublicKey: CryptoKey;
|
||||
} | null;
|
||||
documentEncryptionSettings: {
|
||||
documentSymmetricKey: CryptoKey;
|
||||
} | null;
|
||||
@@ -88,7 +83,6 @@ interface DocEditorProps {
|
||||
|
||||
export const DocEditor = ({
|
||||
doc,
|
||||
encryptionSettings,
|
||||
documentEncryptionSettings,
|
||||
}: DocEditorProps) => {
|
||||
const { isDesktop } = useResponsiveStore();
|
||||
@@ -145,7 +139,6 @@ export const DocEditor = ({
|
||||
docHeader={
|
||||
<DocHeader
|
||||
doc={doc}
|
||||
encryptionSettings={encryptionSettings}
|
||||
documentEncryptionSettings={documentEncryptionSettings}
|
||||
/>
|
||||
}
|
||||
|
||||
+2
-2
@@ -37,7 +37,7 @@ describe('DocToolBox - Licence', () => {
|
||||
|
||||
const { DocToolBox } = await import('../components/DocToolBox');
|
||||
|
||||
render(<DocToolBox doc={doc as any} encryptionSettings={null} />, {
|
||||
render(<DocToolBox doc={doc as any} />, {
|
||||
wrapper: AppWrapper,
|
||||
});
|
||||
const optionsButton = await screen.findByLabelText('Export the document');
|
||||
@@ -55,7 +55,7 @@ describe('DocToolBox - Licence', () => {
|
||||
|
||||
const { DocToolBox } = await import('../components/DocToolBox');
|
||||
|
||||
render(<DocToolBox doc={doc as any} encryptionSettings={null} />, {
|
||||
render(<DocToolBox doc={doc as any} />, {
|
||||
wrapper: AppWrapper,
|
||||
});
|
||||
|
||||
|
||||
@@ -20,11 +20,6 @@ import { DocToolBox } from './DocToolBox';
|
||||
|
||||
interface DocHeaderProps {
|
||||
doc: Doc;
|
||||
encryptionSettings: {
|
||||
userId: string;
|
||||
userPrivateKey: CryptoKey;
|
||||
userPublicKey: CryptoKey;
|
||||
} | null;
|
||||
documentEncryptionSettings?: {
|
||||
documentSymmetricKey: CryptoKey;
|
||||
} | null;
|
||||
@@ -32,7 +27,6 @@ interface DocHeaderProps {
|
||||
|
||||
export const DocHeader = ({
|
||||
doc,
|
||||
encryptionSettings,
|
||||
documentEncryptionSettings,
|
||||
}: DocHeaderProps) => {
|
||||
const { spacingsTokens } = useCunninghamTheme();
|
||||
@@ -80,7 +74,6 @@ export const DocHeader = ({
|
||||
{!isDeletedDoc && (
|
||||
<DocToolBox
|
||||
doc={doc}
|
||||
encryptionSettings={encryptionSettings}
|
||||
documentEncryptionSettings={documentEncryptionSettings}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -31,7 +31,10 @@ import {
|
||||
useDocUtils,
|
||||
useDuplicateDoc,
|
||||
} from '@/docs/doc-management';
|
||||
import { usePublicKeyRegistry } from '@/docs/doc-collaboration';
|
||||
import {
|
||||
usePublicKeyRegistry,
|
||||
useUserEncryption,
|
||||
} from '@/docs/doc-collaboration';
|
||||
import { DocShareModal } from '@/docs/doc-share';
|
||||
import {
|
||||
KEY_LIST_DOC_VERSIONS,
|
||||
@@ -47,11 +50,6 @@ const ModalExport = Export?.ModalExport;
|
||||
|
||||
interface DocToolBoxProps {
|
||||
doc: Doc;
|
||||
encryptionSettings: {
|
||||
userId: string;
|
||||
userPrivateKey: CryptoKey;
|
||||
userPublicKey: CryptoKey;
|
||||
} | null;
|
||||
documentEncryptionSettings?: {
|
||||
documentSymmetricKey: CryptoKey;
|
||||
} | null;
|
||||
@@ -59,7 +57,6 @@ interface DocToolBoxProps {
|
||||
|
||||
export const DocToolBox = ({
|
||||
doc,
|
||||
encryptionSettings,
|
||||
documentEncryptionSettings,
|
||||
}: DocToolBoxProps) => {
|
||||
const { t } = useTranslation();
|
||||
@@ -69,6 +66,7 @@ export const DocToolBox = ({
|
||||
const { isChild, isTopRoot } = useDocUtils(doc);
|
||||
|
||||
const { spacingsTokens, colorsTokens } = useCunninghamTheme();
|
||||
const { encryptionSettings } = useUserEncryption();
|
||||
|
||||
const [isModalRemoveOpen, setIsModalRemoveOpen] = useState(false);
|
||||
const [isModalExportOpen, setIsModalExportOpen] = useState(false);
|
||||
@@ -336,7 +334,6 @@ export const DocToolBox = ({
|
||||
{isModalEncryptOpen && (
|
||||
<ModalEncryptDoc
|
||||
doc={doc}
|
||||
encryptionSettings={encryptionSettings}
|
||||
onClose={() => setIsModalEncryptOpen(false)}
|
||||
onSuccess={() => {
|
||||
//
|
||||
|
||||
+2
-6
@@ -21,6 +21,7 @@ import {
|
||||
generateUserKeyPair,
|
||||
getEncryptionDB,
|
||||
prepareEncryptedSymmetricKeysForUsers,
|
||||
useUserEncryption,
|
||||
} from '@/docs/doc-collaboration';
|
||||
import { createDocAttachment } from '@/docs/doc-editor/api';
|
||||
import { toBase64 } from '@/docs/doc-editor';
|
||||
@@ -121,18 +122,12 @@ const encryptRemoteAttachments = async (
|
||||
|
||||
interface ModalEncryptDocProps {
|
||||
doc: Doc;
|
||||
encryptionSettings: {
|
||||
userId: string;
|
||||
userPrivateKey: CryptoKey;
|
||||
userPublicKey: CryptoKey;
|
||||
} | null;
|
||||
onClose: () => void;
|
||||
onSuccess?: (doc: Doc) => void;
|
||||
}
|
||||
|
||||
export const ModalEncryptDoc = ({
|
||||
doc,
|
||||
encryptionSettings,
|
||||
onClose,
|
||||
onSuccess,
|
||||
}: ModalEncryptDocProps) => {
|
||||
@@ -140,6 +135,7 @@ export const ModalEncryptDoc = ({
|
||||
const { toast } = useToastProvider();
|
||||
const { provider } = useProviderStore();
|
||||
const { user } = useAuth();
|
||||
const { encryptionSettings } = useUserEncryption();
|
||||
const { mutateAsync: updateUser } = useUserUpdate();
|
||||
|
||||
const [isPending, setIsPending] = useState(false);
|
||||
|
||||
+178
-108
@@ -10,6 +10,7 @@ import {
|
||||
ButtonCloseModal,
|
||||
HorizontalSeparator,
|
||||
Icon,
|
||||
Loading,
|
||||
Text,
|
||||
} from '@/components';
|
||||
import {
|
||||
@@ -17,7 +18,11 @@ import {
|
||||
QuickSearchData,
|
||||
QuickSearchGroup,
|
||||
} from '@/components/quick-search/';
|
||||
import { usePublicKeyRegistry } from '@/docs/doc-collaboration';
|
||||
import {
|
||||
useDocumentEncryption,
|
||||
usePublicKeyRegistry,
|
||||
useUserEncryption,
|
||||
} from '@/docs/doc-collaboration';
|
||||
import type { PublicKeyMismatch } from '@/docs/doc-collaboration/hook/usePublicKeyRegistry';
|
||||
import { Doc } from '@/docs/doc-management';
|
||||
import { User, useAuth } from '@/features/auth';
|
||||
@@ -77,6 +82,28 @@ export const DocShareModal = ({
|
||||
|
||||
const { isDesktop } = useResponsiveStore();
|
||||
const { user } = useAuth();
|
||||
|
||||
// When document encryption settings exist they should be passed as prop, on it will use this fallback
|
||||
// that's because in some cases we want them to only be computed at this step (to avoid computing just when listed in a list)
|
||||
const needsDerivation = !documentEncryptionSettings;
|
||||
const { encryptionLoading, encryptionError } = useUserEncryption();
|
||||
const {
|
||||
documentEncryptionLoading,
|
||||
documentEncryptionSettings: derivedEncryptionSettings,
|
||||
documentEncryptionError,
|
||||
} = useDocumentEncryption(
|
||||
needsDerivation ? doc.is_encrypted : undefined,
|
||||
needsDerivation ? doc.encrypted_document_symmetric_key_for_user : undefined,
|
||||
);
|
||||
const effectiveEncryptionSettings =
|
||||
documentEncryptionSettings ?? derivedEncryptionSettings ?? null;
|
||||
const isEncryptionDeriving =
|
||||
needsDerivation && (encryptionLoading || documentEncryptionLoading);
|
||||
const derivedEncryptionError =
|
||||
needsDerivation && doc.is_encrypted
|
||||
? encryptionError || documentEncryptionError
|
||||
: null;
|
||||
|
||||
const { mismatches: keyMismatches, acceptNewKey } = usePublicKeyRegistry(
|
||||
doc.accesses_public_keys_per_user,
|
||||
user?.id,
|
||||
@@ -240,125 +267,168 @@ export const DocShareModal = ({
|
||||
>
|
||||
{liveAnnouncement}
|
||||
</div>
|
||||
<Box
|
||||
$height="auto"
|
||||
$maxHeight={canViewAccesses ? modalContentHeight : 'none'}
|
||||
$overflow="hidden"
|
||||
className="--docs--doc-share-modal noPadding "
|
||||
$justify="space-between"
|
||||
role="dialog"
|
||||
aria-label={t('Share modal content')}
|
||||
>
|
||||
{isEncryptionDeriving && <Loading />}
|
||||
{!isEncryptionDeriving && derivedEncryptionError && (
|
||||
<Box $align="center" $gap="sm" $padding="lg">
|
||||
<Icon iconName="lock" $size="2rem" $theme="warning" />
|
||||
<Text as="h3" $textAlign="center" $margin="0">
|
||||
{t('Encryption keys unavailable')}
|
||||
</Text>
|
||||
<Text $variation="secondary" $textAlign="center" $size="sm">
|
||||
{t(
|
||||
'This is an encrypted document, but your current device does not have the required encryption keys to decrypt it.',
|
||||
)}
|
||||
</Text>
|
||||
{(encryptionError === 'missing_private_key' ||
|
||||
encryptionError === 'missing_public_key') && (
|
||||
<Text $variation="secondary" $textAlign="center" $size="sm">
|
||||
{t(
|
||||
'This usually happens when you switch to a new device or browser without restoring your encryption backup.',
|
||||
)}
|
||||
</Text>
|
||||
)}
|
||||
{documentEncryptionError === 'missing_symmetric_key' && (
|
||||
<Text $variation="secondary" $textAlign="center" $size="sm">
|
||||
{t(
|
||||
'You do not have access to this encrypted document. Ask the document owner to share it with you again.',
|
||||
)}
|
||||
</Text>
|
||||
)}
|
||||
{documentEncryptionError === 'decryption_failed' && (
|
||||
<Text $variation="secondary" $textAlign="center" $size="sm">
|
||||
{t(
|
||||
'Your encryption keys could not decrypt this document. This may happen if your keys were recreated. Ask the document owner to share it with you again.',
|
||||
)}
|
||||
</Text>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
{!isEncryptionDeriving && !derivedEncryptionError && (
|
||||
<Box
|
||||
$flex={1}
|
||||
$css={css`
|
||||
[cmdk-list] {
|
||||
overflow-y: auto;
|
||||
height: ${listHeight};
|
||||
}
|
||||
`}
|
||||
$height="auto"
|
||||
$maxHeight={canViewAccesses ? modalContentHeight : 'none'}
|
||||
$overflow="hidden"
|
||||
className="--docs--doc-share-modal noPadding "
|
||||
$justify="space-between"
|
||||
role="dialog"
|
||||
aria-label={t('Share modal content')}
|
||||
>
|
||||
<Box ref={selectedUsersRef}>
|
||||
{canShare && selectedUsers.length > 0 && (
|
||||
<Box $padding={{ horizontal: 'base' }} $margin={{ top: '12x' }}>
|
||||
<DocShareAddMemberList
|
||||
doc={doc}
|
||||
documentEncryptionSettings={
|
||||
documentEncryptionSettings ?? null
|
||||
}
|
||||
selectedUsers={selectedUsers}
|
||||
onRemoveUser={onRemoveUser}
|
||||
afterInvite={() => {
|
||||
setUserQuery('');
|
||||
setInputValue('');
|
||||
setSelectedUsers([]);
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
{!canViewAccesses && <HorizontalSeparator customPadding="12px" />}
|
||||
</Box>
|
||||
|
||||
<Box data-testid="doc-share-quick-search">
|
||||
{!canViewAccesses && (
|
||||
<Box
|
||||
$height={listHeight}
|
||||
$align="center"
|
||||
$justify="center"
|
||||
$gap="1rem"
|
||||
>
|
||||
<Text
|
||||
$maxWidth="320px"
|
||||
$textAlign="center"
|
||||
$variation="secondary"
|
||||
$size="sm"
|
||||
as="p"
|
||||
<Box
|
||||
$flex={1}
|
||||
$css={css`
|
||||
[cmdk-list] {
|
||||
overflow-y: auto;
|
||||
height: ${listHeight};
|
||||
}
|
||||
`}
|
||||
>
|
||||
<Box ref={selectedUsersRef}>
|
||||
{canShare && selectedUsers.length > 0 && (
|
||||
<Box
|
||||
$padding={{ horizontal: 'base' }}
|
||||
$margin={{ top: '12x' }}
|
||||
>
|
||||
{t(
|
||||
'You can view this document but need additional access to see its members or modify settings.',
|
||||
)}
|
||||
</Text>
|
||||
<ButtonAccessRequest
|
||||
docId={doc.id}
|
||||
variant="secondary"
|
||||
size="small"
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
{canViewAccesses && (
|
||||
<QuickSearch
|
||||
label={t('Search results')}
|
||||
onFilter={(str) => {
|
||||
setInputValue(str);
|
||||
onFilter(str);
|
||||
}}
|
||||
inputValue={inputValue}
|
||||
showInput={canShare}
|
||||
loading={searchUsersQuery.isLoading}
|
||||
placeholder={t('Type a name or email')}
|
||||
>
|
||||
{showInheritedShareContent && (
|
||||
<DocInheritedShareContent
|
||||
rawAccesses={
|
||||
membersQuery?.filter(
|
||||
(access) => access.document.id !== doc.id,
|
||||
) ?? []
|
||||
}
|
||||
<DocShareAddMemberList
|
||||
doc={doc}
|
||||
documentEncryptionSettings={effectiveEncryptionSettings}
|
||||
selectedUsers={selectedUsers}
|
||||
onRemoveUser={onRemoveUser}
|
||||
afterInvite={() => {
|
||||
setUserQuery('');
|
||||
setInputValue('');
|
||||
setSelectedUsers([]);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{showMemberSection && isRootDoc && (
|
||||
<Box $padding={{ horizontal: 'base' }}>
|
||||
<QuickSearchGroupAccessRequest doc={doc} />
|
||||
<QuickSearchGroupInvitation doc={doc} />
|
||||
<QuickSearchGroupMember
|
||||
doc={doc}
|
||||
</Box>
|
||||
)}
|
||||
{!canViewAccesses && (
|
||||
<HorizontalSeparator customPadding="12px" />
|
||||
)}
|
||||
</Box>
|
||||
|
||||
<Box data-testid="doc-share-quick-search">
|
||||
{!canViewAccesses && (
|
||||
<Box
|
||||
$height={listHeight}
|
||||
$align="center"
|
||||
$justify="center"
|
||||
$gap="1rem"
|
||||
>
|
||||
<Text
|
||||
$maxWidth="320px"
|
||||
$textAlign="center"
|
||||
$variation="secondary"
|
||||
$size="sm"
|
||||
as="p"
|
||||
>
|
||||
{t(
|
||||
'You can view this document but need additional access to see its members or modify settings.',
|
||||
)}
|
||||
</Text>
|
||||
<ButtonAccessRequest
|
||||
docId={doc.id}
|
||||
variant="secondary"
|
||||
size="small"
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
{canViewAccesses && (
|
||||
<QuickSearch
|
||||
label={t('Search results')}
|
||||
onFilter={(str) => {
|
||||
setInputValue(str);
|
||||
onFilter(str);
|
||||
}}
|
||||
inputValue={inputValue}
|
||||
showInput={canShare}
|
||||
loading={searchUsersQuery.isLoading}
|
||||
placeholder={t('Type a name or email')}
|
||||
>
|
||||
{showInheritedShareContent && (
|
||||
<DocInheritedShareContent
|
||||
rawAccesses={
|
||||
membersQuery?.filter(
|
||||
(access) => access.document.id !== doc.id,
|
||||
) ?? []
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{showMemberSection && isRootDoc && (
|
||||
<Box $padding={{ horizontal: 'base' }}>
|
||||
<QuickSearchGroupAccessRequest doc={doc} />
|
||||
<QuickSearchGroupInvitation doc={doc} />
|
||||
<QuickSearchGroupMember
|
||||
doc={doc}
|
||||
keyMismatchUserIds={keyMismatchUserIds}
|
||||
keyMismatches={keyMismatches}
|
||||
acceptNewKey={acceptNewKey}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{!showMemberSection && canShare && (
|
||||
<QuickSearchInviteInputSection
|
||||
searchUsersRawData={searchUsersQuery.data}
|
||||
onSelect={onSelect}
|
||||
userQuery={userQuery}
|
||||
isEncrypted={doc.is_encrypted}
|
||||
keyMismatchUserIds={keyMismatchUserIds}
|
||||
keyMismatches={keyMismatches}
|
||||
acceptNewKey={acceptNewKey}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
)}
|
||||
</QuickSearch>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{!showMemberSection && canShare && (
|
||||
<QuickSearchInviteInputSection
|
||||
searchUsersRawData={searchUsersQuery.data}
|
||||
onSelect={onSelect}
|
||||
userQuery={userQuery}
|
||||
isEncrypted={doc.is_encrypted}
|
||||
keyMismatchUserIds={keyMismatchUserIds}
|
||||
keyMismatches={keyMismatches}
|
||||
acceptNewKey={acceptNewKey}
|
||||
/>
|
||||
)}
|
||||
</QuickSearch>
|
||||
<Box ref={handleRef}>
|
||||
{showFooter && (
|
||||
<DocShareModalFooter doc={doc} onClose={onClose} />
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Box ref={handleRef}>
|
||||
{showFooter && <DocShareModalFooter doc={doc} onClose={onClose} />}
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
|
||||
+6
-2
@@ -27,8 +27,12 @@ export const DocShareModalFooter = ({
|
||||
>
|
||||
<HorizontalSeparator $withPadding={true} customPadding="12px" />
|
||||
|
||||
<DocVisibility doc={doc} />
|
||||
<HorizontalSeparator customPadding="12px" />
|
||||
{!doc.is_encrypted && (
|
||||
<>
|
||||
<DocVisibility doc={doc} />
|
||||
<HorizontalSeparator customPadding="12px" />
|
||||
</>
|
||||
)}
|
||||
|
||||
<Box
|
||||
$direction="row"
|
||||
|
||||
@@ -10,8 +10,7 @@ import styled, { css } from 'styled-components';
|
||||
import AllDocs from '@/assets/icons/doc-all.svg';
|
||||
import { Box, Card, Icon, Text } from '@/components';
|
||||
import { DocDefaultFilter, useInfiniteDocs } from '@/docs/doc-management';
|
||||
import { useAuth } from '@/features/auth';
|
||||
import { useEncryption } from '@/features/docs/doc-collaboration';
|
||||
import { useUserEncryption } from '@/features/docs/doc-collaboration';
|
||||
import { useResponsiveStore } from '@/stores';
|
||||
|
||||
import { useInfiniteDocsTrashbin } from '../api';
|
||||
@@ -81,11 +80,7 @@ export const DocsGrid = ({
|
||||
});
|
||||
}, [data?.pages]);
|
||||
|
||||
const { user } = useAuth();
|
||||
const { encryptionLoading, encryptionSettings } = useEncryption(user?.id);
|
||||
// TODO:
|
||||
// TODO: from here `encryptionSettings` should be used in case of adjusting accesses on a document
|
||||
// TODO:
|
||||
const { encryptionLoading, encryptionSettings } = useUserEncryption();
|
||||
|
||||
const loading = isFetching || isLoading || encryptionLoading;
|
||||
const hasDocs = data?.pages.some((page) => page.results.length > 0);
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
import { KEY_AUTH, setAuthUrl, useAuth } from '@/features/auth';
|
||||
import {
|
||||
useDocumentEncryption,
|
||||
useEncryption,
|
||||
useUserEncryption,
|
||||
} from '@/features/docs/doc-collaboration';
|
||||
import { getDocChildren, subPageToTree } from '@/features/docs/doc-tree/';
|
||||
import { useSkeletonStore } from '@/features/skeletons';
|
||||
@@ -93,17 +93,14 @@ const DocPage = ({ id }: DocProps) => {
|
||||
},
|
||||
);
|
||||
|
||||
const { authenticated, user } = useAuth();
|
||||
const { authenticated } = useAuth();
|
||||
const [doc, setDoc] = useState<Doc>();
|
||||
const { encryptionLoading, encryptionSettings, encryptionError } =
|
||||
useEncryption(user?.id);
|
||||
const { encryptionLoading, encryptionError } = useUserEncryption();
|
||||
const {
|
||||
documentEncryptionLoading,
|
||||
documentEncryptionSettings,
|
||||
documentEncryptionError,
|
||||
} = useDocumentEncryption(
|
||||
encryptionLoading,
|
||||
encryptionSettings,
|
||||
doc?.is_encrypted,
|
||||
doc?.encrypted_document_symmetric_key_for_user,
|
||||
);
|
||||
@@ -357,7 +354,6 @@ const DocPage = ({ id }: DocProps) => {
|
||||
</Head>
|
||||
<DocEditor
|
||||
doc={doc}
|
||||
encryptionSettings={encryptionSettings}
|
||||
documentEncryptionSettings={documentEncryptionSettings}
|
||||
/>
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user