Skip to content

Commit

Permalink
feat(chat): integrate sharing into stateful api (Issue #322)(#690)
Browse files Browse the repository at this point in the history
  • Loading branch information
mikitabut authored Feb 13, 2024
1 parent 1d7c0ab commit f2d30ce
Show file tree
Hide file tree
Showing 77 changed files with 1,778 additions and 616 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import {
Message,
Replay,
} from '@/chat/types/chat';
import { constructPath } from '@/chat/utils/app/file';
import { getRootId } from '@/chat/utils/app/id';
import { ApiKeys } from '@/chat/utils/server/api';
import { ModelsUtil } from '@/src/utils';
import { v4 as uuidv4 } from 'uuid';

Expand All @@ -18,7 +21,10 @@ export class ConversationBuilder {

constructor() {
this.conversation = {
id: uuidv4(),
id: constructPath(
getRootId({ apiKey: ApiKeys.Conversations }),
DEFAULT_CONVERSATION_NAME,
),
name: DEFAULT_CONVERSATION_NAME,
messages: [],
model: { id: ModelsUtil.getDefaultModel()!.id },
Expand All @@ -28,6 +34,7 @@ export class ConversationBuilder {
selectedAddons: ModelsUtil.getDefaultModel()!.selectedAddons ?? [],
lastActivityDate: Date.now(),
isMessageStreaming: false,
folderId: getRootId({ apiKey: ApiKeys.Conversations }),
};
}

Expand Down Expand Up @@ -70,7 +77,7 @@ export class ConversationBuilder {
return this;
}

withFolderId(folderId: undefined | string): ConversationBuilder {
withFolderId(folderId: string): ConversationBuilder {
this.conversation.folderId = folderId;
return this;
}
Expand Down
9 changes: 0 additions & 9 deletions apps/chat/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,15 +140,6 @@ const nextConfig = {
},
async headers() {
return [
{
source: '/overlay/script.js',
headers: [
{
key: 'Access-Control-Allow-Origin',
value: '*',
},
],
},
{
source: '/:path*',
headers: [
Expand Down
6 changes: 1 addition & 5 deletions apps/chat/public/locales/en/sidebar.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
{
"share.modal.link.description": "This link is temporary and will be active for 3 days.",
"share.modal.link_conversation": "This conversation and future changes to it will be visible to users who follow the link. Only owner will be able to make changes.",
"share.modal.link_prompt": "This prompt and future changes to it will be visible to users who follow the link. Only owner will be able to make changes.",
"share.modal.link_conversations_folder": "This conversation folder and future changes to it will be visible to users who follow the link. Only owner will be able to make changes.",
"share.modal.link_prompts_folder": "This prompt folder and future changes to it will be visible to users who follow the link. Only owner will be able to make changes."
"share.modal.link.description": "This link is temporary and will be active for 3 days."
}
5 changes: 3 additions & 2 deletions apps/chat/src/components/Chat/ChangePathDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
getPathToFolderById,
validateFolderRenaming,
} from '@/src/utils/app/folders';
import { getRootId } from '@/src/utils/app/id';

import { FeatureType } from '@/src/types/common';
import { SharingType } from '@/src/types/share';
Expand Down Expand Up @@ -132,7 +133,7 @@ export const ChangePathDialog = ({
);

const handleAddFolder = useCallback(
(parentFolderId?: string) => {
(parentFolderId: string) => {
dispatch(
actions.createTemporaryFolder({
relativePath: parentFolderId,
Expand Down Expand Up @@ -206,7 +207,7 @@ export const ChangePathDialog = ({
/>
</SelectFolderHeader>
<SelectFolderFooter
handleNewFolder={() => handleAddFolder()}
handleNewFolder={() => handleAddFolder(getRootId())}
onSelectFolderClick={getPath}
/>
</SelectFolder>
Expand Down
6 changes: 5 additions & 1 deletion apps/chat/src/components/Chat/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -855,7 +855,11 @@ export const ChatView = memo(() => {
showReplayStart={!isNotEmptyConversations}
/>
)}
{isExternal && <ChatExternalControls />}
{isExternal && (
<ChatExternalControls
conversations={selectedConversations}
/>
)}
</ChatInput>
)}

Expand Down
13 changes: 10 additions & 3 deletions apps/chat/src/components/Chat/ChatExternalControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,25 @@ import { useCallback } from 'react';

import { useTranslation } from 'next-i18next';

import { ConversationInfo } from '@/src/types/chat';
import { Translation } from '@/src/types/translation';

import { ConversationsActions } from '@/src/store/conversations/conversations.reducers';
import { useAppDispatch } from '@/src/store/hooks';

export default function ChatExternalControls() {
interface Props {
conversations: ConversationInfo[];
}

export default function ChatExternalControls({ conversations }: Props) {
const { t } = useTranslation(Translation.Chat);
const dispatch = useAppDispatch();

const handleDuplicate = useCallback(() => {
dispatch(ConversationsActions.duplicateSelectedConversations());
}, [dispatch]);
conversations.forEach((conv) => {
dispatch(ConversationsActions.duplicateConversation(conv));
});
}, [conversations, dispatch]);

return (
<button
Expand Down
7 changes: 2 additions & 5 deletions apps/chat/src/components/Chat/Publish/PublishWizard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { onBlur } from '@/src/utils/app/style-helpers';

import { ShareEntity } from '@/src/types/common';
import { DialFile } from '@/src/types/files';
import { ModalState } from '@/src/types/modal';
import {
SharingType,
TargetAudienceFilter,
Expand All @@ -47,8 +48,6 @@ import { PublishAttachment } from './PublishAttachment';
import { TargetAudienceFilterComponent } from './TargetAudienceFilter';
import { UserGroupFilter } from './UserGroupFilter';

import { v4 as uuidv4 } from 'uuid';

interface Props {
entity: ShareEntity;
type: SharingType;
Expand Down Expand Up @@ -77,7 +76,6 @@ export default function PublishWizard({
const { t } = useTranslation(Translation.Chat);
const dispatch = useAppDispatch();
const publishAction = getPublishActionByType(type);
const shareId = useRef(uuidv4());
const nameInputRef = useRef<HTMLInputElement>(null);
const [submitted, setSubmitted] = useState(false);
const [name, setName] = useState<string>(entity.name);
Expand Down Expand Up @@ -181,7 +179,6 @@ export default function PublishWizard({
dispatch(
publishAction({
id: entity.id,
shareUniqueId: shareId.current,
name: trimmedName,
path: trimmedPath,
version: trimmedVersion,
Expand Down Expand Up @@ -226,7 +223,7 @@ export default function PublishWizard({
{ 'w-full': files.length },
)}
dataQa="publish-modal"
isOpen={isOpen}
state={isOpen ? ModalState.OPENED : ModalState.CLOSED}
onClose={onClose}
initialFocus={nameInputRef}
>
Expand Down
9 changes: 2 additions & 7 deletions apps/chat/src/components/Chat/ReportIssueDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import classNames from 'classnames';
import { checkValidity } from '@/src/utils/app/forms';
import { onBlur } from '@/src/utils/app/style-helpers';

import { ModalState } from '@/src/types/modal';
import { ReportIssueBody } from '@/src/types/report-issue';
import { Translation } from '@/src/types/translation';

Expand Down Expand Up @@ -115,22 +116,16 @@ export const ReportIssueDialog: FC<Props> = ({ isOpen, onClose }) => {
[description, dispatch, handleClose, t, title],
);

// Render nothing if the dialog is not open.
if (!isOpen) {
return <></>;
}

const inputClassName = classNames('input-form', 'peer', {
'input-invalid': submitted,
submitted: submitted,
});

// Render the dialog.
return (
<Modal
initialFocus={titleInputRef}
portalId="theme-main"
isOpen={isOpen}
state={isOpen ? ModalState.OPENED : ModalState.CLOSED}
onClose={handleClose}
dataQa="request-api-key-dialog"
overlayClassName="fixed inset-0"
Expand Down
8 changes: 2 additions & 6 deletions apps/chat/src/components/Chat/RequestApiKeyDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import classNames from 'classnames';
import { checkValidity } from '@/src/utils/app/forms';
import { onBlur } from '@/src/utils/app/style-helpers';

import { ModalState } from '@/src/types/modal';
import { RequestAPIKeyBody } from '@/src/types/request-api-key';
import { Translation } from '@/src/types/translation';

Expand Down Expand Up @@ -225,11 +226,6 @@ export const RequestAPIKeyDialog: FC<Props> = ({ isOpen, onClose }) => {
],
);

// Render nothing if the dialog is not open.
if (!isOpen) {
return <></>;
}

// Render the dialog.
const inputClassName = classNames('input-form', 'peer', {
'input-invalid': submitted,
Expand All @@ -244,7 +240,7 @@ export const RequestAPIKeyDialog: FC<Props> = ({ isOpen, onClose }) => {
<Modal
initialFocus={projectNameInputRef}
portalId="theme-main"
isOpen={isOpen}
state={isOpen ? ModalState.OPENED : ModalState.CLOSED}
onClose={handleClose}
dataQa="request-api-key-dialog"
overlayClassName="fixed inset-0"
Expand Down
61 changes: 24 additions & 37 deletions apps/chat/src/components/Chat/ShareModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,37 +10,39 @@ import {

import { useTranslation } from 'next-i18next';

import { getShareActionByType } from '@/src/utils/app/share';

import { ShareEntity } from '@/src/types/common';
import { SharingType } from '@/src/types/share';
import { ModalState } from '@/src/types/modal';
import { Translation } from '@/src/types/translation';

import { useAppDispatch } from '@/src/store/hooks';
import { useAppDispatch, useAppSelector } from '@/src/store/hooks';
import { ShareActions, ShareSelectors } from '@/src/store/share/share.reducers';

import Modal from '../Common/Modal';
import Tooltip from '../Common/Tooltip';

import { v4 as uuidv4 } from 'uuid';

interface Props {
entity: ShareEntity;
type: SharingType;
isOpen: boolean;
onClose: () => void;
}

export default function ShareModal({ entity, isOpen, onClose, type }: Props) {
export default function ShareModal() {
const { t } = useTranslation(Translation.SideBar);
const dispatch = useAppDispatch();
const shareAction = getShareActionByType(type);

const copyButtonRef = useRef<HTMLButtonElement>(null);
const [urlCopied, setUrlCopied] = useState(false);
const [urlWasCopied, setUrlWasCopied] = useState(false);
const shareId = useRef(uuidv4());
const url = `${window?.location.origin}/share/${shareId.current}`;
const timeoutRef = useRef<ReturnType<typeof setTimeout>>();

const modalState = useAppSelector(ShareSelectors.selectShareModalState);
const invitationId = useAppSelector(ShareSelectors.selectInvitationId);
const shareResourceName = useAppSelector(
ShareSelectors.selectShareResourceName,
);
const [url, setUrl] = useState('');

useEffect(() => {
setUrl(`${window?.location.origin}/share/${invitationId || ''}`);
}, [invitationId]);

const handleClose = useCallback(() => {
dispatch(ShareActions.setModalState({ modalState: ModalState.CLOSED }));
}, [dispatch]);

const handleCopy = useCallback(
(e: MouseEvent<HTMLButtonElement> | ClipboardEvent<HTMLInputElement>) => {
e.preventDefault();
Expand All @@ -55,13 +57,10 @@ export default function ShareModal({ entity, isOpen, onClose, type }: Props) {
}, 2000);
if (!urlWasCopied) {
setUrlWasCopied(true);
dispatch(
shareAction({ id: entity.id, shareUniqueId: shareId.current }),
);
}
});
},
[dispatch, entity.id, shareAction, url, urlWasCopied],
[url, urlWasCopied],
);

useEffect(() => () => clearTimeout(timeoutRef.current), []);
Expand All @@ -71,26 +70,14 @@ export default function ShareModal({ entity, isOpen, onClose, type }: Props) {
portalId="theme-main"
containerClassName="inline-block w-full max-w-[424px] p-6"
dataQa="share-modal"
isOpen={isOpen}
onClose={onClose}
state={modalState}
onClose={handleClose}
heading={`${t('Share')}: ${shareResourceName?.trim()}`}
>
<div className="flex flex-col justify-between gap-2">
<h4 className="max-h-[50px] text-base font-semibold">
<Tooltip tooltip={entity.name.trim()}>
<span
className="line-clamp-2 break-words"
data-qa="share-chat-name"
>
{`${t('Share')}: ${entity.name.trim()}`}
</span>
</Tooltip>
</h4>
<p className="text-sm text-secondary">
{t('share.modal.link.description')}
</p>
<p className="text-sm text-secondary">
{t('share.modal.link', { context: type })}
</p>
<div className="relative mt-2">
<Tooltip tooltip={url}>
<input
Expand Down
13 changes: 4 additions & 9 deletions apps/chat/src/components/Chat/UnpublishModal.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import { ClipboardEvent, MouseEvent, useCallback, useRef } from 'react';
import { ClipboardEvent, MouseEvent, useCallback } from 'react';

import { useTranslation } from 'next-i18next';

import { getUnpublishActionByType } from '@/src/utils/app/share';

import { Entity } from '@/src/types/common';
import { ModalState } from '@/src/types/modal';
import { SharingType } from '@/src/types/share';
import { Translation } from '@/src/types/translation';

import { useAppDispatch } from '@/src/store/hooks';

import Modal from '../Common/Modal';

import { v4 as uuidv4 } from 'uuid';

interface Props {
entity: Entity;
type: SharingType;
Expand All @@ -30,8 +29,6 @@ export default function UnpublishModal({
const { t } = useTranslation(Translation.SideBar);
const dispatch = useAppDispatch();
const unpublishAction = getUnpublishActionByType(type);
const shareId = useRef(uuidv4());

const handleClose = useCallback(
(e: MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
Expand All @@ -47,9 +44,7 @@ export default function UnpublishModal({
e.preventDefault();
e.stopPropagation();

dispatch(
unpublishAction({ id: entity.id, shareUniqueId: shareId.current }),
);
dispatch(unpublishAction({ id: entity.id }));
onClose();
},
[dispatch, entity.id, onClose, unpublishAction],
Expand All @@ -60,7 +55,7 @@ export default function UnpublishModal({
portalId="theme-main"
containerClassName="inline-block h-[434px] sm:w-[424px] p-6 w-full"
dataQa="unpublish-modal"
isOpen={isOpen}
state={isOpen ? ModalState.OPENED : ModalState.CLOSED}
onClose={onClose}
>
<div className="flex h-full flex-col justify-between gap-2">
Expand Down
Loading

0 comments on commit f2d30ce

Please sign in to comment.