From ef1c3710401e4c09118dd20b364e120329cd5d69 Mon Sep 17 00:00:00 2001 From: Austin Akers Date: Mon, 16 Dec 2024 13:42:05 -0800 Subject: [PATCH 01/14] created auth layout for public auth routes --- src/components/auth/AuthLayout.jsx | 62 +++++++++++++++++++++++++ src/components/layouts/App.js | 73 ++++-------------------------- 2 files changed, 71 insertions(+), 64 deletions(-) create mode 100644 src/components/auth/AuthLayout.jsx diff --git a/src/components/auth/AuthLayout.jsx b/src/components/auth/AuthLayout.jsx new file mode 100644 index 000000000..ce8f0025f --- /dev/null +++ b/src/components/auth/AuthLayout.jsx @@ -0,0 +1,62 @@ +import { Col, Container, Row } from 'reactstrap'; + +function AuthLayout({ children }) { + return ( + + + +
+

HarperDB Studio

+ Manage all your HarperDB instances. +
    +
  • +

    Manage All Instances

    + Set access, cluster, monitor, and more. +
  • +
  • +

    Embedded API Server

    + HarperDB components give you unlimited application flexibility. +
  • +
  • +

    Fully Managed Cloud & 5G Instances

    + Go from zero to code in minutes. +
  • +
  • +

    Deploy Anywhere

    + +
  • +
+
+ + {children} +
+
+ ); +} + +export default AuthLayout; diff --git a/src/components/layouts/App.js b/src/components/layouts/App.js index 3125720cb..48aaa4a76 100644 --- a/src/components/layouts/App.js +++ b/src/components/layouts/App.js @@ -8,7 +8,6 @@ import useInterval from 'use-interval'; import { positions, useAlert } from 'react-alert'; import { ErrorBoundary } from 'react-error-boundary'; import queryString from 'query-string'; -import { Col, Container, Row } from 'reactstrap'; import appState from '../../functions/state/appState'; import usePersistedUser from '../../functions/state/persistedUser'; @@ -28,6 +27,7 @@ import init from '../../functions/app/init'; import refreshUser from '../../functions/app/refreshUser'; import changeFavIcon from '../../functions/app/changeFavIcon'; import getAkamaiRegions from '../../functions/api/lms/getAkamaiRegions'; +import AuthLayout from '../auth/AuthLayout'; const TopNav = lazy(() => import(/* webpackChunkName: "topnav" */ '../TopNav')); const SignUp = lazy(() => import(/* webpackChunkName: "signUp" */ '../auth/SignUp')); @@ -169,69 +169,14 @@ function App() {
}> - - - -
-

HarperDB Studio

- Manage all your HarperDB instances. -
    -
  • -

    Manage All Instances

    - Set access, cluster, monitor, and more. -
  • -
  • -

    Embedded API Server

    - - HarperDB components give you unlimited application flexibility. - -
  • -
  • -

    Fully Managed Cloud & 5G Instances

    - Go from zero to code in minutes. -
  • -
  • -

    Deploy Anywhere

    - -
  • -
