diff --git a/apps/web/src/app/app.module.scss b/apps/web/src/app/app.module.scss index 1dc1ca7dd87dd18d24b7dd61cf20512b52717888..9c19687bc97b6701b528ea386db287dbdc7e834b 100644 --- a/apps/web/src/app/app.module.scss +++ b/apps/web/src/app/app.module.scss @@ -40,5 +40,8 @@ margin-left: 0.8em; } } + .tabContent-hide { + display: none; + } } } diff --git a/apps/web/src/app/app.module.scss.d.ts b/apps/web/src/app/app.module.scss.d.ts index 6ff3621ba9b235bdb473345835b9e856c566da72..3ca2eddb5bc261c029f0e41692d62e0dc5ed199e 100644 --- a/apps/web/src/app/app.module.scss.d.ts +++ b/apps/web/src/app/app.module.scss.d.ts @@ -4,5 +4,6 @@ declare const classNames: { readonly panel: 'panel'; readonly visualization: 'visualization'; readonly queryBuilder: 'queryBuilder'; + readonly 'tabContent-hide': 'tabContent-hide'; }; export = classNames; diff --git a/apps/web/src/app/panels/Visualization.tsx b/apps/web/src/app/panels/Visualization.tsx index 4aa79b6b35e74a415da7e570a2dfe7ea141453ac..bdbe50bad166e82914a8f57d647c483dc23743fb 100644 --- a/apps/web/src/app/panels/Visualization.tsx +++ b/apps/web/src/app/panels/Visualization.tsx @@ -1,11 +1,17 @@ import React from 'react'; import { RawJSONVis, NodeLinkVis, PaohVis, SemanticSubstrates } from '@graphpolaris/shared/lib/vis'; import { assignNewGraphQueryResult, useAppDispatch } from '@graphpolaris/shared/lib/data-access'; +import { display } from '@graphpolaris/shared/lib/vis/semanticsubstrates/subcomponents/AddPlotButtonComponent.module.scss'; +import { useVisualizationCache } from '@graphpolaris/shared/lib/data-access'; +import { connect } from 'react-redux'; +import { setVisualTab } from '@graphpolaris/shared/lib/data-access/store/visualisationSlice' export const VisualizationPanel = () => { + const vis = useVisualizationCache() return ( <div className="h-full w-full overflow-y-auto"> <h1>Visualization Panel</h1> + <p className='text-sm'>{vis.visual}</p> {/* <div> <button onClick={() => @@ -32,15 +38,23 @@ export const VisualizationPanel = () => { Remove mock result </button> </div> */} - {/* width: '83%', height: '95vh', */} <div className="w-full h-[calc(100%-2rem)]"> - {/* <RawJSONVis /> */} - {/* <PaohVis rowHeight={30} hyperedgeColumnWidth={30} gapBetweenRanges={3} /> */} - <NodeLinkVis /> - {/* <SemanticSubstrates /> */} + <div id="NodeLinkVis" className='tabContent'> + {vis.visual === "NodeLinkVis" ? <><NodeLinkVis /></> : null} + </div> + <div id="RawJSONVis" className='tabContent'> + {vis.visual === "RawJSONVis" ? <><RawJSONVis /></> : null} + </div> + <div id="PaohVis" className='tabContent'> + {vis.visual === "PaohVis" ? <><PaohVis rowHeight={30} hyperedgeColumnWidth={30} gapBetweenRanges={3} /></> : null} + </div> + {/* <div id="SemSubVis" className='tabContent'> + <SemanticSubstrates /> + </div> */} </div> + {/* <div /> */} </div> ); diff --git a/apps/web/src/components/navbar/navbar.tsx b/apps/web/src/components/navbar/navbar.tsx index 60db1b8f0e7561bf218f9ec35ca1aee3de1e5200..24b69be41b10e1beff80557e0b0383c9c1d90f53 100644 --- a/apps/web/src/components/navbar/navbar.tsx +++ b/apps/web/src/components/navbar/navbar.tsx @@ -21,11 +21,15 @@ import { useDatabaseAPI, useSchemaAPI, useSessionCache, + useVisualizationCache, } from '@graphpolaris/shared/lib/data-access'; import { DatabaseMenu } from './databasemenu'; import { NewDatabaseForm } from './AddDatabaseForm/newdatabaseform'; - +// import { changeTabs } from 'src/app/panels/Visualization'; +import { visualization } from 'src/app/app.module.scss'; /** NavbarComponentProps is an interface containing the NavbarViewModel. */ +import { connect } from 'react-redux'; +import { setVisual } from '@graphpolaris/shared/lib/data-access/store/visualisationSlice' export interface NavbarComponentProps { // changeColourPalette: () => void; FIXME move to redux } @@ -46,10 +50,12 @@ export interface NavbarSubComponentState { deleteDb?: String; } + /** NavbarComponent is the View implementation for Navbar */ export const Navbar = (props: NavbarComponentProps) => { const auth = useAuthorizationCache(); const session = useSessionCache(); + const vis = useVisualizationCache(); const api = useDatabaseAPI(); const schemaApi = useSchemaAPI(); const dispatch = useAppDispatch(); @@ -73,11 +79,105 @@ export const Navbar = (props: NavbarComponentProps) => { <div className="w-full h-auto px-5"> <NewDatabaseForm open={addDatabaseFormOpen} onClose={() => setAddDatabaseFormOpen(false)} /> <div title="GraphPolaris" className="navbar w-full"> - <a href="https://graphpolaris.com/" className="w-full"> - <img src={currentLogo} /> - </a> + <div className="w-8/12"> + <a href="https://graphpolaris.com/" > + <img src={currentLogo} /> + </a> + </div> + <div className="dropdown"> + <label tabIndex= {0} className="btn s-1">Vis</label> + <ul tabIndex={0} className="dropdown-content z-[1] menu p-2 shadow bg-base-100 rounded-box w-52"> + <li onClick={()=>{ + dispatch(setVisual("NodeLinkVis")) + }}> + <a>Visualization</a></li> + <li onClick={()=>{ + dispatch(setVisual("RawJSONVis")) + }}> + <a>JSON</a></li> + <li onClick={()=>{ + dispatch(setVisual("PaohVis")) + }}><a>Paoh</a></li> + <li><a>Semantic Substrates</a></li> + </ul> + </div> + <div className="dropdown"> + <label tabIndex= {1} className="btn s-1">Data</label> + <ul tabIndex={1} className="dropdown-content z-[1] menu p-2 shadow bg-base-100 rounded-box w-52"> + <li> + <button + onClick={() => { + setAddDatabaseFormOpen(true); + setMenuOpen(false); + setSubMenuOpen(undefined); + }} + > + Add database + </button> + </li> + <li> + <button + onClick={(e) => { + e.stopPropagation(); + setSubMenuOpen(subMenuOpen === 'changeDb' ? undefined : 'changeDb'); + }} + className={`${session.databases.length === 0 ? 'btn-disabled' : ''} ${ + subMenuOpen === 'changeDb' ? 'btn-active' : '' + }`} + > + Change Database + </button> + {subMenuOpen === 'changeDb' && ( + <DatabaseMenu + onClick={(db) => { + if (session.currentDatabase != db) { + dispatch(updateCurrentDatabase(db)); + } + setSubMenuOpen(undefined); + setMenuOpen(false); + }} + /> + )} + </li> + <li> + <button + onClick={() => setSubMenuOpen(subMenuOpen === 'deleteDb' ? undefined : 'deleteDb')} + className={`${session.databases.length === 0 ? 'btn-disabled' : ''} ${ + subMenuOpen === 'deleteDb' ? 'btn-active' : '' + }`} + > + Delete Database + </button> + {subMenuOpen === 'deleteDb' && ( + <DatabaseMenu + onClick={(db) => { + if (session.currentDatabase === db) { + dispatch(updateCurrentDatabase('')); + } + api.DeleteDatabase(db); + setSubMenuOpen(undefined); + setMenuOpen(false); + }} + /> + )} + </li> + </ul> + </div> + <div className="dropdown"> + <label tabIndex= {2} className="btn s-1">Adv</label> + <ul tabIndex={2} className="dropdown-content z-[1] menu p-2 shadow bg-base-100 rounded-box w-52"> + </ul> + </div> + <div className="dropdown"> + <label tabIndex= {3} className="btn s-1">Share</label> + <ul tabIndex={3} className="dropdown-content z-[1] menu p-2 shadow bg-base-100 rounded-box w-52"> + <li><a>Visual</a></li> + <li><a>Knowledge Base</a></li> + </ul> + </div> + <div className="w-fit"> - <div className=""> + <div className="pl-80"> <button tabIndex={0} className="btn btn-circle btn-ghost hover:bg-gray-200" @@ -86,7 +186,7 @@ export const Navbar = (props: NavbarComponentProps) => { setSubMenuOpen(undefined); }} > - <AccountCircle htmlColor="black" /> + <AccountCircle htmlColor="black"/> </button> {menuOpen && ( <> @@ -104,63 +204,7 @@ export const Navbar = (props: NavbarComponentProps) => { <h2>user: {auth.userID}</h2> <h3 className="text-xs">session: {auth.sessionID}</h3> </div> - <li> - <button - onClick={() => { - setAddDatabaseFormOpen(true); - setMenuOpen(false); - setSubMenuOpen(undefined); - }} - > - Add database - </button> - </li> - <li> - <button - onClick={(e) => { - e.stopPropagation(); - setSubMenuOpen(subMenuOpen === 'changeDb' ? undefined : 'changeDb'); - }} - className={`${session.databases.length === 0 ? 'btn-disabled' : ''} ${ - subMenuOpen === 'changeDb' ? 'btn-active' : '' - }`} - > - Change Database - </button> - {subMenuOpen === 'changeDb' && ( - <DatabaseMenu - onClick={(db) => { - if (session.currentDatabase != db) { - dispatch(updateCurrentDatabase(db)); - } - setSubMenuOpen(undefined); - setMenuOpen(false); - }} - /> - )} - </li> - <li> - <button - onClick={() => setSubMenuOpen(subMenuOpen === 'deleteDb' ? undefined : 'deleteDb')} - className={`${session.databases.length === 0 ? 'btn-disabled' : ''} ${ - subMenuOpen === 'deleteDb' ? 'btn-active' : '' - }`} - > - Delete Database - </button> - {subMenuOpen === 'deleteDb' && ( - <DatabaseMenu - onClick={(db) => { - if (session.currentDatabase === db) { - dispatch(updateCurrentDatabase('')); - } - api.DeleteDatabase(db); - setSubMenuOpen(undefined); - setMenuOpen(false); - }} - /> - )} - </li> + </> ) : ( <> diff --git a/libs/shared/lib/data-access/store/hooks.ts b/libs/shared/lib/data-access/store/hooks.ts index 7463e73c5ecea81390f9d1fdd3d4e98c87e6e04c..9d425a336d97d365ccfb3d0c5e16e87f2858cf5e 100644 --- a/libs/shared/lib/data-access/store/hooks.ts +++ b/libs/shared/lib/data-access/store/hooks.ts @@ -10,6 +10,7 @@ import { } from '@graphpolaris/shared/lib/data-access/store/querybuilderSlice'; import { sessionCacheState } from './sessionSlice'; import { authState } from './authSlice'; +import { visualState } from './visualisationSlice'; // Use throughout your app instead of plain `useDispatch` and `useSelector` export const useAppDispatch: () => AppDispatch = useDispatch; @@ -33,3 +34,4 @@ export const useQuerybuilderHash = () => useAppSelector(selectQuerybuilderHash); export const useConfig = () => useAppSelector(configState); export const useSessionCache = () => useAppSelector(sessionCacheState); export const useAuthorizationCache = () => useAppSelector(authState); +export const useVisualizationCache = () =>useAppSelector(visualState); diff --git a/libs/shared/lib/data-access/store/store.ts b/libs/shared/lib/data-access/store/store.ts index aa32a4d6aba58d3ae82bddf133279c784acfbd5f..5158a13b02b576f55aa958f4fcb1bb6f32cf9419 100644 --- a/libs/shared/lib/data-access/store/store.ts +++ b/libs/shared/lib/data-access/store/store.ts @@ -5,6 +5,7 @@ import schemaSlice from './schemaSlice'; import configSlice from './configSlice'; import sessionSlice from './sessionSlice'; import authSlice from './authSlice'; +import visualisationSlice from './visualisationSlice'; export const store = configureStore({ reducer: { @@ -14,6 +15,7 @@ export const store = configureStore({ sessionCache: sessionSlice, auth: authSlice, config: configSlice, + visualize: visualisationSlice }, middleware: (getDefaultMiddleware) => getDefaultMiddleware({ diff --git a/libs/shared/lib/data-access/store/visualisationSlice.ts b/libs/shared/lib/data-access/store/visualisationSlice.ts new file mode 100644 index 0000000000000000000000000000000000000000..75d27ae7604946c34bb0345b9f2847c08cc39b97 --- /dev/null +++ b/libs/shared/lib/data-access/store/visualisationSlice.ts @@ -0,0 +1,36 @@ +import { createSlice, PayloadAction } from '@reduxjs/toolkit'; +import type { RootState } from './store'; +import { dispatch } from 'd3'; + +// Define the initial state using that type +export const initialState = { + visual: 'NodeLinkVis', + tab: 'NodeLinkTab' + +}; + +export const visualisationSlice = createSlice({ + name: 'visualisation', + // `createSlice` will infer the state type from the `initialState` argument + initialState, + reducers: { + setVisualTab: (state, action) => { + state.visual = action.payload[0] + state.tab = action.payload[1] + }, + setTab: (state, action) => { + state.tab=action.payload + }, + setVisual: (state,action) => { + state.visual=action.payload + } + } + }, +); + +export const {setVisualTab, setTab, setVisual} = visualisationSlice.actions; + +// Other code such as selectors can use the imported `RootState` type +// export const configState = (state: RootState) => state.config; +export const visualState = (state:RootState)=> state.visualize; +export default visualisationSlice.reducer;