From 3f0ada4a9dcab4a560d508e277baeafe57d5c7e7 Mon Sep 17 00:00:00 2001
From: Jing Hua <59118459+ztjhz@users.noreply.github.com>
Date: Fri, 14 Apr 2023 15:29:13 +0800
Subject: [PATCH] Sync to Google Drive (#233)
* google drive api
* fix: google-api
* GoogleCloudStorage
* list files api
* Google Cloud Storage
* move button to side menu
* sync status
* rename file
* show popup for those with cloud sync
* update button style
* auto close modal after logged in
* auto popup every 59min
* set as unauthenticated if update fails
* i18n
* add spin animation
* feat: Toast
* clear toast
* electron: desktop google drive integration
This update includes integration with Google Drive for desktop access,
but requires a new URL, which may cause existing chat data to be lost.
To minimize disruption, users can export their current chat data and
import it into the newer version.
* update note
* error handling
* support multiple drive files
* feat: delete drive file
* i18n
* change style
---
.env.example | 3 +-
electron/index.cjs | 74 +++-
package.json | 1 +
public/locales/da/drive.json | 16 +
public/locales/en-US/drive.json | 16 +
public/locales/en/drive.json | 16 +
public/locales/es/drive.json | 16 +
public/locales/fr/drive.json | 16 +
public/locales/it/drive.json | 16 +
public/locales/ja/drive.json | 16 +
public/locales/ms/drive.json | 16 +
public/locales/nb/drive.json | 16 +
public/locales/sv/drive.json | 16 +
public/locales/zh-CN/drive.json | 16 +
public/locales/zh-HK/drive.json | 16 +
public/locales/zh-TW/drive.json | 16 +
src/App.tsx | 2 +
src/api/google-api.ts | 191 +++++++++
src/api/helper.ts | 22 +
src/assets/icons/GoogleIcon.tsx | 17 +
src/assets/icons/RefreshIcon.tsx | 3 +-
src/assets/icons/TickIcon.tsx | 3 +-
src/components/GoogleSync/GoogleSync.tsx | 379 ++++++++++++++++++
.../GoogleSync/GoogleSyncButton.tsx | 67 ++++
src/components/GoogleSync/index.ts | 1 +
src/components/Menu/ChatFolder.tsx | 6 +-
.../Menu/MenuOptions/MenuOptions.tsx | 4 +
src/components/SettingsMenu/SettingsMenu.tsx | 2 +
src/components/Toast/Toast.tsx | 134 +++++++
src/components/Toast/index.ts | 1 +
src/i18n.ts | 28 +-
src/store/cloud-auth-slice.ts | 50 +++
src/store/cloud-auth-store.ts | 28 ++
src/store/storage/GoogleCloudStorage.ts | 72 ++++
src/store/store.ts | 39 +-
src/store/toast-slice.ts | 26 ++
src/types/google-api.ts | 27 ++
src/types/persist.ts | 5 +
src/utils/google-api.ts | 38 ++
yarn.lock | 5 +
40 files changed, 1407 insertions(+), 29 deletions(-)
create mode 100644 public/locales/da/drive.json
create mode 100644 public/locales/en-US/drive.json
create mode 100644 public/locales/en/drive.json
create mode 100644 public/locales/es/drive.json
create mode 100644 public/locales/fr/drive.json
create mode 100644 public/locales/it/drive.json
create mode 100644 public/locales/ja/drive.json
create mode 100644 public/locales/ms/drive.json
create mode 100644 public/locales/nb/drive.json
create mode 100644 public/locales/sv/drive.json
create mode 100644 public/locales/zh-CN/drive.json
create mode 100644 public/locales/zh-HK/drive.json
create mode 100644 public/locales/zh-TW/drive.json
create mode 100644 src/api/google-api.ts
create mode 100644 src/assets/icons/GoogleIcon.tsx
create mode 100644 src/components/GoogleSync/GoogleSync.tsx
create mode 100644 src/components/GoogleSync/GoogleSyncButton.tsx
create mode 100644 src/components/GoogleSync/index.ts
create mode 100644 src/components/Toast/Toast.tsx
create mode 100644 src/components/Toast/index.ts
create mode 100644 src/store/cloud-auth-slice.ts
create mode 100644 src/store/cloud-auth-store.ts
create mode 100644 src/store/storage/GoogleCloudStorage.ts
create mode 100644 src/store/toast-slice.ts
create mode 100644 src/types/google-api.ts
create mode 100644 src/types/persist.ts
create mode 100644 src/utils/google-api.ts
diff --git a/.env.example b/.env.example
index 2a3d554..4953e2b 100644
--- a/.env.example
+++ b/.env.example
@@ -2,4 +2,5 @@
VITE_CUSTOM_API_ENDPOINT=
VITE_DEFAULT_API_ENDPOINT=
VITE_OPENAI_API_KEY=
-VITE_DEFAULT_SYSTEM_MESSAGE= # Remove this line if you want to use the default system message of Better ChatGPT
\ No newline at end of file
+VITE_DEFAULT_SYSTEM_MESSAGE= # Remove this line if you want to use the default system message of Better ChatGPT
+VITE_GOOGLE_CLIENT_ID= # for syncing data with google drive
\ No newline at end of file
diff --git a/electron/index.cjs b/electron/index.cjs
index aa01c31..26d8454 100644
--- a/electron/index.cjs
+++ b/electron/index.cjs
@@ -6,6 +6,8 @@ const { autoUpdater } = require('electron-updater');
if (require('electron-squirrel-startup')) app.quit();
+const PORT = isDev ? '5173' : '51735';
+
function createWindow() {
let iconPath = '';
if (isDev) {
@@ -30,11 +32,9 @@ function createWindow() {
win.maximize();
win.show();
- win.loadURL(
- isDev
- ? 'http://localhost:5173'
- : `file://${path.join(__dirname, '../dist/index.html')}`
- );
+ isDev || createServer();
+
+ win.loadURL(`http://localhost:${PORT}`);
if (isDev) {
win.webContents.openDevTools({ mode: 'detach' });
@@ -81,3 +81,67 @@ app.on('activate', () => {
createWindow();
}
});
+
+const createServer = () => {
+ // Dependencies
+ const http = require('http');
+ const fs = require('fs');
+ const path = require('path');
+
+ // MIME types for different file extensions
+ const mimeTypes = {
+ '.html': 'text/html',
+ '.css': 'text/css',
+ '.js': 'text/javascript',
+ '.wasm': 'application/wasm',
+ '.jpg': 'image/jpeg',
+ '.jpeg': 'image/jpeg',
+ '.png': 'image/png',
+ '.gif': 'image/gif',
+ '.svg': 'image/svg+xml',
+ '.json': 'application/json',
+ };
+
+ // Create a http server
+ const server = http.createServer((request, response) => {
+ // Get the file path from the URL
+ let filePath =
+ request.url === '/' ? '../dist/index.html' : `../dist/${request.url}`;
+
+ // Get the file extension from the filePath
+ let extname = path.extname(filePath);
+
+ // Set the default MIME type to text/plain
+ let contentType = 'text/plain';
+
+ // Check if the file extension is in the MIME types object
+ if (extname in mimeTypes) {
+ contentType = mimeTypes[extname];
+ }
+
+ // Read the file from the disk
+ fs.readFile(filePath, (error, content) => {
+ if (error) {
+ // If file read error occurs
+ if (error.code === 'ENOENT') {
+ // File not found error
+ response.writeHead(404);
+ response.end('File Not Found');
+ } else {
+ // Server error
+ response.writeHead(500);
+ response.end(`Server Error: ${error.code}`);
+ }
+ } else {
+ // File read successful
+ response.writeHead(200, { 'Content-Type': contentType });
+ response.end(content, 'utf-8');
+ }
+ });
+ });
+
+ // Listen for request on port ${PORT}
+ server.listen(PORT, () => {
+ console.log(`Server listening on http://localhost:${PORT}/`);
+ });
+};
diff --git a/package.json b/package.json
index c6a4c2c..deb4365 100644
--- a/package.json
+++ b/package.json
@@ -41,6 +41,7 @@
},
"dependencies": {
"@dqbd/tiktoken": "^1.0.2",
+ "@react-oauth/google": "^0.9.0",
"electron-is-dev": "^2.0.0",
"electron-squirrel-startup": "^1.0.0",
"electron-updater": "^5.3.0",
diff --git a/public/locales/da/drive.json b/public/locales/da/drive.json
new file mode 100644
index 0000000..b03db6b
--- /dev/null
+++ b/public/locales/da/drive.json
@@ -0,0 +1,16 @@
+{
+ "name": "Google Sync",
+ "tagline": "Effortlessly synchronize your chats and settings with Google Drive.",
+ "button": {
+ "sync": "Sync your chats",
+ "stop": "Stop syncing",
+ "create": "Create new file",
+ "confirm": "Confirm selection"
+ },
+ "notice": "Note: You will need to re-login on every visit or every hour. To avoid your cloud data being overwritten, do not use BetterChatGPT on more than one device at the same time.",
+ "privacy": "Your privacy is important to us, and to ensure it, Better ChatGPT only has non-sensitive access, meaning it can only create, view, and manage its own files and folders.",
+ "toast": {
+ "sync": "Sync successful!",
+ "stop": "Syncing stopped"
+ }
+}
diff --git a/public/locales/en-US/drive.json b/public/locales/en-US/drive.json
new file mode 100644
index 0000000..b03db6b
--- /dev/null
+++ b/public/locales/en-US/drive.json
@@ -0,0 +1,16 @@
+{
+ "name": "Google Sync",
+ "tagline": "Effortlessly synchronize your chats and settings with Google Drive.",
+ "button": {
+ "sync": "Sync your chats",
+ "stop": "Stop syncing",
+ "create": "Create new file",
+ "confirm": "Confirm selection"
+ },
+ "notice": "Note: You will need to re-login on every visit or every hour. To avoid your cloud data being overwritten, do not use BetterChatGPT on more than one device at the same time.",
+ "privacy": "Your privacy is important to us, and to ensure it, Better ChatGPT only has non-sensitive access, meaning it can only create, view, and manage its own files and folders.",
+ "toast": {
+ "sync": "Sync successful!",
+ "stop": "Syncing stopped"
+ }
+}
diff --git a/public/locales/en/drive.json b/public/locales/en/drive.json
new file mode 100644
index 0000000..b03db6b
--- /dev/null
+++ b/public/locales/en/drive.json
@@ -0,0 +1,16 @@
+{
+ "name": "Google Sync",
+ "tagline": "Effortlessly synchronize your chats and settings with Google Drive.",
+ "button": {
+ "sync": "Sync your chats",
+ "stop": "Stop syncing",
+ "create": "Create new file",
+ "confirm": "Confirm selection"
+ },
+ "notice": "Note: You will need to re-login on every visit or every hour. To avoid your cloud data being overwritten, do not use BetterChatGPT on more than one device at the same time.",
+ "privacy": "Your privacy is important to us, and to ensure it, Better ChatGPT only has non-sensitive access, meaning it can only create, view, and manage its own files and folders.",
+ "toast": {
+ "sync": "Sync successful!",
+ "stop": "Syncing stopped"
+ }
+}
diff --git a/public/locales/es/drive.json b/public/locales/es/drive.json
new file mode 100644
index 0000000..b03db6b
--- /dev/null
+++ b/public/locales/es/drive.json
@@ -0,0 +1,16 @@
+{
+ "name": "Google Sync",
+ "tagline": "Effortlessly synchronize your chats and settings with Google Drive.",
+ "button": {
+ "sync": "Sync your chats",
+ "stop": "Stop syncing",
+ "create": "Create new file",
+ "confirm": "Confirm selection"
+ },
+ "notice": "Note: You will need to re-login on every visit or every hour. To avoid your cloud data being overwritten, do not use BetterChatGPT on more than one device at the same time.",
+ "privacy": "Your privacy is important to us, and to ensure it, Better ChatGPT only has non-sensitive access, meaning it can only create, view, and manage its own files and folders.",
+ "toast": {
+ "sync": "Sync successful!",
+ "stop": "Syncing stopped"
+ }
+}
diff --git a/public/locales/fr/drive.json b/public/locales/fr/drive.json
new file mode 100644
index 0000000..b03db6b
--- /dev/null
+++ b/public/locales/fr/drive.json
@@ -0,0 +1,16 @@
+{
+ "name": "Google Sync",
+ "tagline": "Effortlessly synchronize your chats and settings with Google Drive.",
+ "button": {
+ "sync": "Sync your chats",
+ "stop": "Stop syncing",
+ "create": "Create new file",
+ "confirm": "Confirm selection"
+ },
+ "notice": "Note: You will need to re-login on every visit or every hour. To avoid your cloud data being overwritten, do not use BetterChatGPT on more than one device at the same time.",
+ "privacy": "Your privacy is important to us, and to ensure it, Better ChatGPT only has non-sensitive access, meaning it can only create, view, and manage its own files and folders.",
+ "toast": {
+ "sync": "Sync successful!",
+ "stop": "Syncing stopped"
+ }
+}
diff --git a/public/locales/it/drive.json b/public/locales/it/drive.json
new file mode 100644
index 0000000..b03db6b
--- /dev/null
+++ b/public/locales/it/drive.json
@@ -0,0 +1,16 @@
+{
+ "name": "Google Sync",
+ "tagline": "Effortlessly synchronize your chats and settings with Google Drive.",
+ "button": {
+ "sync": "Sync your chats",
+ "stop": "Stop syncing",
+ "create": "Create new file",
+ "confirm": "Confirm selection"
+ },
+ "notice": "Note: You will need to re-login on every visit or every hour. To avoid your cloud data being overwritten, do not use BetterChatGPT on more than one device at the same time.",
+ "privacy": "Your privacy is important to us, and to ensure it, Better ChatGPT only has non-sensitive access, meaning it can only create, view, and manage its own files and folders.",
+ "toast": {
+ "sync": "Sync successful!",
+ "stop": "Syncing stopped"
+ }
+}
diff --git a/public/locales/ja/drive.json b/public/locales/ja/drive.json
new file mode 100644
index 0000000..b03db6b
--- /dev/null
+++ b/public/locales/ja/drive.json
@@ -0,0 +1,16 @@
+{
+ "name": "Google Sync",
+ "tagline": "Effortlessly synchronize your chats and settings with Google Drive.",
+ "button": {
+ "sync": "Sync your chats",
+ "stop": "Stop syncing",
+ "create": "Create new file",
+ "confirm": "Confirm selection"
+ },
+ "notice": "Note: You will need to re-login on every visit or every hour. To avoid your cloud data being overwritten, do not use BetterChatGPT on more than one device at the same time.",
+ "privacy": "Your privacy is important to us, and to ensure it, Better ChatGPT only has non-sensitive access, meaning it can only create, view, and manage its own files and folders.",
+ "toast": {
+ "sync": "Sync successful!",
+ "stop": "Syncing stopped"
+ }
+}
diff --git a/public/locales/ms/drive.json b/public/locales/ms/drive.json
new file mode 100644
index 0000000..b03db6b
--- /dev/null
+++ b/public/locales/ms/drive.json
@@ -0,0 +1,16 @@
+{
+ "name": "Google Sync",
+ "tagline": "Effortlessly synchronize your chats and settings with Google Drive.",
+ "button": {
+ "sync": "Sync your chats",
+ "stop": "Stop syncing",
+ "create": "Create new file",
+ "confirm": "Confirm selection"
+ },
+ "notice": "Note: You will need to re-login on every visit or every hour. To avoid your cloud data being overwritten, do not use BetterChatGPT on more than one device at the same time.",
+ "privacy": "Your privacy is important to us, and to ensure it, Better ChatGPT only has non-sensitive access, meaning it can only create, view, and manage its own files and folders.",
+ "toast": {
+ "sync": "Sync successful!",
+ "stop": "Syncing stopped"
+ }
+}
diff --git a/public/locales/nb/drive.json b/public/locales/nb/drive.json
new file mode 100644
index 0000000..b03db6b
--- /dev/null
+++ b/public/locales/nb/drive.json
@@ -0,0 +1,16 @@
+{
+ "name": "Google Sync",
+ "tagline": "Effortlessly synchronize your chats and settings with Google Drive.",
+ "button": {
+ "sync": "Sync your chats",
+ "stop": "Stop syncing",
+ "create": "Create new file",
+ "confirm": "Confirm selection"
+ },
+ "notice": "Note: You will need to re-login on every visit or every hour. To avoid your cloud data being overwritten, do not use BetterChatGPT on more than one device at the same time.",
+ "privacy": "Your privacy is important to us, and to ensure it, Better ChatGPT only has non-sensitive access, meaning it can only create, view, and manage its own files and folders.",
+ "toast": {
+ "sync": "Sync successful!",
+ "stop": "Syncing stopped"
+ }
+}
diff --git a/public/locales/sv/drive.json b/public/locales/sv/drive.json
new file mode 100644
index 0000000..b03db6b
--- /dev/null
+++ b/public/locales/sv/drive.json
@@ -0,0 +1,16 @@
+{
+ "name": "Google Sync",
+ "tagline": "Effortlessly synchronize your chats and settings with Google Drive.",
+ "button": {
+ "sync": "Sync your chats",
+ "stop": "Stop syncing",
+ "create": "Create new file",
+ "confirm": "Confirm selection"
+ },
+ "notice": "Note: You will need to re-login on every visit or every hour. To avoid your cloud data being overwritten, do not use BetterChatGPT on more than one device at the same time.",
+ "privacy": "Your privacy is important to us, and to ensure it, Better ChatGPT only has non-sensitive access, meaning it can only create, view, and manage its own files and folders.",
+ "toast": {
+ "sync": "Sync successful!",
+ "stop": "Syncing stopped"
+ }
+}
diff --git a/public/locales/zh-CN/drive.json b/public/locales/zh-CN/drive.json
new file mode 100644
index 0000000..b03db6b
--- /dev/null
+++ b/public/locales/zh-CN/drive.json
@@ -0,0 +1,16 @@
+{
+ "name": "Google Sync",
+ "tagline": "Effortlessly synchronize your chats and settings with Google Drive.",
+ "button": {
+ "sync": "Sync your chats",
+ "stop": "Stop syncing",
+ "create": "Create new file",
+ "confirm": "Confirm selection"
+ },
+ "notice": "Note: You will need to re-login on every visit or every hour. To avoid your cloud data being overwritten, do not use BetterChatGPT on more than one device at the same time.",
+ "privacy": "Your privacy is important to us, and to ensure it, Better ChatGPT only has non-sensitive access, meaning it can only create, view, and manage its own files and folders.",
+ "toast": {
+ "sync": "Sync successful!",
+ "stop": "Syncing stopped"
+ }
+}
diff --git a/public/locales/zh-HK/drive.json b/public/locales/zh-HK/drive.json
new file mode 100644
index 0000000..b03db6b
--- /dev/null
+++ b/public/locales/zh-HK/drive.json
@@ -0,0 +1,16 @@
+{
+ "name": "Google Sync",
+ "tagline": "Effortlessly synchronize your chats and settings with Google Drive.",
+ "button": {
+ "sync": "Sync your chats",
+ "stop": "Stop syncing",
+ "create": "Create new file",
+ "confirm": "Confirm selection"
+ },
+ "notice": "Note: You will need to re-login on every visit or every hour. To avoid your cloud data being overwritten, do not use BetterChatGPT on more than one device at the same time.",
+ "privacy": "Your privacy is important to us, and to ensure it, Better ChatGPT only has non-sensitive access, meaning it can only create, view, and manage its own files and folders.",
+ "toast": {
+ "sync": "Sync successful!",
+ "stop": "Syncing stopped"
+ }
+}
diff --git a/public/locales/zh-TW/drive.json b/public/locales/zh-TW/drive.json
new file mode 100644
index 0000000..b03db6b
--- /dev/null
+++ b/public/locales/zh-TW/drive.json
@@ -0,0 +1,16 @@
+{
+ "name": "Google Sync",
+ "tagline": "Effortlessly synchronize your chats and settings with Google Drive.",
+ "button": {
+ "sync": "Sync your chats",
+ "stop": "Stop syncing",
+ "create": "Create new file",
+ "confirm": "Confirm selection"
+ },
+ "notice": "Note: You will need to re-login on every visit or every hour. To avoid your cloud data being overwritten, do not use BetterChatGPT on more than one device at the same time.",
+ "privacy": "Your privacy is important to us, and to ensure it, Better ChatGPT only has non-sensitive access, meaning it can only create, view, and manage its own files and folders.",
+ "toast": {
+ "sync": "Sync successful!",
+ "stop": "Syncing stopped"
+ }
+}
diff --git a/src/App.tsx b/src/App.tsx
index 565dd5d..7f9fb8d 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -9,6 +9,7 @@ import useInitialiseNewChat from '@hooks/useInitialiseNewChat';
import { ChatInterface } from '@type/chat';
import { Theme } from '@type/theme';
import ApiPopup from '@components/ApiPopup';
+import Toast from '@components/Toast';
function App() {
const initialiseNewChat = useInitialiseNewChat();
@@ -78,6 +79,7 @@ function App() {