snapshot of https://github.com/RocketChat/Rocket.Chat.git (develop, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 1s

This commit is contained in:
upstream-mirror
2026-09-16 01:21:02 +05:00
commit 30810eecd7
10161 changed files with 987110 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
import { css } from '@rocket.chat/css-in-js';
import { Box } from '@rocket.chat/fuselage';
import { useAttachmentDimensions } from '@rocket.chat/ui-contexts';
import type { ComponentPropsWithoutRef } from 'react';
const className = css`
white-space: normal;
`;
export type AttachmentProps = ComponentPropsWithoutRef<typeof Box>;
const Attachment = (props: AttachmentProps) => {
const { width } = useAttachmentDimensions();
return (
<Box
rcx-message-attachment
marginBlock={4}
maxWidth={width}
width='full'
display='flex'
overflow='hidden'
flexDirection='column'
className={className}
{...props}
/>
);
};
export default Attachment;

View File

@@ -0,0 +1,10 @@
import { Box } from '@rocket.chat/fuselage';
import type { ComponentPropsWithoutRef } from 'react';
export type AttachmentAuthorProps = ComponentPropsWithoutRef<typeof Box>;
const AttachmentAuthor = (props: AttachmentAuthorProps) => (
<Box display='flex' flexDirection='row' alignItems='center' marginBlockEnd={4} {...props} />
);
export default AttachmentAuthor;

View File

@@ -0,0 +1,7 @@
import { BaseAvatar } from '@rocket.chat/ui-avatar';
export type AttachmentAuthorAvatarProps = { url: string };
const AttachmentAuthorAvatar = ({ url }: AttachmentAuthorAvatarProps) => <BaseAvatar url={url} size='x24' />;
export default AttachmentAuthorAvatar;

View File

@@ -0,0 +1,8 @@
import { Box } from '@rocket.chat/fuselage';
import type { ComponentPropsWithoutRef } from 'react';
export type AttachmentAuthorNameProps = ComponentPropsWithoutRef<typeof Box>;
const AttachmentAuthorName = (props: AttachmentAuthorNameProps) => <Box withTruncatedText fontScale='p2m' marginInline={8} {...props} />;
export default AttachmentAuthorName;

View File

@@ -0,0 +1,9 @@
import { Box } from '@rocket.chat/fuselage';
import type { ComponentPropsWithoutRef } from 'react';
type AttachmentAuthorTimestampProps = ComponentPropsWithoutRef<typeof Box>;
const AttachmentAuthorTimestamp = ({ href, ...props }: AttachmentAuthorTimestampProps) =>
href ? <Box is='a' href={href} color='default' fontScale='c1' {...props} /> : <Box fontScale='c1' {...props} />;
export default AttachmentAuthorTimestamp;

View File

@@ -0,0 +1,25 @@
import { Box } from '@rocket.chat/fuselage';
import type { ReactNode } from 'react';
import Attachment from './Attachment';
export type AttachmentBlockProps = { pre?: ReactNode; color?: string | undefined; children?: ReactNode };
const AttachmentBlock = ({ pre, color = 'annotation', children }: AttachmentBlockProps) => (
<Attachment>
{pre}
<Box
display='flex'
flexDirection='row'
paddingInlineStart={16}
borderRadius={2}
borderInlineStartStyle='solid'
borderInlineStartWidth='default'
borderInlineStartColor={color}
>
{children}
</Box>
</Attachment>
);
export default AttachmentBlock;

View File

@@ -0,0 +1,8 @@
import { Box } from '@rocket.chat/fuselage';
import type { ComponentPropsWithoutRef } from 'react';
export type AttachmentContentProps = ComponentPropsWithoutRef<typeof Box>;
const AttachmentContent = (props: AttachmentContentProps) => <Box rcx-attachment__content width='full' marginBlock={4} {...props} />;
export default AttachmentContent;

View File

@@ -0,0 +1,10 @@
import { Box } from '@rocket.chat/fuselage';
import type { ComponentPropsWithoutRef } from 'react';
export type AttachmentDetailsProps = ComponentPropsWithoutRef<typeof Box>;
const AttachmentDetails = (props: AttachmentDetailsProps) => (
<Box rcx-attachment__details fontScale='p2' color='default' backgroundColor='surface-tint' padding={16} {...props} />
);
export default AttachmentDetails;

View File

@@ -0,0 +1,19 @@
import type { ComponentPropsWithoutRef } from 'react';
import AttachmentDownloadBase from './AttachmentDownloadBase';
import AttachmentEncryptedDownload from './AttachmentEncryptedDownload';
import type Action from '../../Action';
export type AttachmentDownloadProps = Omit<ComponentPropsWithoutRef<typeof Action>, 'icon'> & { title?: string | undefined; href: string };
const AttachmentDownload = ({ title, href, ...props }: AttachmentDownloadProps) => {
const isEncrypted = href.includes('/file-decrypt/');
if (isEncrypted) {
return <AttachmentEncryptedDownload title={title} href={href} {...props} />;
}
return <AttachmentDownloadBase title={title} href={href} {...props} />;
};
export default AttachmentDownload;

