From f0c575b40d3166515203928958c4aa70073298d6 Mon Sep 17 00:00:00 2001 From: Mckay Wrigley Date: Wed, 22 Mar 2023 08:10:00 -0600 Subject: [PATCH] add import/export (#71) --- components/Sidebar/Import.tsx | 34 ++++++++++++++++++++++++++ components/Sidebar/Sidebar.tsx | 8 ++++-- components/Sidebar/SidebarButton.tsx | 2 +- components/Sidebar/SidebarSettings.tsx | 17 +++++++++++-- pages/index.tsx | 13 ++++++++++ utils/app/data.ts | 22 +++++++++++++++++ 6 files changed, 91 insertions(+), 5 deletions(-) create mode 100644 components/Sidebar/Import.tsx create mode 100644 utils/app/data.ts diff --git a/components/Sidebar/Import.tsx b/components/Sidebar/Import.tsx new file mode 100644 index 0000000..4bafde6 --- /dev/null +++ b/components/Sidebar/Import.tsx @@ -0,0 +1,34 @@ +import { Conversation } from "@/types"; +import { IconFileImport } from "@tabler/icons-react"; +import { FC } from "react"; + +interface Props { + onImport: (conversations: Conversation[]) => void; +} + +export const Import: FC = ({ onImport }) => { + return ( +
+ { + if (!e.target.files?.length) return; + + const file = e.target.files[0]; + const reader = new FileReader(); + reader.onload = (e) => { + const conversations: Conversation[] = JSON.parse(e.target?.result as string); + onImport(conversations); + }; + reader.readAsText(file); + }} + /> +
+ +
Import conversations
+
+
+ ); +}; diff --git a/components/Sidebar/Sidebar.tsx b/components/Sidebar/Sidebar.tsx index f85aac8..814e5c3 100644 --- a/components/Sidebar/Sidebar.tsx +++ b/components/Sidebar/Sidebar.tsx @@ -19,9 +19,11 @@ interface Props { onUpdateConversation: (conversation: Conversation, data: KeyValuePair) => void; onApiKeyChange: (apiKey: string) => void; onClearConversations: () => void; + onExportConversations: () => void; + onImportConversations: (conversations: Conversation[]) => void; } -export const Sidebar: FC = ({ loading, conversations, lightMode, selectedConversation, apiKey, onNewConversation, onToggleLightMode, onSelectConversation, onDeleteConversation, onToggleSidebar, onUpdateConversation, onApiKeyChange, onClearConversations }) => { +export const Sidebar: FC = ({ loading, conversations, lightMode, selectedConversation, apiKey, onNewConversation, onToggleLightMode, onSelectConversation, onDeleteConversation, onToggleSidebar, onUpdateConversation, onApiKeyChange, onClearConversations, onExportConversations, onImportConversations }) => { const [searchTerm, setSearchTerm] = useState(""); const [filteredConversations, setFilteredConversations] = useState(conversations); @@ -34,7 +36,7 @@ export const Sidebar: FC = ({ loading, conversations, lightMode, selected }, [searchTerm, conversations]); return ( -
+
); diff --git a/components/Sidebar/SidebarButton.tsx b/components/Sidebar/SidebarButton.tsx index 07e0541..1ba237f 100644 --- a/components/Sidebar/SidebarButton.tsx +++ b/components/Sidebar/SidebarButton.tsx @@ -12,7 +12,7 @@ export const SidebarButton: FC = ({ text, icon, onClick }) => { className="flex py-3 px-3 gap-3 rounded-md hover:bg-gray-500/10 transition-colors duration-200 text-white cursor-pointer w-full items-center" onClick={onClick} > -
{icon}
+
{icon}
{text}
); diff --git a/components/Sidebar/SidebarSettings.tsx b/components/Sidebar/SidebarSettings.tsx index 530be90..0264dae 100644 --- a/components/Sidebar/SidebarSettings.tsx +++ b/components/Sidebar/SidebarSettings.tsx @@ -1,6 +1,8 @@ -import { IconMoon, IconSun } from "@tabler/icons-react"; +import { Conversation } from "@/types"; +import { IconFileExport, IconMoon, IconSun } from "@tabler/icons-react"; import { FC } from "react"; import { ClearConversations } from "./ClearConversations"; +import { Import } from "./Import"; import { Key } from "./Key"; import { SidebarButton } from "./SidebarButton"; @@ -10,18 +12,29 @@ interface Props { onToggleLightMode: (mode: "light" | "dark") => void; onApiKeyChange: (apiKey: string) => void; onClearConversations: () => void; + onExportConversations: () => void; + onImportConversations: (conversations: Conversation[]) => void; } -export const SidebarSettings: FC = ({ lightMode, apiKey, onToggleLightMode, onApiKeyChange, onClearConversations }) => { +export const SidebarSettings: FC = ({ lightMode, apiKey, onToggleLightMode, onApiKeyChange, onClearConversations, onExportConversations, onImportConversations }) => { return (
+ + + } + onClick={() => onExportConversations()} + /> + : } onClick={() => onToggleLightMode(lightMode === "light" ? "dark" : "light")} /> + { + exportConversations(); + }; + + const handleImportConversations = (conversations: Conversation[]) => { + importConversations(conversations); + setConversations(conversations); + setSelectedConversation(conversations[conversations.length - 1]); + }; + const handleSelectConversation = (conversation: Conversation) => { setSelectedConversation(conversation); saveConversation(conversation); @@ -343,6 +354,8 @@ export default function Home() { onUpdateConversation={handleUpdateConversation} onApiKeyChange={handleApiKeyChange} onClearConversations={handleClearConversations} + onExportConversations={handleExportConversations} + onImportConversations={handleImportConversations} /> { + const history = localStorage.getItem("conversationHistory"); + + if (!history) return; + + const blob = new Blob([history], { type: "application/json" }); + const url = URL.createObjectURL(blob); + const link = document.createElement("a"); + link.download = "chatbot_ui_history.json"; + link.href = url; + link.style.display = "none"; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + URL.revokeObjectURL(url); +}; + +export const importConversations = (conversations: Conversation[]) => { + localStorage.setItem("conversationHistory", JSON.stringify(conversations)); +};