Skip to content

Commit

Permalink
feat: additional features for attachments (#222)
Browse files Browse the repository at this point in the history
  • Loading branch information
mikitabut authored Nov 24, 2023
1 parent 5f207c8 commit 4bff925
Show file tree
Hide file tree
Showing 22 changed files with 494 additions and 149 deletions.
2 changes: 1 addition & 1 deletion .env.development
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ IS_IFRAME="false"


# Application UI settings
ENABLED_FEATURES="conversations-section,prompts-section,top-settings,top-clear-conversation,top-chat-info,top-chat-model-settings,empty-chat-settings,header,footer,request-api-key,report-an-issue,likes,conversations-sharing,prompts-sharing,input-files"
ENABLED_FEATURES="conversations-section,prompts-section,top-settings,top-clear-conversation,top-chat-info,top-chat-model-settings,empty-chat-settings,header,footer,request-api-key,report-an-issue,likes,conversations-sharing,prompts-sharing,input-files,attachments-manager"
NEXT_PUBLIC_APP_NAME="Local Development APP Name"
NEXT_PUBLIC_DEFAULT_SYSTEM_PROMPT=""
NEXT_PUBLIC_DEFAULT_TEMPERATURE="1"
Expand Down
8 changes: 8 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"eventsource-parser": "^0.1.0",
"i18next": "^22.4.13",
"isomorphic-dompurify": "^1.8.0",
"mime-types": "^2.1.35",
"next": "13.5.4",
"next-auth": "^4.24.5",
"next-i18next": "^13.2.2",
Expand Down Expand Up @@ -72,6 +73,7 @@
"@trivago/prettier-plugin-sort-imports": "^4.2.0",
"@types/css.escape": "^1.5.0",
"@types/jsdom": "^21.1.1",
"@types/mime-types": "^2.1.4",
"@types/node": "20.9.0",
"@types/react": "18.0.28",
"@types/react-dom": "18.0.11",
Expand Down
9 changes: 5 additions & 4 deletions src/components/Chat/ChatInput/AttachButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { ModelsSelectors } from '@/src/store/models/models.reducers';

import { Menu, MenuItem } from '../../Common/DropdownMenu';
import { Tooltip, TooltipContent, TooltipTrigger } from '../../Common/Tooltip';
import { FileSelect } from '../../Files/FileSelect';
import { FileManagerModal } from '../../Files/FileManagerModal';
import { PreUploadDialog } from '../../Files/PreUploadModal';

export const AttachButton = () => {
Expand Down Expand Up @@ -107,7 +107,7 @@ export const AttachButton = () => {
<div className="flex items-center gap-3">
<IconFileDescription
className="shrink-0 text-gray-500"
size={24}
size={18}
/>
<span>{t('Attach uploaded files')}</span>
</div>
Expand All @@ -118,7 +118,7 @@ export const AttachButton = () => {
className="hover:bg-blue-500/20"
item={
<div className="flex items-center gap-3">
<IconUpload className="shrink-0 text-gray-500" size={24} />
<IconUpload className="shrink-0 text-gray-500" size={18} />
<span>{t('Upload from device')}</span>
</div>
}
Expand All @@ -127,10 +127,11 @@ export const AttachButton = () => {
</Menu>
</div>
{isSelectFilesDialogOpened && (
<FileSelect
<FileManagerModal
isOpen
allowedTypes={availableAttachmentsTypes}
maximumAttachmentsAmount={maximumAttachmentsAmount}
isInConversation={true}
onClose={handleFileSelectClose}
/>
)}
Expand Down
8 changes: 3 additions & 5 deletions src/components/Chat/ChatMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -322,11 +322,9 @@ export const ChatMessage: FC<Props> = memo(
{t(codeWarning)}
</div>
)}
{!!message.custom_content?.attachments?.length && (
<MessageAttachments
attachments={message.custom_content.attachments}
/>
)}
<MessageAttachments
attachments={message.custom_content?.attachments}
/>
<ErrorMessage error={message.errorMessage}></ErrorMessage>
</div>

Expand Down
16 changes: 13 additions & 3 deletions src/components/Chat/MessageAttachment.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
/* eslint-disable @next/next/no-img-element */
import { IconDownload, IconPaperclip } from '@tabler/icons-react';
import { useState } from 'react';
import { useMemo, useState } from 'react';

import { useTranslation } from 'next-i18next';

import { getMappedAttachmentUrl } from '@/src/utils/app/attachments';

import { Attachment } from '@/src/types/chat';
import { ImageMIMEType } from '@/src/types/files';

Expand All @@ -29,6 +31,14 @@ export const MessageAttachment = ({ attachment, isInner }: Props) => {
const [isOpened, setIsOpened] = useState(false);
const [isExpanded, setIsExpanded] = useState(false);
const isOpenable = !attachment.url;
const mappedAttachmentUrl = useMemo(
() => getMappedAttachmentUrl(attachment.url),
[attachment.url],
);
const mappedAttachmentReferenceUrl = useMemo(
() => getMappedAttachmentUrl(attachment.reference_url),
[attachment.reference_url],
);

return (
<div
Expand Down Expand Up @@ -87,7 +97,7 @@ export const MessageAttachment = ({ attachment, isInner }: Props) => {
) : (
<a
download={attachment.title}
href={`api/files?path=${attachment.url}`}
href={mappedAttachmentUrl}
onClick={stopBubbling}
className="text-gray-500 hover:text-blue-500"
>
Expand Down Expand Up @@ -134,7 +144,7 @@ export const MessageAttachment = ({ attachment, isInner }: Props) => {

{attachment.reference_url && (
<a
href={attachment.reference_url}
href={mappedAttachmentReferenceUrl}
target="_blank"
rel="noopener noreferrer"
className="mt-3 block text-blue-500"
Expand Down
22 changes: 17 additions & 5 deletions src/components/Chatbar/components/ChatbarSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ import { useCallback, useState } from 'react';
import { useTranslation } from 'next-i18next';

import { HighlightColor } from '@/src/types/common';
import { Feature } from '@/src/types/features';

import {
ConversationsActions,
ConversationsSelectors,
} from '@/src/store/conversations/conversations.reducers';
import { useAppDispatch, useAppSelector } from '@/src/store/hooks';
import { SettingsSelectors } from '@/src/store/settings/settings.reducers';

import { DEFAULT_CONVERSATION_NAME } from '@/src/constants/default-settings';

Expand All @@ -27,6 +29,7 @@ import {

import FolderPlus from '../../../../public/images/icons/folder-plus.svg';
import { Import } from '../../Settings/Import';
import { ChatbarSettingsContextMenu } from './ChatbarSettingsContextMenu';

export const ChatbarSettings = () => {
const { t } = useTranslation('sidebar');
Expand All @@ -40,6 +43,13 @@ export const ChatbarSettings = () => {
const isStreaming = useAppSelector(
ConversationsSelectors.selectIsConversationsStreaming,
);
const enabledFeatures = useAppSelector(
SettingsSelectors.selectEnabledFeatures,
);
const displayAttachmentFunctionality = enabledFeatures.has(
Feature.AttachmentsManager,
);
const isMoreButtonDisplayed = displayAttachmentFunctionality;

const handleToggleCompare = useCallback(() => {
dispatch(
Expand All @@ -50,12 +60,12 @@ export const ChatbarSettings = () => {
}, [dispatch]);

return (
<div className="flex items-start gap-1 p-2 text-gray-500">
<div className="flex items-start gap-2 p-2 text-gray-500">
{conversations.length > 0 ? (
<Tooltip isTriggerClickable={true}>
<TooltipTrigger>
<button
className="flex h-[38px] w-[38px] cursor-pointer items-center justify-center rounded hover:bg-green/15 hover:text-green md:h-[42px] md:w-[42px]"
className="flex h-[34px] w-[34px] cursor-pointer items-center justify-center rounded hover:bg-green/15 hover:text-green"
onClick={() => {
setIsOpen(true);
}}
Expand Down Expand Up @@ -86,7 +96,7 @@ export const ChatbarSettings = () => {
<Tooltip isTriggerClickable={true}>
<TooltipTrigger>
<button
className="flex h-[38px] w-[38px] cursor-pointer items-center justify-center rounded hover:bg-green/15 hover:text-green md:h-[42px] md:w-[42px]"
className="flex h-[34px] w-[34px] cursor-pointer items-center justify-center rounded hover:bg-green/15 hover:text-green"
onClick={() => {
dispatch(ConversationsActions.exportConversations());
}}
Expand All @@ -101,7 +111,7 @@ export const ChatbarSettings = () => {
<Tooltip isTriggerClickable={true}>
<TooltipTrigger>
<button
className="flex h-[38px] w-[38px] cursor-pointer items-center justify-center rounded hover:bg-green/15 hover:text-green md:h-[42px] md:w-[42px]"
className="flex h-[34px] w-[34px] cursor-pointer items-center justify-center rounded hover:bg-green/15 hover:text-green"
onClick={() =>
dispatch(
ConversationsActions.createFolder({ name: t('New folder') }),
Expand All @@ -118,7 +128,7 @@ export const ChatbarSettings = () => {
<Tooltip isTriggerClickable={true}>
<TooltipTrigger>
<button
className="flex h-[38px] w-[38px] cursor-pointer items-center justify-center rounded hover:bg-green/15 hover:text-green disabled:cursor-not-allowed md:h-[42px] md:w-[42px]"
className="flex h-[34px] w-[34px] cursor-pointer items-center justify-center rounded hover:bg-green/15 hover:text-green disabled:cursor-not-allowed"
onClick={() => {
handleToggleCompare();
}}
Expand All @@ -131,6 +141,8 @@ export const ChatbarSettings = () => {
<TooltipContent>{t('Compare mode')}</TooltipContent>
</Tooltip>

{isMoreButtonDisplayed && <ChatbarSettingsContextMenu />}

<ConfirmDialog
isOpen={isOpen}
heading={t('Confirm clearing all conversations')}
Expand Down
68 changes: 68 additions & 0 deletions src/components/Chatbar/components/ChatbarSettingsContextMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { IconDots, IconPaperclip } from '@tabler/icons-react';
import { useState } from 'react';

import { useTranslation } from 'next-i18next';

import { Feature } from '@/src/types/features';

import { ConversationsSelectors } from '@/src/store/conversations/conversations.reducers';
import { useAppSelector } from '@/src/store/hooks';
import { SettingsSelectors } from '@/src/store/settings/settings.reducers';

import { Menu, MenuItem } from '../../Common/DropdownMenu';
import { FileManagerModal } from '../../Files/FileManagerModal';

export const ChatbarSettingsContextMenu = () => {
const { t } = useTranslation('chatbar');
const [isSelectFilesDialogOpened, setIsSelectFilesDialogOpened] =
useState(false);
const availableAttachmentsTypes = useAppSelector(
ConversationsSelectors.selectAvailableAttachmentsTypes,
);
const maximumAttachmentsAmount = useAppSelector(
ConversationsSelectors.selectMaximumAttachmentsAmount,
);
const enabledFeatures = useAppSelector(
SettingsSelectors.selectEnabledFeatures,
);
const displayAttachmentFunctionality = enabledFeatures.has(
Feature.AttachmentsManager,
);

return (
<>
<Menu
type="contextMenu"
trigger={
<div className="flex h-[34px] w-[34px] items-center justify-center rounded text-gray-500 hover:bg-green/15 hover:text-green">
<IconDots className="rotate-90 " size={24} strokeWidth={1.5} />
</div>
}
>
{displayAttachmentFunctionality && (
<MenuItem
className="hover:bg-blue-500/20"
item={
<div className="flex items-center gap-3">
<IconPaperclip className="shrink-0 text-gray-500" size={18} />
<span>{t('Attachments')}</span>
</div>
}
onClick={() => setIsSelectFilesDialogOpened(true)}
/>
)}
</Menu>

{isSelectFilesDialogOpened && (
<FileManagerModal
isOpen
allowedTypes={availableAttachmentsTypes}
maximumAttachmentsAmount={maximumAttachmentsAmount}
onClose={() => {
setIsSelectFilesDialogOpened(false);
}}
/>
)}
</>
);
};
43 changes: 25 additions & 18 deletions src/components/Files/FileItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,12 @@ export const FileItem = ({ item, level, onEvent }: Props) => {
<div className="flex items-center gap-2 overflow-hidden">
<div className="text-gray-500">
{!isSelected && item.status !== 'FAILED' ? (
<IconFile className="group-hover/file-item:hidden" size={18} />
<IconFile
className={classNames(
item.status !== 'UPLOADING' && 'group-hover/file-item:hidden',
)}
size={18}
/>
) : (
item.status === 'FAILED' && (
<IconExclamationCircle
Expand All @@ -75,23 +80,25 @@ export const FileItem = ({ item, level, onEvent }: Props) => {
/>
)
)}
<div
className={classNames(
'relative h-[18px] w-[18px] group-hover/file-item:flex',
isSelected ? 'flex' : 'hidden',
)}
>
<input
className="checkbox peer h-[18px] w-[18px] bg-gray-100 dark:bg-gray-700"
type="checkbox"
checked={isSelected}
onChange={handleToggleFile}
/>
<IconCheck
size={18}
className="pointer-events-none invisible absolute text-blue-500 peer-checked:visible"
/>
</div>
{item.status !== 'UPLOADING' && (
<div
className={classNames(
'relative h-[18px] w-[18px] group-hover/file-item:flex',
isSelected ? 'flex' : 'hidden',
)}
>
<input
className="checkbox peer h-[18px] w-[18px] bg-gray-100 dark:bg-gray-700"
type="checkbox"
checked={isSelected}
onChange={handleToggleFile}
/>
<IconCheck
size={18}
className="pointer-events-none invisible absolute text-blue-500 peer-checked:visible"
/>
</div>
)}
</div>
<span
className={classNames(
Expand Down
Loading

0 comments on commit 4bff925

Please sign in to comment.