From 2c75aeadc9a7a18881a1f4209e6c946ae8bcdf64 Mon Sep 17 00:00:00 2001 From: Justin Fiedler Date: Sun, 14 Jul 2024 00:50:57 +0000 Subject: [PATCH 01/14] update README --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 29c61de..0b56fe7 100644 --- a/README.md +++ b/README.md @@ -25,16 +25,17 @@ cd packages/webapp npm install npm run dev -# in a new terminal +# in a new terminal (Requires python 3.10+) cd packages/thought_server -virtualenv env -./venv/bin/activate -python thought_server.py +virtualenv venv +source ./venv/bin/activate +pip install -r requirements.txt +. ./launch.sh # in a new terminal cd packages/env npm install -npm run thoughtServer +npm run terminalServer # in a new terminal cd packages/env From 159c760f0c1181e84320c1ae64238219ede2b9aa Mon Sep 17 00:00:00 2001 From: Justin Fiedler Date: Sun, 14 Jul 2024 03:30:49 +0000 Subject: [PATCH 02/14] add basic login screen and sign out button --- packages/webapp/package-lock.json | 106 ++++++++++++------ packages/webapp/package.json | 4 +- packages/webapp/src/App-compiled.css | 4 + packages/webapp/src/App.tsx | 62 +++++++--- .../webapp/src/components/auth/Signout.tsx | 25 +++++ 5 files changed, 152 insertions(+), 49 deletions(-) create mode 100644 packages/webapp/src/components/auth/Signout.tsx diff --git a/packages/webapp/package-lock.json b/packages/webapp/package-lock.json index bdf95f3..7c29b5e 100644 --- a/packages/webapp/package-lock.json +++ b/packages/webapp/package-lock.json @@ -9,7 +9,9 @@ "version": "0.0.1", "dependencies": { "@huggingface/inference": "^2.6.4", - "@supabase/supabase-js": "^2.39.3", + "@supabase/auth-ui-react": "^0.4.7", + "@supabase/auth-ui-shared": "^0.1.8", + "@supabase/supabase-js": "^2.44.2", "@xenova/transformers": "^2.15.1", "draft-js": "^0.11.7", "lodash": "^4.17.21", @@ -1440,18 +1442,50 @@ "win32" ] }, - "node_modules/@supabase/functions-js": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.1.5.tgz", - "integrity": "sha512-BNzC5XhCzzCaggJ8s53DP+WeHHGT/NfTsx2wUSSGKR2/ikLFQTBCDzMvGz/PxYMqRko/LwncQtKXGOYp1PkPaw==", + "node_modules/@stitches/core": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@stitches/core/-/core-1.2.8.tgz", + "integrity": "sha512-Gfkvwk9o9kE9r9XNBmJRfV8zONvXThnm1tcuojL04Uy5uRyqg93DC83lDebl0rocZCfKSjUv+fWYtMQmEDJldg==", + "license": "MIT" + }, + "node_modules/@supabase/auth-js": { + "version": "2.64.2", + "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.64.2.tgz", + "integrity": "sha512-s+lkHEdGiczDrzXJ1YWt2y3bxRi+qIUnXcgkpLSrId7yjBeaXBFygNjTaoZLG02KNcYwbuZ9qkEIqmj2hF7svw==", + "license": "MIT", "dependencies": { "@supabase/node-fetch": "^2.6.14" } }, - "node_modules/@supabase/gotrue-js": { - "version": "2.62.2", - "resolved": "https://registry.npmjs.org/@supabase/gotrue-js/-/gotrue-js-2.62.2.tgz", - "integrity": "sha512-AP6e6W9rQXFTEJ7sTTNYQrNf0LCcnt1hUW+RIgUK+Uh3jbWvcIST7wAlYyNZiMlS9+PYyymWQ+Ykz/rOYSO0+A==", + "node_modules/@supabase/auth-ui-react": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/@supabase/auth-ui-react/-/auth-ui-react-0.4.7.tgz", + "integrity": "sha512-Lp4FQGFh7BMX1Y/BFaUKidbryL7eskj1fl6Lby7BeHrTctbdvDbCMjVKS8wZ2rxuI8FtPS2iU900fSb70FHknQ==", + "dependencies": { + "@stitches/core": "^1.2.8", + "@supabase/auth-ui-shared": "0.1.8", + "prop-types": "^15.7.2", + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "peerDependencies": { + "@supabase/supabase-js": "^2.21.0" + } + }, + "node_modules/@supabase/auth-ui-shared": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@supabase/auth-ui-shared/-/auth-ui-shared-0.1.8.tgz", + "integrity": "sha512-ouQ0DjKcEFg+0gZigFIEgu01V3e6riGZPzgVD0MJsCBNsMsiDT74+GgCEIElMUpTGkwSja3xLwdFRFgMNFKcjg==", + "license": "MIT", + "peerDependencies": { + "@supabase/supabase-js": "^2.21.0" + } + }, + "node_modules/@supabase/functions-js": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.4.1.tgz", + "integrity": "sha512-8sZ2ibwHlf+WkHDUZJUXqqmPvWQ3UHN0W30behOJngVh/qHHekhJLCFbh0AjkE9/FqqXtf9eoVvmYgfCLk5tNA==", + "license": "MIT", "dependencies": { "@supabase/node-fetch": "^2.6.14" } @@ -1460,6 +1494,7 @@ "version": "2.6.15", "resolved": "https://registry.npmjs.org/@supabase/node-fetch/-/node-fetch-2.6.15.tgz", "integrity": "sha512-1ibVeYUacxWYi9i0cf5efil6adJ9WRyZBLivgjs+AUpewx1F3xPi7gLgaASI2SmIQxPoCEjAsLAzKPgMJVgOUQ==", + "license": "MIT", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -1468,17 +1503,19 @@ } }, "node_modules/@supabase/postgrest-js": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-1.9.2.tgz", - "integrity": "sha512-I6yHo8CC9cxhOo6DouDMy9uOfW7hjdsnCxZiaJuIVZm1dBGTFiQPgfMa9zXCamEWzNyWRjZvupAUuX+tqcl5Sw==", + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-1.15.7.tgz", + "integrity": "sha512-TJztay5lcnnKuXjIO/X/aaajOsP8qNeW0k3MqIFoOtRolj5MEAIy8rixNakRk3o23eVCdsuP3iMLYPvOOruH6Q==", + "license": "MIT", "dependencies": { "@supabase/node-fetch": "^2.6.14" } }, "node_modules/@supabase/realtime-js": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.9.3.tgz", - "integrity": "sha512-lAp50s2n3FhGJFq+wTSXLNIDPw5Y0Wxrgt44eM5nLSA3jZNUUP3Oq2Ccd1CbZdVntPCWLZvJaU//pAd2NE+QnQ==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.10.2.tgz", + "integrity": "sha512-qyCQaNg90HmJstsvr2aJNxK2zgoKh9ZZA8oqb7UT2LCh3mj9zpa3Iwu167AuyNxsxrUE8eEJ2yH6wLCij4EApA==", + "license": "MIT", "dependencies": { "@supabase/node-fetch": "^2.6.14", "@types/phoenix": "^1.5.4", @@ -1487,24 +1524,26 @@ } }, "node_modules/@supabase/storage-js": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.5.5.tgz", - "integrity": "sha512-OpLoDRjFwClwc2cjTJZG8XviTiQH4Ik8sCiMK5v7et0MDu2QlXjCAW3ljxJB5+z/KazdMOTnySi+hysxWUPu3w==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.6.0.tgz", + "integrity": "sha512-REAxr7myf+3utMkI2oOmZ6sdplMZZ71/2NEIEMBZHL9Fkmm3/JnaOZVSRqvG4LStYj2v5WhCruCzuMn6oD/Drw==", + "license": "MIT", "dependencies": { "@supabase/node-fetch": "^2.6.14" } }, "node_modules/@supabase/supabase-js": { - "version": "2.39.7", - "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.39.7.tgz", - "integrity": "sha512-1vxsX10Uhc2b+Dv9pRjBjHfqmw2N2h1PyTg9LEfICR3x2xwE24By1MGCjDZuzDKH5OeHCsf4it6K8KRluAAEXA==", + "version": "2.44.2", + "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.44.2.tgz", + "integrity": "sha512-fouCwL1OxqftOwLNgdDUPlNnFuCnt30nS4kLcnTpe6NYKn1PmjxRRBFmKscgHs6FjWyU+32ZG4uBJ29+/BWiDw==", + "license": "MIT", "dependencies": { - "@supabase/functions-js": "2.1.5", - "@supabase/gotrue-js": "2.62.2", + "@supabase/auth-js": "2.64.2", + "@supabase/functions-js": "2.4.1", "@supabase/node-fetch": "2.6.15", - "@supabase/postgrest-js": "1.9.2", - "@supabase/realtime-js": "2.9.3", - "@supabase/storage-js": "2.5.5" + "@supabase/postgrest-js": "1.15.7", + "@supabase/realtime-js": "2.10.2", + "@supabase/storage-js": "2.6.0" } }, "node_modules/@types/babel__core": { @@ -1604,9 +1643,10 @@ "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" }, "node_modules/@types/phoenix": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.4.tgz", - "integrity": "sha512-B34A7uot1Cv0XtaHRYDATltAdKx0BvVKNgYNqE4WjtPUa4VQJM7kxeXcVKaH+KS+kCmZ+6w+QaUdcljiheiBJA==" + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.5.tgz", + "integrity": "sha512-xegpDuR+z0UqG9fwHqNoy3rI7JDlvaPh2TY47Fl80oq6g+hXT+c/LEuE43X48clZ6lOfANl5WrPur9fYO1RJ/w==", + "license": "MIT" }, "node_modules/@types/prop-types": { "version": "15.7.11", @@ -1665,6 +1705,7 @@ "version": "8.5.10", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -5694,9 +5735,10 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/ws": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", - "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "license": "MIT", "engines": { "node": ">=10.0.0" }, diff --git a/packages/webapp/package.json b/packages/webapp/package.json index e882ac2..a836484 100644 --- a/packages/webapp/package.json +++ b/packages/webapp/package.json @@ -12,7 +12,9 @@ }, "dependencies": { "@huggingface/inference": "^2.6.4", - "@supabase/supabase-js": "^2.39.3", + "@supabase/auth-ui-react": "^0.4.7", + "@supabase/auth-ui-shared": "^0.1.8", + "@supabase/supabase-js": "^2.44.2", "@xenova/transformers": "^2.15.1", "draft-js": "^0.11.7", "lodash": "^4.17.21", diff --git a/packages/webapp/src/App-compiled.css b/packages/webapp/src/App-compiled.css index 06089a7..627212a 100644 --- a/packages/webapp/src/App-compiled.css +++ b/packages/webapp/src/App-compiled.css @@ -637,6 +637,10 @@ video { justify-content: flex-end; } +.justify-center { + justify-content: center; +} + .justify-between { justify-content: space-between; } diff --git a/packages/webapp/src/App.tsx b/packages/webapp/src/App.tsx index beaab8e..3eb1138 100644 --- a/packages/webapp/src/App.tsx +++ b/packages/webapp/src/App.tsx @@ -14,6 +14,9 @@ import { throttle } from "lodash"; import { Database } from "./database.types"; import "prosemirror-view/style/prosemirror.css"; import { RealtimePostgresChangesPayload } from "@supabase/supabase-js"; +import { Auth } from "@supabase/auth-ui-react"; +import { ThemeSupa } from '@supabase/auth-ui-shared' +import { SignOutButton } from './components/auth/Signout'; const THOUGHTS_TABLE_NAME = "thoughts"; const APP_INSTANCE_ID = uuidv4(); // used to keep subscriptions from handling their own updates @@ -105,6 +108,7 @@ function App() { const [generatingLoopOn, setGeneratingLoopOn] = useState(false); // Use this to control the generation loop const [generationTrigger, setGenerationTrigger] = useState(null); const [msTillNextThought, setMsTillNextThought] = useState(null); + const [session, setSession] = useState(null) function computeNewThoughtIndex(state: EditorState, appendToEnd?: boolean) { let newThought = null; @@ -255,7 +259,7 @@ function App() { thoughtIdsInSelection.add(node.attrs.id); } }); - + // Check if it's just a cursor position without a selection range. const isCursor = from === to; if (isCursor) { @@ -269,13 +273,13 @@ function App() { } else { // Here you can handle the deletion of thoughts by their IDs. // For example, mark them for deletion in the database, update state, etc. - + if (dispatch) { // Create and dispatch a transaction that deletes the selected range. const deleteTransaction = state.tr.delete(from, to); dispatch(deleteTransaction); } - + // Return true to indicate that the backspace handler has done something, // preventing the default backspace behavior. retVal = true; @@ -290,7 +294,7 @@ function App() { return true; }, }); - + //const backspaceKeyPlugin = keymap({ // Backspace: (state, dispatch) => { // // Use the joinBackward command directly @@ -445,8 +449,25 @@ function App() { setThoughtIdsToUpdate(new Set()); } - const throttlePushToDB = useMemo(() => throttle(pushToDB, 1000), []); + /** + * Auth + */ + useEffect(() => { + // Get session + supabase.auth.getSession().then(({ data: { session } }) => { + setSession(session) + }) + + // Listen for auth state changes + const { data: { subscription } } = supabase.auth.onAuthStateChange((_event, session) => { + setSession(session) + }) + // Remove auth listener on exit + return () => subscription.unsubscribe() + }, []) + + const throttlePushToDB = useMemo(() => throttle(pushToDB, 1000), []); useEffect(() => { if (thoughtIdsToUpdate.size === 0) { return; @@ -794,7 +815,7 @@ function App() { return new Set(prev).add(currentThoughtId); }); } - } + } editorViewRef.current.updateState(newState); }, }); @@ -911,7 +932,7 @@ function App() { async function appendToGeneratedThought(delta: string) { if (delta && editorViewRef.current) { const tr = editorViewRef.current.state.tr; - + let newThoughtPos = null; let newThought = null; @@ -923,7 +944,7 @@ function App() { newThought = node; } }); - + if (newThoughtPos === null) { console.log("No 'thought' node found in the document."); return; @@ -932,14 +953,14 @@ function App() { // Create a text node with the delta content const textNode = editorViewRef.current.state.schema.text(delta); let insertPos = newThoughtPos as number + newThought.nodeSize - 1; - + // Insert the delta text at the end of the last thought tr.insert(insertPos, textNode).scrollIntoView(); - + // Apply highlight mark if needed const highlightMark = editorViewRef.current.state.schema.marks.highlight.create(); tr.addMark(insertPos, insertPos + delta.length, highlightMark); - + editorViewRef.current.dispatch(tr); } } @@ -1028,8 +1049,16 @@ function App() { ); }; - return ( -
+ return !session + ? ( +
+
+ +
+
+ ) + : ( +
@@ -1054,6 +1083,7 @@ function App() { ))}
+ {session && ()}
{envStatus === "attached" ? ( <> @@ -1120,9 +1150,9 @@ function App() { ) : ( ) : null } - {/* + {/*
@@ -1085,34 +1088,8 @@ function App() {
{session && ()}
- {envStatus === "attached" ? ( - <> - Environment - {/* Online Icon */} - - - - - ) : ( - <> - Environment - {/* Offline Icon: Red circle (outline) with a red "X" */} - - {" "} - {/* Red outlined circle with black fill */} - {/* Red X */} - - - )} + Environment +
diff --git a/packages/webapp/src/components/ConnectionStatusIcon.tsx b/packages/webapp/src/components/ConnectionStatusIcon.tsx new file mode 100644 index 0000000..d38a56d --- /dev/null +++ b/packages/webapp/src/components/ConnectionStatusIcon.tsx @@ -0,0 +1,47 @@ +/** + * ConnectionStatusIconProps + */ +export type ConnectionStatusIconProps = { + connected: boolean +} + +/** + * ConnectionStatusIcon + */ +export function ConnectionStatusIcon({ connected }: ConnectionStatusIconProps) { + return connected ? ConnectedIcon() : DisconnectedIcon() +} + +/** + * ConnectedIcon - Green circle + */ +export function ConnectedIcon() { + return ( + + + + ) +} + +/** + * DisconnectedIcon - Red circle (outline) with a red "X" + */ +export function DisconnectedIcon() { + return ( + + {/* Red outlined circle with black fill */} + {" "} + {/* Red X */} + + + ) +} From 105142ca59ae87e4da456ad8b0ba1a765f62e3ba Mon Sep 17 00:00:00 2001 From: Justin Fiedler Date: Sun, 14 Jul 2024 03:39:45 +0000 Subject: [PATCH 05/14] extract HeadlongIcon into dedicated component --- packages/webapp/src/App.tsx | 7 ++----- packages/webapp/src/components/HeadlongIcon.tsx | 9 +++++++++ 2 files changed, 11 insertions(+), 5 deletions(-) create mode 100644 packages/webapp/src/components/HeadlongIcon.tsx diff --git a/packages/webapp/src/App.tsx b/packages/webapp/src/App.tsx index abea4a2..5a402fc 100644 --- a/packages/webapp/src/App.tsx +++ b/packages/webapp/src/App.tsx @@ -18,6 +18,7 @@ import { Auth } from "@supabase/auth-ui-react"; import { ThemeSupa } from '@supabase/auth-ui-shared' import { SignOutButton } from './components/auth/Signout'; import { ConnectionStatusIcon } from './components/ConnectionStatusIcon'; +import { HeadlongIcon } from './components/HeadlongIcon'; const THOUGHTS_TABLE_NAME = "thoughts"; const APP_INSTANCE_ID = uuidv4(); // used to keep subscriptions from handling their own updates @@ -1063,11 +1064,7 @@ function App() { : (
- - - - - + -
- {session && ()} +
Environment
+
diff --git a/packages/webapp/src/components/auth/Signout.tsx b/packages/webapp/src/components/auth/SignOutButton.tsx similarity index 84% rename from packages/webapp/src/components/auth/Signout.tsx rename to packages/webapp/src/components/auth/SignOutButton.tsx index 5081a77..b217d65 100644 --- a/packages/webapp/src/components/auth/Signout.tsx +++ b/packages/webapp/src/components/auth/SignOutButton.tsx @@ -10,7 +10,7 @@ export type SignOutButtonProps = { */ export function SignOutButton({ supabaseClient }: SignOutButtonProps) { return ( - + + ) +} + +export type PasswordInputProps = { + value: String, + placeholder: String | null, + onChange: (event: ChangeEvent) => any, + disabled: Boolean, +} + +function PasswordInput({value, placeholder, onChange, disabled = false}: PasswordInputProps) { + const [type, setType] = useState('password'); + const [icon, setIcon] = useState(eyeOff); + + const handleToggle = () => { + if (type==='password'){ + setIcon(eye); + setType('text') + } else { + setIcon(eyeOff) + setType('password') + } + } + + return ( +
+
+
+ + + + +
+
+
+ ); +} diff --git a/packages/webapp/src/components/auth/SignOutButton.tsx b/packages/webapp/src/components/auth/SignOutButton.tsx index b217d65..5560dc4 100644 --- a/packages/webapp/src/components/auth/SignOutButton.tsx +++ b/packages/webapp/src/components/auth/SignOutButton.tsx @@ -1,14 +1,19 @@ +import { useNavigate } from "react-router-dom"; +import { pathLogin } from '../../routes'; + /** - * ConnectionStatusIconProps + * SignOutButtonProps */ export type SignOutButtonProps = { - supabaseClient: any + supabaseClient: any, } /** - * ConnectionStatusIcon + * SignOutButton */ export function SignOutButton({ supabaseClient }: SignOutButtonProps) { + const navigate = useNavigate() + return (