feat: add pin/unpin functionality to chat history
Adds pin/unpin functionality to the chat history sidebar, allowing users to keep important conversations readily accessible. This improves user experience and helps organize past interactions. This feature includes: - Pin/unpin buttons in the chat history sidebar. - Updated database schema to include `is_pinned` field for chat history items. - Localized translations for pin/unpin actions. - Updated UI to display pinned items at the top of the list.
This commit is contained in:
parent
f01f9d0482
commit
d5df8b5c5f
@ -41,6 +41,7 @@
|
||||
"webSearch": "Søger på internettet",
|
||||
"regenerate": "Regenerer",
|
||||
"edit": "Ændre",
|
||||
"delete": "Slet",
|
||||
"saveAndSubmit": "Gem & Indsend",
|
||||
"editMessage": {
|
||||
"placeholder": "Skriv en besked..."
|
||||
@ -102,5 +103,14 @@
|
||||
"custom": "Brugerdefineret"
|
||||
},
|
||||
"citations": "Citater",
|
||||
"downloadCode": "Download Kode"
|
||||
"downloadCode": "Download Kode",
|
||||
"date": {
|
||||
"pinned": "Fastgjort",
|
||||
"today": "I dag",
|
||||
"yesterday": "I går",
|
||||
"last7Days": "Sidste 7 dage",
|
||||
"older": "Ældre"
|
||||
},
|
||||
"pin": "Fastgør",
|
||||
"unpin": "Frigør"
|
||||
}
|
@ -10,9 +10,6 @@
|
||||
"expandedColumns": {
|
||||
"name": "Navn"
|
||||
},
|
||||
"tooltip": {
|
||||
"delete": "Slet"
|
||||
},
|
||||
"confirm": {
|
||||
"delete": "Er du sikker på du vil slette denne viden?"
|
||||
},
|
||||
|
@ -41,6 +41,7 @@
|
||||
"webSearch": "Web durchsuchen",
|
||||
"regenerate": "Neu generieren",
|
||||
"edit": "Bearbeiten",
|
||||
"delete": "Löschen",
|
||||
"saveAndSubmit": "Speichern & Absenden",
|
||||
"editMessage": {
|
||||
"placeholder": "Nachricht eingeben..."
|
||||
@ -102,5 +103,14 @@
|
||||
"custom": "Benutzerdefiniert"
|
||||
},
|
||||
"citations": "Zitate",
|
||||
"downloadCode": "Code herunterladen"
|
||||
"downloadCode": "Code herunterladen",
|
||||
"date": {
|
||||
"pinned": "Angepinnt",
|
||||
"today": "Heute",
|
||||
"yesterday": "Gestern",
|
||||
"last7Days": "Letzte 7 Tage",
|
||||
"older": "Älter"
|
||||
},
|
||||
"pin": "Anheften",
|
||||
"unpin": "Losheften"
|
||||
}
|
@ -10,9 +10,6 @@
|
||||
"expandedColumns": {
|
||||
"name": "Name"
|
||||
},
|
||||
"tooltip": {
|
||||
"delete": "Löschen"
|
||||
},
|
||||
"confirm": {
|
||||
"delete": "Sind Sie sicher, dass Sie dieses Wissen löschen möchten?"
|
||||
},
|
||||
|
@ -41,6 +41,7 @@
|
||||
"webSearch": "Searching the web",
|
||||
"regenerate": "Regenerate",
|
||||
"edit": "Edit",
|
||||
"delete": "Delete",
|
||||
"saveAndSubmit": "Save & Submit",
|
||||
"editMessage": {
|
||||
"placeholder": "Type a message..."
|
||||
@ -106,5 +107,14 @@
|
||||
"ollama": "Ollama Models",
|
||||
"custom": "Custom Models"
|
||||
},
|
||||
"downloadCode": "Download Code"
|
||||
"downloadCode": "Download Code",
|
||||
"date": {
|
||||
"pinned": "Pinned",
|
||||
"today": "Today",
|
||||
"yesterday": "Yesterday",
|
||||
"last7Days": "Last 7 Days",
|
||||
"older": "Older"
|
||||
},
|
||||
"pin": "Pin",
|
||||
"unpin": "Unpin"
|
||||
}
|
@ -10,9 +10,6 @@
|
||||
"expandedColumns": {
|
||||
"name": "Name"
|
||||
},
|
||||
"tooltip": {
|
||||
"delete": "Delete"
|
||||
},
|
||||
"confirm": {
|
||||
"delete": "Are you sure you want to delete this knowledge?"
|
||||
},
|
||||
|
@ -41,6 +41,7 @@
|
||||
"webSearch": "Buscando en la web",
|
||||
"regenerate": "Regenerar",
|
||||
"edit": "Editar",
|
||||
"delete": "Borrar",
|
||||
"saveAndSubmit": "Guardar y Enviar",
|
||||
"editMessage": {
|
||||
"placeholder": "Ingresar un mensaje..."
|
||||
@ -101,5 +102,14 @@
|
||||
"translate": "Traducir"
|
||||
},
|
||||
"citations": "Citas",
|
||||
"downloadCode": "Descargar Código"
|
||||
"downloadCode": "Descargar Código",
|
||||
"date": {
|
||||
"pinned": "Fijado",
|
||||
"today": "Hoy",
|
||||
"yesterday": "Ayer",
|
||||
"last7Days": "Últimos 7 días",
|
||||
"older": "Más antiguo"
|
||||
},
|
||||
"pin": "Fijar",
|
||||
"unpin": "Desfijar"
|
||||
}
|
@ -10,9 +10,6 @@
|
||||
"expandedColumns": {
|
||||
"name": "Nombre"
|
||||
},
|
||||
"tooltip": {
|
||||
"delete": "Borrar"
|
||||
},
|
||||
"confirm": {
|
||||
"delete": "¿Esta seguro que desea borrar este conocimiento?"
|
||||
},
|
||||
|
@ -41,6 +41,7 @@
|
||||
"webSearch": "جستجوی وب",
|
||||
"regenerate": "ایجاد مجدد",
|
||||
"edit": "ویرایش",
|
||||
"delete": "حذف",
|
||||
"saveAndSubmit": "ذخیره و ارسال",
|
||||
"editMessage": {
|
||||
"placeholder": "یک پیام وارد کنید..."
|
||||
@ -95,5 +96,14 @@
|
||||
"advanced": "تنظیمات بیشتر مدل"
|
||||
},
|
||||
"citations": "منابع",
|
||||
"downloadCode": "دانلود کد"
|
||||
"downloadCode": "دانلود کد",
|
||||
"date": {
|
||||
"pinned": "پین شده",
|
||||
"today": "امروز",
|
||||
"yesterday": "دیروز",
|
||||
"last7Days": "۷ روز گذشته",
|
||||
"older": "قدیمیتر"
|
||||
},
|
||||
"pin": "پین کردن",
|
||||
"unpin": "حذف پین"
|
||||
}
|
@ -10,9 +10,6 @@
|
||||
"expandedColumns": {
|
||||
"name": "نام"
|
||||
},
|
||||
"tooltip": {
|
||||
"delete": "حذف"
|
||||
},
|
||||
"confirm": {
|
||||
"delete": "آیا مطمئن هستید که می خواهید این دانش را حذف کنید؟"
|
||||
},
|
||||
|
@ -41,6 +41,7 @@
|
||||
"webSearch": "Recherche sur le Web",
|
||||
"regenerate": "Régénérer",
|
||||
"edit": "Modifier",
|
||||
"delete": "Supprimer",
|
||||
"saveAndSubmit": "Enregistrer et soumettre",
|
||||
"editMessage": {
|
||||
"placeholder": "Tapez un message..."
|
||||
@ -101,5 +102,14 @@
|
||||
"translate": "Traduire"
|
||||
},
|
||||
"citations": "Citations",
|
||||
"downloadCode": "Télécharger le code"
|
||||
"downloadCode": "Télécharger le code",
|
||||
"date": {
|
||||
"pinned": "Épinglé",
|
||||
"today": "Aujourd'hui",
|
||||
"yesterday": "Hier",
|
||||
"last7Days": "7 derniers jours",
|
||||
"older": "Plus ancien"
|
||||
},
|
||||
"pin": "Épingler",
|
||||
"unpin": "Désépingler"
|
||||
}
|
@ -10,9 +10,6 @@
|
||||
"expandedColumns": {
|
||||
"name": "Nom"
|
||||
},
|
||||
"tooltip": {
|
||||
"delete": "Supprimer"
|
||||
},
|
||||
"confirm": {
|
||||
"delete": "Êtes-vous sûr de vouloir supprimer ces connaissances ?"
|
||||
},
|
||||
|
@ -41,6 +41,7 @@
|
||||
"webSearch": "Ricerca nel Web",
|
||||
"regenerate": "Rigenera",
|
||||
"edit": "Modifica",
|
||||
"delete": "Elimina",
|
||||
"saveAndSubmit": "Salva e Invia",
|
||||
"editMessage": {
|
||||
"placeholder": "Scrivi un messaggio..."
|
||||
@ -101,5 +102,14 @@
|
||||
"translate": "Tradurre"
|
||||
},
|
||||
"citations": "Citazioni",
|
||||
"downloadCode": "Scarica Codice"
|
||||
"downloadCode": "Scarica Codice",
|
||||
"date": {
|
||||
"pinned": "Fissato",
|
||||
"today": "Oggi",
|
||||
"yesterday": "Ieri",
|
||||
"last7Days": "Ultimi 7 Giorni",
|
||||
"older": "Più Vecchi"
|
||||
},
|
||||
"pin": "Fissa",
|
||||
"unpin": "Rimuovi"
|
||||
}
|
@ -10,9 +10,6 @@
|
||||
"expandedColumns": {
|
||||
"name": "Nome"
|
||||
},
|
||||
"tooltip": {
|
||||
"delete": "Elimina"
|
||||
},
|
||||
"confirm": {
|
||||
"delete": "Sei sicuro di voler eliminare questa Knowledge Base?"
|
||||
},
|
||||
|
@ -41,6 +41,7 @@
|
||||
"webSearch": "ウェブを検索中",
|
||||
"regenerate": "再生成",
|
||||
"edit": "編集",
|
||||
"delete": "削除",
|
||||
"saveAndSubmit": "保存して送信",
|
||||
"editMessage": {
|
||||
"placeholder": "メッセージを入力..."
|
||||
@ -87,9 +88,9 @@
|
||||
"placeholder": "GPU(s)に送信するレイヤー数を入力してください"
|
||||
},
|
||||
"systemPrompt": {
|
||||
"label": "一時的なシステムプロンプト",
|
||||
"placeholder": "システムプロンプトを入力",
|
||||
"help": "これは現在のチャットでシステムプロンプトを素早く設定する方法で、選択されたシステムプロンプトが存在する場合はそれを上書きします。"
|
||||
"label": "一時的なシステムプロンプト",
|
||||
"placeholder": "システムプロンプトを入力",
|
||||
"help": "これは現在のチャットでシステムプロンプトを素早く設定する方法で、選択されたシステムプロンプトが存在する場合はそれを上書きします。"
|
||||
}
|
||||
},
|
||||
"advanced": "その他のモデル設定"
|
||||
@ -101,5 +102,14 @@
|
||||
"translate": "翻訳"
|
||||
},
|
||||
"citations": "引用",
|
||||
"downloadCode": "コードをダウンロード"
|
||||
"downloadCode": "コードをダウンロード",
|
||||
"date": {
|
||||
"pinned": "固定",
|
||||
"today": "今日",
|
||||
"yesterday": "昨日",
|
||||
"last7Days": "過去7日間",
|
||||
"older": "それ以前"
|
||||
},
|
||||
"pin": "固定",
|
||||
"unpin": "固定解除"
|
||||
}
|
@ -10,9 +10,6 @@
|
||||
"expandedColumns": {
|
||||
"name": "名前"
|
||||
},
|
||||
"tooltip": {
|
||||
"delete": "削除"
|
||||
},
|
||||
"confirm": {
|
||||
"delete": "この知識を削除してもよろしいですか?"
|
||||
},
|
||||
|
@ -41,6 +41,7 @@
|
||||
"webSearch": "വെബ് തിരയുന്നു",
|
||||
"regenerate": "വീണ്ടും ജനറേറ്റ് ചെയ്യുക",
|
||||
"edit": "എഡിറ്റ് ചെയ്യുക",
|
||||
"delete": "ഇല്ലാതാക്കുക",
|
||||
"saveAndSubmit": "സേവ് ചെയ്ത് സമര്പ്പിക്കുക",
|
||||
"editMessage": {
|
||||
"placeholder": "ഒരു സന്ദേശം ടൈപ്പ് ചെയ്യുക..."
|
||||
@ -100,5 +101,14 @@
|
||||
"translate": "വിവർത്തനം ചെയ്യുക"
|
||||
},
|
||||
"citations": "ഉദ്ധരണികൾ",
|
||||
"downloadCode": "കോഡ് ഡൗൺലോഡ് ചെയ്യുക"
|
||||
"downloadCode": "കോഡ് ഡൗൺലോഡ് ചെയ്യുക",
|
||||
"date": {
|
||||
"pinned": "പിൻ ചെയ്തത്",
|
||||
"today": "ഇന്ന്",
|
||||
"yesterday": "ഇന്നലെ",
|
||||
"last7Days": "കഴിഞ്ഞ 7 ദിവസം",
|
||||
"older": "പഴയത്"
|
||||
},
|
||||
"pin": "പിൻ ചെയ്യുക",
|
||||
"unpin": "അൺപിൻ ചെയ്യുക"
|
||||
}
|
@ -10,9 +10,6 @@
|
||||
"expandedColumns": {
|
||||
"name": "നാമം"
|
||||
},
|
||||
"tooltip": {
|
||||
"delete": "ഇല്ലാതാക്കുക"
|
||||
},
|
||||
"confirm": {
|
||||
"delete": "നിങ്ങൾക്ക് ഈ വിജ്ഞാനം ഇല്ലാതാക്കണമെന്ന് ഉറപ്പാണോ?"
|
||||
},
|
||||
|
@ -41,6 +41,7 @@
|
||||
"webSearch": "Søker på internett",
|
||||
"regenerate": "Regenerer",
|
||||
"edit": "Endre",
|
||||
"delete": "Slett",
|
||||
"saveAndSubmit": "Lagre & Send inn",
|
||||
"editMessage": {
|
||||
"placeholder": "Skriv en melding..."
|
||||
@ -102,5 +103,14 @@
|
||||
"custom": "Egendefinert"
|
||||
},
|
||||
"citations": "Sitater",
|
||||
"downloadCode": "Last ned kode"
|
||||
"downloadCode": "Last ned kode",
|
||||
"date": {
|
||||
"pinned": "Festet",
|
||||
"today": "I dag",
|
||||
"yesterday": "I går",
|
||||
"last7Days": "Siste 7 dager",
|
||||
"older": "Eldre"
|
||||
},
|
||||
"pin": "Fest",
|
||||
"unpin": "Løsne"
|
||||
}
|
@ -10,9 +10,6 @@
|
||||
"expandedColumns": {
|
||||
"name": "Navn"
|
||||
},
|
||||
"tooltip": {
|
||||
"delete": "Slett"
|
||||
},
|
||||
"confirm": {
|
||||
"delete": "Er du sikker på at du vil slette denne kunnskapen?"
|
||||
},
|
||||
|
@ -41,6 +41,7 @@
|
||||
"webSearch": "Pesquisando na web",
|
||||
"regenerate": "Gerar Novamente",
|
||||
"edit": "Editar",
|
||||
"delete": "Excluir",
|
||||
"saveAndSubmit": "Salvar & Enviar",
|
||||
"editMessage": {
|
||||
"placeholder": "Digite uma mensagem..."
|
||||
@ -83,13 +84,13 @@
|
||||
"placeholder": "Digite o valor do Top P (ex: 0.9, 0.95)"
|
||||
},
|
||||
"numGpu": {
|
||||
"label": "Num GPUs",
|
||||
"placeholder": "Digite o número de camadas para enviar para a(s) GPU(s)"
|
||||
"label": "Num GPUs",
|
||||
"placeholder": "Digite o número de camadas para enviar para a(s) GPU(s)"
|
||||
},
|
||||
"systemPrompt": {
|
||||
"label": "Prompt do Sistema Temporário",
|
||||
"placeholder": "Digite o Prompt do Sistema",
|
||||
"help": "Esta é uma maneira rápida de definir o prompt do sistema no chat atual, que substituirá o prompt do sistema selecionado, se existir."
|
||||
"label": "Prompt do Sistema Temporário",
|
||||
"placeholder": "Digite o Prompt do Sistema",
|
||||
"help": "Esta é uma maneira rápida de definir o prompt do sistema no chat atual, que substituirá o prompt do sistema selecionado, se existir."
|
||||
}
|
||||
},
|
||||
"advanced": "Mais Configurações do Modelo"
|
||||
@ -101,5 +102,14 @@
|
||||
"translate": "Traduzir"
|
||||
},
|
||||
"citations": "Citações",
|
||||
"downloadCode": "Baixar Código"
|
||||
"downloadCode": "Baixar Código",
|
||||
"date": {
|
||||
"pinned": "Fixado",
|
||||
"today": "Hoje",
|
||||
"yesterday": "Ontem",
|
||||
"last7Days": "Últimos 7 Dias",
|
||||
"older": "Mais Antigos"
|
||||
},
|
||||
"pin": "Fixar",
|
||||
"unpin": "Desafixar"
|
||||
}
|
@ -10,9 +10,6 @@
|
||||
"expandedColumns": {
|
||||
"name": "Nome"
|
||||
},
|
||||
"tooltip": {
|
||||
"delete": "Excluir"
|
||||
},
|
||||
"confirm": {
|
||||
"delete": "Tem certeza de que deseja excluir este conhecimento?"
|
||||
},
|
||||
|
@ -41,6 +41,7 @@
|
||||
"webSearch": "Поиск в интернете",
|
||||
"regenerate": "Пересоздать",
|
||||
"edit": "Редактировать",
|
||||
"delete": "Удалить",
|
||||
"saveAndSubmit": "Сохранить и отправить",
|
||||
"editMessage": {
|
||||
"placeholder": "Введите сообщение..."
|
||||
@ -101,5 +102,14 @@
|
||||
"translate": "Перевести"
|
||||
},
|
||||
"citations": "Цитаты",
|
||||
"downloadCode": "Скачать код"
|
||||
"downloadCode": "Скачать код",
|
||||
"date": {
|
||||
"pinned": "Закреплено",
|
||||
"today": "Сегодня",
|
||||
"yesterday": "Вчера",
|
||||
"last7Days": "Последние 7 дней",
|
||||
"older": "Ранее"
|
||||
},
|
||||
"pin": "Закрепить",
|
||||
"unpin": "Открепить"
|
||||
}
|
@ -10,9 +10,6 @@
|
||||
"expandedColumns": {
|
||||
"name": "Имя"
|
||||
},
|
||||
"tooltip": {
|
||||
"delete": "Удалить"
|
||||
},
|
||||
"confirm": {
|
||||
"delete": "Вы уверены, что хотите удалить это знание?"
|
||||
},
|
||||
|
@ -41,6 +41,7 @@
|
||||
"webSearch": "搜索网络",
|
||||
"regenerate": "重新生成",
|
||||
"edit": "编辑",
|
||||
"delete": "删除",
|
||||
"saveAndSubmit": "保存 & 提交",
|
||||
"editMessage": {
|
||||
"placeholder": "输入一条消息..."
|
||||
@ -101,5 +102,14 @@
|
||||
"translate": "翻译"
|
||||
},
|
||||
"citations": "引用",
|
||||
"downloadCode": "下载代码"
|
||||
"downloadCode": "下载代码",
|
||||
"date": {
|
||||
"pinned": "已置顶",
|
||||
"today": "今天",
|
||||
"yesterday": "昨天",
|
||||
"last7Days": "最近7天",
|
||||
"older": "更早"
|
||||
},
|
||||
"pin": "置顶",
|
||||
"unpin": "取消置顶"
|
||||
}
|
@ -10,9 +10,6 @@
|
||||
"expandedColumns": {
|
||||
"name": "名称"
|
||||
},
|
||||
"tooltip": {
|
||||
"delete": "删除"
|
||||
},
|
||||
"confirm": {
|
||||
"delete": "您确定要删除此知识吗?"
|
||||
},
|
||||
|
@ -93,7 +93,7 @@ export const KnowledgeSettings = () => {
|
||||
key: "action",
|
||||
render: (text: string, record: any) => (
|
||||
<div className="flex gap-4">
|
||||
<Tooltip title={t("tooltip.delete")}>
|
||||
<Tooltip title={t("common:delete")}>
|
||||
<button
|
||||
disabled={isDeleting}
|
||||
onClick={() => {
|
||||
|
@ -4,11 +4,18 @@ import {
|
||||
formatToChatHistory,
|
||||
formatToMessage,
|
||||
deleteByHistoryId,
|
||||
updateHistory
|
||||
updateHistory,
|
||||
pinHistory
|
||||
} from "@/db"
|
||||
import { Empty, Skeleton } from "antd"
|
||||
import { Empty, Skeleton, Dropdown, Menu } from "antd"
|
||||
import { useMessageOption } from "~/hooks/useMessageOption"
|
||||
import { PencilIcon, Trash2 } from "lucide-react"
|
||||
import {
|
||||
PencilIcon,
|
||||
Trash2,
|
||||
MoreVertical,
|
||||
PinIcon,
|
||||
PinOffIcon
|
||||
} from "lucide-react"
|
||||
import { useNavigate } from "react-router-dom"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import {
|
||||
@ -38,7 +45,46 @@ export const Sidebar = ({ onClose }: Props) => {
|
||||
queryFn: async () => {
|
||||
const db = new PageAssitDatabase()
|
||||
const history = await db.getChatHistories()
|
||||
return history
|
||||
|
||||
const now = new Date()
|
||||
const today = new Date(now.setHours(0, 0, 0, 0))
|
||||
const yesterday = new Date(today)
|
||||
yesterday.setDate(yesterday.getDate() - 1)
|
||||
const lastWeek = new Date(today)
|
||||
lastWeek.setDate(lastWeek.getDate() - 7)
|
||||
|
||||
const pinnedItems = history.filter((item) => item.is_pinned)
|
||||
const todayItems = history.filter(
|
||||
(item) => !item.is_pinned && new Date(item?.createdAt) >= today
|
||||
)
|
||||
const yesterdayItems = history.filter(
|
||||
(item) =>
|
||||
!item.is_pinned &&
|
||||
new Date(item?.createdAt) >= yesterday &&
|
||||
new Date(item?.createdAt) < today
|
||||
)
|
||||
const lastWeekItems = history.filter(
|
||||
(item) =>
|
||||
!item.is_pinned &&
|
||||
new Date(item?.createdAt) >= lastWeek &&
|
||||
new Date(item?.createdAt) < yesterday
|
||||
)
|
||||
const olderItems = history.filter(
|
||||
(item) => !item.is_pinned && new Date(item?.createdAt) < lastWeek
|
||||
)
|
||||
|
||||
const groups = []
|
||||
|
||||
if (pinnedItems.length)
|
||||
groups.push({ label: "pinned", items: pinnedItems })
|
||||
if (todayItems.length) groups.push({ label: "today", items: todayItems })
|
||||
if (yesterdayItems.length)
|
||||
groups.push({ label: "yesterday", items: yesterdayItems })
|
||||
if (lastWeekItems.length)
|
||||
groups.push({ label: "last7days", items: lastWeekItems })
|
||||
if (olderItems.length) groups.push({ label: "older", items: olderItems })
|
||||
|
||||
return groups
|
||||
}
|
||||
})
|
||||
|
||||
@ -67,6 +113,18 @@ export const Sidebar = ({ onClose }: Props) => {
|
||||
}
|
||||
})
|
||||
|
||||
const { mutate: pinChatHistory, isPending: pinLoading } = useMutation({
|
||||
mutationKey: ["pinHistory"],
|
||||
mutationFn: async (data: { id: string; is_pinned: boolean }) => {
|
||||
return await pinHistory(data.id, data.is_pinned)
|
||||
},
|
||||
onSuccess: () => {
|
||||
client.invalidateQueries({
|
||||
queryKey: ["fetchChatHistory"]
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="overflow-y-auto z-99">
|
||||
{status === "success" && chatHistories.length === 0 && (
|
||||
@ -86,51 +144,99 @@ export const Sidebar = ({ onClose }: Props) => {
|
||||
)}
|
||||
{status === "success" && chatHistories.length > 0 && (
|
||||
<div className="flex flex-col gap-2">
|
||||
{chatHistories.map((chat, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex py-2 px-2 items-start gap-3 relative rounded-md truncate hover:pr-4 group transition-opacity duration-300 ease-in-out bg-gray-100 dark:bg-[#232222] dark:text-gray-100 text-gray-800 border hover:bg-gray-200 dark:hover:bg-[#2d2d2d] dark:border-gray-800">
|
||||
<button
|
||||
className="flex-1 overflow-hidden break-all text-start truncate w-full"
|
||||
onClick={async () => {
|
||||
const db = new PageAssitDatabase()
|
||||
const history = await db.getChatHistory(chat.id)
|
||||
setHistoryId(chat.id)
|
||||
setHistory(formatToChatHistory(history))
|
||||
setMessages(formatToMessage(history))
|
||||
const isLastUsedChatModel = await lastUsedChatModelEnabled()
|
||||
if (isLastUsedChatModel) {
|
||||
const currentChatModel = await getLastUsedChatModel(chat.id)
|
||||
if (currentChatModel) {
|
||||
setSelectedModel(currentChatModel)
|
||||
}
|
||||
}
|
||||
navigate("/")
|
||||
onClose()
|
||||
}}>
|
||||
<span className="flex-grow truncate">{chat.title}</span>
|
||||
</button>
|
||||
<div className="flex flex-row gap-3">
|
||||
<button
|
||||
onClick={() => {
|
||||
const newTitle = prompt(t("editHistoryTitle"), chat.title)
|
||||
|
||||
if (newTitle) {
|
||||
editHistory({ id: chat.id, title: newTitle })
|
||||
}
|
||||
}}
|
||||
className="text-gray-500 dark:text-gray-400 opacity-80">
|
||||
<PencilIcon className="w-4 h-4" />
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={() => {
|
||||
if (!confirm(t("deleteHistoryConfirmation"))) return
|
||||
deleteHistory(chat.id)
|
||||
}}
|
||||
className="text-red-500 dark:text-red-400 opacity-80">
|
||||
<Trash2 className=" w-4 h-4 " />
|
||||
</button>
|
||||
{chatHistories.map((group, groupIndex) => (
|
||||
<div key={groupIndex}>
|
||||
<h3 className="px-2 text-sm font-medium text-gray-500">
|
||||
{t(`common:date:${group.label}`)}
|
||||
</h3>
|
||||
<div className="flex flex-col gap-2 mt-2">
|
||||
{group.items.map((chat, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex py-2 px-2 items-start gap-3 relative rounded-md truncate hover:pr-4 group transition-opacity duration-300 ease-in-out bg-gray-100 dark:bg-[#232222] dark:text-gray-100 text-gray-800 border hover:bg-gray-200 dark:hover:bg-[#2d2d2d] dark:border-gray-800">
|
||||
<button
|
||||
className="flex-1 overflow-hidden break-all text-start truncate w-full"
|
||||
onClick={async () => {
|
||||
const db = new PageAssitDatabase()
|
||||
const history = await db.getChatHistory(chat.id)
|
||||
setHistoryId(chat.id)
|
||||
setHistory(formatToChatHistory(history))
|
||||
setMessages(formatToMessage(history))
|
||||
const isLastUsedChatModel =
|
||||
await lastUsedChatModelEnabled()
|
||||
if (isLastUsedChatModel) {
|
||||
const currentChatModel = await getLastUsedChatModel(
|
||||
chat.id
|
||||
)
|
||||
if (currentChatModel) {
|
||||
setSelectedModel(currentChatModel)
|
||||
}
|
||||
}
|
||||
navigate("/")
|
||||
onClose()
|
||||
}}>
|
||||
<span className="flex-grow truncate">{chat.title}</span>
|
||||
</button>
|
||||
<div className="flex items-center gap-2">
|
||||
<Dropdown
|
||||
overlay={
|
||||
<Menu>
|
||||
<Menu.Item
|
||||
key="pin"
|
||||
icon={
|
||||
chat.is_pinned ? (
|
||||
<PinOffIcon className="w-4 h-4" />
|
||||
) : (
|
||||
<PinIcon className="w-4 h-4" />
|
||||
)
|
||||
}
|
||||
onClick={() =>
|
||||
pinChatHistory({
|
||||
id: chat.id,
|
||||
is_pinned: !chat.is_pinned
|
||||
})
|
||||
}
|
||||
disabled={pinLoading}>
|
||||
{chat.is_pinned
|
||||
? t("common:unpin")
|
||||
: t("common:pin")}
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
key="edit"
|
||||
icon={<PencilIcon className="w-4 h-4" />}
|
||||
onClick={() => {
|
||||
const newTitle = prompt(
|
||||
t("editHistoryTitle"),
|
||||
chat.title
|
||||
)
|
||||
if (newTitle) {
|
||||
editHistory({ id: chat.id, title: newTitle })
|
||||
}
|
||||
}}>
|
||||
{t("common:edit")}
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
key="delete"
|
||||
icon={<Trash2 className="w-4 h-4" />}
|
||||
danger
|
||||
onClick={() => {
|
||||
if (!confirm(t("deleteHistoryConfirmation")))
|
||||
return
|
||||
deleteHistory(chat.id)
|
||||
}}>
|
||||
{t("common:delete")}
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
}
|
||||
trigger={["click"]}
|
||||
placement="bottomRight">
|
||||
<button className="text-gray-500 dark:text-gray-400 opacity-80 hover:opacity-100">
|
||||
<MoreVertical className="w-4 h-4" />
|
||||
</button>
|
||||
</Dropdown>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
@ -8,6 +8,7 @@ type HistoryInfo = {
|
||||
title: string
|
||||
is_rag: boolean
|
||||
message_source?: "copilot" | "web-ui"
|
||||
is_pinned?: boolean
|
||||
createdAt: number
|
||||
}
|
||||
|
||||
@ -232,7 +233,11 @@ export const generateID = () => {
|
||||
})
|
||||
}
|
||||
|
||||
export const saveHistory = async (title: string, is_rag?: boolean, message_source?: "copilot" | "web-ui") => {
|
||||
export const saveHistory = async (
|
||||
title: string,
|
||||
is_rag?: boolean,
|
||||
message_source?: "copilot" | "web-ui"
|
||||
) => {
|
||||
const id = generateID()
|
||||
const createdAt = Date.now()
|
||||
const history = { id, title, createdAt, is_rag, message_source }
|
||||
@ -317,6 +322,18 @@ export const updateHistory = async (id: string, title: string) => {
|
||||
db.db.set({ chatHistories: newChatHistories })
|
||||
}
|
||||
|
||||
export const pinHistory = async (id: string, is_pinned: boolean) => {
|
||||
const db = new PageAssitDatabase()
|
||||
const chatHistories = await db.getChatHistories()
|
||||
const newChatHistories = chatHistories.map((history) => {
|
||||
if (history.id === id) {
|
||||
history.is_pinned = is_pinned
|
||||
}
|
||||
return history
|
||||
})
|
||||
db.db.set({ chatHistories: newChatHistories })
|
||||
}
|
||||
|
||||
export const removeMessageUsingHistoryId = async (history_id: string) => {
|
||||
const db = new PageAssitDatabase()
|
||||
const chatHistory = await db.getChatHistory(history_id)
|
||||
@ -490,7 +507,6 @@ export const getRecentChatFromCopilot = async () => {
|
||||
return { history, messages }
|
||||
}
|
||||
|
||||
|
||||
export const getTitleById = async (id: string) => {
|
||||
const db = new PageAssitDatabase()
|
||||
const title = await db.getChatHistoryTitleById(id)
|
||||
|
Loading…
x
Reference in New Issue
Block a user