Improvement/V2/generic_obscure_component_wrapper (#4794)

Created PrivateContent Component to be used as wrapper. 

This way all tools that need to obscure contents can update this
wrapper.

---------

Co-authored-by: Connor Yoh <[email protected]>
Co-authored-by: James Brunton <[email protected]>
This commit is contained in:
ConnorYoh
2025-11-10 11:24:14 +00:00
committed by GitHub
co-authored by Connor Yoh James Brunton
parent 45389340ed
commit f4543d26cd
18 changed files with 237 additions and 166 deletions
@@ -3,6 +3,7 @@ import { Menu, Loader, Group, Text } from '@mantine/core';
import VisibilityIcon from '@mui/icons-material/Visibility';
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
import FitText from '@app/components/shared/FitText';
import { PrivateContent } from '@app/components/shared/PrivateContent';
interface FileDropdownMenuProps {
displayName: string;
@@ -31,7 +32,9 @@ export const FileDropdownMenu: React.FC<FileDropdownMenuProps> = ({
) : (
<VisibilityIcon fontSize="small" />
)}
<FitText text={displayName} fontSize={14} minimumFontScale={0.6} className="ph-no-capture" />
<PrivateContent>
<FitText text={displayName} fontSize={14} minimumFontScale={0.6} />
</PrivateContent>
<KeyboardArrowDownIcon fontSize="small" />
</div>
</Menu.Target>
@@ -61,7 +64,9 @@ export const FileDropdownMenu: React.FC<FileDropdownMenuProps> = ({
>
<Group gap="xs" style={{ width: '100%', justifyContent: 'space-between' }}>
<div style={{ flex: 1, textAlign: 'left', minWidth: 0 }}>
<FitText text={itemName} fontSize={14} minimumFontScale={0.7} className="ph-no-capture" />
<PrivateContent>
<FitText text={itemName} fontSize={14} minimumFontScale={0.7} />
</PrivateContent>
</div>
{file.versionNumber && file.versionNumber > 1 && (
<Text size="xs" c="dimmed">
@@ -0,0 +1,40 @@
import React from 'react';
interface PrivateContentProps extends React.HTMLAttributes<HTMLSpanElement> {
children: React.ReactNode;
}
/**
* Wrapper component for content that should not be captured by analytics tools.
* Currently applies the 'ph-no-capture' className to prevent PostHog capture.
*
* Uses `display: contents` to be layout-invisible - the wrapper exists in the DOM
* for analytics filtering, but doesn't affect layout, flexbox, grid, or styling.
*
* Use this component to wrap any content containing sensitive or private information
* that should be excluded from analytics tracking.
*
* @example
* <PrivateContent>
* <Text>Sensitive filename.pdf</Text>
* </PrivateContent>
*
* <PrivateContent>
* <img src={thumbnail} alt="preview" />
* </PrivateContent>
*/
export const PrivateContent: React.FC<PrivateContentProps> = ({
children,
className = '',
style,
...props
}) => {
const combinedClassName = `ph-no-capture${className ? ` ${className}` : ''}`;
const combinedStyle = { display: 'contents' as const, ...style };
return (
<span className={combinedClassName} style={combinedStyle} {...props}>
{children}
</span>
);
};
@@ -9,6 +9,7 @@ import PictureAsPdfIcon from "@mui/icons-material/PictureAsPdf";
import { WorkbenchType, isValidWorkbench } from '@app/types/workbench';
import type { CustomWorkbenchViewInstance } from '@app/contexts/ToolWorkflowContext';
import { FileDropdownMenu } from '@app/components/shared/FileDropdownMenu';
import { PrivateContent } from '@app/components/shared/PrivateContent';
const viewOptionStyle: React.CSSProperties = {
@@ -54,7 +55,7 @@ const createViewOptions = (
) : (
<VisibilityIcon fontSize="small" />
)}
<span className="ph-no-capture">{displayName}</span>
<PrivateContent>{displayName}</PrivateContent>
</div>
),
value: "viewer",
@@ -2,6 +2,7 @@ import React from 'react';
import { Box, Center, Image } from '@mantine/core';
import PictureAsPdfIcon from '@mui/icons-material/PictureAsPdf';
import { StirlingFileStub } from '@app/types/fileContext';
import { PrivateContent } from '@app/components/shared/PrivateContent';
export interface DocumentThumbnailProps {
file: File | StirlingFileStub | null;
@@ -35,13 +36,14 @@ const DocumentThumbnail: React.FC<DocumentThumbnailProps> = ({
if (thumbnail) {
return (
<Box style={containerStyle} onClick={onClick}>
<Image
className='ph-no-capture'
src={thumbnail}
alt={`Preview of ${file.name}`}
fit="contain"
style={{ maxWidth: '100%', maxHeight: '100%' }}
/>
<PrivateContent>
<Image
src={thumbnail}
alt={`Preview of ${file.name}`}
fit="contain"
style={{ maxWidth: '100%', maxHeight: '100%' }}
/>
</PrivateContent>
{children}
</Box>
);
@@ -50,13 +52,14 @@ const DocumentThumbnail: React.FC<DocumentThumbnailProps> = ({
return (
<Box style={containerStyle} onClick={onClick}>
<Center style={{ width: '100%', height: '100%', backgroundColor: 'var(--mantine-color-gray-1)', borderRadius: '0.25rem' }}>
<PictureAsPdfIcon
className='ph-no-capture'
style={{
fontSize: '2rem',
color: 'var(--mantine-color-gray-6)'
}}
/>
<PrivateContent>
<PictureAsPdfIcon
style={{
fontSize: '2rem',
color: 'var(--mantine-color-gray-6)'
}}
/>
</PrivateContent>
</Center>
{children}
</Box>