diff --git a/apps/web/src/app/app.tsx b/apps/web/src/app/app.tsx index 6f35a8bf9eced150129dc6d6f58bd8abb2e6259f..5e896d874824a5fcb7eba4d2e438f0ee284ce310 100644 --- a/apps/web/src/app/app.tsx +++ b/apps/web/src/app/app.tsx @@ -12,7 +12,7 @@ import { } from '@graphpolaris/shared/lib/data-access'; import { WebSocketHandler } from '@graphpolaris/shared/lib/data-access/socket'; import Broker from '@graphpolaris/shared/lib/data-access/socket/broker'; -import { assignNewGraphQueryResult, useAppDispatch, useML, useMLEnabledHash } from '@graphpolaris/shared/lib/data-access/store'; +import { assignNewGraphQueryResult, useAppDispatch, useConfig, useML, useMLEnabledHash } from '@graphpolaris/shared/lib/data-access/store'; import { GraphQueryResultFromBackend, GraphQueryResultFromBackendPayload, @@ -28,7 +28,8 @@ import { logout } from '@graphpolaris/shared/lib/data-access/store/authSlice'; import { SchemaFromBackend } from '@graphpolaris/shared/lib/schema'; import { LinkPredictionInstance, setMLResult, allMLTypes } from '@graphpolaris/shared/lib/data-access/store/mlSlice'; import { Resizable } from '@graphpolaris/shared/lib/components/Resizable'; -import { BrokerAlerts } from '@graphpolaris/shared/lib/data-access/socket/broker/brokerAlerts'; +import { DashboardAlerts } from '@graphpolaris/shared/lib/data-access/authorization/dashboardAlerts'; +import { addError } from '@graphpolaris/shared/lib/data-access/store/configSlice'; export interface App {} @@ -46,6 +47,7 @@ export function App(props: App) { const [authCheck, setAuthCheck] = useState(false); const ml = useML(); const mlHash = useMLEnabledHash(); + const config = useConfig(); // for testing purposes // useEffect(() => { @@ -83,7 +85,9 @@ export function App(props: App) { // console.log('Auth changed', auth.authorized, isLogin); if (auth.authorized) { console.debug('App is authorized; Getting Databases', isLogin); - api.GetAllDatabases({ updateSessionCache: true }); + api.GetAllDatabases({ updateSessionCache: true }).catch((e) => { + dispatch(addError(e)); + }); setAuthCheck(true); } else { // dispatch(logout()); @@ -106,7 +110,7 @@ export function App(props: App) { return ( <div className="h-screen w-screen"> - <BrokerAlerts /> + <DashboardAlerts /> <div className={'h-screen w-screen ' + (!auth.authorized ? 'blur-sm pointer-events-none ' : '')}> <div className="flex flex-col h-screen max-h-screen relative"> <aside className="h-[4rem]"> diff --git a/apps/web/src/components/navbar/AddDatabaseForm/newdatabaseform.tsx b/apps/web/src/components/navbar/AddDatabaseForm/newdatabaseform.tsx index f370f9fddd573e89b76efecb505fc399773d08c2..643e4d53a060568c60ac24fb4a4355850362af3b 100644 --- a/apps/web/src/components/navbar/AddDatabaseForm/newdatabaseform.tsx +++ b/apps/web/src/components/navbar/AddDatabaseForm/newdatabaseform.tsx @@ -3,13 +3,16 @@ import { DatabaseType, databaseNameMapping, databaseProtocolMapping, + useAppDispatch, useDatabaseAPI, useSchemaAPI, } from '@graphpolaris/shared/lib/data-access'; import React, { useEffect, useRef, useState } from 'react'; import { RequiredInput } from './requiredinput'; +import { addError } from '@graphpolaris/shared/lib/data-access/store/configSlice'; export const NewDatabaseForm = (props: { onClose(): void; open: boolean }) => { + const dispatch = useAppDispatch(); const ref = useRef<HTMLDialogElement>(null); const [state, setState] = useState<AddDatabaseRequest>({ // username: 'root', @@ -67,9 +70,14 @@ export const NewDatabaseForm = (props: { onClose(): void; open: boolean }) => { function handleSubmitClicked(): void { ref.current?.close(); if (!Object.values(hasError).some((e) => e === true)) { - api.AddDatabase(state, { updateDatabaseCache: true, setAsCurrent: true }).then(() => { - schemaApi.RequestSchema(state.name); - }); + api + .AddDatabase(state, { updateDatabaseCache: true, setAsCurrent: true }) + .then(() => { + schemaApi.RequestSchema(state.name); + }) + .catch((e) => { + dispatch(addError(e)); + }); } // props.onSubmit(state); } @@ -77,7 +85,7 @@ export const NewDatabaseForm = (props: { onClose(): void; open: boolean }) => { return ( <dialog ref={ref}> <form - className="card flex gap-4 p-5 rounded-sm shadow-lg" + className="card flex gap-4 p-4 rounded-sm" onSubmit={(event: React.FormEvent) => { event.preventDefault(); handleSubmitClicked(); diff --git a/apps/web/src/components/navbar/navbar.tsx b/apps/web/src/components/navbar/navbar.tsx index 8813d233652cdeeb44e37a43ad44954d749282a2..9dba3a8f1522c2b6c5e230de7dda7b1c795cfc71 100644 --- a/apps/web/src/components/navbar/navbar.tsx +++ b/apps/web/src/components/navbar/navbar.tsx @@ -24,6 +24,7 @@ import { } from '@graphpolaris/shared/lib/data-access'; import { DatabaseMenu } from './databasemenu'; import { NewDatabaseForm } from './AddDatabaseForm/newdatabaseform'; +import { addError } from '@graphpolaris/shared/lib/data-access/store/configSlice'; /** NavbarComponentProps is an interface containing the NavbarViewModel. */ export interface NavbarComponentProps { @@ -62,9 +63,14 @@ export const Navbar = (props: NavbarComponentProps) => { * Called when the user clicks on the 'submit' button of the add database form. */ function onAddDatabaseFormSubmit(request: AddDatabaseRequest): Promise<void | Response> { - return api.AddDatabase(request, { updateDatabaseCache: true, setAsCurrent: true }).then(() => { - schemaApi.RequestSchema(request.name); - }); + return api + .AddDatabase(request, { updateDatabaseCache: true, setAsCurrent: true }) + .then(() => { + schemaApi.RequestSchema(request.name); + }) + .catch((e) => { + dispatch(addError(e)); + }); } const currentLogo = !'dark' ? logo_white : logo; // TODO: support dark mode @@ -156,7 +162,9 @@ export const Navbar = (props: NavbarComponentProps) => { if (session.currentDatabase === db) { dispatch(updateCurrentDatabase('')); } - api.DeleteDatabase(db); + api.DeleteDatabase(db).catch((e) => { + dispatch(addError(e)); + }); setSubMenuOpen(undefined); setMenuOpen(false); }} diff --git a/libs/shared/lib/data-access/api/database.ts b/libs/shared/lib/data-access/api/database.ts index b2a2fa39a22cce3d9ff2738fac241b5152a7a80e..8176654b4b19c2777b5f575a8ae93442d091bf0d 100644 --- a/libs/shared/lib/data-access/api/database.ts +++ b/libs/shared/lib/data-access/api/database.ts @@ -59,7 +59,7 @@ export const useDatabaseAPI = () => { reject(response.statusText); } if (setAsCurrent) dispatch(updateCurrentDatabase(request.name)); - if (updateDatabaseCache) GetAllDatabases({ updateSessionCache: true }); + if (updateDatabaseCache) GetAllDatabases({ updateSessionCache: true }).catch(reject); resolve(); }); @@ -81,8 +81,7 @@ export const useDatabaseAPI = () => { if (!response.ok) { const text = await response.text(); console.error(text); - return []; - // throw Error(response.statusText) + throw Error(response.statusText); } const json = await response.json(); if (updateDatabaseCache) dispatch(updateDatabaseList(json.databases)); @@ -103,7 +102,7 @@ export const useDatabaseAPI = () => { reject(response.statusText); } - if (updateDatabaseCache) GetAllDatabases({ updateSessionCache: true }); + if (updateDatabaseCache) GetAllDatabases({ updateSessionCache: true }).catch(reject); resolve(); }); diff --git a/libs/shared/lib/data-access/api/index.ts b/libs/shared/lib/data-access/api/index.ts index d2e1deca1f0dcc633ba7eae964cadd5343d61586..c31d6f4c9e5397bf6979083e195719cca4e0fc26 100644 --- a/libs/shared/lib/data-access/api/index.ts +++ b/libs/shared/lib/data-access/api/index.ts @@ -1,4 +1,3 @@ export * from './database'; -export * from './user'; export * from './schema'; export * from './query'; diff --git a/libs/shared/lib/data-access/api/query.ts b/libs/shared/lib/data-access/api/query.ts index 5fc727eca895d07fe250f896321a3637e87e91e1..524e19e1c6caf44af0473cb4aa7420c999b86ee7 100644 --- a/libs/shared/lib/data-access/api/query.ts +++ b/libs/shared/lib/data-access/api/query.ts @@ -22,7 +22,7 @@ export const useQueryAPI = () => { if (!response?.ok) { const ret = await response.text(); console.error(response, ret); - return; + throw Error(response.statusText); } const ret = await response.json(); console.debug('Sent Query EXECUTION', ret); diff --git a/libs/shared/lib/data-access/api/user.ts b/libs/shared/lib/data-access/api/user.ts deleted file mode 100644 index 4f4c3d2193bfb2ae72e82e8412a34c0adf9d9064..0000000000000000000000000000000000000000 --- a/libs/shared/lib/data-access/api/user.ts +++ /dev/null @@ -1,42 +0,0 @@ -// All user related API calls - -import { useAuthorizationCache } from '../store'; - -export type User = { - Name: string; - Email: string; - SignInProvider: number; -}; - -export const useUserAPI = () => { - const { accessToken } = useAuthorizationCache(); - const domain = import.meta.env.BACKEND_URL; - - function GetUserInfo(): Promise<User> { - return new Promise<User>((resolve, reject) => { - fetch(`${domain}/user/`, { - method: 'GET', - credentials: 'same-origin', - headers: new Headers({ - Authorization: 'Bearer ' + accessToken, - }), - }) - .then((response: Response) => { - if (!response.ok) { - reject(response.statusText); - } - - return response.json(); - }) - .then((json: any) => { - resolve({ - Name: json.name, - Email: json.email, - SignInProvider: json.sign_in_provider, - }); - }); - }); - } - - return { GetUserInfo }; -}; diff --git a/libs/shared/lib/data-access/socket/broker/brokerAlerts.tsx b/libs/shared/lib/data-access/authorization/dashboardAlerts.tsx similarity index 96% rename from libs/shared/lib/data-access/socket/broker/brokerAlerts.tsx rename to libs/shared/lib/data-access/authorization/dashboardAlerts.tsx index a2b96066b0e2c2ddeca47c58945e47dbc9cc790b..92c945161c006eef7eb2f7fe5a20c0db4010e2b8 100644 --- a/libs/shared/lib/data-access/socket/broker/brokerAlerts.tsx +++ b/libs/shared/lib/data-access/authorization/dashboardAlerts.tsx @@ -1,7 +1,6 @@ import React, { ReactNode, useEffect, useState } from 'react'; import Broker from '@graphpolaris/shared/lib/data-access/socket/broker'; import { useImmer } from 'use-immer'; -import styles from './brokerAlerts.module.scss'; import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline'; type Message = { @@ -9,7 +8,7 @@ type Message = { className: string; }; -export const BrokerAlerts = (props: { timer?: number }) => { +export const DashboardAlerts = (props: { timer?: number }) => { const [messages, setMessages] = useImmer<{ data: any; routingKey: string; message: Message; showing: boolean }[]>([]); const timer = props.timer || 1200; diff --git a/libs/shared/lib/data-access/socket/backend-messenger/index.tsx b/libs/shared/lib/data-access/socket/backend-messenger/index.tsx index acaf5792d816947ba9a8a216df64822bd58ec76f..8106715f68ebdfb8af18ce2996c2cd6c590be5bd 100644 --- a/libs/shared/lib/data-access/socket/backend-messenger/index.tsx +++ b/libs/shared/lib/data-access/socket/backend-messenger/index.tsx @@ -18,7 +18,7 @@ export default class BackendMessenger implements BackendMessengerRepository { /** * Sends a fetch request to the Datastrophe domain. * @param {string} body The request body you want to send. Should be stringified JSON. - * @param {string} requestURL The URL you want to perform this request to, appended to 'datastrophe.science.uu.nl'. + * @param {string} requestURL The URL you want to perform this request'. * @param {string} requestMethod The method of your request. Most used are: POST, GET. * @returns {Promise<void>} A promise which is resolved once a response with status 200 has been received. */ @@ -41,7 +41,7 @@ export default class BackendMessenger implements BackendMessengerRepository { /** * Sendrequest sends a GET request to the backend. - * @param requestURL The URL you want to perform this request to, appended to 'datastrophe.science.uu.nl'. + * @param requestURL The URL you want to perform this request'. * @returns {Promise<void>} A promise which is resolved once a response with status 200 has been received. */ public SendRequest(requestURL: string): Promise<Response> { diff --git a/libs/shared/lib/data-access/store/configSlice.ts b/libs/shared/lib/data-access/store/configSlice.ts index 9e8f71a7bad08713f5b6e918e4e939be4b390260..0b297df62d4bacf922bb260a8762ee30ab570442 100644 --- a/libs/shared/lib/data-access/store/configSlice.ts +++ b/libs/shared/lib/data-access/store/configSlice.ts @@ -2,23 +2,43 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import type { RootState } from './store'; // Define the initial state using that type -export const initialState = { +export const initialState: { + queryListOpen: boolean; + queryStatusList: { + queries: Record<string, any>; + queryIDsOrder: string[]; + }; + functionsMenuOpen: boolean; + currentDatabaseKey: string; + elementsperDatabaseObject: Record<string, number>; + autoSendQueries: boolean; + errors: string[]; +} = { queryListOpen: false, queryStatusList: { queries: {}, queryIDsOrder: [] }, functionsMenuOpen: false, currentDatabaseKey: '', elementsperDatabaseObject: {}, autoSendQueries: true, + errors: [], }; export const configSlice = createSlice({ name: 'config', // `createSlice` will infer the state type from the `initialState` argument initialState, - reducers: {}, + reducers: { + addError: (state, action: PayloadAction<string>) => { + console.error('Error Received!', action.payload); + state.errors.push(action.payload); + }, + removeLastError: (state) => { + state.errors.shift(); + }, + }, }); -export const {} = configSlice.actions; +export const { addError, removeLastError } = configSlice.actions; // Other code such as selectors can use the imported `RootState` type export const configState = (state: RootState) => state.config; diff --git a/libs/shared/lib/querybuilder/query-utils/query2backend.ts b/libs/shared/lib/querybuilder/query-utils/query2backend.ts index 9e24d3f55a466cfd0da7b932ef082f7fa8bced3a..4255bbb0bdd65888c978ddc6a90ad1f7f997d8cd 100644 --- a/libs/shared/lib/querybuilder/query-utils/query2backend.ts +++ b/libs/shared/lib/querybuilder/query-utils/query2backend.ts @@ -289,7 +289,7 @@ export function Query2BackendQuery( return ret; }); - console.info('New query', graph, query); + console.debug('New processed query', graph, query); return query; } diff --git a/libs/shared/lib/vis/nodelink/nodelinkvis.tsx b/libs/shared/lib/vis/nodelink/nodelinkvis.tsx index 47adee5747c89d16b7e5676794cc227de84db0c7..065f5d26de282039e592cfaede6323ef6ce42d0c 100644 --- a/libs/shared/lib/vis/nodelink/nodelinkvis.tsx +++ b/libs/shared/lib/vis/nodelink/nodelinkvis.tsx @@ -52,6 +52,8 @@ export const NodeLinkVis = React.memo((props: Props) => { useEffect(() => { if (graphQueryResult) { + console.log('graphQueryResult', graphQueryResult); + setGraph( parseQueryResult(graphQueryResult, ml, { defaultX: (ref.current?.clientWidth || 1000) / 2, @@ -64,17 +66,6 @@ export const NodeLinkVis = React.memo((props: Props) => { const onClickedNode = (node: NodeType, ml: ML) => { console.log('shortestPath', graph, ml.shortestPath.enabled); if (graph) { - // //If node is already clicked we should remove it from the list. - // if (highlightNodes.includes(node)) { - // const index = highlightNodes.indexOf(node, 0); - // setHighlightNodes(highlightNodes.splice(index, 1)); - // } else { - // //Else add it to the list. - // setHighlightNodes(highlightNodes.concat(node)); - // } - // //Update the list of edges that need to be highlighted - // setHighlightedLinks(getRelatedLinks(graph, highlightNodes, ml.communityDetection.jaccard_threshold || -1)); - if (ml.shortestPath.enabled) { console.log('shortestPath'); @@ -107,28 +98,8 @@ export const NodeLinkVis = React.memo((props: Props) => { } }; - // useEffect(() => { - // if (ml && graph) { - // // const g = processML(ml, graph as GraphType); - // // console.log(g); - - // setGraph((draft) => { - // const g = processML(ml, draft as GraphType); - // return g; - // }); - // } - // }, [ml]); - return ( <> - {/* <input - onChange={(v) => - dispatch(changePrimary({ main: v.currentTarget.value })) - } - type="color" - name="head" - value={theme.palette.primary.main} - /> */} <div className="h-full w-full overflow-hidden" ref={ref}> <NLPixi graph={graph}