Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NEW] Attachment Files Redesign #27470

Merged
merged 30 commits into from
Jan 18, 2023
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
f11c79c
wip
hugocostadev Dec 5, 2022
f41c2c2
Merge remote-tracking branch 'origin/develop' into feat/attachment-file
hugocostadev Dec 5, 2022
3c98a7c
feat: New File attachment Component
hugocostadev Dec 6, 2022
6251bdc
Merge remote-tracking branch 'origin/develop' into feat/attachment-file
hugocostadev Dec 6, 2022
64d41eb
fixing importings
hugocostadev Dec 6, 2022
d85b737
removing unnecessary code
hugocostadev Dec 6, 2022
eea6b03
Update
gabriellsh Dec 20, 2022
1d09a49
Merge branch 'develop' of github.com:RocketChat/Rocket.Chat into feat…
gabriellsh Dec 20, 2022
16d18e6
update again :'(
gabriellsh Dec 20, 2022
ea1e8d2
Merge branch 'develop' into feat/attachment-file
hugocostadev Dec 28, 2022
dd56686
fix: lint error
hugocostadev Dec 28, 2022
ed0ec74
Merge remote-tracking branch 'origin/develop' into feat/attachment-file
hugocostadev Dec 29, 2022
9e24540
fix: fixing e2e tests selector
hugocostadev Dec 29, 2022
219670a
Merge remote-tracking branch 'origin/develop' into feat/attachment-file
hugocostadev Jan 2, 2023
3cf97af
Merge branch 'develop' into feat/attachment-file
hugocostadev Jan 3, 2023
d60ac77
Merge remote-tracking branch 'origin/develop' into feat/attachment-file
hugocostadev Jan 4, 2023
3893888
reverting attachments to old max-width
hugocostadev Jan 4, 2023
43621a7
fix: prefetching image size when sizes are not avalible
hugocostadev Jan 5, 2023
a44a18a
Merge remote-tracking branch 'origin/develop' into feat/attachment-file
hugocostadev Jan 5, 2023
5a95ba5
updating yarn.lock
hugocostadev Jan 5, 2023
72d2caa
creating function helper to get file extension
hugocostadev Jan 5, 2023
f2c9941
rewriting tests
hugocostadev Jan 5, 2023
70c590e
Merge branch 'develop' into feat/attachment-file
tassoevan Jan 10, 2023
061db82
Merge branch 'develop' into feat/attachment-file
tassoevan Jan 10, 2023
6c69c5e
Merge branch 'develop' into feat/attachment-file
casalsgh Jan 10, 2023
3fe066f
Workaround flaky E2E test
tassoevan Jan 11, 2023
bb79137
Merge branch 'develop' of github.com:RocketChat/Rocket.Chat into feat…
tassoevan Jan 11, 2023
5a2b2c4
fix: editing attachment description
hugocostadev Jan 11, 2023
63958ba
Merge remote-tracking branch 'origin/develop' into feat/attachment-file
hugocostadev Jan 11, 2023
b56ac3e
Merge remote-tracking branch 'origin/develop' into feat/attachment-file
hugocostadev Jan 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/meteor/app/file-upload/server/lib/FileUpload.js
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ export const FileUpload = {
},