View File

@@ -0,0 +1,26 @@
import type { ComponentProps } from 'react';
import { useTranslation } from 'react-i18next';
import Action from '../../Action';
export type AttachmentDownloadBaseProps = Omit<ComponentProps<typeof Action>, 'icon'> & { title?: string | undefined; href: string };
const AttachmentDownloadBase = ({ title, href, disabled, ...props }: AttachmentDownloadBaseProps) => {
const { t } = useTranslation();
return (
<Action
icon='cloud-arrow-down'
href={`${href}?download`}
title={disabled ? t('Download_Disabled') : t('Download')}
is='a'
target='_blank'
rel='noopener noreferrer'
download={title}
disabled={disabled}
{...props}
/>
);
};
export default AttachmentDownloadBase;

View File

@@ -0,0 +1,14 @@
import type { ComponentProps } from 'react';
import AttachmentDownloadBase from './AttachmentDownloadBase';
import { useDownloadFromServiceWorker } from '../../../../../hooks/useDownloadFromServiceWorker';
type AttachmentDownloadProps = ComponentProps<typeof AttachmentDownloadBase>;
const AttachmentEncryptedDownload = ({ title, href, ...props }: AttachmentDownloadProps) => {
const encryptedAnchorProps = useDownloadFromServiceWorker(href, title);
return <AttachmentDownloadBase {...props} {...encryptedAnchorProps} title={title} href={href} />;
};
export default AttachmentEncryptedDownload;

View File

@@ -0,0 +1,97 @@
import { Box } from '@rocket.chat/fuselage';
import { useAttachmentDimensions } from '@rocket.chat/ui-contexts';
import { memo, useState, useMemo } from 'react';
import ImageBox from './image/ImageBox';
import Load from './image/Load';
import Retry from './image/Retry';
export type AttachmentImageProps = {
previewUrl?: string;
dataSrc?: string;
src: string;
loadImage?: boolean;
setLoadImage: () => void;
id: string | undefined;
width: number;
height: number;
alt?: string;
} & ({ loadImage: true } | { loadImage: false; setLoadImage: () => void });
const getDimensions = (
originalWidth: number,
originalHeight: number,
limits: { width: number; height: number },
): { width: number; height: number; ratio: number } => {
const widthRatio = originalWidth / limits.width;
const heightRatio = originalHeight / limits.height;
if (widthRatio > heightRatio) {
const width = Math.min(originalWidth, limits.width);
const height = (width / originalWidth) * originalHeight;
return { width, height, ratio: (height / width) * 100 };
}
const height = Math.min(originalHeight, limits.height);
const width = (height / originalHeight) * originalWidth;
return { width, height, ratio: (height / width) * 100 };
};
const AttachmentImage = ({ id, previewUrl, dataSrc, loadImage = true, setLoadImage, src, alt = '', ...size }: AttachmentImageProps) => {
const limits = useAttachmentDimensions();
const [error, setError] = useState(false);
const { width = limits.width, height = limits.height } = size;
const { setHasNoError } = useMemo(
() => ({
setHasNoError: (): void => setError(false),
}),
[],
);
const dimensions = getDimensions(width, height, limits);
const background = previewUrl && `url(${previewUrl}) center center / cover no-repeat fixed`;
if (!loadImage) {
return <Load width={dimensions.width || limits.width} height={dimensions.height || limits.height} load={setLoadImage} />;
}
if (error) {
return <Retry retry={setHasNoError} />;
}
return (
<Box width={dimensions.width} maxWidth='full' position='relative'>
<Box paddingBlockStart={`${dimensions.ratio}%`} position='relative'>
<ImageBox
is='picture'
position='absolute'
onError={() => setError(true)}
style={{
...(previewUrl && { background, boxSizing: 'content-box' }),
top: 0,
left: 0,
bottom: 0,
right: 0,
}}
>
<img
data-id={id}
className='gallery-item'
data-src={dataSrc || src}
src={src}
alt={alt}
width={dimensions.width}
height={dimensions.height}
loading='lazy'
/>
</ImageBox>
</Box>
</Box>
);
};
export default memo(AttachmentImage);

View File

@@ -0,0 +1,8 @@
import { Box } from '@rocket.chat/fuselage';
import type { ComponentPropsWithoutRef } from 'react';
export type AttachmentInnerProps = ComponentPropsWithoutRef<typeof Box>;
const AttachmentInner = (props: AttachmentInnerProps) => <Box {...props} />;
export default AttachmentInner;

View File

@@ -0,0 +1,14 @@
import type { Box } from '@rocket.chat/fuselage';
import { IconButton } from '@rocket.chat/fuselage';
import type { ComponentPropsWithoutRef } from 'react';
import { useTranslation } from 'react-i18next';
type AttachmentAuthorMessageLinkProps = ComponentPropsWithoutRef<typeof Box>;
const AttachmentAuthorMessageLink = ({ href, ...props }: AttachmentAuthorMessageLinkProps) => {
const { t } = useTranslation();
return <IconButton marginInlineStart={4} mini is='a' href={href} icon='jump' title={t('Jump_to_message')} {...props} />;
};
export default AttachmentAuthorMessageLink;

