-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: update history list ui and implement delete / update /search (#4)
* feat: update history list ui and implement delete / update /search Signed-off-by: Lin Wang <[email protected]> * refactor: Address PR comments Signed-off-by: Lin Wang <[email protected]> --------- Signed-off-by: Lin Wang <[email protected]>
- Loading branch information
Showing
8 changed files
with
504 additions
and
61 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import React, { useCallback, useRef } from 'react'; | ||
|
||
import { EuiConfirmModal, EuiFieldText, EuiSpacer, EuiText } from '@elastic/eui'; | ||
import { usePatchSession } from '../hooks/use_sessions'; | ||
|
||
interface EditConversationNameModalProps { | ||
onClose?: (status: 'updated' | 'cancelled' | 'errored') => void; | ||
sessionId: string; | ||
defaultTitle: string; | ||
} | ||
|
||
export const EditConversationNameModal = ({ | ||
onClose, | ||
sessionId, | ||
defaultTitle, | ||
}: EditConversationNameModalProps) => { | ||
const titleInputRef = useRef<HTMLInputElement>(null); | ||
const { loading, abortController, patchSession } = usePatchSession(); | ||
|
||
const handleCancel = useCallback(() => { | ||
abortController?.abort(); | ||
onClose?.('cancelled'); | ||
}, [onClose, abortController]); | ||
const handleConfirm = useCallback(async () => { | ||
const title = titleInputRef.current?.value.trim(); | ||
if (!title) { | ||
return; | ||
} | ||
try { | ||
await patchSession(sessionId, title); | ||
} catch (_e) { | ||
onClose?.('errored'); | ||
return; | ||
} | ||
onClose?.('updated'); | ||
}, [onClose, sessionId, patchSession]); | ||
|
||
return ( | ||
<EuiConfirmModal | ||
title="Edit conversation name" | ||
onCancel={handleCancel} | ||
onConfirm={handleConfirm} | ||
cancelButtonText="Cancel" | ||
confirmButtonText="Confirm name" | ||
confirmButtonDisabled={loading} | ||
isLoading={loading} | ||
> | ||
<EuiText size="s"> | ||
<p>Please enter a new name for your conversation.</p> | ||
</EuiText> | ||
<EuiSpacer size="xs" /> | ||
<EuiFieldText inputRef={titleInputRef} defaultValue={defaultTitle} /> | ||
</EuiConfirmModal> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import React, { useCallback } from 'react'; | ||
import { | ||
EuiButtonIcon, | ||
EuiFlexGroup, | ||
EuiFlexItem, | ||
EuiHorizontalRule, | ||
EuiLink, | ||
EuiPanel, | ||
EuiText, | ||
} from '@elastic/eui'; | ||
import moment from 'moment'; | ||
|
||
interface ChatHistory { | ||
id: string; | ||
title: string; | ||
updatedTimeMs: number; | ||
} | ||
|
||
interface ChatHistoryListItemProps extends ChatHistory { | ||
hasBottomBorder?: boolean; | ||
onTitleClick?: (id: string, title: string) => void; | ||
onDeleteClick?: (conversation: { id: string }) => void; | ||
onEditClick?: (conversation: { id: string; title: string }) => void; | ||
} | ||
|
||
export const ChatHistoryListItem = ({ | ||
id, | ||
title, | ||
updatedTimeMs, | ||
hasBottomBorder = true, | ||
onTitleClick, | ||
onDeleteClick, | ||
onEditClick, | ||
}: ChatHistoryListItemProps) => { | ||
const handleTitleClick = useCallback(() => { | ||
onTitleClick?.(id, title); | ||
}, [onTitleClick, id, title]); | ||
|
||
const handleDeleteClick = useCallback(() => { | ||
onDeleteClick?.({ id }); | ||
}, [onDeleteClick, id]); | ||
|
||
const handleEditClick = useCallback(() => { | ||
onEditClick?.({ id, title }); | ||
}, [onEditClick, id, title]); | ||
|
||
return ( | ||
<> | ||
<EuiFlexGroup gutterSize="xs"> | ||
<EuiFlexItem> | ||
<EuiLink onClick={handleTitleClick}> | ||
<EuiText size="s"> | ||
<p | ||
style={{ | ||
display: '-webkit-box', | ||
WebkitLineClamp: 2, | ||
WebkitBoxOrient: 'vertical', | ||
overflow: 'hidden', | ||
}} | ||
> | ||
{title} | ||
</p> | ||
</EuiText> | ||
</EuiLink> | ||
<EuiText size="s" color="subdued"> | ||
{moment(updatedTimeMs).format('MMMM D, YYYY')} at{' '} | ||
{moment(updatedTimeMs).format('h:m A')} | ||
</EuiText> | ||
</EuiFlexItem> | ||
<EuiFlexItem grow={false}> | ||
<EuiFlexGroup gutterSize="s"> | ||
<EuiFlexItem grow={false}> | ||
<EuiButtonIcon | ||
onClick={handleEditClick} | ||
iconType="pencil" | ||
color="ghost" | ||
aria-label="Edit conversation name" | ||
/> | ||
</EuiFlexItem> | ||
<EuiFlexItem grow={false}> | ||
<EuiButtonIcon | ||
onClick={handleDeleteClick} | ||
iconType="trash" | ||
color="danger" | ||
aria-label="Delete conversation" | ||
/> | ||
</EuiFlexItem> | ||
</EuiFlexGroup> | ||
</EuiFlexItem> | ||
</EuiFlexGroup> | ||
{hasBottomBorder && <EuiHorizontalRule />} | ||
</> | ||
); | ||
}; | ||
|
||
export interface ChatHistoryListProps { | ||
chatHistories: ChatHistory[]; | ||
onChatHistoryTitleClick?: (id: string, title: string) => void; | ||
onChatHistoryDeleteClick?: (conversation: { id: string }) => void; | ||
onChatHistoryEditClick?: (conversation: { id: string; title: string }) => void; | ||
} | ||
|
||
export const ChatHistoryList = ({ | ||
chatHistories, | ||
onChatHistoryTitleClick, | ||
onChatHistoryEditClick, | ||
onChatHistoryDeleteClick, | ||
}: ChatHistoryListProps) => { | ||
return ( | ||
<> | ||
<EuiPanel hasBorder hasShadow> | ||
{chatHistories.map((item, index) => ( | ||
<ChatHistoryListItem | ||
key={item.id} | ||
id={item.id} | ||
title={item.title} | ||
updatedTimeMs={item.updatedTimeMs} | ||
hasBottomBorder={index + 1 < chatHistories.length} | ||
onTitleClick={onChatHistoryTitleClick} | ||
onEditClick={onChatHistoryEditClick} | ||
onDeleteClick={onChatHistoryDeleteClick} | ||
/> | ||
))} | ||
</EuiPanel> | ||
</> | ||
); | ||
}; |
Oops, something went wrong.