uploadsOnValidate(file) {
if (!/^image\/((x-windows-)?bmp|p?jpeg|png|gif)$/.test(file.type)) {
if (!/^image\/((x-windows-)?bmp|p?jpeg|png|gif|webp)$/.test(file.type)) {
return;
}

Expand Down
8 changes: 8 additions & 0 deletions apps/meteor/app/file-upload/server/methods/sendFileMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import { Meteor } from 'meteor/meteor';
import { Match, check } from 'meteor/check';
import type { MessageAttachment, FileAttachmentProps, IUser, IUpload, AtLeast } from '@rocket.chat/core-typings';
import { Rooms, Uploads } from '@rocket.chat/models';
import { parse } from '@rocket.chat/message-parser';

import { callbacks } from '../../../../lib/callbacks';
import { FileUpload } from '../lib/FileUpload';
import { canAccessRoom } from '../../../authorization/server/functions/canAccessRoom';
import { SystemLogger } from '../../../../server/lib/logger/system';
import { omit } from '../../../../lib/utils/omit';
import { getFileExtension } from '../../../../lib/utils/getFileExtension';

function validateFileRequiredFields(file: Partial<IUpload>): asserts file is AtLeast<IUpload, '_id' | 'name' | 'type' | 'size'> {
const requiredFields = ['_id', 'name', 'type', 'size'];
Expand Down Expand Up @@ -44,6 +46,7 @@ export const parseFileIntoMessageAttachments = async (
title: file.name,
type: 'file',
description: file?.description,
descriptionMd: file.description ? parse(file.description) : undefined,
title_link: fileUrl,
title_link_download: true,
image_url: fileUrl,
Expand Down Expand Up @@ -83,6 +86,7 @@ export const parseFileIntoMessageAttachments = async (
title: file.name,
type: 'file',
description: file.description,
descriptionMd: file.description ? parse(file.description) : undefined,
title_link: fileUrl,
title_link_download: true,
audio_url: fileUrl,
Expand All @@ -95,6 +99,7 @@ export const parseFileIntoMessageAttachments = async (
title: file.name,
type: 'file',
description: file.description,
descriptionMd: file.description ? parse(file.description) : undefined,
title_link: fileUrl,
title_link_download: true,
video_url: fileUrl,
Expand All @@ -106,9 +111,12 @@ export const parseFileIntoMessageAttachments = async (
const attachment = {
title: file.name,
type: 'file',
format: getFileExtension(file.name),
description: file.description,
descriptionMd: file.description ? parse(file.description) : undefined,
title_link: fileUrl,
title_link_download: true,
size: file.size as number,
};
attachments.push(attachment);
}
Expand Down
25 changes: 25 additions & 0 deletions apps/meteor/client/components/message/MessageCollapsible.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Box } from '@rocket.chat/fuselage';
import type { ReactElement, ReactNode } from 'react';
import React from 'react';

import AttachmentDownload from './content/attachments/structure/AttachmentDownload';
import AttachmentSize from './content/attachments/structure/AttachmentSize';
import { useCollapse } from './hooks/useCollapse';

type MessageCollapsibleProps = { children?: ReactNode; title?: string; hasDownload?: boolean; link?: string; size?: number };

const MessageCollapsible = ({ children, title, hasDownload, link, size }: MessageCollapsibleProps): ReactElement => {
const [collapsed, collapse] = useCollapse(false);

return (
<>
<Box display='flex' flexDirection='row' color='hint' fontScale='c1' alignItems='center'>
{title} {size && <AttachmentSize size={size} />} {collapse}{' '}
{hasDownload && link && <AttachmentDownload title={title} href={link} />}
</Box>
{!collapsed && children}
</>
);
};

export default MessageCollapsible;
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import type { FC } from 'react';
import React from 'react';

import { AudioAttachment } from './file/AudioAttachment';
import type { GenericFileAttachmentProps } from './file/GenericFileAttachment';
import { GenericFileAttachment } from './file/GenericFileAttachment';
import { ImageAttachment } from './file/ImageAttachment';
import { VideoAttachment } from './file/VideoAttachment';
Expand All @@ -19,9 +18,8 @@ export const FileAttachment: FC<FileAttachmentProps> = (attachment) => {
if (isFileVideoAttachment(attachment)) {
return <VideoAttachment {...attachment} />;
}
// if (isFilePDFAttachment(attachment)) { return <PDFAttachment {...attachment} />; }

return <GenericFileAttachment {...(attachment as GenericFileAttachmentProps)} />;
return <GenericFileAttachment {...attachment} />;
};

export { GenericFileAttachment, ImageAttachment, VideoAttachment };
Original file line number Diff line number Diff line change
Expand Up @@ -4,45 +4,28 @@ import type { FC } from 'react';
import React from 'react';

import MarkdownText from '../../../../MarkdownText';
import { useCollapse } from '../../../hooks/useCollapse';
import Attachment from '../structure/Attachment';
import AttachmentContent from '../structure/AttachmentContent';
import AttachmentDescription from '../structure/AttachmentDescription';
import AttachmentDownload from '../structure/AttachmentDownload';
import AttachmentRow from '../structure/AttachmentRow';
import AttachmentSize from '../structure/AttachmentSize';
import AttachmentTitle from '../structure/AttachmentTitle';
import MessageCollapsible from '../../../MessageCollapsible';
import MessageContentBody from '../../../MessageContentBody';

export const AudioAttachment: FC<AudioAttachmentProps> = ({
title,
audio_url: url,
audio_type: type,
collapsed: collapsedDefault = false,
audio_size: size,
description,
descriptionMd,
title_link: link,
title_link_download: hasDownload,
}) => {
const [collapsed, collapse] = useCollapse(collapsedDefault);
const getURL = useMediaUrl();
return (
<Attachment>
<AttachmentDescription>
<MarkdownText parseEmoji variant='inline' content={description} />
</AttachmentDescription>
<AttachmentRow>
<AttachmentTitle>{title}</AttachmentTitle>
{size && <AttachmentSize size={size} />}
{collapse}
{hasDownload && link && <AttachmentDownload title={title} href={getURL(link)} />}
</AttachmentRow>
{!collapsed && (
<AttachmentContent border='none'>
<audio controls preload='metadata'>
<source src={getURL(url)} type={type} />
</audio>
</AttachmentContent>
)}
</Attachment>
<>
{descriptionMd ? <MessageContentBody md={descriptionMd} /> : <MarkdownText parseEmoji content={description} />}
<MessageCollapsible title={title} hasDownload={hasDownload} link={getURL(link || url)} size={size}>
<audio controls preload='metadata'>
<source src={getURL(url)} type={type} />
</audio>
</MessageCollapsible>
</>
);
};
Original file line number Diff line number Diff line change
@@ -1,48 +1,51 @@
import type { FileProp, MessageAttachmentBase } from '@rocket.chat/core-typings';
import type { MessageAttachmentBase } from '@rocket.chat/core-typings';
import {
MessageGenericPreview,
MessageGenericPreviewContent,
MessageGenericPreviewIcon,
MessageGenericPreviewTitle,
MessageGenericPreviewDescription,
} from '@rocket.chat/fuselage';
import { useMediaUrl } from '@rocket.chat/ui-contexts';
import type { FC } from 'react';
import React from 'react';

import { getFileExtension } from '../../../../../../lib/utils/getFileExtension';
import MarkdownText from '../../../../MarkdownText';
import Attachment from '../structure/Attachment';
import AttachmentDescription from '../structure/AttachmentDescription';
import AttachmentDownload from '../structure/AttachmentDownload';
import AttachmentRow from '../structure/AttachmentRow';
import MessageCollapsible from '../../../MessageCollapsible';
import MessageContentBody from '../../../MessageContentBody';
import AttachmentSize from '../structure/AttachmentSize';
import AttachmentTitle from '../structure/AttachmentTitle';
import AttachmentTitleLink from '../structure/AttachmentTitleLink';

export type GenericFileAttachmentProps = {
file?: FileProp;
} & MessageAttachmentBase;

export const GenericFileAttachment: FC<GenericFileAttachmentProps> = ({
export const GenericFileAttachment: FC<MessageAttachmentBase> = ({
title,
// collapsed: collapsedDefault = false,
description,
descriptionMd,
title_link: link,
title_link_download: hasDownload,
file: {
size,
// format,
// name,
} = {},
size,
format,
}) => {
// const [collapsed, collapse] = useCollapse(collapsedDefault);
const getURL = useMediaUrl();
return (
<Attachment>
{description && (
<AttachmentDescription>
<MarkdownText parseEmoji content={description} />
</AttachmentDescription>
)}
<AttachmentRow>
{hasDownload && link ? <AttachmentTitleLink link={getURL(link)} title={title} /> : <AttachmentTitle>{title}</AttachmentTitle>}
{size && <AttachmentSize size={size} />}

{hasDownload && link && <AttachmentDownload title={title} href={getURL(link)} />}
</AttachmentRow>
</Attachment>
return (
<>
{descriptionMd ? <MessageContentBody md={descriptionMd} /> : <MarkdownText parseEmoji content={description} />}
<MessageCollapsible title={title} hasDownload={hasDownload} link={link}>
<MessageGenericPreview style={{ maxWidth: 368, width: '100%' }}>
<MessageGenericPreviewContent
thumb={<MessageGenericPreviewIcon name='attachment-file' type={format || getFileExtension(title)} />}
>
<MessageGenericPreviewTitle externalUrl={hasDownload && link ? getURL(link) : undefined} data-qa-type='attachment-title-link'>
{title}
</MessageGenericPreviewTitle>
{size && (
<MessageGenericPreviewDescription>
<AttachmentSize size={size} wrapper={false} />
</MessageGenericPreviewDescription>
)}
</MessageGenericPreviewContent>
</MessageGenericPreview>
</MessageCollapsible>
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,48 +4,34 @@ import type { FC } from 'react';
import React from 'react';

import MarkdownText from '../../../../MarkdownText';
import { useCollapse } from '../../../hooks/useCollapse';
import MessageCollapsible from '../../../MessageCollapsible';
import MessageContentBody from '../../../MessageContentBody';
import Attachment from '../structure/Attachment';
import AttachmentContent from '../structure/AttachmentContent';
import AttachmentDescription from '../structure/AttachmentDescription';
import AttachmentDownload from '../structure/AttachmentDownload';
import AttachmentImage from '../structure/AttachmentImage';
import AttachmentRow from '../structure/AttachmentRow';
import AttachmentSize from '../structure/AttachmentSize';
import AttachmentTitle from '../structure/AttachmentTitle';
import { useLoadImage } from './hooks/useLoadImage';

export const ImageAttachment: FC<ImageAttachmentProps> = ({
title,
image_url: url,
image_preview: imagePreview,
collapsed: collapsedDefault = false,
image_size: size,
image_dimensions: imageDimensions = {
height: 360,
width: 480,
width: 368,
height: 368,
},
description,
descriptionMd,
title_link: link,
title_link_download: hasDownload,
}) => {
const [loadImage, setLoadImage] = useLoadImage();
const [collapsed, collapse] = useCollapse(collapsedDefault);
const getURL = useMediaUrl();

return (
<Attachment>
{description && (
<AttachmentDescription>
<MarkdownText parseEmoji variant='inline' content={description} />
</AttachmentDescription>
)}
<AttachmentRow>
<AttachmentTitle>{title}</AttachmentTitle>
{size && <AttachmentSize size={size} />}
{collapse}
{hasDownload && link && <AttachmentDownload title={title} href={getURL(link)} />}
</AttachmentRow>
{!collapsed && (
{descriptionMd ? <MessageContentBody md={descriptionMd} /> : <MarkdownText parseEmoji content={description} />}
<MessageCollapsible title={title} hasDownload={hasDownload} link={getURL(link || url)} size={size}>
<AttachmentContent>
<AttachmentImage
{...imageDimensions}
Expand All @@ -56,7 +42,7 @@ export const ImageAttachment: FC<ImageAttachmentProps> = ({
previewUrl={`data:image/png;base64,${imagePreview}`}
/>
</AttachmentContent>
)}
</MessageCollapsible>
</Attachment>
);
};
Original file line number Diff line number Diff line change
@@ -1,61 +1,36 @@
import type { VideoAttachmentProps } from '@rocket.chat/core-typings';
import { css } from '@rocket.chat/css-in-js';
import { Box, Palette } from '@rocket.chat/fuselage';
import { Box, MessageGenericPreview } from '@rocket.chat/fuselage';
import { useMediaUrl } from '@rocket.chat/ui-contexts';
import type { FC } from 'react';
import React from 'react';

import { userAgentMIMETypeFallback } from '../../../../../lib/utils/userAgentMIMETypeFallback';
import MarkdownText from '../../../../MarkdownText';
import { useCollapse } from '../../../hooks/useCollapse';
import Attachment from '../structure/Attachment';
import AttachmentContent from '../structure/AttachmentContent';
import AttachmentDetails from '../structure/AttachmentDetails';
import AttachmentDownload from '../structure/AttachmentDownload';
import AttachmentRow from '../structure/AttachmentRow';
import AttachmentSize from '../structure/AttachmentSize';
import AttachmentTitle from '../structure/AttachmentTitle';

const videoAttachmentCss = css`
border: 1px solid ${Palette.stroke['stroke-extra-light']} !important;
border-radius: 2px;
display: flex;
flex-direction: column;
`;
import MessageCollapsible from '../../../MessageCollapsible';
import MessageContentBody from '../../../MessageContentBody';

export const VideoAttachment: FC<VideoAttachmentProps> = ({
title,
video_url: url,
video_type: type,
collapsed: collapsedDefault = false,
video_size: size,
description,
descriptionMd,
title_link: link,
title_link_download: hasDownload,
}) => {
const [collapsed, collapse] = useCollapse(collapsedDefault);
const getURL = useMediaUrl();

return (
<Attachment>
<AttachmentRow>
<AttachmentTitle>{title}</AttachmentTitle>
{size && <AttachmentSize size={size} />}
{collapse}
{hasDownload && link && <AttachmentDownload title={title} href={getURL(link)} />}
</AttachmentRow>
{!collapsed && (
<AttachmentContent width='full' className={videoAttachmentCss}>
<Box is='video' width='full' controls preload='metadata'>
<>
{descriptionMd ? <MessageContentBody md={descriptionMd} /> : <MarkdownText parseEmoji content={description} />}
<MessageCollapsible title={title} hasDownload={hasDownload} link={getURL(link || url)} size={size}>
<MessageGenericPreview style={{ maxWidth: 368, width: '100%' }}>
<Box is='video' controls preload='metadata'>
<source src={getURL(url)} type={userAgentMIMETypeFallback(type)} />
</Box>
{description && (
<AttachmentDetails is='figcaption'>
<MarkdownText parseEmoji variant='inline' content={description} />
</AttachmentDetails>
)}
</AttachmentContent>
)}
</Attachment>
</MessageGenericPreview>
</MessageCollapsible>
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const AttachmentDownload: FC<AttachmentDownloadProps> = ({ title, href, ...props
const t = useTranslation();
return (
<Action
icon='download'
icon='cloud-arrow-down'
href={`${href}?download`}
title={t('Download')}
is='a'
Expand Down
Loading