View File

@@ -0,0 +1,10 @@
import { Box } from '@rocket.chat/fuselage';
import type { ComponentPropsWithoutRef } from 'react';
export type AttachmentRowProps = ComponentPropsWithoutRef<typeof Box>;
const AttachmentRow = (props: AttachmentRowProps) => (
<Box marginInline={-2} marginBlockEnd={2} rcx-message-attachment display='flex' alignItems='center' {...props} />
);
export default AttachmentRow;

View File

@@ -0,0 +1,21 @@
import type { Box } from '@rocket.chat/fuselage';
import type { ComponentPropsWithoutRef } from 'react';
import Title from './AttachmentTitle';
import { useFormatMemorySize } from '../../../../../hooks/useFormatMemorySize';
export type AttachmentSizeProps = ComponentPropsWithoutRef<typeof Box> & { size: number; wrapper?: boolean };
const AttachmentSize = ({ size, wrapper = true, ...props }: AttachmentSizeProps) => {
const format = useFormatMemorySize();
const formattedSize = wrapper ? `(${format(size)})` : format(size);
return (
<Title flexShrink={0} {...props}>
{formattedSize}
</Title>
);
};
export default AttachmentSize;

View File

@@ -0,0 +1,22 @@
import { Box } from '@rocket.chat/fuselage';
import type { ComponentPropsWithoutRef } from 'react';
import { useTranslation } from 'react-i18next';
export type AttachmentTextProps = ComponentPropsWithoutRef<typeof Box>;
const AttachmentText = (props: AttachmentTextProps) => {
const { t } = useTranslation();
return (
<Box
role='document'
aria-roledescription={t('message_attachment')}
marginBlockEnd={4}
marginInline={2}
fontScale='p2'
color='default'
{...props}
/>
);
};
export default AttachmentText;

View File

@@ -0,0 +1,12 @@
import { Box, Avatar } from '@rocket.chat/fuselage';
import { memo } from 'react';
export type AttachmentThumbProps = { url: string };
const AttachmentThumb = ({ url }: AttachmentThumbProps) => (
<Box marginInlineStart={8}>
<Avatar {...({ url, size: 'x48' } as any)} />
</Box>
);
export default memo(AttachmentThumb);

View File

@@ -0,0 +1,8 @@
import { Box } from '@rocket.chat/fuselage';
import type { ComponentPropsWithoutRef } from 'react';
export type AttachmentTitleProps = ComponentPropsWithoutRef<typeof Box>;
const AttachmentTitle = (props: AttachmentTitleProps) => <Box withTruncatedText marginInline={2} fontScale='c1' color='hint' {...props} />;
export default AttachmentTitle;

View File

@@ -0,0 +1,23 @@
import { Box } from '@rocket.chat/fuselage';
import type { ComponentPropsWithoutRef } from 'react';
export type ImageBoxProps = ComponentPropsWithoutRef<typeof Box>;
const ImageBox = (props: ImageBoxProps) => (
<Box
display='flex'
maxWidth='full'
flexDirection='column'
justifyContent='center'
alignItems='center'
alignContent='center'
borderRadius={2}
borderWidth='default'
borderStyle='solid'
borderColor='extra-light'
position='relative'
{...props}
/>
);
export default ImageBox;

View File

@@ -0,0 +1,31 @@
import { css } from '@rocket.chat/css-in-js';
import { Box, Icon, Palette } from '@rocket.chat/fuselage';
import type { ComponentPropsWithoutRef } from 'react';
import { useTranslation } from 'react-i18next';
import ImageBox from './ImageBox';
export type LoadProps = ComponentPropsWithoutRef<typeof Box> & { load: () => void };
const Load = ({ load, ...props }: LoadProps) => {
const { t } = useTranslation();
const clickable = css`
cursor: pointer;
background: ${Palette.surface['surface-tint']};
&:hover,
&:focus {
background: ${Palette.surface['surface-hover']};
}
`;
return (
<ImageBox className={clickable} {...props} onClick={load}>
<Icon name='image' color='hint' size='x64' />
<Box fontScale='h2' color='default'>
{t('Click_to_load')}
</Box>
</ImageBox>
);
};
export default Load;

View File

@@ -0,0 +1,30 @@
import { css } from '@rocket.chat/css-in-js';
import { Box, Icon, Palette } from '@rocket.chat/fuselage';
import { useTranslation } from 'react-i18next';
import ImageBox from './ImageBox';
export type RetryProps = { retry: () => void };
const Retry = ({ retry }: RetryProps) => {
const { t } = useTranslation();
const clickable = css`
cursor: pointer;
background: ${Palette.surface['surface-tint']};
&:hover,
&:focus {
background: ${Palette.surface['surface-hover']};
}
`;
return (
<ImageBox className={clickable} onClick={retry} size='x160'>
<Icon name='refresh' color='hint' size='x64' />
<Box fontScale='h3' color='default' textAlign='center'>
{t('Retry')}
</Box>
</ImageBox>
);
};
export default Retry;