Skip to content

Commit

Permalink
feat: pin conv
Browse files Browse the repository at this point in the history
  • Loading branch information
edwardzjl committed Jan 31, 2024
1 parent e5082ba commit f808c1f
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 9 deletions.
1 change: 1 addition & 0 deletions api/chatbot/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
class Conversation(JsonModel):
title: str
owner: str = Field(index=True)
pinned: bool = False
created_at: datetime = Field(default_factory=utcnow)
updated_at: datetime = created_at

Expand Down
13 changes: 10 additions & 3 deletions api/chatbot/routers/conversation.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ async def get_conversations(
userid: Annotated[str | None, UserIdHeader()] = None
) -> list[Conversation]:
convs = await ORMConversation.find(ORMConversation.owner == userid).all()
convs.sort(key=lambda x: x.updated_at, reverse=True)
convs.sort(key=lambda x: (x.pinned, x.updated_at), reverse=True)
return [Conversation(**conv.dict()) for conv in convs]


Expand Down Expand Up @@ -72,9 +72,16 @@ async def update_conversation(
payload: UpdateConversation,
userid: Annotated[str | None, UserIdHeader()] = None,
) -> ConversationDetail:
modified = False
conv = await ORMConversation.get(conversation_id)
conv.title = payload.title
await conv.save()
if payload.title is not None:
conv.title = payload.title
modified = True
if payload.pinned is not None:
conv.pinned = payload.pinned
modified = True
if modified:
await conv.save()
return ConversationDetail(**conv.dict())


Expand Down
4 changes: 3 additions & 1 deletion api/chatbot/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class Conversation(BaseModel):
id: Optional[str] = None
title: str
owner: str
pinned: bool = False
created_at: datetime = Field(default_factory=utcnow)
updated_at: datetime = created_at

Expand All @@ -92,7 +93,8 @@ class CreateConversation(BaseModel):


class UpdateConversation(BaseModel):
title: str
title: Optional[str] = None
pinned: Optional[bool] = None


class UserProfile(BaseModel):
Expand Down
1 change: 1 addition & 0 deletions web/src/routes/conversation/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export async function action({ params, request }) {
},
body: JSON.stringify({
title: conversation.title,
pinned: conversation.pinned,
}),
})
if (!resp.ok) {
Expand Down
26 changes: 21 additions & 5 deletions web/src/routes/root/SideMenuButton/index.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import "./index.css";

import { useState, useRef } from "react";
import { useSubmit } from "react-router-dom";
import { useFetcher } from "react-router-dom";
import Tooltip from "@mui/material/Tooltip";

import AutoAwesomeIcon from '@mui/icons-material/AutoAwesome';
import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline";
import DriveFileRenameOutlineIcon from "@mui/icons-material/DriveFileRenameOutline";
import MoreVertIcon from '@mui/icons-material/MoreVert';
import AutoAwesomeIcon from '@mui/icons-material/AutoAwesome';
import PushPinOutlinedIcon from '@mui/icons-material/PushPinOutlined';

import { DropdownMenu, DropdownHeader, DropdownList } from "components/DropdownMenu";
import { summarizeConversation } from "requests";
Expand All @@ -21,7 +22,7 @@ import { summarizeConversation } from "requests";
* @returns
*/
const ChatTab = ({ chat, isActive, onDeleteClick }) => {
const submit = useSubmit();
const fetcher = useFetcher();

const titleRef = useRef(null);
const [titleEditable, setTitleEditable] = useState("false");
Expand All @@ -36,8 +37,8 @@ const ChatTab = ({ chat, isActive, onDeleteClick }) => {

const renameChat = async (title) => {
setTitleEditable("false");
submit(
{ title: title },
fetcher.submit(
{ ...chat, title: title },
{ method: "put", action: `/conversations/${chat.id}`, encType: "application/json" }
);
// Maybe set snackbar to inform user?
Expand All @@ -63,6 +64,13 @@ const ChatTab = ({ chat, isActive, onDeleteClick }) => {
});
}

const flipPin = () => {
fetcher.submit(
{ ...chat, pinned: !chat.pinned },
{ method: "put", action: `/conversations/${chat.id}`, encType: "application/json" }
);
};

return (
<>
<Tooltip title={titleRef.current?.innerText}>
Expand All @@ -84,6 +92,14 @@ const ChatTab = ({ chat, isActive, onDeleteClick }) => {
<MoreVertIcon />
</DropdownHeader>
<DropdownList className="chat-op-menu-list">
<li>
<button className="chat-op-menu-item" onClick={flipPin}>
{/* TODO: there's no 'unpin' icon in material icons for now. */}
{/* Please see <https://github.com/google/material-design-icons/issues/1595> */}
{chat.pinned ? <PushPinOutlinedIcon /> : <PushPinOutlinedIcon />}
<span className="chat-op-menu-item-text">{chat.pinned ? "Unpin" : "Pin"}</span>
</button>
</li>
<li>
<button className="chat-op-menu-item" onClick={onSummarizeClick}>
<AutoAwesomeIcon />
Expand Down
3 changes: 3 additions & 0 deletions web/src/routes/root/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ export async function loader() {
lastSevenDays.setDate(lastSevenDays.getDate() - 7);

const groupedConvs = Object.groupBy(conversations, (item) => {
if (item.pinned) {
return "pinned";
}
const itemDate = new Date(item.updated_at);
if (itemDate.toDateString() === today.toDateString()) {
return "Today";
Expand Down

0 comments on commit f808c1f

Please sign in to comment.