From caeec8f1653232241fc1c75e500712ec2ba14926 Mon Sep 17 00:00:00 2001
From: Leonardo Christino <leomilho@gmail.com>
Date: Wed, 31 Jan 2024 15:17:45 +0100
Subject: [PATCH] feat(demo): inclusion of demo user support

---
 .../dbConnectionSelector.tsx                  |  2 +-
 libs/shared/lib/data-access/api/eventBus.tsx  | 16 +++++-
 libs/shared/lib/data-access/api/wsState.tsx   | 10 ++++
 .../WebSocketHandler.tsx                      |  3 +-
 .../lib/data-access/store/sessionSlice.ts     | 49 +++++++++++++++----
 5 files changed, 66 insertions(+), 14 deletions(-)

diff --git a/apps/web/src/components/navbar/DatabaseManagement/dbConnectionSelector.tsx b/apps/web/src/components/navbar/DatabaseManagement/dbConnectionSelector.tsx
index d0309b037..5c2a554dc 100644
--- a/apps/web/src/components/navbar/DatabaseManagement/dbConnectionSelector.tsx
+++ b/apps/web/src/components/navbar/DatabaseManagement/dbConnectionSelector.tsx
@@ -83,7 +83,7 @@ export default function DatabaseSelector({}) {
                   <LoadingSpinner />
                   <p className="ml-2 truncate">Connecting to {session.saveStates[session.currentSaveState].name}</p>
                 </>
-              ) : session.currentSaveState ? (
+              ) : session.currentSaveState && session.currentSaveState in session.saveStates ? (
                 <>
                   <div
                     className={`h-2 w-2 rounded-full ${
diff --git a/libs/shared/lib/data-access/api/eventBus.tsx b/libs/shared/lib/data-access/api/eventBus.tsx
index 1f41476ff..235fe3656 100644
--- a/libs/shared/lib/data-access/api/eventBus.tsx
+++ b/libs/shared/lib/data-access/api/eventBus.tsx
@@ -24,9 +24,10 @@ import { QueryBuilderState } from '@graphpolaris/shared/lib/data-access/store/qu
 import { QueryMultiGraph, Query2BackendQuery } from '@graphpolaris/shared/lib/querybuilder';
 import { SchemaFromBackend } from '@graphpolaris/shared/lib/schema';
 import { useRef, useState, useEffect } from 'react';
-import { DatabaseInfo, DatabaseStatus, SaveStateI, TestDatabaseConnectionResponse, wsGetStates } from './wsState';
+import { DatabaseInfo, DatabaseStatus, SaveStateI, TestDatabaseConnectionResponse, wsGetState, wsGetStates } from './wsState';
 import { wsSchemaRequest } from './wsSchema';
-import { addSaveState, testedSaveState, updateSaveStateList } from '../store/sessionSlice';
+import { addSaveState, testedSaveState, updateCurrentSaveState, updateSaveStateList } from '../store/sessionSlice';
+import { URLParams, getParam } from './url';
 
 export const EventBus = (props: { onRunQuery: Function; onAuthorized: Function }) => {
   const { login } = useAuth();
@@ -69,6 +70,7 @@ export const EventBus = (props: { onRunQuery: Function; onAuthorized: Function }
 
     login();
 
+    // Setup cleanup
     return () => {
       Broker.instance().unSubscribeAll('schema_result');
       Broker.instance().unSubscribeAll('query_result');
@@ -99,7 +101,17 @@ export const EventBus = (props: { onRunQuery: Function; onAuthorized: Function }
       WebSocketHandler.instance()
         .useAuth(auth)
         .connect(() => {
+          console.log('WS connected', session.currentSaveState, window.location.search);
+
+          // Process URL Params
+          const paramSaveState = getParam(URLParams.saveState);
+          if (paramSaveState) {
+            wsGetState(paramSaveState);
+            dispatch(updateCurrentSaveState(paramSaveState));
+          }
+
           wsGetStates();
+
           // WebSocketHandler.instance().sendMessage({ //TODO!!
           //   sessionID: auth?.sessionID || '',
           //   key: 'broadcastState',
diff --git a/libs/shared/lib/data-access/api/wsState.tsx b/libs/shared/lib/data-access/api/wsState.tsx
index f227653a7..b33e8b36b 100644
--- a/libs/shared/lib/data-access/api/wsState.tsx
+++ b/libs/shared/lib/data-access/api/wsState.tsx
@@ -39,6 +39,14 @@ export type SaveStateI = {
   db: DatabaseInfo;
 };
 
+export function wsGetState(saveStateId: string) {
+  WebSocketHandler.instance().sendMessage({
+    key: 'state',
+    subKey: 'get',
+    body: { saveStateId: saveStateId }, //messageTypeGetSaveState
+  });
+}
+
 export function wsGetStates() {
   WebSocketHandler.instance().sendMessage({
     key: 'state',
@@ -53,6 +61,8 @@ export function wsSelectState(saveStateId: string | undefined) {
     subKey: 'select',
     body: { saveStateId: saveStateId }, //messageTypeGetSaveState
   });
+  console.log('saveStateId', saveStateId);
+
   WebSocketHandler.instance().useSaveStateID(saveStateId);
   setParam(URLParams.saveState, saveStateId);
 }
diff --git a/libs/shared/lib/data-access/socket/backend-message-receiver/WebSocketHandler.tsx b/libs/shared/lib/data-access/socket/backend-message-receiver/WebSocketHandler.tsx
index 096738ed4..7272e9ac8 100644
--- a/libs/shared/lib/data-access/socket/backend-message-receiver/WebSocketHandler.tsx
+++ b/libs/shared/lib/data-access/socket/backend-message-receiver/WebSocketHandler.tsx
@@ -48,7 +48,8 @@ export class WebSocketHandler implements BackendMessageReceiver {
     if (this.webSocket) this.close();
 
     const params = new URLSearchParams(window.location.search);
-    if (this.authHeader?.userID) params.set('userID', this.authHeader?.userID ?? ''); // TODO!! need a better more safe way to do this
+    // Most of these parameters are only really used in DEV
+    if (this.authHeader?.userID) params.set('userID', this.authHeader?.userID ?? '');
     if (this.authHeader?.roomID) params.set('roomID', this.authHeader?.roomID ?? '');
     if (this.saveStateID) params.set('saveStateID', this.saveStateID ?? '');
     if (this.authHeader?.sessionID) params.set('sessionID', this.authHeader?.sessionID ?? '');
diff --git a/libs/shared/lib/data-access/store/sessionSlice.ts b/libs/shared/lib/data-access/store/sessionSlice.ts
index da99e4797..07818ab5f 100644
--- a/libs/shared/lib/data-access/store/sessionSlice.ts
+++ b/libs/shared/lib/data-access/store/sessionSlice.ts
@@ -1,6 +1,6 @@
 import { createSlice, PayloadAction } from '@reduxjs/toolkit';
 import type { RootState } from './store';
-import { DatabaseStatus, SaveStateI, wsSelectState } from '../api/wsState';
+import { DatabaseStatus, SaveStateI, wsSelectState, wsTestSaveStateConnection } from '../api/wsState';
 import { getParam, URLParams } from '../api/url';
 
 /** Message format of the error message from the backend */
@@ -30,29 +30,58 @@ export const sessionSlice = createSlice({
       wsSelectState(state.currentSaveState);
     },
     updateSaveStateList(state, action: PayloadAction<SaveStateI[]>) {
+      // Does NOT clear the states, just adds in new data
       let newState: Record<string, SaveStateI> = {};
       action.payload.forEach((ss) => {
         newState[ss.id] = ss;
+        // Keep db status (e.g. tested) if already tested
+        if (ss.id in state.saveStates) {
+          newState[ss.id].db.status = state.saveStates[ss.id].db.status || newState[ss.id].db.status;
+        }
+      });
+      state.saveStates = { ...state.saveStates, ...newState };
 
-        // Keep db status (e.g. tested) from old state
-        // DB is always the same for a given save state, but if this changes, this code will break
+      const paramSaveState = getParam(URLParams.saveState);
+      if (!state.currentSaveState) {
+        if (paramSaveState && paramSaveState in state.saveStates) {
+          state.currentSaveState = paramSaveState;
+        } else if (Object.keys(state.saveStates).length > 0) {
+          state.currentSaveState = Object.keys(state.saveStates)[0];
+        } else state.currentSaveState = undefined;
+        wsSelectState(state.currentSaveState);
+      }
+    },
+    setSaveStateList(state, action: PayloadAction<SaveStateI[]>) {
+      // Clears the states and puts in new data
+      let newState: Record<string, SaveStateI> = {};
+      action.payload.forEach((ss) => {
+        newState[ss.id] = ss;
         if (ss.id in state.saveStates) {
-          newState[ss.id].db.status = state.saveStates[ss.id].db.status;
+          newState[ss.id].db.status = state.saveStates[ss.id].db.status || newState[ss.id].db.status;
         }
       });
       state.saveStates = newState;
 
-      state.currentSaveState = getParam(URLParams.saveState) || state.currentSaveState;
-      if (!state.currentSaveState || !(state.currentSaveState in state.saveStates)) {
-        if (Object.keys(state.saveStates).length > 0) {
+      const paramSaveState = getParam(URLParams.saveState);
+      if (!state.currentSaveState) {
+        if (paramSaveState && paramSaveState in state.saveStates) {
+          state.currentSaveState = paramSaveState;
+        } else if (Object.keys(state.saveStates).length > 0) {
           state.currentSaveState = Object.keys(state.saveStates)[0];
         } else state.currentSaveState = undefined;
+        wsSelectState(state.currentSaveState);
       }
-      wsSelectState(state.currentSaveState);
     },
     addSaveState(state, action: PayloadAction<SaveStateI>) {
       if (state.saveStates === undefined) state.saveStates = {};
-      state.saveStates[action.payload.id] = action.payload;
+      if (action.payload.id in state.saveStates) {
+        // Keep db status tested if was already tested
+        const status = state.saveStates[action.payload.id].db.status || action.payload.db.status;
+        state.saveStates[action.payload.id] = action.payload;
+        state.saveStates[action.payload.id].db.status = status;
+      } else {
+        state.saveStates[action.payload.id] = action.payload;
+      }
       state.currentSaveState = action.payload.id;
       wsSelectState(state.currentSaveState);
     },
@@ -64,7 +93,7 @@ export const sessionSlice = createSlice({
   },
 });
 
-export const { updateCurrentSaveState, updateSaveStateList, addSaveState, testedSaveState } = sessionSlice.actions;
+export const { updateCurrentSaveState, updateSaveStateList, setSaveStateList, addSaveState, testedSaveState } = sessionSlice.actions;
 
 // Other code such as selectors can use the imported `RootState` type
 export const sessionCacheState = (state: RootState) => state.sessionCache;
-- 
GitLab