From f19345c652cfcf1bdf13d0a44a2f302e0cd1aa4c Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Sun, 6 Aug 2023 09:28:22 -0700 Subject: feat: :construction: Router and new history page --- extension/react-app/src/components/DebugPanel.tsx | 99 ----------------------- extension/react-app/src/components/Layout.tsx | 28 +++++++ 2 files changed, 28 insertions(+), 99 deletions(-) delete mode 100644 extension/react-app/src/components/DebugPanel.tsx create mode 100644 extension/react-app/src/components/Layout.tsx (limited to 'extension/react-app/src/components') diff --git a/extension/react-app/src/components/DebugPanel.tsx b/extension/react-app/src/components/DebugPanel.tsx deleted file mode 100644 index fffb6c6e..00000000 --- a/extension/react-app/src/components/DebugPanel.tsx +++ /dev/null @@ -1,99 +0,0 @@ -import React, { useEffect, useState } from "react"; -import styled from "styled-components"; -import { postVscMessage } from "../vscode"; -import { useDispatch } from "react-redux"; -import { - setApiUrl, - setVscMachineId, - setSessionId, - setVscMediaUrl, - setDataSwitchOn, -} from "../redux/slices/configSlice"; -import { setHighlightedCode } from "../redux/slices/miscSlice"; -import { updateFileSystem } from "../redux/slices/debugContexSlice"; -import { defaultBorderRadius, secondaryDark, vscBackground } from "."; -interface DebugPanelProps { - tabs: { - element: React.ReactElement; - title: string; - }[]; -} - -const TabBar = styled.div<{ numTabs: number }>` - display: grid; - grid-template-columns: repeat(${(props) => props.numTabs}, 1fr); -`; - -const TabsAndBodyDiv = styled.div` - height: 100%; - border-radius: ${defaultBorderRadius}; - scrollbar-base-color: transparent; -`; - -function DebugPanel(props: DebugPanelProps) { - const dispatch = useDispatch(); - useEffect(() => { - const eventListener = (event: any) => { - switch (event.data.type) { - case "onLoad": - dispatch(setApiUrl(event.data.apiUrl)); - dispatch(setVscMachineId(event.data.vscMachineId)); - dispatch(setSessionId(event.data.sessionId)); - dispatch(setVscMediaUrl(event.data.vscMediaUrl)); - dispatch(setDataSwitchOn(event.data.dataSwitchOn)); - break; - case "highlightedCode": - dispatch(setHighlightedCode(event.data.rangeInFile)); - dispatch(updateFileSystem(event.data.filesystem)); - break; - } - }; - window.addEventListener("message", eventListener); - postVscMessage("onLoad", {}); - return () => window.removeEventListener("message", eventListener); - }, []); - - const [currentTab, setCurrentTab] = useState(0); - - return ( - - {props.tabs.length > 1 && ( - - {props.tabs.map((tab, index) => { - return ( -
setCurrentTab(index)} - > - {tab.title} -
- ); - })} -
- )} - {props.tabs.map((tab, index) => { - return ( - - ); - })} -
- ); -} - -export default DebugPanel; diff --git a/extension/react-app/src/components/Layout.tsx b/extension/react-app/src/components/Layout.tsx new file mode 100644 index 00000000..d1688299 --- /dev/null +++ b/extension/react-app/src/components/Layout.tsx @@ -0,0 +1,28 @@ +import styled from "styled-components"; +import { defaultBorderRadius } from "."; +import { Outlet } from "react-router-dom"; + +const LayoutTopDiv = styled.div` + height: 100%; + border-radius: ${defaultBorderRadius}; + scrollbar-base-color: transparent; + scrollbar-width: thin; +`; +const Layout = () => { + return ( + +
+ +
+
+ ); +}; + +export default Layout; -- cgit v1.2.3-70-g09d2 From 31e7c9828f985eceb16b4c9c749cc5d4d9fd5beb Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Sun, 6 Aug 2023 13:28:22 -0700 Subject: feat: :construction: react-router-dom work --- .../src/continuedev/server/session_manager.py | 4 + extension/react-app/package-lock.json | 219 ++++----------------- extension/react-app/package.json | 2 +- extension/react-app/src/App.tsx | 36 ++-- extension/react-app/src/components/Layout.tsx | 1 + extension/react-app/src/main.tsx | 10 +- extension/react-app/src/pages/error.tsx | 17 ++ extension/react-app/src/pages/gui.tsx | 5 +- extension/react-app/src/pages/history.tsx | 23 ++- 9 files changed, 108 insertions(+), 209 deletions(-) create mode 100644 extension/react-app/src/pages/error.tsx (limited to 'extension/react-app/src/components') diff --git a/continuedev/src/continuedev/server/session_manager.py b/continuedev/src/continuedev/server/session_manager.py index dade9853..f876c9a9 100644 --- a/continuedev/src/continuedev/server/session_manager.py +++ b/continuedev/src/continuedev/server/session_manager.py @@ -159,5 +159,9 @@ session_manager = SessionManager() async def list_sessions(): """List all sessions""" sessions_list_file = getSessionsListFilePath() + if not os.path.exists(sessions_list_file): + print("Returning empty sessions list") + return [] sessions = json.load(open(sessions_list_file, "r")) + print("Returning sessions list: ", sessions) return sessions diff --git a/extension/react-app/package-lock.json b/extension/react-app/package-lock.json index b5e32316..b057fe20 100644 --- a/extension/react-app/package-lock.json +++ b/extension/react-app/package-lock.json @@ -18,7 +18,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-redux": "^8.0.5", - "react-router-dom": "^5.2.0", + "react-router-dom": "^6.14.2", "react-switch": "^7.0.0", "react-syntax-highlighter": "^15.5.0", "react-tooltip": "^5.18.0", @@ -872,6 +872,14 @@ "node": ">= 8" } }, + "node_modules/@remix-run/router": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.7.2.tgz", + "integrity": "sha512-7Lcn7IqGMV+vizMPoEl5F0XDshcdDYtMI6uJLQdQz5CfZAwy3vvGKYSUk789qndt5dEC4HfSjviSYlSoHGL2+A==", + "engines": { + "node": ">=14" + } + }, "node_modules/@swc/core": { "version": "1.3.73", "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.73.tgz", @@ -2250,19 +2258,6 @@ "node": "*" } }, - "node_modules/history": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", - "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", - "dependencies": { - "@babel/runtime": "^7.1.2", - "loose-envify": "^1.2.0", - "resolve-pathname": "^3.0.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0", - "value-equal": "^1.0.1" - } - }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -2433,11 +2428,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" - }, "node_modules/jiti": { "version": "1.19.1", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.1.tgz", @@ -3513,14 +3503,6 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "node_modules/path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dependencies": { - "isarray": "0.0.1" - } - }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -3842,61 +3824,35 @@ } }, "node_modules/react-router": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz", - "integrity": "sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==", - "dependencies": { - "@babel/runtime": "^7.1.2", - "history": "^4.9.0", - "hoist-non-react-statics": "^3.1.0", - "loose-envify": "^1.3.1", - "mini-create-react-context": "^0.4.0", - "path-to-regexp": "^1.7.0", - "prop-types": "^15.6.2", - "react-is": "^16.6.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.14.2.tgz", + "integrity": "sha512-09Zss2dE2z+T1D03IheqAFtK4UzQyX8nFPWx6jkwdYzGLXd5ie06A6ezS2fO6zJfEb/SpG6UocN2O1hfD+2urQ==", + "dependencies": { + "@remix-run/router": "1.7.2" + }, + "engines": { + "node": ">=14" }, "peerDependencies": { - "react": ">=15" + "react": ">=16.8" } }, "node_modules/react-router-dom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.2.0.tgz", - "integrity": "sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA==", + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.14.2.tgz", + "integrity": "sha512-5pWX0jdKR48XFZBuJqHosX3AAHjRAzygouMTyimnBPOLdY3WjzUSKhus2FVMihUFWzeLebDgr4r8UeQFAct7Bg==", "dependencies": { - "@babel/runtime": "^7.1.2", - "history": "^4.9.0", - "loose-envify": "^1.3.1", - "prop-types": "^15.6.2", - "react-router": "5.2.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" + "@remix-run/router": "1.7.2", + "react-router": "6.14.2" }, - "peerDependencies": { - "react": ">=15" - } - }, - "node_modules/react-router/node_modules/mini-create-react-context": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", - "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", - "dependencies": { - "@babel/runtime": "^7.12.1", - "tiny-warning": "^1.0.3" + "engines": { + "node": ">=14" }, "peerDependencies": { - "prop-types": "^15.0.0", - "react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + "react": ">=16.8", + "react-dom": ">=16.8" } }, - "node_modules/react-router/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, "node_modules/react-switch": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/react-switch/-/react-switch-7.0.0.tgz", @@ -4291,11 +4247,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/resolve-pathname": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", - "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" - }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -4536,16 +4487,6 @@ "node": ">=0.8" } }, - "node_modules/tiny-invariant": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz", - "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==" - }, - "node_modules/tiny-warning": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", - "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" - }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -4781,11 +4722,6 @@ "node": ">=8" } }, - "node_modules/value-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", - "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" - }, "node_modules/vfile": { "version": "5.3.7", "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", @@ -5470,6 +5406,11 @@ "fastq": "^1.6.0" } }, + "@remix-run/router": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.7.2.tgz", + "integrity": "sha512-7Lcn7IqGMV+vizMPoEl5F0XDshcdDYtMI6uJLQdQz5CfZAwy3vvGKYSUk789qndt5dEC4HfSjviSYlSoHGL2+A==" + }, "@swc/core": { "version": "1.3.73", "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.73.tgz", @@ -6446,19 +6387,6 @@ "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==" }, - "history": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", - "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", - "requires": { - "@babel/runtime": "^7.1.2", - "loose-envify": "^1.2.0", - "resolve-pathname": "^3.0.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0", - "value-equal": "^1.0.1" - } - }, "hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -6573,11 +6501,6 @@ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==" }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" - }, "jiti": { "version": "1.19.1", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.1.tgz", @@ -7268,14 +7191,6 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "requires": { - "isarray": "0.0.1" - } - }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -7462,50 +7377,20 @@ } }, "react-router": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz", - "integrity": "sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==", - "requires": { - "@babel/runtime": "^7.1.2", - "history": "^4.9.0", - "hoist-non-react-statics": "^3.1.0", - "loose-envify": "^1.3.1", - "mini-create-react-context": "^0.4.0", - "path-to-regexp": "^1.7.0", - "prop-types": "^15.6.2", - "react-is": "^16.6.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" - }, - "dependencies": { - "mini-create-react-context": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", - "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==", - "requires": { - "@babel/runtime": "^7.12.1", - "tiny-warning": "^1.0.3" - } - }, - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - } + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.14.2.tgz", + "integrity": "sha512-09Zss2dE2z+T1D03IheqAFtK4UzQyX8nFPWx6jkwdYzGLXd5ie06A6ezS2fO6zJfEb/SpG6UocN2O1hfD+2urQ==", + "requires": { + "@remix-run/router": "1.7.2" } }, "react-router-dom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.2.0.tgz", - "integrity": "sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA==", + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.14.2.tgz", + "integrity": "sha512-5pWX0jdKR48XFZBuJqHosX3AAHjRAzygouMTyimnBPOLdY3WjzUSKhus2FVMihUFWzeLebDgr4r8UeQFAct7Bg==", "requires": { - "@babel/runtime": "^7.1.2", - "history": "^4.9.0", - "loose-envify": "^1.3.1", - "prop-types": "^15.6.2", - "react-router": "5.2.0", - "tiny-invariant": "^1.0.2", - "tiny-warning": "^1.0.0" + "@remix-run/router": "1.7.2", + "react-router": "6.14.2" } }, "react-switch": { @@ -7798,11 +7683,6 @@ "supports-preserve-symlinks-flag": "^1.0.0" } }, - "resolve-pathname": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", - "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" - }, "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -7967,16 +7847,6 @@ "thenify": ">= 3.1.0 < 4" } }, - "tiny-invariant": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz", - "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==" - }, - "tiny-warning": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", - "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" - }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -8132,11 +8002,6 @@ "sade": "^1.7.3" } }, - "value-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", - "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" - }, "vfile": { "version": "5.3.7", "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", diff --git a/extension/react-app/package.json b/extension/react-app/package.json index 5eb58c8a..b4762990 100644 --- a/extension/react-app/package.json +++ b/extension/react-app/package.json @@ -19,7 +19,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-redux": "^8.0.5", - "react-router-dom": "^5.2.0", + "react-router-dom": "^6.14.2", "react-switch": "^7.0.0", "react-syntax-highlighter": "^15.5.0", "react-tooltip": "^5.18.0", diff --git a/extension/react-app/src/App.tsx b/extension/react-app/src/App.tsx index 15b536db..48ecebaa 100644 --- a/extension/react-app/src/App.tsx +++ b/extension/react-app/src/App.tsx @@ -4,12 +4,6 @@ import Layout from "./components/Layout"; import { createContext, useEffect } from "react"; import useContinueGUIProtocol from "./hooks/useWebsocket"; import ContinueGUIClientProtocol from "./hooks/ContinueGUIClientProtocol"; -import { - BrowserRouter as Router, - Route, - Routes, - BrowserRouter, -} from "react-router-dom"; import { useDispatch } from "react-redux"; import { setApiUrl, @@ -21,6 +15,30 @@ import { import { updateFileSystem } from "./redux/slices/debugContexSlice"; import { setHighlightedCode } from "./redux/slices/miscSlice"; import { postVscMessage } from "./vscode"; +import { createBrowserRouter, RouterProvider } from "react-router-dom"; +import ErrorPage from "./pages/error"; + +const router = createBrowserRouter([ + { + path: "/", + element: , + errorElement: , + children: [ + { + path: "/index.html", + element: , + }, + { + path: "/", + element: , + }, + { + path: "/history", + element: , + }, + ], + }, +]); export const GUIClientContext = createContext< ContinueGUIClientProtocol | undefined @@ -53,11 +71,7 @@ function App() { return ( - - } /> - } /> - } /> - + ); } diff --git a/extension/react-app/src/components/Layout.tsx b/extension/react-app/src/components/Layout.tsx index d1688299..47ed9cc3 100644 --- a/extension/react-app/src/components/Layout.tsx +++ b/extension/react-app/src/components/Layout.tsx @@ -8,6 +8,7 @@ const LayoutTopDiv = styled.div` scrollbar-base-color: transparent; scrollbar-width: thin; `; + const Layout = () => { return ( diff --git a/extension/react-app/src/main.tsx b/extension/react-app/src/main.tsx index 1b70e786..1776490c 100644 --- a/extension/react-app/src/main.tsx +++ b/extension/react-app/src/main.tsx @@ -7,14 +7,6 @@ import "./index.css"; import posthog from "posthog-js"; import { PostHogProvider } from "posthog-js/react"; -import { createBrowserRouter, RouterProvider } from "react-router-dom"; - -const router = createBrowserRouter([ - { - path: "/", - element: , - }, -]); console.log("Starting React"); @@ -27,7 +19,7 @@ ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( - + diff --git a/extension/react-app/src/pages/error.tsx b/extension/react-app/src/pages/error.tsx new file mode 100644 index 00000000..5267c405 --- /dev/null +++ b/extension/react-app/src/pages/error.tsx @@ -0,0 +1,17 @@ +import { useRouteError } from "react-router-dom"; + +export default function ErrorPage() { + const error: any = useRouteError(); + console.error(error); + + return ( +
+

Error in Continue React App

+

+ {error.statusText || error.message} +

+
+
{error.stack}
+
+ ); +} diff --git a/extension/react-app/src/pages/gui.tsx b/extension/react-app/src/pages/gui.tsx index 247789d6..d565e64f 100644 --- a/extension/react-app/src/pages/gui.tsx +++ b/extension/react-app/src/pages/gui.tsx @@ -34,6 +34,7 @@ import { setBottomMessageCloseTimeout, } from "../redux/slices/uiStateSlice"; import RingLoader from "../components/RingLoader"; +import { useNavigate } from "react-router-dom"; const TopGUIDiv = styled.div` overflow: hidden; @@ -83,6 +84,8 @@ interface GUIProps { } function GUI(props: GUIProps) { + const navigate = useNavigate(); + const client = useContext(GUIClientContext); const posthog = usePostHog(); @@ -595,7 +598,7 @@ If you already have an LLM deployed on your own infrastructure, or would like to { // Go to /history page - document.location.href = "/history"; + navigate("/history"); }} text="History" > diff --git a/extension/react-app/src/pages/history.tsx b/extension/react-app/src/pages/history.tsx index 6539f0f5..052fe5be 100644 --- a/extension/react-app/src/pages/history.tsx +++ b/extension/react-app/src/pages/history.tsx @@ -1,22 +1,26 @@ import React, { useContext, useEffect, useState } from "react"; import { SessionInfo } from "../../../schema/SessionInfo"; import { GUIClientContext } from "../App"; -import fetch from "node-fetch"; import { useSelector } from "react-redux"; import { RootStore } from "../redux/store"; +import { useNavigate } from "react-router-dom"; function History() { + const navigate = useNavigate(); const [sessions, setSessions] = useState([]); const client = useContext(GUIClientContext); const apiUrl = useSelector((state: RootStore) => state.config.apiUrl); useEffect(() => { const fetchSessions = async () => { - console.log("fetching sessions"); + console.log("fetching sessions from: ", apiUrl); if (!apiUrl) { return; } const response = await fetch(`${apiUrl}/sessions/list`); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } const json = await response.json(); console.log(json); setSessions(json); @@ -25,23 +29,22 @@ function History() { }, [client]); return ( -
- +
+

History

+
{sessions.map((session, index) => ( -- cgit v1.2.3-70-g09d2 From 712b110ac67e7bff0729b903512bda7f4c77c8d9 Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Sun, 6 Aug 2023 16:16:50 -0700 Subject: refactor: :recycle: refactor bottom bar into Layout --- extension/react-app/src/components/Layout.tsx | 183 ++++++- extension/react-app/src/pages/gui.tsx | 555 +++++++-------------- .../react-app/src/redux/slices/uiStateSlice.ts | 26 +- extension/react-app/src/redux/store.ts | 4 + 4 files changed, 403 insertions(+), 365 deletions(-) (limited to 'extension/react-app/src/components') diff --git a/extension/react-app/src/components/Layout.tsx b/extension/react-app/src/components/Layout.tsx index 47ed9cc3..30cb5df2 100644 --- a/extension/react-app/src/components/Layout.tsx +++ b/extension/react-app/src/components/Layout.tsx @@ -1,6 +1,29 @@ import styled from "styled-components"; -import { defaultBorderRadius } from "."; +import { defaultBorderRadius, secondaryDark, vscForeground } from "."; import { Outlet } from "react-router-dom"; +import Onboarding from "./Onboarding"; +import TextDialog from "./TextDialog"; +import { useContext } from "react"; +import { GUIClientContext } from "../App"; +import { useDispatch, useSelector } from "react-redux"; +import { RootStore } from "../redux/store"; +import { + setBottomMessage, + setBottomMessageCloseTimeout, + setDialogEntryOn, + setDialogMessage, + setShowDialog, +} from "../redux/slices/uiStateSlice"; +import { + PlusIcon, + FolderIcon, + BookOpenIcon, + ChatBubbleOvalLeftEllipsisIcon, +} from "@heroicons/react/24/outline"; +import HeaderButtonWithText from "./HeaderButtonWithText"; +import { useNavigate } from "react-router-dom"; + +// #region Styled Components const LayoutTopDiv = styled.div` height: 100%; @@ -9,7 +32,56 @@ const LayoutTopDiv = styled.div` scrollbar-width: thin; `; +const BottomMessageDiv = styled.div<{ displayOnBottom: boolean }>` + position: fixed; + bottom: ${(props) => (props.displayOnBottom ? "50px" : undefined)}; + top: ${(props) => (props.displayOnBottom ? undefined : "50px")}; + left: 0; + right: 0; + margin: 8px; + margin-top: 0; + background-color: ${secondaryDark}; + color: ${vscForeground}; + border-radius: ${defaultBorderRadius}; + padding: 12px; + z-index: 100; + box-shadow: 0px 0px 2px 0px ${vscForeground}; + max-height: 50vh; + overflow: scroll; +`; + +const Footer = styled.footer` + display: flex; + flex-direction: row; + gap: 8px; + justify-content: right; + padding: 8px; + align-items: center; + margin-top: 8px; + border-top: 0.1px solid gray; +`; + +// #endregion + const Layout = () => { + const navigate = useNavigate(); + const client = useContext(GUIClientContext); + const dispatch = useDispatch(); + const { showDialog, dialogEntryOn, dialogMessage } = useSelector( + (state: RootStore) => state.uiState + ); + + // #region Selectors + const vscMediaUrl = useSelector( + (state: RootStore) => state.config.vscMediaUrl + ); + + const { bottomMessage, displayBottomMessageOnBottom } = useSelector( + (state: RootStore) => state.uiState + ); + + // #endregion + return (
{ gridTemplateRows: "1fr auto", }} > + + { + client?.sendMainInput(`/feedback ${text}`); + dispatch(setShowDialog(false)); + }} + onClose={() => { + dispatch(setShowDialog(false)); + }} + message={dialogMessage} + entryOn={dialogEntryOn} + /> + + { + dispatch(setBottomMessageCloseTimeout(undefined)); + }} + onMouseLeave={(e) => { + if (!e.buttons) { + dispatch(setBottomMessage(undefined)); + } + }} + hidden={!bottomMessage} + > + {bottomMessage} + +
+ {vscMediaUrl && ( + + + + )} + { + // Show the dialog + dispatch( + setDialogMessage(`Continue uses GPT-4 by default, but works with any model. If you'd like to keep your code completely private, there are few options: + + Run a local model with ggml: [5 minute quickstart](https://github.com/continuedev/ggml-server-example) + + Use Azure OpenAI service, which is GDPR and HIPAA compliant: [Tutorial](https://continue.dev/docs/customization#azure-openai-service) + + If you already have an LLM deployed on your own infrastructure, or would like to do so, please contact us at hi@continue.dev. + `) + ); + dispatch(setDialogEntryOn(false)); + dispatch(setShowDialog(true)); + }} + text={"Use Private Model"} + > +
+ 🔒 +
+
+ { + client?.loadSession(undefined); + }} + text="New Session" + > + + + { + navigate("/history"); + }} + text="History" + > + + + + + + + + { + // Set dialog open + dispatch( + setDialogMessage( + "Having trouble using Continue? Want a new feature? Let us know! This box is anonymous, but we will promptly address your feedback." + ) + ); + dispatch(setDialogEntryOn(true)); + dispatch(setShowDialog(true)); + }} + text="Feedback" + > + + +
); diff --git a/extension/react-app/src/pages/gui.tsx b/extension/react-app/src/pages/gui.tsx index dab429b5..e2e3431a 100644 --- a/extension/react-app/src/pages/gui.tsx +++ b/extension/react-app/src/pages/gui.tsx @@ -1,9 +1,5 @@ import styled from "styled-components"; -import { - defaultBorderRadius, - secondaryDark, - vscForeground, -} from "../components"; +import { defaultBorderRadius } from "../components"; import Loader from "../components/Loader"; import ContinueButton from "../components/ContinueButton"; import { ContextItem, FullState } from "../../../schema/FullState"; @@ -12,51 +8,21 @@ import { History } from "../../../schema/History"; import { HistoryNode } from "../../../schema/HistoryNode"; import StepContainer from "../components/StepContainer"; import { GUIClientContext } from "../App"; -import { - BookOpenIcon, - ChatBubbleOvalLeftEllipsisIcon, - TrashIcon, - PlusIcon, - FolderIcon, -} from "@heroicons/react/24/outline"; import ComboBox from "../components/ComboBox"; -import TextDialog from "../components/TextDialog"; -import HeaderButtonWithText from "../components/HeaderButtonWithText"; import { usePostHog } from "posthog-js/react"; import { useDispatch, useSelector } from "react-redux"; import { RootStore } from "../redux/store"; import { postVscMessage } from "../vscode"; import UserInputContainer from "../components/UserInputContainer"; -import Onboarding from "../components/Onboarding"; import { isMetaEquivalentKeyPressed } from "../util"; import { setBottomMessage, - setBottomMessageCloseTimeout, + setDialogEntryOn, + setDialogMessage, + setDisplayBottomMessageOnBottom, + setShowDialog, } from "../redux/slices/uiStateSlice"; import RingLoader from "../components/RingLoader"; -import { useNavigate } from "react-router-dom"; - -const TopGUIDiv = styled.div` - overflow: hidden; -`; - -const BottomMessageDiv = styled.div<{ displayOnBottom: boolean }>` - position: fixed; - bottom: ${(props) => (props.displayOnBottom ? "50px" : undefined)}; - top: ${(props) => (props.displayOnBottom ? undefined : "50px")}; - left: 0; - right: 0; - margin: 8px; - margin-top: 0; - background-color: ${secondaryDark}; - color: ${vscForeground}; - border-radius: ${defaultBorderRadius}; - padding: 12px; - z-index: 100; - box-shadow: 0px 0px 2px 0px ${vscForeground}; - max-height: 50vh; - overflow: scroll; -`; const UserInputQueueItem = styled.div` border-radius: ${defaultBorderRadius}; @@ -66,43 +32,19 @@ const UserInputQueueItem = styled.div` text-align: center; `; -const Footer = styled.footer<{ dataSwitchChecked: boolean }>` - display: flex; - flex-direction: row; - gap: 8px; - justify-content: right; - padding: 8px; - align-items: center; - margin-top: 8px; - border-top: 0.1px solid gray; - background-color: ${(props) => - props.dataSwitchChecked ? "#12887a33" : "transparent"}; -`; - interface GUIProps { firstObservation?: any; } function GUI(props: GUIProps) { - const navigate = useNavigate(); - + // #region Hooks const client = useContext(GUIClientContext); const posthog = usePostHog(); + const dispatch = useDispatch(); - const vscMachineId = useSelector( - (state: RootStore) => state.config.vscMachineId - ); - const [dataSwitchChecked, setDataSwitchChecked] = useState(false); - const dataSwitchOn = useSelector( - (state: RootStore) => state.config.dataSwitchOn - ); - - useEffect(() => { - if (typeof dataSwitchOn !== "undefined") { - setDataSwitchChecked(dataSwitchOn); - } - }, [dataSwitchOn]); + // #endregion + // #region State const [waitingForSteps, setWaitingForSteps] = useState(false); const [userInputQueue, setUserInputQueue] = useState([]); const [addingHighlightedCode, setAddingHighlightedCode] = useState(false); @@ -139,41 +81,33 @@ function GUI(props: GUIProps) { ], current_index: 3, } as any); + const [waitingForClient, setWaitingForClient] = useState(true); + const [showLoading, setShowLoading] = useState(false); - const vscMediaUrl = useSelector( - (state: RootStore) => state.config.vscMediaUrl - ); - const [showFeedbackDialog, setShowFeedbackDialog] = useState(false); - const [feedbackDialogMessage, setFeedbackDialogMessage] = useState< - string | JSX.Element - >(""); - const [feedbackEntryOn, setFeedbackEntryOn] = useState(true); - - const dispatch = useDispatch(); - const bottomMessage = useSelector( - (state: RootStore) => state.uiState.bottomMessage - ); + // #endregion - const [displayBottomMessageOnBottom, setDisplayBottomMessageOnBottom] = - useState(true); + // #region Refs const mainTextInputRef = useRef(null); + const topGuiDivRef = useRef(null); + // #endregion - const aboveComboBoxDivRef = useRef(null); + // #region Effects + // Set displayBottomMessageOnBottom + const aboveComboBoxDivRef = useRef(null); + const bottomMessage = useSelector( + (state: RootStore) => state.uiState.bottomMessage + ); useEffect(() => { if (!aboveComboBoxDivRef.current) return; - if ( - aboveComboBoxDivRef.current.getBoundingClientRect().top > - window.innerHeight / 2 - ) { - setDisplayBottomMessageOnBottom(false); - } else { - setDisplayBottomMessageOnBottom(true); - } + dispatch( + setDisplayBottomMessageOnBottom( + aboveComboBoxDivRef.current.getBoundingClientRect().top < + window.innerHeight / 2 + ) + ); }, [bottomMessage, aboveComboBoxDivRef.current]); - const topGuiDivRef = useRef(null); - const [scrollTimeout, setScrollTimeout] = useState( null ); @@ -264,7 +198,8 @@ function GUI(props: GUIProps) { scrollToBottom(); }, [waitingForSteps]); - const [waitingForClient, setWaitingForClient] = useState(true); + // #endregion + useEffect(() => { if (client && waitingForClient) { setWaitingForClient(false); @@ -327,62 +262,66 @@ function GUI(props: GUIProps) { (currentCount + 1).toString() ); if (currentCount === 25) { - setFeedbackDialogMessage( -
- 👋 Thanks for using Continue. We are a beta product and love - working closely with our first users. If you're interested in - speaking, enter your name and email. We won't use this information - for anything other than reaching out. -
-
-
{ - e.preventDefault(); - posthog?.capture("user_interest_form", { - name: e.target.elements[0].value, - email: e.target.elements[1].value, - }); - setFeedbackDialogMessage( -
- Thanks! We'll be in touch soon. -
- ); - }} - style={{ - display: "flex", - flexDirection: "column", - gap: "10px", - }} - > - - - - -
+ + + + + + ) ); - setFeedbackEntryOn(false); - setShowFeedbackDialog(true); + dispatch(setDialogEntryOn(false)); + dispatch(setShowDialog(true)); } } else { localStorage.setItem("mainTextEntryCounter", "1"); @@ -395,7 +334,6 @@ function GUI(props: GUIProps) { client.sendStepUserInput(input, index); }; - const [showLoading, setShowLoading] = useState(false); useEffect(() => { const timeout = setTimeout(() => { setShowLoading(true); @@ -405,228 +343,121 @@ function GUI(props: GUIProps) { clearTimeout(timeout); }; }, []); - - // const iterations = useSelector(selectIterations); return ( - <> - - { - client?.sendMainInput(`/feedback ${text}`); - setShowFeedbackDialog(false); - }} - onClose={() => { - setShowFeedbackDialog(false); - }} - message={feedbackDialogMessage} - entryOn={feedbackEntryOn} - /> - - { - if (e.key === "Enter" && e.ctrlKey) { - onMainTextInput(); - } - }} - > - {showLoading && typeof client === "undefined" && ( - <> - -

- Continue Server Starting -

-

{ - postVscMessage("toggleDevTools", {}); - }} - > - Click to view logs -

-
- Tip: Drag the Continue logo from the far left of the window to the - right, then toggle Continue using option/alt+command+m. -
- - )} - {history?.timeline.map((node: HistoryNode, index: number) => { - return node.step.name === "User Input" ? ( - node.step.hide || ( - { - client?.deleteAtIndex(index); - }} - historyNode={node} - > - {node.step.description as string} - - ) - ) : ( - { - const nextStepsOpen = [...stepsOpen]; - nextStepsOpen[index] = !nextStepsOpen[index]; - setStepsOpen(nextStepsOpen); - }} - onToggleAll={() => { - const shouldOpen = !stepsOpen[index]; - setStepsOpen((prev) => prev.map(() => shouldOpen)); - }} - key={index} - onUserInput={(input: string) => { - onStepUserInput(input, index); - }} - inFuture={index > history?.current_index} - historyNode={node} - onReverse={() => { - client?.reverseToIndex(index); - }} - onRetry={() => { - client?.retryAtIndex(index); - setWaitingForSteps(true); - }} +
{ + if (e.key === "Enter" && e.ctrlKey) { + onMainTextInput(); + } + }} + > + {showLoading && typeof client === "undefined" && ( + <> + +

+ Continue Server Starting +

+

{ + postVscMessage("toggleDevTools", {}); + }} + > + Click to view logs +

+
+ Tip: Drag the Continue logo from the far left of the window to the + right, then toggle Continue using option/alt+command+m. +
+ + )} + {history?.timeline.map((node: HistoryNode, index: number) => { + return node.step.name === "User Input" ? ( + node.step.hide || ( + { client?.deleteAtIndex(index); }} - /> - ); - })} - {waitingForSteps && } - -
- {userInputQueue.map((input) => { - return {input}; - })} -
+ historyNode={node} + > + {node.step.description as string} +
+ ) + ) : ( + { + const nextStepsOpen = [...stepsOpen]; + nextStepsOpen[index] = !nextStepsOpen[index]; + setStepsOpen(nextStepsOpen); + }} + onToggleAll={() => { + const shouldOpen = !stepsOpen[index]; + setStepsOpen((prev) => prev.map(() => shouldOpen)); + }} + key={index} + onUserInput={(input: string) => { + onStepUserInput(input, index); + }} + inFuture={index > history?.current_index} + historyNode={node} + onReverse={() => { + client?.reverseToIndex(index); + }} + onRetry={() => { + client?.retryAtIndex(index); + setWaitingForSteps(true); + }} + onDelete={() => { + client?.deleteAtIndex(index); + }} + /> + ); + })} + {waitingForSteps && } -
- { - onMainTextInput(e); - e.stopPropagation(); - e.preventDefault(); - }} - onInputValueChange={() => {}} - items={availableSlashCommands} - selectedContextItems={selectedContextItems} - onToggleAddContext={() => { - client?.toggleAddingHighlightedCode(); - }} - addingHighlightedCode={addingHighlightedCode} - /> - - - { - dispatch(setBottomMessageCloseTimeout(undefined)); +
+ {userInputQueue.map((input) => { + return {input}; + })} +
+ +
+ { + onMainTextInput(e); + e.stopPropagation(); + e.preventDefault(); }} - onMouseLeave={(e) => { - if (!e.buttons) { - dispatch(setBottomMessage(undefined)); - } + onInputValueChange={() => {}} + items={availableSlashCommands} + selectedContextItems={selectedContextItems} + onToggleAddContext={() => { + client?.toggleAddingHighlightedCode(); }} - hidden={!bottomMessage} - > - {bottomMessage} - -
- {vscMediaUrl && ( - - - - )} - { - // Show the dialog - setFeedbackDialogMessage( - `Continue uses GPT-4 by default, but works with any model. If you'd like to keep your code completely private, there are few options: - -Run a local model with ggml: [5 minute quickstart](https://github.com/continuedev/ggml-server-example) - -Use Azure OpenAI service, which is GDPR and HIPAA compliant: [Tutorial](https://continue.dev/docs/customization#azure-openai-service) - -If you already have an LLM deployed on your own infrastructure, or would like to do so, please contact us at hi@continue.dev. - ` - ); - setFeedbackEntryOn(false); - setShowFeedbackDialog(true); - }} - text={"Use Private Model"} - > -
- 🔒 -
-
- { - client?.loadSession(undefined); - }} - text="New Session" - > - - - { - // Go to /history page - navigate("/history"); - }} - text="History" - > - - - - - - - - { - // Set dialog open - setFeedbackDialogMessage( - "Having trouble using Continue? Want a new feature? Let us know! This box is anonymous, but we will promptly address your feedback." - ); - setFeedbackEntryOn(true); - setShowFeedbackDialog(true); - }} - text="Feedback" - > - - -
- + addingHighlightedCode={addingHighlightedCode} + /> + +
); } diff --git a/extension/react-app/src/redux/slices/uiStateSlice.ts b/extension/react-app/src/redux/slices/uiStateSlice.ts index 837d19e9..d34596c9 100644 --- a/extension/react-app/src/redux/slices/uiStateSlice.ts +++ b/extension/react-app/src/redux/slices/uiStateSlice.ts @@ -5,6 +5,10 @@ export const uiStateSlice = createSlice({ initialState: { bottomMessage: undefined, bottomMessageCloseTimeout: undefined, + showDialog: false, + dialogMessage: "", + dialogEntryOn: false, + displayBottomMessageOnBottom: true, }, reducers: { setBottomMessage: (state, action) => { @@ -16,9 +20,27 @@ export const uiStateSlice = createSlice({ } state.bottomMessageCloseTimeout = action.payload; }, + setDialogMessage: (state, action) => { + state.dialogMessage = action.payload; + }, + setDialogEntryOn: (state, action) => { + state.dialogEntryOn = action.payload; + }, + setShowDialog: (state, action) => { + state.showDialog = action.payload; + }, + setDisplayBottomMessageOnBottom: (state, action) => { + state.displayBottomMessageOnBottom = action.payload; + }, }, }); -export const { setBottomMessage, setBottomMessageCloseTimeout } = - uiStateSlice.actions; +export const { + setBottomMessage, + setBottomMessageCloseTimeout, + setDialogMessage, + setDialogEntryOn, + setShowDialog, + setDisplayBottomMessageOnBottom, +} = uiStateSlice.actions; export default uiStateSlice.reducer; diff --git a/extension/react-app/src/redux/store.ts b/extension/react-app/src/redux/store.ts index d49513e5..aa8f5e7b 100644 --- a/extension/react-app/src/redux/store.ts +++ b/extension/react-app/src/redux/store.ts @@ -35,6 +35,10 @@ export interface RootStore { uiState: { bottomMessage: JSX.Element | undefined; bottomMessageCloseTimeout: NodeJS.Timeout | undefined; + displayBottomMessageOnBottom: boolean; + showDialog: boolean; + dialogMessage: string | JSX.Element; + dialogEntryOn: boolean; }; } -- cgit v1.2.3-70-g09d2
{ // client?.loadSession(session.id); - // document.location.href = "/gui"; + navigate("/"); }} > -
{session.title}
-
- {session.date_created} -
+
{session.title}
+
{session.date_created}