feat: chat history management in Setting page
This PR simply add a chat history management section in settings page: a new List carrying one ListItem and three grouping buttons: clear, import and export. So users can transfer chat history across devices.
All modifications were made by reusing existing components.
Note that on line 516 of app/components/settings.tsx, I reused the password-input-container class to group three buttons, but I know this could be more elegant by creating a new class.
And I've tried to translate some of the locale files, but not all of them. The rest are now filled with English.
I know this PR may not be merged by the owner. You can fork the corresponding changes from my forked repo if you need this feature.
本PR在设置页面增加了一个聊天记录的项目,支持清空、导入、导出位于 localStorage 中的 StoreKey.Chat。
调整以最小改动为原则,因此在group三个按钮的时候复用了password-input-container 样式。
我尝试翻译了一些语言文件,但不是所有,剩余的用了英语。
这个PR可能不会被合并,如果你需要这个功能可以从我fork的仓库中抓取。
Cheers all!
Demo hex.im
Screenshot
把这个功能放在settings页面的原因是导入导出应该是非频繁操作。另外在settings页面中新增一个List的原因是不知道这个ListItem放在哪个List中比较合适,欢迎帮我调整。
这个交互比较合理,后续的 webdav 云同步可以和这个放在一起
如果能处理sessions列表合并与去重问题就好了(需要同步处理globalId)。
不过还是感谢,期待这个功能很久了,前几天我是用Python写了个脚本处理的两个浏览器记录合并问题。
如果能处理
sessions列表合并与去重问题就好了(需要同步处理globalId)。不过还是感谢,期待这个功能很久了,前几天我是用Python写了个脚本处理的两个浏览器记录合并问题。
你好,德银。
正如我在PR中所说,在这个调整中我想要实现一个简单的聊天记录跨设备的时候可以迁移的功能,而这个功能在我的假设中是一个低频率,非同时的行为,因此我认为不依托任何目标位置(本地/远程)的简单覆盖是可以满足大部分情况下的需求的。
另外,我在add confirmation before browsing for the files to be imported中又增加了导入前的警告,避免用户意外覆盖掉目前的记录。
在我的理解中,你需要的应该是一个可以基于某个目标位置(本地/远程)进行同步的功能,这个功能和导入导出具有不一样的业务含义和实现逻辑,因为并不是在所有时候我都需要保持各个地方的记录都是最新的。可见这个功能作者已经在计划中了,我这边就先不涉及了。
在这个基础上实现了合并重复聊天,但是目前无法处理聊天进度不同的重复聊天,只能两个全部保留了,另外实现了将导出文件名用日期命名:
function createHistoryFileName() {
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0'); // JS month index starts from 0
const day = String(now.getDate()).padStart(2, '0');
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
return `chats-${year}_${month}_${day}-${hours}_${minutes}.json`;
}
// clear chat history
const clearHistory = () => {
localStorage.removeItem(StoreKey.Chat);
location.reload();
};
// download chat history
const chatHistory = JSON.parse(localStorage.getItem(StoreKey.Chat) ?? "");
const downloadHistory = () => {
const filename = createHistoryFileName(); // 使用函数生成的文件名替代原来的文件名
downloadAs(JSON.stringify(chatHistory), filename);
};
const importHistory = () => {
readFromFile().then((content) => {
try {
const importedChatHistory = JSON.parse(content);
const currentChatHistory = JSON.parse(localStorage.getItem(StoreKey.Chat) || '{"state": {"sessions": []}}');
const currentSessions = currentChatHistory.state.sessions;
// 遍历每个导入的会话
for (const importedSession of importedChatHistory.state.sessions) {
let isDuplicate = false;
// 检查导入的会话是否与当前会话重复
for (const currentSession of currentSessions) {
if (currentSession.id === importedSession.id && currentSession.lastUpdate === importedSession.lastUpdate) {
isDuplicate = true;
break;
}
}
// 如果不是重复的,检查id是否需要调整,然后添加到当前会话
if (!isDuplicate) {
for (const currentSession of currentSessions) {
if (currentSession.id === importedSession.id) {
importedSession.id += 0.1; // 在 id 上加一个小数点
break;
}
}
// 将导入的会话添加到当前会话列表
currentSessions.push(importedSession);
}
}
// 保存更新后的聊天历史记录
currentChatHistory.state.sessions = currentSessions;
localStorage.setItem(StoreKey.Chat, JSON.stringify(currentChatHistory));
console.log(`[Chat History] Successfully imported!`);
showToast(Locale.Settings.ChatHistory.ImportToast);
location.reload();
} catch (e) {
console.error(`[Chat History] Error importing chat history: ${e}`);
}
});
};