From ee3dea74cf4fa7358ef73071e1b41466391ec341 Mon Sep 17 00:00:00 2001 From: 1ilit <1ilit@proton.me> Date: Tue, 27 Aug 2024 11:08:30 +0400 Subject: [PATCH 01/14] Add share to header --- src/components/EditorHeader/ControlPanel.jsx | 21 +++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/components/EditorHeader/ControlPanel.jsx b/src/components/EditorHeader/ControlPanel.jsx index 86171df..006201d 100644 --- a/src/components/EditorHeader/ControlPanel.jsx +++ b/src/components/EditorHeader/ControlPanel.jsx @@ -9,6 +9,7 @@ import { IconUndo, IconRedo, IconEdit, + IconShareStroked, } from "@douyinfe/semi-icons"; import { Link, useNavigate } from "react-router-dom"; import icon from "../../assets/icon_dark_64.png"; @@ -1355,8 +1356,22 @@ export default function ControlPanel({ return ( <> - {layout.header && header()} - {layout.toolbar && toolbar()} +
+ {layout.header && ( +
+ {header()} + +
+ )} + {layout.toolbar && toolbar()} +
From 75f930ba768c7f4d31505602cceece0206eb7760 Mon Sep 17 00:00:00 2001 From: 1ilit <1ilit@proton.me> Date: Tue, 27 Aug 2024 17:30:32 +0400 Subject: [PATCH 02/14] Set up upload workflow --- .env.sample | 3 +- package-lock.json | 366 +++++++++++++++++++ package.json | 1 + src/components/EditorHeader/ControlPanel.jsx | 3 +- src/components/EditorHeader/Modal/Modal.jsx | 3 + src/components/EditorHeader/Modal/Share.jsx | 56 +++ src/data/constants.js | 1 + src/i18n/locales/en.js | 2 + src/utils/modalData.js | 4 + 9 files changed, 437 insertions(+), 2 deletions(-) create mode 100644 src/components/EditorHeader/Modal/Share.jsx diff --git a/.env.sample b/.env.sample index c87806f..153c5ae 100644 --- a/.env.sample +++ b/.env.sample @@ -1 +1,2 @@ -VITE_BACKEND_URL=http://backend.com \ No newline at end of file +VITE_BACKEND_URL=http://backend.com +VITE_GITHUB_ACCESS_TOKEN=my_access_token \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index bb91cbf..8c96638 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,6 +29,7 @@ "jspdf": "^2.5.1", "lexical": "^0.12.5", "node-sql-parser": "^5.3.1", + "octokit": "^4.0.2", "react": "^18.2.0", "react-dom": "^18.2.0", "react-hotkeys-hook": "^4.4.1", @@ -1519,6 +1520,326 @@ "node": ">= 8" } }, + "node_modules/@octokit/app": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@octokit/app/-/app-15.1.0.tgz", + "integrity": "sha512-TkBr7QgOmE6ORxvIAhDbZsqPkF7RSqTY4pLTtUQCvr6dTXqvi2fFo46q3h1lxlk/sGMQjqyZ0kEahkD/NyzOHg==", + "dependencies": { + "@octokit/auth-app": "^7.0.0", + "@octokit/auth-unauthenticated": "^6.0.0", + "@octokit/core": "^6.1.2", + "@octokit/oauth-app": "^7.0.0", + "@octokit/plugin-paginate-rest": "^11.0.0", + "@octokit/types": "^13.0.0", + "@octokit/webhooks": "^13.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/auth-app": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-app/-/auth-app-7.1.0.tgz", + "integrity": "sha512-cazGaJPSgeZ8NkVYeM/C5l/6IQ5vZnsI8p1aMucadCkt/bndI+q+VqwrlnWbASRmenjOkf1t1RpCKrif53U8gw==", + "dependencies": { + "@octokit/auth-oauth-app": "^8.1.0", + "@octokit/auth-oauth-user": "^5.1.0", + "@octokit/request": "^9.1.1", + "@octokit/request-error": "^6.1.1", + "@octokit/types": "^13.4.1", + "lru-cache": "^10.0.0", + "universal-github-app-jwt": "^2.2.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/auth-app/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" + }, + "node_modules/@octokit/auth-oauth-app": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-app/-/auth-oauth-app-8.1.1.tgz", + "integrity": "sha512-5UtmxXAvU2wfcHIPPDWzVSAWXVJzG3NWsxb7zCFplCWEmMCArSZV0UQu5jw5goLQXbFyOr5onzEH37UJB3zQQg==", + "dependencies": { + "@octokit/auth-oauth-device": "^7.0.0", + "@octokit/auth-oauth-user": "^5.0.1", + "@octokit/request": "^9.0.0", + "@octokit/types": "^13.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/auth-oauth-device": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-device/-/auth-oauth-device-7.1.1.tgz", + "integrity": "sha512-HWl8lYueHonuyjrKKIup/1tiy0xcmQCdq5ikvMO1YwkNNkxb6DXfrPjrMYItNLyCP/o2H87WuijuE+SlBTT8eg==", + "dependencies": { + "@octokit/oauth-methods": "^5.0.0", + "@octokit/request": "^9.0.0", + "@octokit/types": "^13.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/auth-oauth-user": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-user/-/auth-oauth-user-5.1.1.tgz", + "integrity": "sha512-rRkMz0ErOppdvEfnemHJXgZ9vTPhBuC6yASeFaB7I2yLMd7QpjfrL1mnvRPlyKo+M6eeLxrKanXJ9Qte29SRsw==", + "dependencies": { + "@octokit/auth-oauth-device": "^7.0.1", + "@octokit/oauth-methods": "^5.0.0", + "@octokit/request": "^9.0.1", + "@octokit/types": "^13.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/auth-token": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-5.1.1.tgz", + "integrity": "sha512-rh3G3wDO8J9wSjfI436JUKzHIxq8NaiL0tVeB2aXmG6p/9859aUOAjA9pmSPNGGZxfwmaJ9ozOJImuNVJdpvbA==", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/auth-unauthenticated": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-unauthenticated/-/auth-unauthenticated-6.1.0.tgz", + "integrity": "sha512-zPSmfrUAcspZH/lOFQnVnvjQZsIvmfApQH6GzJrkIunDooU1Su2qt2FfMTSVPRp7WLTQyC20Kd55lF+mIYaohQ==", + "dependencies": { + "@octokit/request-error": "^6.0.1", + "@octokit/types": "^13.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/core": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-6.1.2.tgz", + "integrity": "sha512-hEb7Ma4cGJGEUNOAVmyfdB/3WirWMg5hDuNFVejGEDFqupeOysLc2sG6HJxY2etBp5YQu5Wtxwi020jS9xlUwg==", + "dependencies": { + "@octokit/auth-token": "^5.0.0", + "@octokit/graphql": "^8.0.0", + "@octokit/request": "^9.0.0", + "@octokit/request-error": "^6.0.1", + "@octokit/types": "^13.0.0", + "before-after-hook": "^3.0.2", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/endpoint": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.1.tgz", + "integrity": "sha512-JYjh5rMOwXMJyUpj028cu0Gbp7qe/ihxfJMLc8VZBMMqSwLgOxDI1911gV4Enl1QSavAQNJcwmwBF9M0VvLh6Q==", + "dependencies": { + "@octokit/types": "^13.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/graphql": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-8.1.1.tgz", + "integrity": "sha512-ukiRmuHTi6ebQx/HFRCXKbDlOh/7xEV6QUXaE7MJEKGNAncGI/STSbOkl12qVXZrfZdpXctx5O9X1AIaebiDBg==", + "dependencies": { + "@octokit/request": "^9.0.0", + "@octokit/types": "^13.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/oauth-app": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@octokit/oauth-app/-/oauth-app-7.1.3.tgz", + "integrity": "sha512-EHXbOpBkSGVVGF1W+NLMmsnSsJRkcrnVmDKt0TQYRBb6xWfWzoi9sBD4DIqZ8jGhOWO/V8t4fqFyJ4vDQDn9bg==", + "dependencies": { + "@octokit/auth-oauth-app": "^8.0.0", + "@octokit/auth-oauth-user": "^5.0.1", + "@octokit/auth-unauthenticated": "^6.0.0-beta.1", + "@octokit/core": "^6.0.0", + "@octokit/oauth-authorization-url": "^7.0.0", + "@octokit/oauth-methods": "^5.0.0", + "@types/aws-lambda": "^8.10.83", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/oauth-authorization-url": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@octokit/oauth-authorization-url/-/oauth-authorization-url-7.1.1.tgz", + "integrity": "sha512-ooXV8GBSabSWyhLUowlMIVd9l1s2nsOGQdlP2SQ4LnkEsGXzeCvbSbCPdZThXhEFzleGPwbapT0Sb+YhXRyjCA==", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/oauth-methods": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@octokit/oauth-methods/-/oauth-methods-5.1.2.tgz", + "integrity": "sha512-C5lglRD+sBlbrhCUTxgJAFjWgJlmTx5bQ7Ch0+2uqRjYv7Cfb5xpX4WuSC9UgQna3sqRGBL9EImX9PvTpMaQ7g==", + "dependencies": { + "@octokit/oauth-authorization-url": "^7.0.0", + "@octokit/request": "^9.1.0", + "@octokit/request-error": "^6.1.0", + "@octokit/types": "^13.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "22.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.2.0.tgz", + "integrity": "sha512-QBhVjcUa9W7Wwhm6DBFu6ZZ+1/t/oYxqc2tp81Pi41YNuJinbFRx8B133qVOrAaBbF7D/m0Et6f9/pZt9Rc+tg==" + }, + "node_modules/@octokit/openapi-webhooks-types": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-webhooks-types/-/openapi-webhooks-types-8.3.0.tgz", + "integrity": "sha512-vKLsoR4xQxg4Z+6rU/F65ItTUz/EXbD+j/d4mlq2GW8TsA4Tc8Kdma2JTAAJ5hrKWUQzkR/Esn2fjsqiVRYaQg==" + }, + "node_modules/@octokit/plugin-paginate-graphql": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-graphql/-/plugin-paginate-graphql-5.2.2.tgz", + "integrity": "sha512-7znSVvlNAOJisCqAnjN1FtEziweOHSjPGAuc5W58NeGNAr/ZB57yCsjQbXDlWsVryA7hHQaEQPcBbJYFawlkyg==", + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "11.3.3", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.3.3.tgz", + "integrity": "sha512-o4WRoOJZlKqEEgj+i9CpcmnByvtzoUYC6I8PD2SA95M+BJ2x8h7oLcVOg9qcowWXBOdcTRsMZiwvM3EyLm9AfA==", + "dependencies": { + "@octokit/types": "^13.5.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-13.2.4.tgz", + "integrity": "sha512-gusyAVgTrPiuXOdfqOySMDztQHv6928PQ3E4dqVGEtOvRXAKRbJR4b1zQyniIT9waqaWk/UDaoJ2dyPr7Bk7Iw==", + "dependencies": { + "@octokit/types": "^13.5.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-retry": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-7.1.1.tgz", + "integrity": "sha512-G9Ue+x2odcb8E1XIPhaFBnTTIrrUDfXN05iFXiqhR+SeeeDMMILcAnysOsxUpEWcQp2e5Ft397FCXTcPkiPkLw==", + "dependencies": { + "@octokit/request-error": "^6.0.0", + "@octokit/types": "^13.0.0", + "bottleneck": "^2.15.3" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-throttling": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-9.3.1.tgz", + "integrity": "sha512-Qd91H4liUBhwLB2h6jZ99bsxoQdhgPk6TdwnClPyTBSDAdviGPceViEgUwj+pcQDmB/rfAXAXK7MTochpHM3yQ==", + "dependencies": { + "@octokit/types": "^13.0.0", + "bottleneck": "^2.15.3" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": "^6.0.0" + } + }, + "node_modules/@octokit/request": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-9.1.3.tgz", + "integrity": "sha512-V+TFhu5fdF3K58rs1pGUJIDH5RZLbZm5BI+MNF+6o/ssFNT4vWlCh/tVpF3NxGtP15HUxTTMUbsG5llAuU2CZA==", + "dependencies": { + "@octokit/endpoint": "^10.0.0", + "@octokit/request-error": "^6.0.1", + "@octokit/types": "^13.1.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/request-error": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.4.tgz", + "integrity": "sha512-VpAhIUxwhWZQImo/dWAN/NpPqqojR6PSLgLYAituLM6U+ddx9hCioFGwBr5Mi+oi5CLeJkcAs3gJ0PYYzU6wUg==", + "dependencies": { + "@octokit/types": "^13.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/types": { + "version": "13.5.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.5.0.tgz", + "integrity": "sha512-HdqWTf5Z3qwDVlzCrP8UJquMwunpDiMPt5er+QjGzL4hqr/vBVY/MauQgS1xWxCDT1oMx1EULyqxncdCY/NVSQ==", + "dependencies": { + "@octokit/openapi-types": "^22.2.0" + } + }, + "node_modules/@octokit/webhooks": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@octokit/webhooks/-/webhooks-13.3.0.tgz", + "integrity": "sha512-TUkJLtI163Bz5+JK0O+zDkQpn4gKwN+BovclUvCj6pI/6RXrFqQvUMRS2M+Rt8Rv0qR3wjoMoOPmpJKeOh0nBg==", + "dependencies": { + "@octokit/openapi-webhooks-types": "8.3.0", + "@octokit/request-error": "^6.0.1", + "@octokit/webhooks-methods": "^5.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/webhooks-methods": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@octokit/webhooks-methods/-/webhooks-methods-5.1.0.tgz", + "integrity": "sha512-yFZa3UH11VIxYnnoOYCVoJ3q4ChuSOk2IVBBQ0O3xtKX4x9bmKb/1t+Mxixv2iUhzMdOl1qeWJqEhouXXzB3rQ==", + "engines": { + "node": ">= 18" + } + }, "node_modules/@remix-run/router": { "version": "1.14.0", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.14.0.tgz", @@ -1743,6 +2064,11 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/aws-lambda": { + "version": "8.10.143", + "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.143.tgz", + "integrity": "sha512-u5vzlcR14ge/4pMTTMDQr3MF0wEe38B2F9o84uC4F43vN5DGTy63npRrB6jQhyt+C0lGv4ZfiRcRkqJoZuPnmg==" + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -2260,6 +2586,11 @@ "node": ">= 0.6.0" } }, + "node_modules/before-after-hook": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-3.0.2.tgz", + "integrity": "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==" + }, "node_modules/bezier-easing": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/bezier-easing/-/bezier-easing-2.1.0.tgz", @@ -2282,6 +2613,11 @@ "node": ">=8" } }, + "node_modules/bottleneck": { + "version": "2.19.5", + "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", + "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==" + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -4639,6 +4975,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/octokit": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/octokit/-/octokit-4.0.2.tgz", + "integrity": "sha512-wbqF4uc1YbcldtiBFfkSnquHtECEIpYD78YUXI6ri1Im5OO2NLo6ZVpRdbJpdnpZ05zMrVPssNiEo6JQtea+Qg==", + "dependencies": { + "@octokit/app": "^15.0.0", + "@octokit/core": "^6.0.0", + "@octokit/oauth-app": "^7.0.0", + "@octokit/plugin-paginate-graphql": "^5.0.0", + "@octokit/plugin-paginate-rest": "^11.0.0", + "@octokit/plugin-rest-endpoint-methods": "^13.0.0", + "@octokit/plugin-retry": "^7.0.0", + "@octokit/plugin-throttling": "^9.0.0", + "@octokit/request-error": "^6.0.0", + "@octokit/types": "^13.0.0" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -5952,6 +6308,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/universal-github-app-jwt": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/universal-github-app-jwt/-/universal-github-app-jwt-2.2.0.tgz", + "integrity": "sha512-G5o6f95b5BggDGuUfKDApKaCgNYy2x7OdHY0zSMF081O0EJobw+1130VONhrA7ezGSV2FNOGyM+KQpQZAr9bIQ==" + }, + "node_modules/universal-user-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.2.tgz", + "integrity": "sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q==" + }, "node_modules/update-browserslist-db": { "version": "1.0.13", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", diff --git a/package.json b/package.json index eff0007..982a19e 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "jspdf": "^2.5.1", "lexical": "^0.12.5", "node-sql-parser": "^5.3.1", + "octokit": "^4.0.2", "react": "^18.2.0", "react-dom": "^18.2.0", "react-hotkeys-hook": "^4.4.1", diff --git a/src/components/EditorHeader/ControlPanel.jsx b/src/components/EditorHeader/ControlPanel.jsx index 006201d..643f5f6 100644 --- a/src/components/EditorHeader/ControlPanel.jsx +++ b/src/components/EditorHeader/ControlPanel.jsx @@ -1365,8 +1365,9 @@ export default function ControlPanel({ className="text-base me-2 pe-6 ps-5 py-[18px] rounded-md" size="default" icon={} + onClick={() => setModal(MODAL.SHARE)} > - Share + {t("share")}
)} diff --git a/src/components/EditorHeader/Modal/Modal.jsx b/src/components/EditorHeader/Modal/Modal.jsx index d8acd8f..dd11a9f 100644 --- a/src/components/EditorHeader/Modal/Modal.jsx +++ b/src/components/EditorHeader/Modal/Modal.jsx @@ -42,6 +42,7 @@ import { useTranslation } from "react-i18next"; import { importSQL } from "../../../utils/importSQL"; import { databases } from "../../../data/databases"; import { isRtl } from "../../../i18n/utils/rtl"; +import Share from "./Share"; const languageExtension = { sql: [sql()], @@ -328,6 +329,8 @@ export default function Modal({ return ; case MODAL.LANGUAGE: return ; + case MODAL.SHARE: + return ; default: return <>; } diff --git a/src/components/EditorHeader/Modal/Share.jsx b/src/components/EditorHeader/Modal/Share.jsx new file mode 100644 index 0000000..b870b04 --- /dev/null +++ b/src/components/EditorHeader/Modal/Share.jsx @@ -0,0 +1,56 @@ +import { Button, Banner } from "@douyinfe/semi-ui"; +import { IconLink } from "@douyinfe/semi-icons"; +import { useTranslation } from "react-i18next"; +import { Octokit } from "octokit"; + +export default function Share() { + const { t } = useTranslation(); + + const generateLink = async () => { + const octokit = new Octokit({ + auth: import.meta.env.VITE_GITHUB_ACCESS_TOKEN, + }); + + try { + const res = await octokit.request("POST /gists", { + description: "Hello world", + public: false, + files: { + "test.json": { + content: '{"Hello":"WORLD"}', + }, + }, + headers: { + "X-GitHub-Api-Version": "2022-11-28", + }, + }); + console.log(res); + } catch (e) { + console.error(e); + } + }; + + return ( +
+ + +
+ ); +} diff --git a/src/data/constants.js b/src/data/constants.js index 6ffb577..59bd4ff 100644 --- a/src/data/constants.js +++ b/src/data/constants.js @@ -91,6 +91,7 @@ export const MODAL = { IMPORT_SRC: 8, TABLE_WIDTH: 9, LANGUAGE: 10, + SHARE: 11, }; export const STATUS = { diff --git a/src/i18n/locales/en.js b/src/i18n/locales/en.js index 944e44b..9774a1b 100644 --- a/src/i18n/locales/en.js +++ b/src/i18n/locales/en.js @@ -236,6 +236,8 @@ const en = { empty_index_name: "Declared an index with no name in table '{{tableName}}'", didnt_find_diagram: "Oops! Didn't find the diagram.", unsigned: "Unsigned", + share: "Share", + generate_link: "Generate link" }, }; diff --git a/src/utils/modalData.js b/src/utils/modalData.js index d72ba6e..f4fbf45 100644 --- a/src/utils/modalData.js +++ b/src/utils/modalData.js @@ -23,6 +23,8 @@ export const getModalTitle = (modal) => { return i18n.t("table_width"); case MODAL.LANGUAGE: return i18n.t("language"); + case MODAL.SHARE: + return i18n.t("share"); default: return ""; } @@ -55,6 +57,8 @@ export const getOkText = (modal) => { return i18n.t("save_as"); case MODAL.NEW: return i18n.t("create"); + case MODAL.SHARE: + return i18n.t("share"); default: return i18n.t("confirm"); } From 488641ddccaebe72ab8955d1478a1c4f8290f48a Mon Sep 17 00:00:00 2001 From: 1ilit <1ilit@proton.me> Date: Tue, 27 Aug 2024 23:39:14 +0400 Subject: [PATCH 03/14] Add modal for github token --- src/components/EditorHeader/ControlPanel.jsx | 3 + .../EditorHeader/Modal/GithubToken.jsx | 43 +++++++++++++ src/components/EditorHeader/Modal/Modal.jsx | 18 +++++- src/components/EditorHeader/Modal/Share.jsx | 63 ++++++++++++++----- src/data/constants.js | 1 + src/i18n/locales/en.js | 3 +- src/index.css | 4 ++ src/utils/modalData.js | 2 + 8 files changed, 117 insertions(+), 20 deletions(-) create mode 100644 src/components/EditorHeader/Modal/GithubToken.jsx diff --git a/src/components/EditorHeader/ControlPanel.jsx b/src/components/EditorHeader/ControlPanel.jsx index 643f5f6..042561d 100644 --- a/src/components/EditorHeader/ControlPanel.jsx +++ b/src/components/EditorHeader/ControlPanel.jsx @@ -1290,6 +1290,9 @@ export default function ControlPanel({ language: { function: () => setModal(MODAL.LANGUAGE), }, + github_token: { + function: () => setModal(MODAL.GITHUB_TOKEN), + }, flush_storage: { warning: { title: t("flush_storage"), diff --git a/src/components/EditorHeader/Modal/GithubToken.jsx b/src/components/EditorHeader/Modal/GithubToken.jsx new file mode 100644 index 0000000..56ac2d4 --- /dev/null +++ b/src/components/EditorHeader/Modal/GithubToken.jsx @@ -0,0 +1,43 @@ +import { Button, Input } from "@douyinfe/semi-ui"; +import { useTranslation } from "react-i18next"; + +export default function GithubToken({ token, setToken }) { + const { t } = useTranslation(); + + const clearToken = () => { + localStorage.removeItem("github_token"); + setToken(""); + }; + + return ( +
+
+ Set your{" "} + + personal access token + {" "} + here if you wish to save diagrams to your gists. +
+
+ setToken(v)} + /> +
+
+ *This will be stored in the local storage +
+
+ ); +} diff --git a/src/components/EditorHeader/Modal/Modal.jsx b/src/components/EditorHeader/Modal/Modal.jsx index dd11a9f..a2c1e98 100644 --- a/src/components/EditorHeader/Modal/Modal.jsx +++ b/src/components/EditorHeader/Modal/Modal.jsx @@ -43,6 +43,7 @@ import { importSQL } from "../../../utils/importSQL"; import { databases } from "../../../data/databases"; import { isRtl } from "../../../i18n/utils/rtl"; import Share from "./Share"; +import GithubToken from "./GithubToken"; const languageExtension = { sql: [sql()], @@ -82,6 +83,9 @@ export default function Modal({ const [selectedTemplateId, setSelectedTemplateId] = useState(-1); const [selectedDiagramId, setSelectedDiagramId] = useState(0); const [saveAsTitle, setSaveAsTitle] = useState(title); + const [token, setToken] = useState( + localStorage.getItem("github_token") ?? "", + ); const overwriteDiagram = () => { setTables(importData.tables); @@ -238,6 +242,14 @@ export default function Modal({ setModal(MODAL.NONE); createNewDiagram(selectedTemplateId); return; + case MODAL.GITHUB_TOKEN: + setModal(MODAL.NONE); + if (token !== "") { + localStorage.setItem("github_token", token); + } else { + localStorage.removeItem("github_token"); + } + return; default: setModal(MODAL.NONE); return; @@ -320,7 +332,7 @@ export default function Modal({ ); } else { return ( -
+
); @@ -330,7 +342,9 @@ export default function Modal({ case MODAL.LANGUAGE: return ; case MODAL.SHARE: - return ; + return ; + case MODAL.GITHUB_TOKEN: + return ; default: return <>; } diff --git a/src/components/EditorHeader/Modal/Share.jsx b/src/components/EditorHeader/Modal/Share.jsx index b870b04..f8af1b9 100644 --- a/src/components/EditorHeader/Modal/Share.jsx +++ b/src/components/EditorHeader/Modal/Share.jsx @@ -1,14 +1,21 @@ -import { Button, Banner } from "@douyinfe/semi-ui"; +import { Banner, Button, Spin } from "@douyinfe/semi-ui"; import { IconLink } from "@douyinfe/semi-icons"; import { useTranslation } from "react-i18next"; import { Octokit } from "octokit"; +import { useState } from "react"; +import { MODAL } from "../../../data/constants"; -export default function Share() { +export default function Share({ setModal }) { const { t } = useTranslation(); + const [loading, setLoading] = useState(false); const generateLink = async () => { + setLoading(true); + const userToken = localStorage.getItem("github_token"); + const octokit = new Octokit({ - auth: import.meta.env.VITE_GITHUB_ACCESS_TOKEN, + auth: + userToken ?? import.meta.env.VITE_GITHUB_ACCESS_TOKEN, }); try { @@ -27,30 +34,52 @@ export default function Share() { console.log(res); } catch (e) { console.error(e); + } finally { + setLoading(false); } }; return ( -
+
+
  • + Generating a link will create a gist with the JSON representation + of the diagram. +
  • +
  • + You can create the gist from your account by providing your token + + . +
  • +
  • + Sharing will not create a live real-time collaboration session. +
  • + + } /> - +
    + +
    ); } diff --git a/src/data/constants.js b/src/data/constants.js index 59bd4ff..69e9d33 100644 --- a/src/data/constants.js +++ b/src/data/constants.js @@ -92,6 +92,7 @@ export const MODAL = { TABLE_WIDTH: 9, LANGUAGE: 10, SHARE: 11, + GITHUB_TOKEN: 12, }; export const STATUS = { diff --git a/src/i18n/locales/en.js b/src/i18n/locales/en.js index 9774a1b..634de80 100644 --- a/src/i18n/locales/en.js +++ b/src/i18n/locales/en.js @@ -237,7 +237,8 @@ const en = { didnt_find_diagram: "Oops! Didn't find the diagram.", unsigned: "Unsigned", share: "Share", - generate_link: "Generate link" + generate_link: "Generate link", + github_token: "GitHub Token", }, }; diff --git a/src/index.css b/src/index.css index 11a352b..62a845d 100644 --- a/src/index.css +++ b/src/index.css @@ -58,6 +58,10 @@ background-color: rgba(var(--semi-blue-6), 1); } +.semi-spin-wrapper{ + color: inherit; +} + ::-webkit-scrollbar { width: 8px; height: 8px; diff --git a/src/utils/modalData.js b/src/utils/modalData.js index f4fbf45..2b996c9 100644 --- a/src/utils/modalData.js +++ b/src/utils/modalData.js @@ -25,6 +25,8 @@ export const getModalTitle = (modal) => { return i18n.t("language"); case MODAL.SHARE: return i18n.t("share"); + case MODAL.GITHUB_TOKEN: + return i18n.t("github_token"); default: return ""; } From 7dcecf3c1fd6021e8305b6b8a880bc64c50dd2a2 Mon Sep 17 00:00:00 2001 From: 1ilit <1ilit@proton.me> Date: Thu, 29 Aug 2024 17:05:47 +0400 Subject: [PATCH 04/14] Create and update gist on click --- src/components/EditorHeader/ControlPanel.jsx | 12 +-- src/components/EditorHeader/Modal/Share.jsx | 51 +--------- src/components/EditorHeader/ShareButton.jsx | 97 ++++++++++++++++++++ src/components/Workspace.jsx | 34 +++++-- 4 files changed, 125 insertions(+), 69 deletions(-) create mode 100644 src/components/EditorHeader/ShareButton.jsx diff --git a/src/components/EditorHeader/ControlPanel.jsx b/src/components/EditorHeader/ControlPanel.jsx index 042561d..1961046 100644 --- a/src/components/EditorHeader/ControlPanel.jsx +++ b/src/components/EditorHeader/ControlPanel.jsx @@ -9,7 +9,6 @@ import { IconUndo, IconRedo, IconEdit, - IconShareStroked, } from "@douyinfe/semi-icons"; import { Link, useNavigate } from "react-router-dom"; import icon from "../../assets/icon_dark_64.png"; @@ -71,6 +70,7 @@ import { exportSQL } from "../../utils/exportSQL"; import { databases } from "../../data/databases"; import { jsonToMermaid } from "../../utils/exportAs/mermaid"; import { isRtl } from "../../i18n/utils/rtl"; +import ShareButton from "./ShareButton"; export default function ControlPanel({ diagramId, @@ -1363,15 +1363,7 @@ export default function ControlPanel({ {layout.header && (
    {header()} - +
    )} {layout.toolbar && toolbar()} diff --git a/src/components/EditorHeader/Modal/Share.jsx b/src/components/EditorHeader/Modal/Share.jsx index f8af1b9..bc4896d 100644 --- a/src/components/EditorHeader/Modal/Share.jsx +++ b/src/components/EditorHeader/Modal/Share.jsx @@ -1,43 +1,7 @@ -import { Banner, Button, Spin } from "@douyinfe/semi-ui"; -import { IconLink } from "@douyinfe/semi-icons"; -import { useTranslation } from "react-i18next"; -import { Octokit } from "octokit"; -import { useState } from "react"; +import { Banner } from "@douyinfe/semi-ui"; import { MODAL } from "../../../data/constants"; export default function Share({ setModal }) { - const { t } = useTranslation(); - const [loading, setLoading] = useState(false); - - const generateLink = async () => { - setLoading(true); - const userToken = localStorage.getItem("github_token"); - - const octokit = new Octokit({ - auth: - userToken ?? import.meta.env.VITE_GITHUB_ACCESS_TOKEN, - }); - - try { - const res = await octokit.request("POST /gists", { - description: "Hello world", - public: false, - files: { - "test.json": { - content: '{"Hello":"WORLD"}', - }, - }, - headers: { - "X-GitHub-Api-Version": "2022-11-28", - }, - }); - console.log(res); - } catch (e) { - console.error(e); - } finally { - setLoading(false); - } - }; return (
    @@ -68,18 +32,7 @@ export default function Share({ setModal }) { } /> -
    - -
    +
    ); } diff --git a/src/components/EditorHeader/ShareButton.jsx b/src/components/EditorHeader/ShareButton.jsx new file mode 100644 index 0000000..826a2b0 --- /dev/null +++ b/src/components/EditorHeader/ShareButton.jsx @@ -0,0 +1,97 @@ +import { Button, Spin } from "@douyinfe/semi-ui"; +import { IconShareStroked } from "@douyinfe/semi-icons"; +import { useTranslation } from "react-i18next"; +import { Octokit } from "octokit"; +import { MODAL } from "../../data/constants"; +import { useContext, useState } from "react"; +import { IdContext } from "../Workspace"; + +export default function ShareButton({ setModal }) { + const { t } = useTranslation(); + const { gistId, setGistId } = useContext(IdContext); + const [loading, setLoading] = useState(false); + + const updateGist = async () => { + setLoading(true); + const userToken = localStorage.getItem("github_token"); + + const octokit = new Octokit({ + auth: userToken ?? import.meta.env.VITE_GITHUB_ACCESS_TOKEN, + }); + + try { + const res = await octokit.request(`PATCH /gists/${gistId}`, { + gist_id: gistId, + description: "drawDB diagram", + files: { + "test.json": { + content: '{"Hello":"SEAMAN"}', + }, + }, + headers: { + "X-GitHub-Api-Version": "2022-11-28", + }, + }); + console.log(res); + } catch (e) { + console.error(e); + } finally { + setLoading(false); + } + }; + + const generateLink = async () => { + setLoading(true); + const userToken = localStorage.getItem("github_token"); + + const octokit = new Octokit({ + auth: userToken ?? import.meta.env.VITE_GITHUB_ACCESS_TOKEN, + }); + + try { + const res = await octokit.request("POST /gists", { + description: "drawDB diagram", + public: false, + files: { + "test.json": { + content: '{"Hello":"WORLD"}', + }, + }, + headers: { + "X-GitHub-Api-Version": "2022-11-28", + }, + }); + setGistId(res.data.id); + } catch (e) { + console.error(e); + } finally { + setLoading(false); + } + }; + + const onShare = async () => { + try { + if (!gistId || gistId === "") { + await generateLink(); + } else { + await updateGist(); + } + } catch (e) { + console.error(e); + } finally { + setModal(MODAL.SHARE); + } + }; + + return ( + + ); +} diff --git a/src/components/Workspace.jsx b/src/components/Workspace.jsx index 4d8c803..b0e861f 100644 --- a/src/components/Workspace.jsx +++ b/src/components/Workspace.jsx @@ -1,4 +1,4 @@ -import { useState, useEffect, useCallback } from "react"; +import { useState, useEffect, useCallback, createContext } from "react"; import ControlPanel from "./EditorHeader/ControlPanel"; import Canvas from "./EditorCanvas/Canvas"; import { CanvasContextProvider } from "../context/CanvasContext"; @@ -24,8 +24,11 @@ import { useTranslation } from "react-i18next"; import { databases } from "../data/databases"; import { isRtl } from "../i18n/utils/rtl"; +export const IdContext = createContext({ gistId: "" }); + export default function WorkSpace() { const [id, setId] = useState(0); + const [gistId, setGistId] = useState(""); const [title, setTitle] = useState("Untitled Diagram"); const [resize, setResize] = useState(false); const [width, setWidth] = useState(340); @@ -72,6 +75,7 @@ export default function WorkSpace() { .add({ database: database, name: title, + gistId: gistId ?? "", lastModified: new Date(), tables: tables, references: relationships, @@ -100,6 +104,7 @@ export default function WorkSpace() { notes: notes, areas: areas, todos: tasks, + gistId: gistId ?? "", pan: transform.pan, zoom: transform.zoom, ...(databases[database].hasEnums && { enums: enums }), @@ -146,6 +151,7 @@ export default function WorkSpace() { setSaveState, database, enums, + gistId, ]); const load = useCallback(async () => { @@ -161,6 +167,7 @@ export default function WorkSpace() { setDatabase(DB.GENERIC); } setId(d.id); + setGistId(d.gistId); setTitle(d.name); setTables(d.tables); setRelationships(d.references); @@ -196,6 +203,7 @@ export default function WorkSpace() { setDatabase(DB.GENERIC); } setId(diagram.id); + setGistId(diagram.gistId); setTitle(diagram.name); setTables(diagram.tables); setRelationships(diagram.references); @@ -327,11 +335,15 @@ export default function WorkSpace() { setSaveState, ]); + useEffect(() => { + setSaveState(State.SAVING); + }, [gistId, setSaveState]); + useEffect(() => { if (saveState !== State.SAVING) return; save(); - }, [id, saveState, save]); + }, [id, gistId, saveState, save]); useEffect(() => { document.title = "Editor | drawDB"; @@ -341,14 +353,16 @@ export default function WorkSpace() { return (
    - + + +
    e.isPrimary && setResize(false)} From 3f24ceaf93aa928f1157a164ad584718ef738d1c Mon Sep 17 00:00:00 2001 From: 1ilit <1ilit@proton.me> Date: Thu, 29 Aug 2024 19:53:10 +0400 Subject: [PATCH 05/14] Copy share url --- src/components/EditorHeader/ControlPanel.jsx | 12 +- src/components/EditorHeader/Modal/Share.jsx | 136 +++++++++++++++---- src/components/EditorHeader/ShareButton.jsx | 97 ------------- src/i18n/locales/en.js | 2 +- 4 files changed, 117 insertions(+), 130 deletions(-) delete mode 100644 src/components/EditorHeader/ShareButton.jsx diff --git a/src/components/EditorHeader/ControlPanel.jsx b/src/components/EditorHeader/ControlPanel.jsx index 1961046..6d8cdfe 100644 --- a/src/components/EditorHeader/ControlPanel.jsx +++ b/src/components/EditorHeader/ControlPanel.jsx @@ -9,6 +9,7 @@ import { IconUndo, IconRedo, IconEdit, + IconShareStroked, } from "@douyinfe/semi-icons"; import { Link, useNavigate } from "react-router-dom"; import icon from "../../assets/icon_dark_64.png"; @@ -70,7 +71,6 @@ import { exportSQL } from "../../utils/exportSQL"; import { databases } from "../../data/databases"; import { jsonToMermaid } from "../../utils/exportAs/mermaid"; import { isRtl } from "../../i18n/utils/rtl"; -import ShareButton from "./ShareButton"; export default function ControlPanel({ diagramId, @@ -1363,7 +1363,15 @@ export default function ControlPanel({ {layout.header && (
    {header()} - + {" "}
    )} {layout.toolbar && toolbar()} diff --git a/src/components/EditorHeader/Modal/Share.jsx b/src/components/EditorHeader/Modal/Share.jsx index bc4896d..33c2434 100644 --- a/src/components/EditorHeader/Modal/Share.jsx +++ b/src/components/EditorHeader/Modal/Share.jsx @@ -1,38 +1,114 @@ -import { Banner } from "@douyinfe/semi-ui"; +import { Button, Input, Spin, Toast } from "@douyinfe/semi-ui"; import { MODAL } from "../../../data/constants"; +import { useCallback, useContext, useEffect, useState, useMemo } from "react"; +import { useTranslation } from "react-i18next"; +import { Octokit } from "octokit"; +import { IdContext } from "../../Workspace"; +import { IconLink } from "@douyinfe/semi-icons"; export default function Share({ setModal }) { + const { t } = useTranslation(); + const { gistId, setGistId } = useContext(IdContext); + const [loading, setLoading] = useState(false); + + const userToken = localStorage.getItem("github_token"); + const octokit = useMemo(() => { + return new Octokit({ + auth: userToken ?? import.meta.env.VITE_GITHUB_ACCESS_TOKEN, + }); + }, [userToken]); + const url = useMemo( + () => window.location.href + "?shareId=" + gistId, + [gistId], + ); + + const updateGist = useCallback(async () => { + setLoading(true); + try { + await octokit.request(`PATCH /gists/${gistId}`, { + gist_id: gistId, + description: "drawDB diagram", + files: { + "test.json": { + content: '{"Hello":"SEAMAN"}', + }, + }, + headers: { + "X-GitHub-Api-Version": "2022-11-28", + }, + }); + } catch (e) { + console.error(e); + } finally { + setLoading(false); + } + }, [gistId, octokit]); + + const generateLink = useCallback(async () => { + setLoading(true); + try { + const res = await octokit.request("POST /gists", { + description: "drawDB diagram", + public: false, + files: { + "test.json": { + content: '{"Hello":"WORLD"}', + }, + }, + headers: { + "X-GitHub-Api-Version": "2022-11-28", + }, + }); + setGistId(res.data.id); + } catch (e) { + console.error(e); + } finally { + setLoading(false); + } + }, [octokit, setGistId]); + + useEffect(() => { + const updateOrGenerateLink = async () => { + try { + if (!gistId || gistId === "") { + await generateLink(); + } else { + await updateGist(); + } + } catch (e) { + console.error(e); + } finally { + setModal(MODAL.SHARE); + } + }; + updateOrGenerateLink(); + }, [gistId, generateLink, setModal, updateGist]); + + const copyLink = () => { + navigator.clipboard + .writeText(url) + .then(() => { + Toast.success(t("copied_to_clipboard")); + }) + .catch(() => { + Toast.error(t("oops_smth_went_wrong")); + }); + }; + + if (loading) + return ( +
    + +
    {t("loading")}
    +
    + ); return ( -
    - -
  • - Generating a link will create a gist with the JSON representation - of the diagram. -
  • -
  • - You can create the gist from your account by providing your token - - . -
  • -
  • - Sharing will not create a live real-time collaboration session. -
  • - - } - /> - +
    + +
    ); } diff --git a/src/components/EditorHeader/ShareButton.jsx b/src/components/EditorHeader/ShareButton.jsx deleted file mode 100644 index 826a2b0..0000000 --- a/src/components/EditorHeader/ShareButton.jsx +++ /dev/null @@ -1,97 +0,0 @@ -import { Button, Spin } from "@douyinfe/semi-ui"; -import { IconShareStroked } from "@douyinfe/semi-icons"; -import { useTranslation } from "react-i18next"; -import { Octokit } from "octokit"; -import { MODAL } from "../../data/constants"; -import { useContext, useState } from "react"; -import { IdContext } from "../Workspace"; - -export default function ShareButton({ setModal }) { - const { t } = useTranslation(); - const { gistId, setGistId } = useContext(IdContext); - const [loading, setLoading] = useState(false); - - const updateGist = async () => { - setLoading(true); - const userToken = localStorage.getItem("github_token"); - - const octokit = new Octokit({ - auth: userToken ?? import.meta.env.VITE_GITHUB_ACCESS_TOKEN, - }); - - try { - const res = await octokit.request(`PATCH /gists/${gistId}`, { - gist_id: gistId, - description: "drawDB diagram", - files: { - "test.json": { - content: '{"Hello":"SEAMAN"}', - }, - }, - headers: { - "X-GitHub-Api-Version": "2022-11-28", - }, - }); - console.log(res); - } catch (e) { - console.error(e); - } finally { - setLoading(false); - } - }; - - const generateLink = async () => { - setLoading(true); - const userToken = localStorage.getItem("github_token"); - - const octokit = new Octokit({ - auth: userToken ?? import.meta.env.VITE_GITHUB_ACCESS_TOKEN, - }); - - try { - const res = await octokit.request("POST /gists", { - description: "drawDB diagram", - public: false, - files: { - "test.json": { - content: '{"Hello":"WORLD"}', - }, - }, - headers: { - "X-GitHub-Api-Version": "2022-11-28", - }, - }); - setGistId(res.data.id); - } catch (e) { - console.error(e); - } finally { - setLoading(false); - } - }; - - const onShare = async () => { - try { - if (!gistId || gistId === "") { - await generateLink(); - } else { - await updateGist(); - } - } catch (e) { - console.error(e); - } finally { - setModal(MODAL.SHARE); - } - }; - - return ( - - ); -} diff --git a/src/i18n/locales/en.js b/src/i18n/locales/en.js index 634de80..7053848 100644 --- a/src/i18n/locales/en.js +++ b/src/i18n/locales/en.js @@ -237,7 +237,7 @@ const en = { didnt_find_diagram: "Oops! Didn't find the diagram.", unsigned: "Unsigned", share: "Share", - generate_link: "Generate link", + copy_link: "Copy link", github_token: "GitHub Token", }, }; From 65a86ee4f59d33067ac5ef6651790422b6eba270 Mon Sep 17 00:00:00 2001 From: 1ilit <1ilit@proton.me> Date: Fri, 30 Aug 2024 11:09:50 +0400 Subject: [PATCH 06/14] Remodel the copy link modal --- src/components/EditorHeader/ControlPanel.jsx | 2 + src/components/EditorHeader/Modal/Modal.jsx | 8 +-- src/components/EditorHeader/Modal/Share.jsx | 65 ++++++++++++++------ 3 files changed, 53 insertions(+), 22 deletions(-) diff --git a/src/components/EditorHeader/ControlPanel.jsx b/src/components/EditorHeader/ControlPanel.jsx index 6d8cdfe..e1bc35f 100644 --- a/src/components/EditorHeader/ControlPanel.jsx +++ b/src/components/EditorHeader/ControlPanel.jsx @@ -71,6 +71,7 @@ import { exportSQL } from "../../utils/exportSQL"; import { databases } from "../../data/databases"; import { jsonToMermaid } from "../../utils/exportAs/mermaid"; import { isRtl } from "../../i18n/utils/rtl"; +import Share from "./Modal/Share"; export default function ControlPanel({ diagramId, @@ -1376,6 +1377,7 @@ export default function ControlPanel({ )} {layout.toolbar && toolbar()}
    + { + if (modal === MODAL.SHARE) return; switch (modal) { case MODAL.IMPORT: return ( @@ -341,8 +341,8 @@ export default function Modal({ return ; case MODAL.LANGUAGE: return ; - case MODAL.SHARE: - return ; + // case MODAL.SHARE: + // return ; case MODAL.GITHUB_TOKEN: return ; default: @@ -354,7 +354,7 @@ export default function Modal({ { setExportData(() => ({ diff --git a/src/components/EditorHeader/Modal/Share.jsx b/src/components/EditorHeader/Modal/Share.jsx index 33c2434..58f46f3 100644 --- a/src/components/EditorHeader/Modal/Share.jsx +++ b/src/components/EditorHeader/Modal/Share.jsx @@ -1,13 +1,14 @@ -import { Button, Input, Spin, Toast } from "@douyinfe/semi-ui"; +import { Button, Input, Modal, Spin, Toast } from "@douyinfe/semi-ui"; import { MODAL } from "../../../data/constants"; import { useCallback, useContext, useEffect, useState, useMemo } from "react"; import { useTranslation } from "react-i18next"; import { Octokit } from "octokit"; import { IdContext } from "../../Workspace"; import { IconLink } from "@douyinfe/semi-icons"; +import { isRtl } from "../../../i18n/utils/rtl"; -export default function Share({ setModal }) { - const { t } = useTranslation(); +export default function Share({ modal, setModal }) { + const { t, i18n } = useTranslation(); const { gistId, setGistId } = useContext(IdContext); const [loading, setLoading] = useState(false); @@ -78,7 +79,7 @@ export default function Share({ setModal }) { } catch (e) { console.error(e); } finally { - setModal(MODAL.SHARE); + setLoading(false); } }; updateOrGenerateLink(); @@ -95,20 +96,48 @@ export default function Share({ setModal }) { }); }; - if (loading) - return ( -
    - -
    {t("loading")}
    -
    - ); - return ( -
    - - -
    + } + onCancel={() => setModal(MODAL.NONE)} + centered + closeOnEsc={true} + cancelText={t("cancel")} + width={600} + bodyStyle={{ + maxHeight: window.innerHeight - 280, + overflow: "auto", + direction: "ltr", + }} + > + {loading ? ( +
    + +
    {t("loading")}
    +
    + ) : ( +
    +
    + + +
    +
    +
    + * Sharing this link will not create a live real-time collaboration + session +
    +
    + )} +
    ); } From ed7fd87f7a026851f878952f6d335664cbba16a0 Mon Sep 17 00:00:00 2001 From: 1ilit <1ilit@proton.me> Date: Sat, 31 Aug 2024 19:49:43 +0400 Subject: [PATCH 07/14] Fix gists being controlled on button load --- src/components/EditorHeader/ControlPanel.jsx | 9 +- src/components/EditorHeader/Modal/Modal.jsx | 8 +- src/components/EditorHeader/Modal/Share.jsx | 118 ++++++++++--------- src/components/Workspace.jsx | 49 +++++++- 4 files changed, 116 insertions(+), 68 deletions(-) diff --git a/src/components/EditorHeader/ControlPanel.jsx b/src/components/EditorHeader/ControlPanel.jsx index e1bc35f..834a4de 100644 --- a/src/components/EditorHeader/ControlPanel.jsx +++ b/src/components/EditorHeader/ControlPanel.jsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useContext, useState } from "react"; import { IconCaretdown, IconChevronRight, @@ -71,7 +71,7 @@ import { exportSQL } from "../../utils/exportSQL"; import { databases } from "../../data/databases"; import { jsonToMermaid } from "../../utils/exportAs/mermaid"; import { isRtl } from "../../i18n/utils/rtl"; -import Share from "./Modal/Share"; +import { IdContext } from "../Workspace"; export default function ControlPanel({ diagramId, @@ -114,6 +114,7 @@ export default function ControlPanel({ const { selectedElement, setSelectedElement } = useSelect(); const { transform, setTransform } = useTransform(); const { t, i18n } = useTranslation(); + const { setGistId } = useContext(IdContext); const navigate = useNavigate(); const invertLayout = (component) => @@ -783,6 +784,7 @@ export default function ControlPanel({ setEnums([]); setUndoStack([]); setRedoStack([]); + setGistId(""); }) .catch(() => Toast.error(t("oops_smth_went_wrong"))); }, @@ -1372,12 +1374,11 @@ export default function ControlPanel({ onClick={() => setModal(MODAL.SHARE)} > {t("share")} - {" "} +
    )} {layout.toolbar && toolbar()}
    - { - if (modal === MODAL.SHARE) return; switch (modal) { case MODAL.IMPORT: return ( @@ -341,8 +341,8 @@ export default function Modal({ return ; case MODAL.LANGUAGE: return ; - // case MODAL.SHARE: - // return ; + case MODAL.SHARE: + return ; case MODAL.GITHUB_TOKEN: return ; default: @@ -354,7 +354,7 @@ export default function Modal({ { setExportData(() => ({ diff --git a/src/components/EditorHeader/Modal/Share.jsx b/src/components/EditorHeader/Modal/Share.jsx index 58f46f3..c776576 100644 --- a/src/components/EditorHeader/Modal/Share.jsx +++ b/src/components/EditorHeader/Modal/Share.jsx @@ -1,16 +1,27 @@ -import { Button, Input, Modal, Spin, Toast } from "@douyinfe/semi-ui"; -import { MODAL } from "../../../data/constants"; +import { Button, Input, Spin, Toast } from "@douyinfe/semi-ui"; import { useCallback, useContext, useEffect, useState, useMemo } from "react"; import { useTranslation } from "react-i18next"; import { Octokit } from "octokit"; import { IdContext } from "../../Workspace"; import { IconLink } from "@douyinfe/semi-icons"; -import { isRtl } from "../../../i18n/utils/rtl"; +import { + useAreas, + useDiagram, + useEnums, + useNotes, + useTypes, +} from "../../../hooks"; +import { databases } from "../../../data/databases"; -export default function Share({ modal, setModal }) { - const { t, i18n } = useTranslation(); +export default function Share({ title }) { + const { t } = useTranslation(); const { gistId, setGistId } = useContext(IdContext); - const [loading, setLoading] = useState(false); + const [loading, setLoading] = useState(true); + const { tables, relationships, database } = useDiagram(); + const { notes } = useNotes(); + const { areas } = useAreas(); + const { types } = useTypes(); + const { enums } = useEnums(); const userToken = localStorage.getItem("github_token"); const octokit = useMemo(() => { @@ -23,6 +34,19 @@ export default function Share({ modal, setModal }) { [gistId], ); + const diagramToString = useCallback(() => { + return JSON.stringify({ + tables: tables, + relationships: relationships, + notes: notes, + subjectAreas: areas, + database: database, + ...(databases[database].hasTypes && { types: types }), + ...(databases[database].hasEnums && { enums: enums }), + title: title, + }); + }, [areas, notes, tables, relationships, database, title, enums, types]); + const updateGist = useCallback(async () => { setLoading(true); try { @@ -30,8 +54,8 @@ export default function Share({ modal, setModal }) { gist_id: gistId, description: "drawDB diagram", files: { - "test.json": { - content: '{"Hello":"SEAMAN"}', + "share.json": { + content: diagramToString(), }, }, headers: { @@ -43,7 +67,7 @@ export default function Share({ modal, setModal }) { } finally { setLoading(false); } - }, [gistId, octokit]); + }, [gistId, octokit, diagramToString]); const generateLink = useCallback(async () => { setLoading(true); @@ -52,8 +76,8 @@ export default function Share({ modal, setModal }) { description: "drawDB diagram", public: false, files: { - "test.json": { - content: '{"Hello":"WORLD"}', + "share.json": { + content: diagramToString(), }, }, headers: { @@ -66,7 +90,7 @@ export default function Share({ modal, setModal }) { } finally { setLoading(false); } - }, [octokit, setGistId]); + }, [octokit, setGistId, diagramToString]); useEffect(() => { const updateOrGenerateLink = async () => { @@ -83,7 +107,7 @@ export default function Share({ modal, setModal }) { } }; updateOrGenerateLink(); - }, [gistId, generateLink, setModal, updateGist]); + }, [gistId, generateLink, updateGist]); const copyLink = () => { navigator.clipboard @@ -96,48 +120,32 @@ export default function Share({ modal, setModal }) { }); }; + if (loading) + return ( +
    + +
    {t("loading")}
    +
    + ); + return ( - } - onCancel={() => setModal(MODAL.NONE)} - centered - closeOnEsc={true} - cancelText={t("cancel")} - width={600} - bodyStyle={{ - maxHeight: window.innerHeight - 280, - overflow: "auto", - direction: "ltr", - }} - > - {loading ? ( -
    - -
    {t("loading")}
    -
    - ) : ( -
    -
    - - -
    -
    -
    - * Sharing this link will not create a live real-time collaboration - session -
    -
    - )} -
    +
    +
    + + +
    +
    +
    + * Sharing this link will not create a live real-time collaboration + session +
    +
    ); } diff --git a/src/components/Workspace.jsx b/src/components/Workspace.jsx index b0e861f..a845b51 100644 --- a/src/components/Workspace.jsx +++ b/src/components/Workspace.jsx @@ -1,4 +1,10 @@ -import { useState, useEffect, useCallback, createContext } from "react"; +import { + useState, + useEffect, + useCallback, + createContext, + useMemo, +} from "react"; import ControlPanel from "./EditorHeader/ControlPanel"; import Canvas from "./EditorCanvas/Canvas"; import { CanvasContextProvider } from "../context/CanvasContext"; @@ -23,6 +29,8 @@ import { Modal } from "@douyinfe/semi-ui"; import { useTranslation } from "react-i18next"; import { databases } from "../data/databases"; import { isRtl } from "../i18n/utils/rtl"; +import { useSearchParams } from "react-router-dom"; +import { Octokit } from "octokit"; export const IdContext = createContext({ gistId: "" }); @@ -54,7 +62,13 @@ export default function WorkSpace() { } = useDiagram(); const { undoStack, redoStack, setUndoStack, setRedoStack } = useUndoRedo(); const { t, i18n } = useTranslation(); - + let [searchParams] = useSearchParams(); + const userToken = localStorage.getItem("github_token"); + const octokit = useMemo(() => { + return new Octokit({ + auth: userToken ?? import.meta.env.VITE_GITHUB_ACCESS_TOKEN, + }); + }, [userToken]); const handleResize = (e) => { if (!resize) return; const w = isRtl(i18n.language) ? window.innerWidth - e.clientX : e.clientX; @@ -307,6 +321,24 @@ export default function WorkSpace() { selectedDb, ]); + const loadFromGist = useCallback( + async (shareId) => { + try { + const res = await octokit.request(`GET /gists/${shareId}`, { + gist_id: shareId, + headers: { + "X-GitHub-Api-Version": "2022-11-28", + }, + }); + const diagramSrc = res.data.files["share.json"].content; + console.log(diagramSrc); + } catch (e) { + console.log(e); + } + }, + [octokit], + ); + useEffect(() => { if ( tables?.length === 0 && @@ -336,7 +368,9 @@ export default function WorkSpace() { ]); useEffect(() => { - setSaveState(State.SAVING); + if (gistId && gistId !== "") { + setSaveState(State.SAVING); + } }, [gistId, setSaveState]); useEffect(() => { @@ -348,8 +382,13 @@ export default function WorkSpace() { useEffect(() => { document.title = "Editor | drawDB"; - load(); - }, [load]); + const shareId = searchParams.get("shareId"); + if (shareId) { + loadFromGist(shareId); + } else { + load(); + } + }, [load, searchParams, loadFromGist]); return (
    From c6c24d02b99eed0490712248447beec2dbbc6920 Mon Sep 17 00:00:00 2001 From: 1ilit <1ilit@proton.me> Date: Sun, 1 Sep 2024 13:22:04 +0400 Subject: [PATCH 08/14] Load diagram from gist --- src/components/Workspace.jsx | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/components/Workspace.jsx b/src/components/Workspace.jsx index a845b51..af1c321 100644 --- a/src/components/Workspace.jsx +++ b/src/components/Workspace.jsx @@ -331,12 +331,35 @@ export default function WorkSpace() { }, }); const diagramSrc = res.data.files["share.json"].content; - console.log(diagramSrc); + const d = JSON.parse(diagramSrc); + console.log(d); + window.name = ""; + setDatabase(d.database); + setTitle(d.title); + setTables(d.tables); + setRelationships(d.relationships); + setNotes(d.notes); + setAreas(d.subjectAreas); + if (databases[d.database].hasTypes) { + setTypes(d.types ?? []); + } + if (databases[d.database].hasEnums) { + setEnums(d.enums ?? []); + } } catch (e) { console.log(e); } }, - [octokit], + [ + octokit, + setAreas, + setDatabase, + setEnums, + setNotes, + setRelationships, + setTables, + setTypes, + ], ); useEffect(() => { From 9aec2f02d042848b58ae228cf407a1a650f80905 Mon Sep 17 00:00:00 2001 From: 1ilit <1ilit@proton.me> Date: Sun, 1 Sep 2024 19:15:58 +0400 Subject: [PATCH 09/14] Prevent creating duplicates when loading from gist --- src/components/EditorHeader/Modal/Modal.jsx | 2 ++ src/components/EditorHeader/Modal/Share.jsx | 15 +++++++++++++- src/components/Workspace.jsx | 22 +++++++++++++++++++-- src/data/db.js | 4 ++-- 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/components/EditorHeader/Modal/Modal.jsx b/src/components/EditorHeader/Modal/Modal.jsx index a550753..d187929 100644 --- a/src/components/EditorHeader/Modal/Modal.jsx +++ b/src/components/EditorHeader/Modal/Modal.jsx @@ -388,7 +388,9 @@ export default function Modal({ ((modal === MODAL.IMG || modal === MODAL.CODE) && !exportData.data) || (modal === MODAL.SAVEAS && saveAsTitle === "") || (modal === MODAL.IMPORT_SRC && importSource.src === ""), + hidden: modal === MODAL.SHARE, }} + hasCancel={modal !== MODAL.SHARE} cancelText={t("cancel")} width={getModalWidth(modal)} bodyStyle={{ diff --git a/src/components/EditorHeader/Modal/Share.jsx b/src/components/EditorHeader/Modal/Share.jsx index c776576..35260d1 100644 --- a/src/components/EditorHeader/Modal/Share.jsx +++ b/src/components/EditorHeader/Modal/Share.jsx @@ -9,6 +9,7 @@ import { useDiagram, useEnums, useNotes, + useTransform, useTypes, } from "../../../hooks"; import { databases } from "../../../data/databases"; @@ -22,6 +23,7 @@ export default function Share({ title }) { const { areas } = useAreas(); const { types } = useTypes(); const { enums } = useEnums(); + const { transform } = useTransform(); const userToken = localStorage.getItem("github_token"); const octokit = useMemo(() => { @@ -44,8 +46,19 @@ export default function Share({ title }) { ...(databases[database].hasTypes && { types: types }), ...(databases[database].hasEnums && { enums: enums }), title: title, + transform: transform, }); - }, [areas, notes, tables, relationships, database, title, enums, types]); + }, [ + areas, + notes, + tables, + relationships, + database, + title, + enums, + types, + transform, + ]); const updateGist = useCallback(async () => { setLoading(true); diff --git a/src/components/Workspace.jsx b/src/components/Workspace.jsx index af1c321..30e1734 100644 --- a/src/components/Workspace.jsx +++ b/src/components/Workspace.jsx @@ -37,6 +37,7 @@ export const IdContext = createContext({ gistId: "" }); export default function WorkSpace() { const [id, setId] = useState(0); const [gistId, setGistId] = useState(""); + const [loadedFromGistId, setLoadedFromGistId] = useState(""); const [title, setTitle] = useState("Untitled Diagram"); const [resize, setResize] = useState(false); const [width, setWidth] = useState(340); @@ -98,6 +99,7 @@ export default function WorkSpace() { todos: tasks, pan: transform.pan, zoom: transform.zoom, + loadedFromGistId: loadedFromGistId, ...(databases[database].hasEnums && { enums: enums }), ...(databases[database].hasTypes && { types: types }), }) @@ -121,6 +123,7 @@ export default function WorkSpace() { gistId: gistId ?? "", pan: transform.pan, zoom: transform.zoom, + loadedFromGistId: loadedFromGistId, ...(databases[database].hasEnums && { enums: enums }), ...(databases[database].hasTypes && { types: types }), }) @@ -166,6 +169,7 @@ export default function WorkSpace() { database, enums, gistId, + loadedFromGistId, ]); const load = useCallback(async () => { @@ -182,6 +186,7 @@ export default function WorkSpace() { } setId(d.id); setGistId(d.gistId); + setLoadedFromGistId(d.loadedFromGistId); setTitle(d.name); setTables(d.tables); setRelationships(d.references); @@ -218,6 +223,7 @@ export default function WorkSpace() { } setId(diagram.id); setGistId(diagram.gistId); + setLoadedFromGistId(diagram.loadedFromGistId); setTitle(diagram.name); setTables(diagram.tables); setRelationships(diagram.references); @@ -323,6 +329,13 @@ export default function WorkSpace() { const loadFromGist = useCallback( async (shareId) => { + const d = await db.diagrams.get({ loadedFromGistId: shareId }); + if (d) { + window.name = "d " + d.id; + } else { + window.name = ""; + } + try { const res = await octokit.request(`GET /gists/${shareId}`, { gist_id: shareId, @@ -332,14 +345,16 @@ export default function WorkSpace() { }); const diagramSrc = res.data.files["share.json"].content; const d = JSON.parse(diagramSrc); - console.log(d); - window.name = ""; + setUndoStack([]); + setRedoStack([]); + setLoadedFromGistId(shareId); setDatabase(d.database); setTitle(d.title); setTables(d.tables); setRelationships(d.relationships); setNotes(d.notes); setAreas(d.subjectAreas); + setTransform(d.transform); if (databases[d.database].hasTypes) { setTypes(d.types ?? []); } @@ -359,6 +374,9 @@ export default function WorkSpace() { setRelationships, setTables, setTypes, + setTransform, + setRedoStack, + setUndoStack, ], ); diff --git a/src/data/db.js b/src/data/db.js index 8355a5c..c9ef3af 100644 --- a/src/data/db.js +++ b/src/data/db.js @@ -3,8 +3,8 @@ import { templateSeeds } from "./seeds"; export const db = new Dexie("drawDB"); -db.version(5).stores({ - diagrams: "++id, lastModified", +db.version(6).stores({ + diagrams: "++id, lastModified, &loadedFromGistId", templates: "++id, custom", }); From 59a388f44c30dee801083301c145a936e53b3146 Mon Sep 17 00:00:00 2001 From: 1ilit <1ilit@proton.me> Date: Sun, 1 Sep 2024 19:52:23 +0400 Subject: [PATCH 10/14] Fix wrong url being generated for shared diagrams --- src/components/EditorHeader/Modal/Share.jsx | 21 ++++++--------------- src/components/Workspace.jsx | 19 +++---------------- src/data/db.js | 2 +- src/data/octokit.js | 5 +++++ 4 files changed, 15 insertions(+), 32 deletions(-) create mode 100644 src/data/octokit.js diff --git a/src/components/EditorHeader/Modal/Share.jsx b/src/components/EditorHeader/Modal/Share.jsx index 35260d1..420ff41 100644 --- a/src/components/EditorHeader/Modal/Share.jsx +++ b/src/components/EditorHeader/Modal/Share.jsx @@ -1,7 +1,6 @@ import { Button, Input, Spin, Toast } from "@douyinfe/semi-ui"; -import { useCallback, useContext, useEffect, useState, useMemo } from "react"; +import { useCallback, useContext, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; -import { Octokit } from "octokit"; import { IdContext } from "../../Workspace"; import { IconLink } from "@douyinfe/semi-icons"; import { @@ -13,6 +12,7 @@ import { useTypes, } from "../../../hooks"; import { databases } from "../../../data/databases"; +import { octokit } from "../../../data/octokit"; export default function Share({ title }) { const { t } = useTranslation(); @@ -24,17 +24,8 @@ export default function Share({ title }) { const { types } = useTypes(); const { enums } = useEnums(); const { transform } = useTransform(); - - const userToken = localStorage.getItem("github_token"); - const octokit = useMemo(() => { - return new Octokit({ - auth: userToken ?? import.meta.env.VITE_GITHUB_ACCESS_TOKEN, - }); - }, [userToken]); - const url = useMemo( - () => window.location.href + "?shareId=" + gistId, - [gistId], - ); + const url = + window.location.origin + window.location.pathname + "?shareId=" + gistId; const diagramToString = useCallback(() => { return JSON.stringify({ @@ -80,7 +71,7 @@ export default function Share({ title }) { } finally { setLoading(false); } - }, [gistId, octokit, diagramToString]); + }, [gistId, diagramToString]); const generateLink = useCallback(async () => { setLoading(true); @@ -103,7 +94,7 @@ export default function Share({ title }) { } finally { setLoading(false); } - }, [octokit, setGistId, diagramToString]); + }, [setGistId, diagramToString]); useEffect(() => { const updateOrGenerateLink = async () => { diff --git a/src/components/Workspace.jsx b/src/components/Workspace.jsx index 30e1734..0ecbb20 100644 --- a/src/components/Workspace.jsx +++ b/src/components/Workspace.jsx @@ -1,10 +1,4 @@ -import { - useState, - useEffect, - useCallback, - createContext, - useMemo, -} from "react"; +import { useState, useEffect, useCallback, createContext } from "react"; import ControlPanel from "./EditorHeader/ControlPanel"; import Canvas from "./EditorCanvas/Canvas"; import { CanvasContextProvider } from "../context/CanvasContext"; @@ -30,7 +24,7 @@ import { useTranslation } from "react-i18next"; import { databases } from "../data/databases"; import { isRtl } from "../i18n/utils/rtl"; import { useSearchParams } from "react-router-dom"; -import { Octokit } from "octokit"; +import { octokit } from "../data/octokit"; export const IdContext = createContext({ gistId: "" }); @@ -64,12 +58,6 @@ export default function WorkSpace() { const { undoStack, redoStack, setUndoStack, setRedoStack } = useUndoRedo(); const { t, i18n } = useTranslation(); let [searchParams] = useSearchParams(); - const userToken = localStorage.getItem("github_token"); - const octokit = useMemo(() => { - return new Octokit({ - auth: userToken ?? import.meta.env.VITE_GITHUB_ACCESS_TOKEN, - }); - }, [userToken]); const handleResize = (e) => { if (!resize) return; const w = isRtl(i18n.language) ? window.innerWidth - e.clientX : e.clientX; @@ -335,7 +323,6 @@ export default function WorkSpace() { } else { window.name = ""; } - try { const res = await octokit.request(`GET /gists/${shareId}`, { gist_id: shareId, @@ -345,6 +332,7 @@ export default function WorkSpace() { }); const diagramSrc = res.data.files["share.json"].content; const d = JSON.parse(diagramSrc); + setGistId("") setUndoStack([]); setRedoStack([]); setLoadedFromGistId(shareId); @@ -366,7 +354,6 @@ export default function WorkSpace() { } }, [ - octokit, setAreas, setDatabase, setEnums, diff --git a/src/data/db.js b/src/data/db.js index c9ef3af..adddd91 100644 --- a/src/data/db.js +++ b/src/data/db.js @@ -4,7 +4,7 @@ import { templateSeeds } from "./seeds"; export const db = new Dexie("drawDB"); db.version(6).stores({ - diagrams: "++id, lastModified, &loadedFromGistId", + diagrams: "++id, lastModified, loadedFromGistId", templates: "++id, custom", }); diff --git a/src/data/octokit.js b/src/data/octokit.js new file mode 100644 index 0000000..d922073 --- /dev/null +++ b/src/data/octokit.js @@ -0,0 +1,5 @@ +import { Octokit } from "octokit"; + +export const octokit = new Octokit({ + auth: import.meta.env.VITE_GITHUB_ACCESS_TOKEN, +}); From 85cf795fc968d8ced3267e7b503f035ef1a823a0 Mon Sep 17 00:00:00 2001 From: 1ilit <1ilit@proton.me> Date: Sun, 1 Sep 2024 20:24:09 +0400 Subject: [PATCH 11/14] Prevent the diagram from getting overwritten when reloaded --- src/components/Workspace.jsx | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/components/Workspace.jsx b/src/components/Workspace.jsx index 0ecbb20..ed06ae5 100644 --- a/src/components/Workspace.jsx +++ b/src/components/Workspace.jsx @@ -57,7 +57,7 @@ export default function WorkSpace() { } = useDiagram(); const { undoStack, redoStack, setUndoStack, setRedoStack } = useUndoRedo(); const { t, i18n } = useTranslation(); - let [searchParams] = useSearchParams(); + let [searchParams, setSearchParams] = useSearchParams(); const handleResize = (e) => { if (!resize) return; const w = isRtl(i18n.language) ? window.innerWidth - e.clientX : e.clientX; @@ -70,6 +70,8 @@ export default function WorkSpace() { const saveAsDiagram = window.name === "" || op === "d" || op === "lt"; if (saveAsDiagram) { + searchParams.delete("shareId"); + setSearchParams(searchParams); if ( (id === 0 && window.name === "") || window.name.split(" ")[0] === "lt" @@ -144,6 +146,8 @@ export default function WorkSpace() { }); } }, [ + searchParams, + setSearchParams, tables, relationships, notes, @@ -317,9 +321,11 @@ export default function WorkSpace() { const loadFromGist = useCallback( async (shareId) => { - const d = await db.diagrams.get({ loadedFromGistId: shareId }); - if (d) { - window.name = "d " + d.id; + const existingDiagram = await db.diagrams.get({ + loadedFromGistId: shareId, + }); + if (existingDiagram) { + window.name = "d " + existingDiagram.id; } else { window.name = ""; } @@ -332,7 +338,7 @@ export default function WorkSpace() { }); const diagramSrc = res.data.files["share.json"].content; const d = JSON.parse(diagramSrc); - setGistId("") + setGistId(""); setUndoStack([]); setRedoStack([]); setLoadedFromGistId(shareId); From 6eddfd983f9a5d221cead1efdced6c7a1139966c Mon Sep 17 00:00:00 2001 From: 1ilit <1ilit@proton.me> Date: Sun, 1 Sep 2024 20:36:20 +0400 Subject: [PATCH 12/14] Remove github token modal --- src/components/EditorHeader/ControlPanel.jsx | 3 -- .../EditorHeader/Modal/GithubToken.jsx | 43 ------------------- src/components/EditorHeader/Modal/Modal.jsx | 14 ------ src/components/Workspace.jsx | 1 - src/data/constants.js | 1 - src/i18n/locales/en.js | 1 - src/utils/modalData.js | 2 - 7 files changed, 65 deletions(-) delete mode 100644 src/components/EditorHeader/Modal/GithubToken.jsx diff --git a/src/components/EditorHeader/ControlPanel.jsx b/src/components/EditorHeader/ControlPanel.jsx index 834a4de..7eb3cc1 100644 --- a/src/components/EditorHeader/ControlPanel.jsx +++ b/src/components/EditorHeader/ControlPanel.jsx @@ -1293,9 +1293,6 @@ export default function ControlPanel({ language: { function: () => setModal(MODAL.LANGUAGE), }, - github_token: { - function: () => setModal(MODAL.GITHUB_TOKEN), - }, flush_storage: { warning: { title: t("flush_storage"), diff --git a/src/components/EditorHeader/Modal/GithubToken.jsx b/src/components/EditorHeader/Modal/GithubToken.jsx deleted file mode 100644 index 56ac2d4..0000000 --- a/src/components/EditorHeader/Modal/GithubToken.jsx +++ /dev/null @@ -1,43 +0,0 @@ -import { Button, Input } from "@douyinfe/semi-ui"; -import { useTranslation } from "react-i18next"; - -export default function GithubToken({ token, setToken }) { - const { t } = useTranslation(); - - const clearToken = () => { - localStorage.removeItem("github_token"); - setToken(""); - }; - - return ( -
    -
    - Set your{" "} - - personal access token - {" "} - here if you wish to save diagrams to your gists. -
    -
    - setToken(v)} - /> -
    -
    - *This will be stored in the local storage -
    -
    - ); -} diff --git a/src/components/EditorHeader/Modal/Modal.jsx b/src/components/EditorHeader/Modal/Modal.jsx index d187929..009b689 100644 --- a/src/components/EditorHeader/Modal/Modal.jsx +++ b/src/components/EditorHeader/Modal/Modal.jsx @@ -43,7 +43,6 @@ import { useTranslation } from "react-i18next"; import { importSQL } from "../../../utils/importSQL"; import { databases } from "../../../data/databases"; import { isRtl } from "../../../i18n/utils/rtl"; -import GithubToken from "./GithubToken"; const languageExtension = { sql: [sql()], @@ -83,9 +82,6 @@ export default function Modal({ const [selectedTemplateId, setSelectedTemplateId] = useState(-1); const [selectedDiagramId, setSelectedDiagramId] = useState(0); const [saveAsTitle, setSaveAsTitle] = useState(title); - const [token, setToken] = useState( - localStorage.getItem("github_token") ?? "", - ); const overwriteDiagram = () => { setTables(importData.tables); @@ -242,14 +238,6 @@ export default function Modal({ setModal(MODAL.NONE); createNewDiagram(selectedTemplateId); return; - case MODAL.GITHUB_TOKEN: - setModal(MODAL.NONE); - if (token !== "") { - localStorage.setItem("github_token", token); - } else { - localStorage.removeItem("github_token"); - } - return; default: setModal(MODAL.NONE); return; @@ -343,8 +331,6 @@ export default function Modal({ return ; case MODAL.SHARE: return ; - case MODAL.GITHUB_TOKEN: - return ; default: return <>; } diff --git a/src/components/Workspace.jsx b/src/components/Workspace.jsx index ed06ae5..77436f0 100644 --- a/src/components/Workspace.jsx +++ b/src/components/Workspace.jsx @@ -338,7 +338,6 @@ export default function WorkSpace() { }); const diagramSrc = res.data.files["share.json"].content; const d = JSON.parse(diagramSrc); - setGistId(""); setUndoStack([]); setRedoStack([]); setLoadedFromGistId(shareId); diff --git a/src/data/constants.js b/src/data/constants.js index 69e9d33..59bd4ff 100644 --- a/src/data/constants.js +++ b/src/data/constants.js @@ -92,7 +92,6 @@ export const MODAL = { TABLE_WIDTH: 9, LANGUAGE: 10, SHARE: 11, - GITHUB_TOKEN: 12, }; export const STATUS = { diff --git a/src/i18n/locales/en.js b/src/i18n/locales/en.js index 7053848..1c0898d 100644 --- a/src/i18n/locales/en.js +++ b/src/i18n/locales/en.js @@ -238,7 +238,6 @@ const en = { unsigned: "Unsigned", share: "Share", copy_link: "Copy link", - github_token: "GitHub Token", }, }; diff --git a/src/utils/modalData.js b/src/utils/modalData.js index 2b996c9..f4fbf45 100644 --- a/src/utils/modalData.js +++ b/src/utils/modalData.js @@ -25,8 +25,6 @@ export const getModalTitle = (modal) => { return i18n.t("language"); case MODAL.SHARE: return i18n.t("share"); - case MODAL.GITHUB_TOKEN: - return i18n.t("github_token"); default: return ""; } From 877ec72e03defb8aabc1b7ab91e4561dfa0f0547 Mon Sep 17 00:00:00 2001 From: 1ilit <1ilit@proton.me> Date: Sun, 1 Sep 2024 20:40:48 +0400 Subject: [PATCH 13/14] Disable sharing for templates --- src/components/EditorHeader/ControlPanel.jsx | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/components/EditorHeader/ControlPanel.jsx b/src/components/EditorHeader/ControlPanel.jsx index 7eb3cc1..f175e78 100644 --- a/src/components/EditorHeader/ControlPanel.jsx +++ b/src/components/EditorHeader/ControlPanel.jsx @@ -1363,15 +1363,17 @@ export default function ControlPanel({ {layout.header && (
    {header()} - + {window.name.split(" ")[0] !== "t" && ( + + )}
    )} {layout.toolbar && toolbar()} From fcf2251e9bfef0a64bdcb477a937a49269cd266b Mon Sep 17 00:00:00 2001 From: 1ilit <1ilit@proton.me> Date: Sun, 1 Sep 2024 21:14:18 +0400 Subject: [PATCH 14/14] Handle incorrect links and corrupted files --- src/components/EditorHeader/ControlPanel.jsx | 4 +++- src/components/EditorHeader/Modal/Share.jsx | 5 +---- src/components/Workspace.jsx | 2 ++ src/data/constants.js | 1 + src/i18n/locales/en.js | 3 +++ 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/components/EditorHeader/ControlPanel.jsx b/src/components/EditorHeader/ControlPanel.jsx index dbd5c64..593e69d 100644 --- a/src/components/EditorHeader/ControlPanel.jsx +++ b/src/components/EditorHeader/ControlPanel.jsx @@ -1084,7 +1084,7 @@ export default function ControlPanel({ data: result, extension: "md", })); - } + }, }, ], function: () => {}, @@ -1604,6 +1604,8 @@ export default function ControlPanel({ return t("saving"); case State.ERROR: return t("failed_to_save"); + case State.FAILED_TO_LOAD: + return t("failed_to_load"); default: return ""; } diff --git a/src/components/EditorHeader/Modal/Share.jsx b/src/components/EditorHeader/Modal/Share.jsx index 420ff41..3731a3e 100644 --- a/src/components/EditorHeader/Modal/Share.jsx +++ b/src/components/EditorHeader/Modal/Share.jsx @@ -146,10 +146,7 @@ export default function Share({ title }) {

    -
    - * Sharing this link will not create a live real-time collaboration - session -
    +
    {t("share_info")}
    ); } diff --git a/src/components/Workspace.jsx b/src/components/Workspace.jsx index 77436f0..ce9a4f6 100644 --- a/src/components/Workspace.jsx +++ b/src/components/Workspace.jsx @@ -356,6 +356,7 @@ export default function WorkSpace() { } } catch (e) { console.log(e); + setSaveState(State.FAILED_TO_LOAD); } }, [ @@ -369,6 +370,7 @@ export default function WorkSpace() { setTransform, setRedoStack, setUndoStack, + setSaveState, ], ); diff --git a/src/data/constants.js b/src/data/constants.js index 59bd4ff..e17b7d1 100644 --- a/src/data/constants.js +++ b/src/data/constants.js @@ -77,6 +77,7 @@ export const State = { SAVED: 2, LOADING: 3, ERROR: 4, + FAILED_TO_LOAD: 5, }; export const MODAL = { diff --git a/src/i18n/locales/en.js b/src/i18n/locales/en.js index 8304eb1..cebfac6 100644 --- a/src/i18n/locales/en.js +++ b/src/i18n/locales/en.js @@ -239,6 +239,9 @@ const en = { share: "Share", copy_link: "Copy link", readme: "README", + failed_to_load: "Failed to load. Make sure the link is correct.", + share_info: + "* Sharing this link will not create a live real-time collaboration session.", }, };