wip allow revealing all medias at once
This commit is contained in:
@@ -40,6 +40,7 @@ import { DocsBlockNoteEditor } from '../types';
|
||||
import { randomColor } from '../utils';
|
||||
|
||||
import { BlockNoteSuggestionMenu } from './BlockNoteSuggestionMenu';
|
||||
import { EncryptedDocBanner } from './EncryptedDocBanner';
|
||||
import { EncryptionProvider } from './EncryptionProvider';
|
||||
import { BlockNoteToolbar } from './BlockNoteToolBar/BlockNoteToolbar';
|
||||
import { cssComments, useComments } from './comments/';
|
||||
@@ -249,6 +250,7 @@ export const BlockNoteEditor = ({
|
||||
|
||||
return (
|
||||
<EncryptionProvider symmetricKey={symmetricKey}>
|
||||
<EncryptedDocBanner />
|
||||
<Box
|
||||
ref={refEditorContainer}
|
||||
$css={css`
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
import { Button } from '@gouvfr-lasuite/cunningham-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Box, Icon } from '@/components';
|
||||
|
||||
import { useEncryption } from './EncryptionProvider';
|
||||
|
||||
export const EncryptedDocBanner = () => {
|
||||
const { t } = useTranslation();
|
||||
const { isEncrypted, pendingPlaceholders, requestRevealAll } =
|
||||
useEncryption();
|
||||
|
||||
if (!isEncrypted || pendingPlaceholders === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Box
|
||||
$direction="row"
|
||||
$align="center"
|
||||
$justify="flex-end"
|
||||
$padding={{ horizontal: '54px', vertical: '3xs' }}
|
||||
>
|
||||
<Button
|
||||
size="small"
|
||||
variant="tertiary"
|
||||
onClick={requestRevealAll}
|
||||
icon={<Icon iconName="visibility" $size="sm" $color="inherit" />}
|
||||
>
|
||||
{t('Reveal all media')}
|
||||
</Button>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
+41
-1
@@ -6,6 +6,7 @@ import {
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
import { decryptContent } from '@/docs/doc-collaboration/encryption';
|
||||
@@ -37,11 +38,23 @@ const MIME_MAP: Record<string, string> = {
|
||||
interface EncryptionContextValue {
|
||||
isEncrypted: boolean;
|
||||
decryptFileUrl: (url: string) => Promise<string>;
|
||||
revealAllCounter: number;
|
||||
requestRevealAll: () => void;
|
||||
pendingPlaceholders: number;
|
||||
registerPlaceholder: () => void;
|
||||
unregisterPlaceholder: () => void;
|
||||
}
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
const DEFAULT_VALUE: EncryptionContextValue = {
|
||||
isEncrypted: false,
|
||||
decryptFileUrl: async (url: string) => url,
|
||||
revealAllCounter: 0,
|
||||
requestRevealAll: noop,
|
||||
pendingPlaceholders: 0,
|
||||
registerPlaceholder: noop,
|
||||
unregisterPlaceholder: noop,
|
||||
};
|
||||
|
||||
const EncryptionContext = createContext<EncryptionContextValue>(DEFAULT_VALUE);
|
||||
@@ -56,6 +69,20 @@ export const EncryptionProvider = ({
|
||||
children,
|
||||
}: EncryptionProviderProps) => {
|
||||
const blobUrlCacheRef = useRef<Map<string, string>>(new Map());
|
||||
const [revealAllCounter, setRevealAllCounter] = useState(0);
|
||||
const [pendingPlaceholders, setPendingPlaceholders] = useState(0);
|
||||
|
||||
const requestRevealAll = useCallback(() => {
|
||||
setRevealAllCounter((c) => c + 1);
|
||||
}, []);
|
||||
|
||||
const registerPlaceholder = useCallback(() => {
|
||||
setPendingPlaceholders((c) => c + 1);
|
||||
}, []);
|
||||
|
||||
const unregisterPlaceholder = useCallback(() => {
|
||||
setPendingPlaceholders((c) => Math.max(0, c - 1));
|
||||
}, []);
|
||||
|
||||
const decryptFileUrl = useCallback(
|
||||
async (url: string): Promise<string> => {
|
||||
@@ -103,8 +130,21 @@ export const EncryptionProvider = ({
|
||||
() => ({
|
||||
isEncrypted: !!symmetricKey,
|
||||
decryptFileUrl,
|
||||
revealAllCounter,
|
||||
requestRevealAll,
|
||||
pendingPlaceholders,
|
||||
registerPlaceholder,
|
||||
unregisterPlaceholder,
|
||||
}),
|
||||
[symmetricKey, decryptFileUrl],
|
||||
[
|
||||
symmetricKey,
|
||||
decryptFileUrl,
|
||||
revealAllCounter,
|
||||
requestRevealAll,
|
||||
pendingPlaceholders,
|
||||
registerPlaceholder,
|
||||
unregisterPlaceholder,
|
||||
],
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { useEncryption } from '../components/EncryptionProvider';
|
||||
import { ANALYZE_URL } from '../conf';
|
||||
|
||||
export const useDecryptMedia = (url: string | undefined) => {
|
||||
const { isEncrypted, decryptFileUrl } = useEncryption();
|
||||
const {
|
||||
isEncrypted,
|
||||
decryptFileUrl,
|
||||
revealAllCounter,
|
||||
registerPlaceholder,
|
||||
unregisterPlaceholder,
|
||||
} = useEncryption();
|
||||
const [resolvedUrl, setResolvedUrl] = useState<string | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [hasError, setHasError] = useState(false);
|
||||
@@ -28,11 +34,41 @@ export const useDecryptMedia = (url: string | undefined) => {
|
||||
}
|
||||
}, [url, resolvedUrl, isLoading, decryptFileUrl]);
|
||||
|
||||
// Auto-decrypt when "Reveal all" is requested
|
||||
const decryptRef = useRef(decrypt);
|
||||
decryptRef.current = decrypt;
|
||||
|
||||
useEffect(() => {
|
||||
if (revealAllCounter > 0 && isEncrypted && url && !isAnalyzing) {
|
||||
void decryptRef.current();
|
||||
}
|
||||
}, [revealAllCounter, isEncrypted, url, isAnalyzing]);
|
||||
|
||||
const showPlaceholder =
|
||||
isEncrypted && !resolvedUrl && !hasError && !!url && !isAnalyzing;
|
||||
|
||||
const showMedia = !!url && !isAnalyzing && (!isEncrypted || !!resolvedUrl);
|
||||
|
||||
// Track pending placeholders in the provider
|
||||
const wasShowingPlaceholder = useRef(false);
|
||||
useEffect(() => {
|
||||
if (showPlaceholder && !wasShowingPlaceholder.current) {
|
||||
registerPlaceholder();
|
||||
wasShowingPlaceholder.current = true;
|
||||
} else if (!showPlaceholder && wasShowingPlaceholder.current) {
|
||||
unregisterPlaceholder();
|
||||
wasShowingPlaceholder.current = false;
|
||||
}
|
||||
}, [showPlaceholder, registerPlaceholder, unregisterPlaceholder]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (wasShowingPlaceholder.current) {
|
||||
unregisterPlaceholder();
|
||||
}
|
||||
};
|
||||
}, [unregisterPlaceholder]);
|
||||
|
||||
return {
|
||||
isEncrypted,
|
||||
resolvedUrl,
|
||||
|
||||
Reference in New Issue
Block a user