-
- - - - } path="/" /> - : } path="/sign-up" /> - : } path="/reset-password" /> - } /> - - -
-
+ + + } path="/" /> + : } path="/sign-up" /> + : } path="/reset-password" /> + } /> + +
From e98f42d02ec845c9d3a347479e6254650dbef8e5 Mon Sep 17 00:00:00 2001 From: Austin Akers Date: Mon, 16 Dec 2024 14:02:05 -0800 Subject: [PATCH 02/14] added protected routes for dashboard routes --- src/components/layouts/App.js | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/components/layouts/App.js b/src/components/layouts/App.js index 48aaa4a76..391ab9c05 100644 --- a/src/components/layouts/App.js +++ b/src/components/layouts/App.js @@ -53,6 +53,13 @@ function ValidatedRoute(auth) { return ; } +function PrivateRoute(auth) { + if (auth.auth.user_id) { + return ; + } + return ; +} + function App() { const canonicalUrl = document.querySelector('link[rel="canonical"]'); const navigate = useNavigate(); @@ -152,15 +159,18 @@ function App() { > {/* can we put instance routes in here, each in a suspense tag (since they're lazily loaded) */} - : } path="/update-password" /> - : } path="/profile/*" /> - : }> - } path="/o/:customer_id/i/:compute_stack_id/*" /> - } path="/o/:customer_id/instances/:action?/:purchaseStep?" /> - } path="/o/:customer_id/*" /> + {/* create protected routes */} + }> + : } path="/update-password" /> + : } path="/profile/*" /> + : }> + } path="/o/:customer_id/i/:compute_stack_id/*" /> + } path="/o/:customer_id/instances/:action?/:purchaseStep?" /> + } path="/o/:customer_id/*" /> + + : } path="/:list?/:action?" /> + } /> - : } path="/:list?/:action?" /> - } /> From 063f1073df5a6f38615468dc953162ebea4a4a36 Mon Sep 17 00:00:00 2001 From: Austin Akers Date: Mon, 16 Dec 2024 21:37:16 -0800 Subject: [PATCH 03/14] simplified App.js layouts and routing --- src/components/auth/AuthLayout.jsx | 5 ++- src/components/layouts/App.js | 64 ++++++++++++------------------ 2 files changed, 29 insertions(+), 40 deletions(-) diff --git a/src/components/auth/AuthLayout.jsx b/src/components/auth/AuthLayout.jsx index ce8f0025f..5516514b2 100644 --- a/src/components/auth/AuthLayout.jsx +++ b/src/components/auth/AuthLayout.jsx @@ -1,3 +1,4 @@ +import { Outlet } from 'react-router'; import { Col, Container, Row } from 'reactstrap'; function AuthLayout({ children }) { @@ -53,7 +54,9 @@ function AuthLayout({ children }) { - {children} + + + ); diff --git a/src/components/layouts/App.js b/src/components/layouts/App.js index 391ab9c05..accded7e0 100644 --- a/src/components/layouts/App.js +++ b/src/components/layouts/App.js @@ -57,7 +57,7 @@ function PrivateRoute(auth) { if (auth.auth.user_id) { return ; } - return ; + return ; } function App() { @@ -145,51 +145,37 @@ function App() { {fetchingUser ? (
- +
- ) : loggedIn ? ( -
- - - - - } - > - {/* can we put instance routes in here, each in a suspense tag (since they're lazily loaded) */} + ) : ( +
+ + }> - {/* create protected routes */} - }> - : } path="/update-password" /> - : } path="/profile/*" /> - : }> - } path="/o/:customer_id/i/:compute_stack_id/*" /> - } path="/o/:customer_id/instances/:action?/:purchaseStep?" /> - } path="/o/:customer_id/*" /> + {loggedIn ? ( + <> + : } path="/update-password" /> + : } path="/profile/*" /> + : }> + } path="/o/:customer_id/i/:compute_stack_id/*" /> + } path="/o/:customer_id/instances/:action?/:purchaseStep?" /> + } path="/o/:customer_id/*" /> + + : } path="/:list?/:action?" /> + } /> + + ) : ( + }> + } path="/" /> + : } path="/sign-up" /> + : } path="/reset-password" /> + } /> - : } path="/:list?/:action?" /> - } /> - + )}
- ) : ( -
- - }> - - - } path="/" /> - : } path="/sign-up" /> - : } path="/reset-password" /> - } /> - - - - -
)}
From 5df7c0e37e3ed36cbc5ad9864f6d8dc5be5affea Mon Sep 17 00:00:00 2001 From: Austin Akers Date: Mon, 16 Dec 2024 21:38:37 -0800 Subject: [PATCH 04/14] removed dead code --- src/components/layouts/App.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/components/layouts/App.js b/src/components/layouts/App.js index accded7e0..749717fed 100644 --- a/src/components/layouts/App.js +++ b/src/components/layouts/App.js @@ -53,13 +53,6 @@ function ValidatedRoute(auth) { return ; } -function PrivateRoute(auth) { - if (auth.auth.user_id) { - return ; - } - return ; -} - function App() { const canonicalUrl = document.querySelector('link[rel="canonical"]'); const navigate = useNavigate(); From af7128e7142e971b40b3de94597a612e440c785f Mon Sep 17 00:00:00 2001 From: Austin Akers Date: Mon, 16 Dec 2024 23:01:59 -0800 Subject: [PATCH 05/14] fixed duplicate api call bug for describe_table --- .../instance/browse/BrowseDatatable.js | 6 +++-- src/components/instance/browse/index.js | 25 +++---------------- src/functions/instance/getTableData.js | 4 +++ 3 files changed, 11 insertions(+), 24 deletions(-) diff --git a/src/components/instance/browse/BrowseDatatable.js b/src/components/instance/browse/BrowseDatatable.js index 6fac83120..ea6cee0e8 100644 --- a/src/components/instance/browse/BrowseDatatable.js +++ b/src/components/instance/browse/BrowseDatatable.js @@ -18,7 +18,7 @@ let controller; let controller2; let controller3; -function BrowseDatatable({ tableState, setTableState, activeTable, tableDescriptionAttributes }) { +function BrowseDatatable({ tableState, setTableState, activeTable }) { const navigate = useNavigate(); const { compute_stack_id, schema, table, customer_id } = useParams(); const auth = useStoreState(instanceState, (s) => s.auth); @@ -74,6 +74,7 @@ function BrowseDatatable({ tableState, setTableState, activeTable, tableDescript hashAttribute, dynamicAttributesFromDataTable, dataTableColumns, + schemaAttributes, error, } = await getTableData({ schema, @@ -114,6 +115,7 @@ function BrowseDatatable({ tableState, setTableState, activeTable, tableDescript hashAttribute, dataTableColumns, dynamicAttributesFromDataTable, + schemaAttributes, error, }); } @@ -175,7 +177,7 @@ function BrowseDatatable({ tableState, setTableState, activeTable, tableDescript columns={tableState.dataTableColumns || []} data={tableState.tableData || []} error={tableState.error} - tableDescriptionAttributes={tableDescriptionAttributes} + tableDescriptionAttributes={tableState.schemaAttributes} dynamicAttributesFromDataTable={tableState.dynamicAttributesFromDataTable} currentPage={tableState.page} pageSize={tableState.pageSize} diff --git a/src/components/instance/browse/index.js b/src/components/instance/browse/index.js index dda00d0d7..b1c7f4b9f 100644 --- a/src/components/instance/browse/index.js +++ b/src/components/instance/browse/index.js @@ -14,7 +14,7 @@ import EmptyPrompt from '../../shared/EmptyPrompt'; import buildInstanceStructure from '../../../functions/instance/browse/buildInstanceStructure'; import { clearTableDescriptionCache } from '../../../functions/instance/state/describeTableCache'; -const DataTable = lazy(() => import(/* webpackChunkName: "browse-datatable" */ './BrowseDatatable')); +const BrowseDatatable = lazy(() => import(/* webpackChunkName: "browse-datatable" */ './BrowseDatatable')); const EntityManager = lazy(() => import(/* webpackChunkName: "browse-entitymanager" */ './EntityManager')); const JSONEditor = lazy(() => import(/* webpackChunkName: "browse-jsonviewer" */ './JSONEditor')); const CSVUpload = lazy(() => import(/* webpackChunkName: "browse-csvupload" */ './CsvUpload')); @@ -40,7 +40,7 @@ function NoPrimaryKeyMessage({ table }) { No Primary Key - + The table {`'${table}'`} does not have a primary key. The HarperDB Studio does not currently support tables without a primary key defined. Please see the{' '} @@ -85,20 +85,6 @@ function BrowseIndex() { buildInstanceStructure({ auth, url }); }; - useEffect(() => { - const fetchDescribeTable = async () => { - if (table) { - try { - const result = await describeTable({ auth, url, schema, table }); - setTableDescription(result); - } catch (e) { - addError(e); - } - } - }; - fetchDescribeTable(); - }, [auth, url, schema, table]); - useEffect(() => { if (tableDescription) { setHasHashAttr(Boolean(tableDescription.hash_attribute)); @@ -198,12 +184,7 @@ function BrowseIndex() { ) : schema && table && action && entities.activeTable ? ( ) : schema && table && entities.activeTable ? ( - + ) : schema && table && !hasHashAttr ? ( ) : ( diff --git a/src/functions/instance/getTableData.js b/src/functions/instance/getTableData.js index d23e29cd9..919d21a80 100644 --- a/src/functions/instance/getTableData.js +++ b/src/functions/instance/getTableData.js @@ -29,6 +29,7 @@ export default async ({ schema, table, filtered, pageSize, onlyCached, sorted, p let newData = []; let allAttributes = false; let hashAttribute = false; + let schemaAttributes = []; let get_attributes = ['*']; let dynamicAttributesFromDataTable = []; const offset = page * pageSize; @@ -46,6 +47,7 @@ export default async ({ schema, table, filtered, pageSize, onlyCached, sorted, p } const { record_count, attributes, hash_attribute } = result; + schemaAttributes = attributes; allAttributes = attributes.map((a) => a.attribute); if (hash_attribute === undefined) { hashAttribute = '$id'; @@ -55,6 +57,7 @@ export default async ({ schema, table, filtered, pageSize, onlyCached, sorted, p } newTotalRecords = record_count; + schemaAttributes = attributes; newTotalPages = newTotalRecords && Math.ceil(newTotalRecords / pageSize); } catch (e) { fetchError = e.message; @@ -124,6 +127,7 @@ export default async ({ schema, table, filtered, pageSize, onlyCached, sorted, p newTotalRecords, newTotalPages, hashAttribute, + schemaAttributes, dataTableColumns, error: fetchError === 'table' ? `You are not authorized to view ${schema}:${table}` : fetchError, dynamicAttributesFromDataTable, From a9dda643fa14fa9ba6aff88735aa613eb0d936a0 Mon Sep 17 00:00:00 2001 From: Austin Akers Date: Tue, 17 Dec 2024 14:23:34 -0800 Subject: [PATCH 06/14] removed tableDescription state and replace it with tableState from Store --- src/components/instance/browse/index.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/components/instance/browse/index.js b/src/components/instance/browse/index.js index b1c7f4b9f..3d16a311d 100644 --- a/src/components/instance/browse/index.js +++ b/src/components/instance/browse/index.js @@ -5,7 +5,6 @@ import { useStoreState } from 'pullstate'; import { ErrorBoundary } from 'react-error-boundary'; import instanceState from '../../../functions/state/instanceState'; -import describeTable from '../../../functions/api/instance/describeTable'; import ErrorFallback from '../../shared/ErrorFallback'; import addError from '../../../functions/api/lms/addError'; @@ -68,7 +67,6 @@ function BrowseIndex() { const structure = useStoreState(instanceState, (s) => s.structure); const [entities, setEntities] = useState({ schemas: [], tables: [], activeTable: false }); const [tableState, setTableState] = useState(defaultTableState); - const [tableDescription, setTableDescription] = useState(null); const baseUrl = `/o/${customer_id}/i/${compute_stack_id}/browse`; const showForm = instanceAuths[compute_stack_id]?.super || instanceAuths[compute_stack_id]?.structure === true; const showTableForm = @@ -86,10 +84,10 @@ function BrowseIndex() { }; useEffect(() => { - if (tableDescription) { - setHasHashAttr(Boolean(tableDescription.hash_attribute)); + if (tableState) { + setHasHashAttr(Boolean(tableState.hashAttribute)); } - }, [tableDescription]); + }, [tableState]); const validate = () => { if (structure) { From c8e8cf21d9e95bec299c145acfbb9c843de6360e Mon Sep 17 00:00:00 2001 From: Austin Akers Date: Tue, 17 Dec 2024 14:44:36 -0800 Subject: [PATCH 07/14] only sync instance structure when navigating to a new table --- src/components/instance/browse/EntityManagerRow.js | 14 ++++++++++---- src/components/instance/browse/index.js | 6 ------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/components/instance/browse/EntityManagerRow.js b/src/components/instance/browse/EntityManagerRow.js index 81e210ba7..1a46c27d6 100644 --- a/src/components/instance/browse/EntityManagerRow.js +++ b/src/components/instance/browse/EntityManagerRow.js @@ -58,6 +58,9 @@ function EntityManagerRow({ item, itemType, baseUrl, isActive, toggleDropItem, i toggleConfirmDropItem(false); }; + const syncInstanceStructure = () => { + buildInstanceStructure({ auth, url }); + }; const handleSetActive = () => isActive || isDropping || isConfirmingDropItem ? false : navigate(`${baseUrl}/${item}`); @@ -66,7 +69,10 @@ function EntityManagerRow({ item, itemType, baseUrl, isActive, toggleDropItem, i key={item} title={`View${isActive ? 'ing' : ''} ${itemType} ${item}`} className={`item-row ${isActive ? 'active' : ''}`} - onClick={handleSetActive} + onClick={() => { + handleSetActive(); + syncInstanceStructure(); + }} tabIndex="0" > @@ -86,7 +92,7 @@ function EntityManagerRow({ item, itemType, baseUrl, isActive, toggleDropItem, i title={`confirm drop ${itemType} ${item}`} onClick={confirmItemForDrop} > - + ) : isDropping ? ( @@ -106,7 +112,7 @@ function EntityManagerRow({ item, itemType, baseUrl, isActive, toggleDropItem, i title={`Drop ${itemType} ${item}`} onClick={selectItemForDrop} > - + ) : isActive ? ( + ); +} + +export default SortOrgs; From 53484ac0dfdb0863fb1d8ea859a4cc94fa338cb8 Mon Sep 17 00:00:00 2001 From: Austin Akers Date: Wed, 15 Jan 2025 14:18:50 -0800 Subject: [PATCH 11/14] styled sort orgs button --- src/components/organizations/SubNav.js | 2 +- src/components/organizations/filter/SortOrgs.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/organizations/SubNav.js b/src/components/organizations/SubNav.js index ac122e2b9..2b6d17c81 100644 --- a/src/components/organizations/SubNav.js +++ b/src/components/organizations/SubNav.js @@ -17,8 +17,8 @@ function SubNav() { diff --git a/src/components/organizations/filter/SortOrgs.js b/src/components/organizations/filter/SortOrgs.js index 72f6dee10..f4442130c 100644 --- a/src/components/organizations/filter/SortOrgs.js +++ b/src/components/organizations/filter/SortOrgs.js @@ -21,7 +21,7 @@ function SortOrgs() { return (