From 1ab129ca0ca59387197ecff221bfd931b03a8797 Mon Sep 17 00:00:00 2001
From: "Vink, S.A. (Sjoerd)" <s.a.vink@uu.nl>
Date: Sat, 6 Apr 2024 15:43:58 +0000
Subject: [PATCH] feat(visManager): vis manager, settings and vis-related fixes

---
 apps/web/src/app/app.tsx                      |  97 +++++--
 .../dbConnectionSelector.tsx                  |  31 +-
 .../DatabaseManagement/forms/databaseForm.tsx |   2 +-
 .../DatabaseManagement/forms/settings.tsx     |   2 +-
 .../src/components/navbar/databasemenu.tsx    |  17 --
 apps/web/src/components/navbar/navbar.tsx     | 120 ++++----
 .../components/navbar/search/SearchBar.tsx    | 260 -----------------
 .../src/components/onboarding/onboarding.tsx  |   2 +-
 .../use-cases/{types.tsx => types.ts}         |   0
 apps/web/src/main.css                         |   2 +-
 libs/config/tailwind.config.js                |   3 +
 libs/shared/lib/components/Dialog.tsx         |   7 +-
 libs/shared/lib/components/Resizable.tsx      |  89 ++++--
 .../components/buttons/buttons.module.scss    |  10 +-
 .../buttons/buttons.module.scss.d.ts          |   3 +-
 libs/shared/lib/components/buttons/index.tsx  |  16 +-
 .../lib/components/color-mode/index.tsx       |   4 +-
 libs/shared/lib/components/controls/index.tsx |   2 +-
 .../dropdowns/dropdowns.module.scss           |   2 +-
 .../shared/lib/components/dropdowns/index.tsx |  19 +-
 .../lib/components/icon/icon.stories.tsx      |  19 +-
 libs/shared/lib/components/icon/index.tsx     |   2 +-
 libs/shared/lib/components/inputs/index.tsx   |  85 +++++-
 .../lib/components/inputs/number.stories.tsx  |  36 +++
 .../shared/lib/components/inputs/overview.mdx |   2 +-
 .../selectors/axis.stories.tsx                |   0
 .../selectors/axis.tsx                        |   4 +-
 .../selectors/color.stories.tsx               |   0
 .../selectors/color.tsx                       |   4 +-
 .../selectors}/encodings.types.ts             |   2 +-
 .../selectors/index.ts                        |   0
 .../selectors/opacity.stories.tsx             |   0
 .../selectors/opacity.tsx                     |   4 +-
 .../selectors/shape.stories.tsx               |   0
 .../selectors/shape.tsx                       |   2 +-
 .../selectors/size.stories.tsx                |   0
 .../selectors/size.tsx                        |   4 +-
 libs/shared/lib/components/tooltip/index.tsx  |  48 ----
 .../store/graphQueryResultSlice.ts            | 116 ++++----
 .../lib/data-access/store/interactionSlice.ts |  35 +++
 .../data-access/store/visualizationSlice.ts   |  48 ++--
 .../theme/colorPaletteConfigSlice.ts          |   2 +-
 .../lib/querybuilder/panel/querybuilder.tsx   | 266 +++++++++---------
 .../panel/querysidepanel/queryMLDialog.tsx    |  66 ++---
 .../querysidepanel/querySettingsDialog.tsx    |   2 +-
 .../customFlowPills/entitypill/entitypill.tsx |   4 +-
 .../customFlowPills/logicpill/logicpill.tsx   |   2 +-
 libs/shared/lib/schema/panel/index.ts         |   3 -
 .../lib/schema/panel/schema.stories.tsx       |   4 +-
 libs/shared/lib/schema/panel/schema.tsx       | 132 +++------
 libs/shared/lib/schema/panel/schemaDialog.tsx |  99 +++----
 .../lib/schema/pills/edges/node-edge.tsx      |   2 +-
 .../lib/schema/pills/edges/self-edge.tsx      |   2 +-
 .../popup/attribute-analytics-popup-menu.tsx  |   2 +-
 .../attribute-analytics-popup-menu.tsx        |   2 +-
 .../lib/schema/schema-utils/flow-utils.ts     |   2 +-
 libs/shared/lib/sidebar/index.tsx             |  55 ++++
 libs/shared/lib/sidebar/search/searchbar.tsx  | 182 ++++++++++++
 .../shared/lib/sidebar}/search/similarity.ts  |   2 +-
 libs/shared/lib/vis/common/index.ts           |   1 +
 .../vis/{shared/Types.tsx => common/types.ts} |  70 ++---
 libs/shared/lib/vis/components/bar.tsx        | 112 ++++++++
 .../lib/vis/components/config/components.tsx  |  24 ++
 .../lib/vis/components/config/index.tsx       |   2 +
 .../lib/vis/components/config/panel.tsx       |  86 ++++++
 libs/shared/lib/vis/components/panel.tsx      |  30 ++
 .../vis/configuration/advanced/advanced.tsx   |  25 --
 .../lib/vis/configuration/advanced/index.ts   |   1 -
 .../vis/configuration/encodings/accessor.tsx  |  61 ----
 .../vis/configuration/encodings/encoding.tsx  |  67 -----
 .../lib/vis/configuration/encodings/index.ts  |   2 -
 .../vis/configuration/encodings/selector.tsx  |  54 ----
 libs/shared/lib/vis/configuration/index.ts    |   1 -
 .../vis/configuration/interactions/index.ts   |   2 -
 .../interactions/interaction.tsx              |  12 -
 .../interactions/interaction.types.ts         |   7 -
 .../vis/configuration/panel/panel-header.tsx  |  37 ---
 .../vis/configuration/panel/panel-item.tsx    |  27 --
 .../lib/vis/configuration/panel/panel.tsx     |  82 ------
 .../vis/configuration/panel/panel.types.ts    |  13 -
 .../lib/vis/configuration/settings/index.ts   |   2 -
 .../vis/configuration/settings/settings.tsx   |  44 ---
 .../configuration/settings/settings.types.ts  |  10 -
 libs/shared/lib/vis/hooks/hooks.types.ts      |  12 +
 libs/shared/lib/vis/hooks/index.ts            |   2 +
 .../lib/vis/hooks/useVisualizationManager.tsx | 154 ++++++++++
 libs/shared/lib/vis/index.ts                  |   2 +-
 .../lib/vis/shared/AttributeDataType.test.tsx |  69 -----
 .../lib/vis/shared/AttributeDataType.tsx      | 119 --------
 libs/shared/lib/vis/shared/InputDataTypes.tsx |  52 ----
 .../lib/vis/shared/SchemaResultType.test.tsx  |  87 ------
 .../lib/vis/shared/SchemaResultType.tsx       |  46 ---
 .../shared/VisConfigPanel/ArrowRightIcon.svg  |   1 -
 .../VisConfigPanel/QuestionMarkIcon.svg       |   5 -
 .../VisConfigPanel.module.scss.d.ts           |   9 -
 libs/shared/lib/vis/types.ts                  |  39 ---
 libs/shared/lib/vis/views/index.tsx           |   3 +
 libs/shared/lib/vis/views/noData.tsx          |  30 ++
 libs/shared/lib/vis/views/querying.tsx        |  10 +
 libs/shared/lib/vis/views/recommender.tsx     |  38 +++
 libs/shared/lib/vis/visualizationManager.tsx  | 103 -------
 libs/shared/lib/vis/visualizationPanel.tsx    | 110 --------
 .../archive/geovis/{types.tsx => types.ts}    |   0
 .../mapvis/components/FilterMenu.tsx          |   2 +-
 .../mapvis/components/LayerPanel.tsx          |   2 +-
 .../mapvis/components/MapPanel.tsx            |   4 +-
 .../vis/visualizations/mapvis/graphModel.tsx  |   2 +-
 .../choropleth-layer/ChoroplethLayer.tsx      |  20 +-
 .../layers/edge-arc-layer/EdgeArcLayer.tsx    |   2 +-
 .../mapvis/layers/edge-layer/EdgeLayer.tsx    |   4 +-
 .../mapvis/layers/heatmap-layer/HeatLayer.tsx |  20 +-
 .../mapvis/layers/icon-layer/IconLayer.tsx    |   4 +-
 .../mapvis/layers/node-layer/NodeLayer.tsx    |   2 +-
 .../layers/nodelink-layer/NodeLinkLayer.tsx   |  20 +-
 .../visualizations/mapvis/mapvis.stories.tsx  |  45 ++-
 .../lib/vis/visualizations/mapvis/mapvis.tsx  |  28 +-
 .../mapvis/{Types.tsx => types.ts}            |   0
 .../lib/vis/visualizations/mapvis/utlis.tsx   |   2 +-
 .../matrixvis/components/MatrixPixi.tsx       |  46 ++-
 .../matrixvis/components/MatrixPopup.tsx      |   2 +-
 .../components/ReorderingManager.tsx          |   3 +-
 .../matrixvis/matrix.stories.tsx              |  89 +++---
 .../visualizations/matrixvis/matrixvis.tsx    |  66 ++++-
 .../matrixvis/{Types.tsx => types.ts}         |   8 +-
 .../components/NLMachineLearning.tsx          |   2 -
 .../nodelinkvis/components/NLPixi.tsx         |   3 +-
 .../nodelinkvis/nodelinkvis.stories.tsx       | 174 +++++-------
 .../nodelinkvis/nodelinkvis.tsx               | 164 ++++++++---
 .../vis/visualizations/nodelinkvis/types.ts   |   8 +-
 .../paohvis/components/HyperEdgesRange.tsx    |   2 +-
 .../paohvis/components/MakePaohvisMenu.tsx    |  31 +-
 .../components/PaohvisFilterComponent.tsx     |   9 +-
 .../paohvis/paohvis.stories.tsx               | 123 ++++----
 .../vis/visualizations/paohvis/paohvis.tsx    | 172 +++++------
 .../paohvis/{Types.tsx => types.ts}           |   0
 .../paohvis/utils/AttributesFilterUseCase.tsx |   4 +-
 .../utils/CalcEntitiesFromQueryResult.tsx     |   4 +-
 ...EntityAttrAndRelNamesFromSchemaUseCase.tsx | 130 ---------
 .../utils}/ResultNodeLinkParserUseCase.tsx    |  34 +--
 .../paohvis/utils/SortUseCase.tsx             |  19 +-
 .../utils/ToPaohvisDataParserUsecase.tsx      |  16 +-
 .../paohvis/utils}/VisConfigPanel.module.scss |   4 +-
 .../paohvis/utils}/VisConfigPanel.tsx         |  15 -
 .../visualizations/paohvis/utils/utils.tsx    |  11 +-
 .../rawjsonvis/rawjsonvis.stories.tsx         |  88 ++----
 .../visualizations/rawjsonvis/rawjsonvis.tsx  |  99 +++++--
 .../subcomponents/OptimizedAutocomplete.tsx   |  94 -------
 .../components/{types.tsx => types.ts}        |   0
 .../semanticsubstratesvis.stories.tsx         |  70 ++---
 .../semanticsubstratesvis.tsx                 |  37 ++-
 .../tablevis/components/Table.tsx             |  12 +-
 .../tablevis/tablevis.stories.tsx             |  69 ++---
 .../vis/visualizations/tablevis/tablevis.tsx  |  98 +++++--
 libs/shared/package.json                      |   1 +
 pnpm-lock.yaml                                | 108 ++++++-
 155 files changed, 2481 insertions(+), 3082 deletions(-)
 delete mode 100644 apps/web/src/components/navbar/databasemenu.tsx
 delete mode 100644 apps/web/src/components/navbar/search/SearchBar.tsx
 rename apps/web/src/components/onboarding/use-cases/{types.tsx => types.ts} (100%)
 create mode 100644 libs/shared/lib/components/inputs/number.stories.tsx
 rename libs/shared/lib/{vis/configuration/encodings => components}/selectors/axis.stories.tsx (100%)
 rename libs/shared/lib/{vis/configuration/encodings => components}/selectors/axis.tsx (66%)
 rename libs/shared/lib/{vis/configuration/encodings => components}/selectors/color.stories.tsx (100%)
 rename libs/shared/lib/{vis/configuration/encodings => components}/selectors/color.tsx (83%)
 rename libs/shared/lib/{vis/configuration/encodings => components/selectors}/encodings.types.ts (94%)
 rename libs/shared/lib/{vis/configuration/encodings => components}/selectors/index.ts (100%)
 rename libs/shared/lib/{vis/configuration/encodings => components}/selectors/opacity.stories.tsx (100%)
 rename libs/shared/lib/{vis/configuration/encodings => components}/selectors/opacity.tsx (82%)
 rename libs/shared/lib/{vis/configuration/encodings => components}/selectors/shape.stories.tsx (100%)
 rename libs/shared/lib/{vis/configuration/encodings => components}/selectors/shape.tsx (74%)
 rename libs/shared/lib/{vis/configuration/encodings => components}/selectors/size.stories.tsx (100%)
 rename libs/shared/lib/{vis/configuration/encodings => components}/selectors/size.tsx (81%)
 create mode 100644 libs/shared/lib/data-access/store/interactionSlice.ts
 create mode 100644 libs/shared/lib/sidebar/index.tsx
 create mode 100644 libs/shared/lib/sidebar/search/searchbar.tsx
 rename {apps/web/src/components/navbar => libs/shared/lib/sidebar}/search/similarity.ts (96%)
 create mode 100644 libs/shared/lib/vis/common/index.ts
 rename libs/shared/lib/vis/{shared/Types.tsx => common/types.ts} (61%)
 create mode 100644 libs/shared/lib/vis/components/bar.tsx
 create mode 100644 libs/shared/lib/vis/components/config/components.tsx
 create mode 100644 libs/shared/lib/vis/components/config/index.tsx
 create mode 100644 libs/shared/lib/vis/components/config/panel.tsx
 create mode 100644 libs/shared/lib/vis/components/panel.tsx
 delete mode 100644 libs/shared/lib/vis/configuration/advanced/advanced.tsx
 delete mode 100644 libs/shared/lib/vis/configuration/advanced/index.ts
 delete mode 100644 libs/shared/lib/vis/configuration/encodings/accessor.tsx
 delete mode 100644 libs/shared/lib/vis/configuration/encodings/encoding.tsx
 delete mode 100644 libs/shared/lib/vis/configuration/encodings/index.ts
 delete mode 100644 libs/shared/lib/vis/configuration/encodings/selector.tsx
 delete mode 100644 libs/shared/lib/vis/configuration/index.ts
 delete mode 100644 libs/shared/lib/vis/configuration/interactions/index.ts
 delete mode 100644 libs/shared/lib/vis/configuration/interactions/interaction.tsx
 delete mode 100644 libs/shared/lib/vis/configuration/interactions/interaction.types.ts
 delete mode 100644 libs/shared/lib/vis/configuration/panel/panel-header.tsx
 delete mode 100644 libs/shared/lib/vis/configuration/panel/panel-item.tsx
 delete mode 100644 libs/shared/lib/vis/configuration/panel/panel.tsx
 delete mode 100644 libs/shared/lib/vis/configuration/panel/panel.types.ts
 delete mode 100644 libs/shared/lib/vis/configuration/settings/index.ts
 delete mode 100644 libs/shared/lib/vis/configuration/settings/settings.tsx
 delete mode 100644 libs/shared/lib/vis/configuration/settings/settings.types.ts
 create mode 100644 libs/shared/lib/vis/hooks/hooks.types.ts
 create mode 100644 libs/shared/lib/vis/hooks/index.ts
 create mode 100644 libs/shared/lib/vis/hooks/useVisualizationManager.tsx
 delete mode 100644 libs/shared/lib/vis/shared/AttributeDataType.test.tsx
 delete mode 100644 libs/shared/lib/vis/shared/AttributeDataType.tsx
 delete mode 100644 libs/shared/lib/vis/shared/InputDataTypes.tsx
 delete mode 100644 libs/shared/lib/vis/shared/SchemaResultType.test.tsx
 delete mode 100644 libs/shared/lib/vis/shared/SchemaResultType.tsx
 delete mode 100644 libs/shared/lib/vis/shared/VisConfigPanel/ArrowRightIcon.svg
 delete mode 100644 libs/shared/lib/vis/shared/VisConfigPanel/QuestionMarkIcon.svg
 delete mode 100644 libs/shared/lib/vis/shared/VisConfigPanel/VisConfigPanel.module.scss.d.ts
 delete mode 100644 libs/shared/lib/vis/types.ts
 create mode 100644 libs/shared/lib/vis/views/index.tsx
 create mode 100644 libs/shared/lib/vis/views/noData.tsx
 create mode 100644 libs/shared/lib/vis/views/querying.tsx
 create mode 100644 libs/shared/lib/vis/views/recommender.tsx
 delete mode 100644 libs/shared/lib/vis/visualizationManager.tsx
 delete mode 100644 libs/shared/lib/vis/visualizationPanel.tsx
 rename libs/shared/lib/vis/visualizations/mapvis/archive/geovis/{types.tsx => types.ts} (100%)
 rename libs/shared/lib/vis/visualizations/mapvis/{Types.tsx => types.ts} (100%)
 rename libs/shared/lib/vis/visualizations/matrixvis/{Types.tsx => types.ts} (92%)
 rename libs/shared/lib/vis/visualizations/paohvis/{Types.tsx => types.ts} (100%)
 delete mode 100644 libs/shared/lib/vis/visualizations/paohvis/utils/CalcEntityAttrAndRelNamesFromSchemaUseCase.tsx
 rename libs/shared/lib/vis/{shared => visualizations/paohvis/utils}/ResultNodeLinkParserUseCase.tsx (73%)
 rename libs/shared/lib/vis/{shared/VisConfigPanel => visualizations/paohvis/utils}/VisConfigPanel.module.scss (97%)
 rename libs/shared/lib/vis/{shared/VisConfigPanel => visualizations/paohvis/utils}/VisConfigPanel.tsx (62%)
 delete mode 100644 libs/shared/lib/vis/visualizations/semanticsubstrates/subcomponents/OptimizedAutocomplete.tsx
 rename libs/shared/lib/vis/visualizations/semanticsubstratesvis/components/{types.tsx => types.ts} (100%)

diff --git a/apps/web/src/app/app.tsx b/apps/web/src/app/app.tsx
index 882fb72c8..b8f1628d7 100644
--- a/apps/web/src/app/app.tsx
+++ b/apps/web/src/app/app.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useRef, useState } from 'react';
+import React, { useEffect, useState } from 'react';
 import {
   useAppDispatch,
   useAuthorizationCache,
@@ -13,16 +13,19 @@ import { Navbar } from '../components/navbar/navbar';
 import { Resizable } from '@graphpolaris/shared/lib/components/Resizable';
 import { DashboardAlerts } from '@graphpolaris/shared/lib/data-access/authorization/dashboardAlerts';
 import { EventBus } from '@graphpolaris/shared/lib/data-access/api/eventBus';
-import Onboarding from '../components/onboarding/onboarding';
+import { Onboarding } from '../components/onboarding/onboarding';
 import { wsQueryRequest } from '@graphpolaris/shared/lib/data-access/broker';
 import { URLParams, setParam } from '@graphpolaris/shared/lib/data-access/api/url';
-
-import { Schema } from '@graphpolaris/shared/lib/schema/panel';
 import { VisualizationPanel } from '@graphpolaris/shared/lib/vis';
 import { QueryBuilder } from '@graphpolaris/shared/lib/querybuilder';
-// const Schema = React.lazy(() => import('@graphpolaris/shared/lib/schema/panel'));
-// const VisualizationPanel = React.lazy(() => import('@graphpolaris/shared/lib/vis'));
-// const QueryBuilder = React.lazy(() => import('@graphpolaris/shared/lib/querybuilder'));
+import { SideNavTab, Sidebar } from '@graphpolaris/shared/lib/sidebar';
+import { useVisualizationManager } from '@graphpolaris/shared/lib/vis/hooks';
+import { ConfigPanel } from '@graphpolaris/shared/lib/vis/components/config';
+import { Tooltip, TooltipTrigger, Button, TooltipContent, TooltipProvider } from '@graphpolaris/shared';
+import { ControlContainer } from '@graphpolaris/shared/lib/components/controls';
+import { Searchbar } from '@graphpolaris/shared/lib/sidebar/search/searchbar';
+import { Schema } from '@graphpolaris/shared/lib/schema/panel';
+import { Fullscreen, FitScreen, Remove, Schema as SchemaIcon, Search as SearchIcon } from '@mui/icons-material';
 
 export type App = {
   load?: string;
@@ -35,6 +38,7 @@ export function App(props: App) {
   const session = useSessionCache();
   const dispatch = useAppDispatch();
   const queryBuilderSettings = useQuerybuilderSettings();
+  const manager = useVisualizationManager();
 
   const runQuery = () => {
     if (session?.currentSaveState && query) {
@@ -54,6 +58,8 @@ export function App(props: App) {
   }, [props]);
 
   const [authCheck, setAuthCheck] = useState(false);
+  const [tab, setTab] = useState<SideNavTab>('Schema');
+  const [visFullSize, setVisFullSize] = useState<boolean>(false);
 
   return (
     <div className="h-screen w-screen overflow-clip">
@@ -69,25 +75,74 @@ export function App(props: App) {
           <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-auto w-auto">
+              <aside className="absolute w-full h-12">
                 <Navbar />
               </aside>
-              <main className="flex w-screen h-[calc(100%-4.2rem)]">
+              <main className="grow flex flex-row h-screen pt-12">
+                <Sidebar onTab={(tab) => setTab(tab)} />
                 <Resizable divisorSize={3} horizontal={true} defaultProportion={0.33}>
-                  <div className="h-full w-full panel">
-                    <Schema auth={authCheck} />
-                  </div>
-                  <div className="h-full w-full">
-                    <Resizable divisorSize={3} horizontal={false}>
-                      <div className="w-full h-full panel">
-                        <VisualizationPanel />
+                  {tab !== undefined ? (
+                    <div className="flex flex-col border w-full h-full bg-light">
+                      <div className="sticky shrink-0 top-0 flex items-stretch justify-between h-7 bg-secondary-100 border-b border-secondary-200 max-w-full">
+                        <div className="flex items-center">
+                          <h1 className="text-xs font-semibold text-secondary-600 px-2 truncate">{tab}</h1>
+                        </div>
+                        <div className="shrink-0 sticky right-0 px-0.5 ml-auto items-center flex">
+                          <ControlContainer>
+                            <TooltipProvider delayDuration={100}>
+                              <Tooltip>
+                                <TooltipTrigger asChild>
+                                  <Button type="secondary" variant="ghost" size="xs" iconComponent={<Remove />} onClick={() => {}} />
+                                </TooltipTrigger>
+                                <TooltipContent side={'top'}>
+                                  <p>Hide</p>
+                                </TooltipContent>
+                              </Tooltip>
+                              {tab === 'Schema' && (
+                                <Tooltip>
+                                  <TooltipTrigger asChild>
+                                    <Button type="secondary" variant="ghost" size="xs" iconComponent={<FitScreen />} onClick={() => {}} />
+                                  </TooltipTrigger>
+                                  <TooltipContent side={'top'}>
+                                    <p>Fit to screen</p>
+                                  </TooltipContent>
+                                </Tooltip>
+                              )}
+                              {tab === 'Search' && (
+                                <Tooltip>
+                                  <TooltipTrigger asChild>
+                                    <Button type="secondary" variant="ghost" size="xs" iconComponent={<Fullscreen />} onClick={() => {}} />
+                                  </TooltipTrigger>
+                                  <TooltipContent side={'top'}>
+                                    <p>Mock icon</p>
+                                  </TooltipContent>
+                                </Tooltip>
+                              )}
+                            </TooltipProvider>
+                          </ControlContainer>
+                        </div>
                       </div>
-                      <div className="w-full h-full panel">
-                        <QueryBuilder onRunQuery={runQuery} />
-                      </div>
-                    </Resizable>
-                  </div>
+                      {tab === 'Search' && <Searchbar />}
+                      {tab === 'Schema' && <Schema auth={authCheck} />}
+                    </div>
+                  ) : null}
+
+                  <Resizable divisorSize={3} horizontal={false}>
+                    <VisualizationPanel
+                      manager={manager}
+                      fullSize={() => {
+                        setVisFullSize(!visFullSize);
+                        tab === undefined && setTab('Schema');
+                        tab !== undefined && setTab(undefined);
+                      }}
+                    />
+
+                    <QueryBuilder onRunQuery={runQuery} />
+                  </Resizable>
                 </Resizable>
+                <div className="info-panel flex h-full w-60 ml-[3px] shrink-0 overflow-auto bg-light border">
+                  <ConfigPanel manager={manager} />
+                </div>
               </main>
             </div>
           </div>
diff --git a/apps/web/src/components/navbar/DatabaseManagement/dbConnectionSelector.tsx b/apps/web/src/components/navbar/DatabaseManagement/dbConnectionSelector.tsx
index 0a68e06a1..6ed8758c7 100644
--- a/apps/web/src/components/navbar/DatabaseManagement/dbConnectionSelector.tsx
+++ b/apps/web/src/components/navbar/DatabaseManagement/dbConnectionSelector.tsx
@@ -1,5 +1,5 @@
 import React, { useEffect, useState } from 'react';
-import { Add, Delete, Settings } from '@mui/icons-material';
+import { Add, Delete, Settings, StorageOutlined } from '@mui/icons-material';
 import { useAppDispatch, useSchemaGraph, useSessionCache, useAuthorizationCache } from '@graphpolaris/shared/lib/data-access';
 import { deleteSaveState, selectSaveState } from '@graphpolaris/shared/lib/data-access/store/sessionSlice';
 import { SettingsForm } from './forms/settings';
@@ -10,6 +10,7 @@ import { clearQB } from '@graphpolaris/shared/lib/data-access/store/querybuilder
 import { clearSchema } from '@graphpolaris/shared/lib/data-access/store/schemaSlice';
 import { DatabaseStatus, SaveStateI, nilUUID, wsDeleteState } from '@graphpolaris/shared/lib/data-access/broker';
 import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@graphpolaris/shared/lib/components/tooltip';
+import { Icon } from '@graphpolaris/shared';
 
 export default function DatabaseSelector({}) {
   const dispatch = useAppDispatch();
@@ -85,8 +86,9 @@ export default function DatabaseSelector({}) {
             }}
           />
         )}
-        <DropdownContainer ref={dbSelectionMenuRef} className="w-[20rem]">
+        <DropdownContainer ref={dbSelectionMenuRef} className="w-[18rem]">
           <DropdownButton
+            size="md"
             disabled={connecting || authCache.authorized === false || !!authCache.roomID}
             title={
               <div className="flex items-center">
@@ -96,14 +98,17 @@ export default function DatabaseSelector({}) {
                     <p className="ml-2 truncate">Connecting to {session.saveStates[session.currentSaveState].name}</p>
                   </>
                 ) : session.currentSaveState && session.currentSaveState in session.saveStates && session.currentSaveState !== nilUUID ? (
-                  <>
-                    <div
-                      className={`h-2 w-2 rounded-full ${
-                        session.testedSaveState[session.currentSaveState] === DatabaseStatus.tested ? 'bg-success-500' : 'bg-danger-500'
-                      }`}
-                    />
-                    <p className="ml-2 truncate">Connected DB: {session.saveStates[session.currentSaveState].name}</p>
-                  </>
+                  <div className="flex items-center">
+                    <div className="relative self-center">
+                      <Icon component={<StorageOutlined />} size={20} />
+
+                      <div
+                        className={`absolute bottom-0 left-0 h-2 w-2 border border-light rounded-full ${session.testedSaveState[session.currentSaveState] === DatabaseStatus.tested ? 'bg-success-500' : 'bg-danger-500'}`}
+                      />
+                    </div>
+
+                    <p className="ml-2 truncate">{session.saveStates[session.currentSaveState].name}</p>
+                  </div>
                 ) : session.saveStates === undefined ? (
                   <>
                     <LoadingSpinner />
@@ -128,7 +133,7 @@ export default function DatabaseSelector({}) {
           />
 
           {dbSelectionMenuOpen && session.saveStates !== undefined && (
-            <DropdownItemContainer align="top-10 w-full">
+            <DropdownItemContainer align="top-10 w-full z-30">
               <li
                 className="flex items-center p-2 hover:bg-secondary-50 cursor-pointer"
                 onClick={(e) => {
@@ -210,7 +215,7 @@ export default function DatabaseSelector({}) {
                             <TooltipTrigger>
                               <Settings />
                             </TooltipTrigger>
-                            <TooltipContent side={'bottom'}>
+                            <TooltipContent side={'top'}>
                               <p>Change the connection details</p>
                             </TooltipContent>
                           </Tooltip>
@@ -233,7 +238,7 @@ export default function DatabaseSelector({}) {
                             <TooltipTrigger>
                               <Delete />
                             </TooltipTrigger>
-                            <TooltipContent side={'bottom'}>
+                            <TooltipContent side={'top'}>
                               <p>Delete the database</p>
                             </TooltipContent>
                           </Tooltip>
diff --git a/apps/web/src/components/navbar/DatabaseManagement/forms/databaseForm.tsx b/apps/web/src/components/navbar/DatabaseManagement/forms/databaseForm.tsx
index 4eeba3be4..db78c4740 100644
--- a/apps/web/src/components/navbar/DatabaseManagement/forms/databaseForm.tsx
+++ b/apps/web/src/components/navbar/DatabaseManagement/forms/databaseForm.tsx
@@ -7,7 +7,7 @@ import {
   databaseProtocolMapping,
   nilUUID,
 } from '@graphpolaris/shared/lib/data-access';
-import Input from '@graphpolaris/shared/lib/components/inputs';
+import { Input } from '@graphpolaris/shared/lib/components/inputs';
 import { useImmer } from 'use-immer';
 import { initialState as qbInitialState } from '@graphpolaris/shared/lib/data-access/store/querybuilderSlice';
 
diff --git a/apps/web/src/components/navbar/DatabaseManagement/forms/settings.tsx b/apps/web/src/components/navbar/DatabaseManagement/forms/settings.tsx
index eef51b9ed..233899f09 100644
--- a/apps/web/src/components/navbar/DatabaseManagement/forms/settings.tsx
+++ b/apps/web/src/components/navbar/DatabaseManagement/forms/settings.tsx
@@ -114,7 +114,7 @@ export const SettingsForm = (props: { onClose(): void; open: 'add' | 'update'; s
   return (
     <Dialog open={!!props.open} onClose={props.onClose} className="lg:min-w-[50rem]">
       <div className="flex justify-between align-center">
-        <h1 className="text-xl font-bold">{formTitle} Database Connection</h1>
+        <h2 className="text-xl font-bold">{formTitle} Database Connection</h2>
         <div>
           {sampleDataPanel === true ? (
             <Button variant="outline" label="Go back" onClick={() => setSampleDataPanel(false)} />
diff --git a/apps/web/src/components/navbar/databasemenu.tsx b/apps/web/src/components/navbar/databasemenu.tsx
deleted file mode 100644
index 15a2e2f18..000000000
--- a/apps/web/src/components/navbar/databasemenu.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import React from 'react';
-import { SaveStateI, useSessionCache } from '@graphpolaris/shared/lib/data-access';
-
-export const DatabaseMenu = (props: { onClick: (database: string) => void }) => {
-  const session = useSessionCache();
-
-  return (
-    <ul className="menu dropdown-content absolute right-48 z-[1] p-2 shadow-xl bg-secondary-50 rounded-box w-52" tabIndex={0}>
-      {session.saveStates &&
-        Object.values(session.saveStates).map((ss: SaveStateI) => (
-          <li key={ss.name}>
-            <button onClick={() => props.onClick(ss.name)}>{ss.name}</button>
-          </li>
-        ))}
-    </ul>
-  );
-};
diff --git a/apps/web/src/components/navbar/navbar.tsx b/apps/web/src/components/navbar/navbar.tsx
index 92c7a548d..f9c975f77 100644
--- a/apps/web/src/components/navbar/navbar.tsx
+++ b/apps/web/src/components/navbar/navbar.tsx
@@ -12,10 +12,8 @@ import React, { useState, useRef, useEffect } from 'react';
 import logo_white from './gp-logo-white.svg';
 import logo from './gp-logo.svg';
 import { useAuthorizationCache, useAuth } from '@graphpolaris/shared/lib/data-access';
-import { SearchBar } from './search/SearchBar';
 import DatabaseSelector from './DatabaseManagement/dbConnectionSelector';
 import { DropdownItem, DropdownItemContainer } from '@graphpolaris/shared/lib/components/dropdowns';
-import ColorMode from '@graphpolaris/shared/lib/components/color-mode';
 import GpLogo from './gp-logo';
 
 export const Navbar = () => {
@@ -24,8 +22,6 @@ export const Navbar = () => {
   const authCache = useAuthorizationCache();
   const [menuOpen, setMenuOpen] = useState(false);
 
-  const currentLogo = !'dark' ? logo_white : logo; // TODO: support dark mode
-
   useEffect(() => {
     const handleClickOutside = (event: MouseEvent) => {
       if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
@@ -41,75 +37,65 @@ export const Navbar = () => {
   const buildInfo = import.meta.env.GRAPHPOLARIS_VERSION;
 
   return (
-    <div className="w-full h-auto px-5">
-      <div className="navbar flex items-center justify-between w-auto gap-2 xl:gap-10">
-        <a href="https://graphpolaris.com/" target="_blank" className="w-[10rem] md:w-fit shrink-0 text-dark">
-          <GpLogo className="w-48" />
-        </a>
-        <DatabaseSelector />
+    <nav className="w-full px-4 h-12 flex flex-row items-center gap-2 md:gap-3 lg:gap-4">
+      <a href="https://graphpolaris.com/" target="_blank" className="shrink-0 text-dark">
+        <GpLogo className="h-7" />
+      </a>
+      <DatabaseSelector />
 
-        <div>
-          <SearchBar />
-          <ColorMode />
-          <div className="w-fit" ref={dropdownRef}>
-            <div
-              className="relative inline-flex items-center justify-center w-8 h-8 overflow-hidden bg-secondary-500 rounded hover:bg-secondary-600 transition-colors duration-150 ease-in-out cursor-pointer"
-              onClick={() => setMenuOpen(!menuOpen)}
-            >
-              <span className="font-medium text-light">{authCache.username?.slice(0, 2).toUpperCase()}</span>
-            </div>
+      <div className="ml-auto">
+        <div className="w-fit" ref={dropdownRef}>
+          <div
+            className="relative inline-flex items-center justify-center w-8 h-8 overflow-hidden bg-secondary-500 rounded-full hover:bg-secondary-600 transition-colors duration-150 ease-in-out cursor-pointer"
+            onClick={() => setMenuOpen(!menuOpen)}
+          >
+            <span className="font-medium text-light">{authCache.username?.slice(0, 2).toUpperCase()}</span>
+          </div>
 
-            {menuOpen && (
-              <DropdownItemContainer className="w-56" align="right-7">
-                <div className="menu-title border-b">
-                  <h2>user: {authCache.username}</h2>
-                  <h3 className="text-xs break-words">session: {authCache.sessionID}</h3>
-                </div>
+          {menuOpen && (
+            <DropdownItemContainer className="w-56 z-30" align="right-3">
+              <div className="p-2 text-sm border-b">
+                <h2 className="font-bold">user: {authCache.username}</h2>
+                <h3 className="text-xs break-words">session: {authCache.sessionID}</h3>
+              </div>
 
-                {authCache.authorized ? (
-                  <>
-                    <DropdownItem
-                      value="Share"
-                      onClick={() => {
-                        auth.newShareRoom();
-                      }}
-                      // submenu={
-                      //   <>
-                      //     <DropdownItem value="Visual" onClick={() => {}} />
-                      //     <DropdownItem value="Knowledge base" onClick={() => {}} />
-                      //   </>
-                      // }
-                    />
-                    <DropdownItem
-                      value="Advanced"
-                      submenu={
-                        <>
-                          <DropdownItem value="TBD" onClick={() => {}} />
-                        </>
-                      }
-                    />
-                    <DropdownItem value="Settings" onClick={() => {}} />
-                    <DropdownItem value="Log out" onClick={() => {}} />
-                  </>
-                ) : (
-                  <>
-                    <DropdownItem value="Login" onClick={() => {}} />
-                  </>
-                )}
+              {authCache.authorized ? (
+                <>
+                  <DropdownItem
+                    value="Share"
+                    onClick={() => {
+                      auth.newShareRoom();
+                    }}
+                  />
+                  <DropdownItem
+                    value="Advanced"
+                    submenu={
+                      <>
+                        <DropdownItem value="TBD" onClick={() => {}} />
+                      </>
+                    }
+                  />
+                  <DropdownItem value="Settings" onClick={() => {}} />
+                  <DropdownItem value="Log out" onClick={() => {}} />
+                </>
+              ) : (
+                <>
+                  <DropdownItem value="Login" onClick={() => {}} />
+                </>
+              )}
 
-                {authCache?.roomID && (
-                  <div className="menu-title border-b">
-                    <h3 className="text-xs break-words">Share ID: {authCache.roomID}</h3>
-                  </div>
-                )}
-                <div className="menu-title border-t">
-                  <h3 className="text-xs">Version: {buildInfo}</h3>
+              {authCache?.roomID && (
+                <div className="p-2 border-b">
+                  <h3 className="text-xs break-words">Share ID: {authCache.roomID}</h3>
                 </div>
-              </DropdownItemContainer>
-            )}
-          </div>
+              )}
+              <div className="p-2 border-t">
+                <h3 className="text-xs">Version: {buildInfo}</h3>
+              </div>
+            </DropdownItemContainer>
+          )}
         </div>
       </div>
-    </div>
+    </nav>
   );
 };
diff --git a/apps/web/src/components/navbar/search/SearchBar.tsx b/apps/web/src/components/navbar/search/SearchBar.tsx
deleted file mode 100644
index e5182032b..000000000
--- a/apps/web/src/components/navbar/search/SearchBar.tsx
+++ /dev/null
@@ -1,260 +0,0 @@
-import React from 'react';
-import {
-  useAppDispatch,
-  useGraphQueryResult,
-  useSchemaGraph,
-  useQuerybuilderGraph,
-  useSearchResult,
-  AppDispatch,
-  useRecentSearches,
-} from '@graphpolaris/shared/lib/data-access';
-import { filterData } from './similarity';
-import { Search as SearchIcon } from '@mui/icons-material';
-import {
-  addSearchResultData,
-  addSearchResultSchema,
-  addSearchResultQueryBuilder,
-  CATEGORY_KEYS,
-  addRecentSearch,
-} from '@graphpolaris/shared/lib/data-access/store/searchResultSlice';
-import { QueryMultiGraph } from '@graphpolaris/shared/lib/querybuilder/model/graphology/utils';
-
-const SIMILARITY_THRESHOLD = 0.7;
-
-const CATEGORY_ACTIONS: {
-  [key in CATEGORY_KEYS]: (payload: { nodes: Record<string, any>[]; edges: Record<string, any>[] }, dispatch: AppDispatch) => void;
-} = {
-  data: (payload: { nodes: Record<string, any>[]; edges: Record<string, any>[] }, dispatch: AppDispatch) => {
-    dispatch(addSearchResultData(payload));
-  },
-  schema: (payload: { nodes: Record<string, any>[]; edges: Record<string, any>[] }, dispatch: AppDispatch) => {
-    dispatch(addSearchResultSchema(payload));
-  },
-  querybuilder: (payload: { nodes: Record<string, any>[]; edges: Record<string, any>[] }, dispatch: AppDispatch) => {
-    dispatch(addSearchResultQueryBuilder(payload));
-  },
-};
-
-const SEARCH_CATEGORIES: CATEGORY_KEYS[] = Object.keys(CATEGORY_ACTIONS) as CATEGORY_KEYS[];
-
-export function SearchBar({}) {
-  const inputRef = React.useRef<HTMLInputElement>(null);
-  const searchbarRef = React.useRef<HTMLDivElement>(null);
-  const dispatch = useAppDispatch();
-  const results = useSearchResult();
-  const recentSearches = useRecentSearches();
-  const schema = useSchemaGraph();
-  const graphData = useGraphQueryResult();
-  const querybuilderData = useQuerybuilderGraph();
-  const [search, setSearch] = React.useState<string>('');
-  const [searchOpen, setSearchOpen] = React.useState<boolean>(false);
-
-  const dataSources: {
-    [key: string]: { nodes: Record<string, any>[]; edges: Record<string, any>[] };
-  } = {
-    data: graphData,
-    schema: schema,
-    querybuilder: querybuilderData as QueryMultiGraph,
-  };
-
-  const toggleSearch = () => {
-    setSearchOpen(true);
-    if (!searchOpen && inputRef.current) {
-      inputRef.current.focus();
-    }
-  };
-
-  React.useEffect(() => {
-    const handleKeyPress = (event: KeyboardEvent) => {
-      if (event.key === 'Enter') {
-        if (searchOpen && search !== '') {
-          dispatch(addRecentSearch(search));
-        }
-      }
-    };
-    window.addEventListener('keydown', handleKeyPress);
-    return () => window.removeEventListener('keydown', handleKeyPress);
-  }, [searchOpen, search]);
-
-  React.useEffect(() => {
-    const handleKeyPress = (event: KeyboardEvent) => {
-      if (event.key === '/') {
-        if (!searchOpen) {
-          setSearchOpen(true);
-          setSearch('');
-        }
-      }
-    };
-    window.addEventListener('keydown', handleKeyPress);
-    return () => window.removeEventListener('keydown', handleKeyPress);
-  }, [searchOpen]);
-
-  React.useEffect(() => {
-    if (searchOpen && inputRef.current) {
-      inputRef.current.focus();
-      setSearch('');
-    }
-  }, [searchOpen]);
-
-  React.useEffect(() => {
-    const handleKeyPress = (event: KeyboardEvent) => {
-      if (event.key === 'Escape') {
-        if (searchOpen) {
-          setSearchOpen(false);
-          setSearch('');
-        }
-      }
-    };
-    window.addEventListener('keydown', handleKeyPress);
-    return () => window.removeEventListener('keydown', handleKeyPress);
-  }, [searchOpen]);
-
-  React.useEffect(() => {
-    handleSearch();
-  }, [search]);
-
-  const handleSearch = () => {
-    let query = search.toLowerCase();
-    const categories = search.match(/@[^ ]+/g);
-
-    if (categories) {
-      categories.map((category) => {
-        query = query.replace(category, '').trim();
-        const cat = category.substring(1);
-
-        if (cat in CATEGORY_ACTIONS) {
-          const categoryAction = CATEGORY_ACTIONS[cat as CATEGORY_KEYS];
-          const data = dataSources[cat];
-
-          const payload = {
-            nodes: filterData(query, data.nodes, SIMILARITY_THRESHOLD),
-            edges: filterData(query, data.edges, SIMILARITY_THRESHOLD),
-          };
-          categoryAction(payload, dispatch);
-        }
-      });
-    } else {
-      for (const category of SEARCH_CATEGORIES) {
-        const categoryAction = CATEGORY_ACTIONS[category];
-        const data = dataSources[category];
-
-        const payload = {
-          nodes: filterData(query, data.nodes, SIMILARITY_THRESHOLD),
-          edges: filterData(query, data.edges, SIMILARITY_THRESHOLD),
-        };
-
-        categoryAction(payload, dispatch);
-      }
-    }
-  };
-
-  React.useEffect(() => {
-    const handleClickOutside = ({ target }: MouseEvent) => {
-      if (inputRef.current && target && !inputRef.current.contains(target as Node) && !searchbarRef?.current?.contains(target as Node)) {
-        setSearch('');
-        setSearchOpen(false);
-      }
-    };
-    document.addEventListener('click', handleClickOutside);
-    return () => {
-      document.removeEventListener('click', handleClickOutside);
-    };
-  }, []);
-
-  return (
-    <div className="searchbar">
-      {searchOpen && <div className="fixed inset-0 bg-black bg-opacity-50 z-40"></div>}
-      <div className="mr-2" ref={searchbarRef}>
-        <div
-          className="flex items-center border border-secondary-300 hover:bg-secondary-50 px-2 rounded text-sm w-44 h-8 text-secondary-900 cursor-pointer"
-          onClick={toggleSearch}
-        >
-          <SearchIcon />
-          <span className="ml-1 text-secondary-900">
-            Type <span className="border border-secondary-900 rounded px-1">/</span> to search
-          </span>
-        </div>
-
-        {searchOpen && (
-          <div className="fixed flex flex-col left-1/2 -translate-x-1/2 w-9/12 max-h-1/2 top-2 items-start justify-center z-50 bg-secondary-200 rounded">
-            <div className="p-3 w-full">
-              {/* <label className="sr-only">Search</label> */}
-              <div className="relative">
-                <div className="absolute inset-y-0 start-0 flex items-center ps-3 pointer-events-none">
-                  <SearchIcon className="text-secondary500" />
-                </div>
-                <input
-                  type="text"
-                  ref={inputRef}
-                  value={search}
-                  onChange={(e) => setSearch(e.target.value)}
-                  id="input-group-search"
-                  className="block w-full p-2 ps-10 text-sm text-secondary-900 border border-secondary-300 rounded bg-secondary-50 focus:ring-blue-500 focus:border-blue-500 focus:ring-0"
-                  placeholder="Search database"
-                ></input>
-              </div>
-            </div>
-
-            {recentSearches.length !== 0 && (
-              <div className="px-3 pb-3">
-                <p className="text-sm">Recent searches</p>
-                {recentSearches.slice(0, 3).map((term) => (
-                  <p key={term} className="ml-1 text-sm text-secondary-500 cursor-pointer" onClick={() => setSearch(term)}>
-                    {term}
-                  </p>
-                ))}
-              </div>
-            )}
-            {search !== '' && (
-              <div className="z-10 rounded card-bordered w-full overflow-auto max-h-[60vh] px-3 pb-3">
-                <p className="font-bold text-sm">Results</p>
-                {SEARCH_CATEGORIES.every((category) => results[category].nodes.length === 0 && results[category].edges.length === 0) ? (
-                  <div className="ml-1 text-sm">
-                    <p className="text-secondary-500">Found no matches...</p>
-                  </div>
-                ) : (
-                  SEARCH_CATEGORIES.map((category, index) => {
-                    if (results[category].nodes.length > 0 || results[category].edges.length > 0) {
-                      return (
-                        <div key={index}>
-                          <div className="flex justify-between p-2 text-lg">
-                            <p className="font-bold text-sm">{category.charAt(0).toUpperCase() + category.slice(1)}</p>
-                            <p className="font-bold text-sm">{results[category].nodes.length + results[category].edges.length} results</p>
-                          </div>
-                          <div className="h-[1px] w-full bg-secondary-200"></div>
-                          {Object.values(Object.values(results[category]))
-                            .flat()
-                            .map((item, index) => (
-                              <div
-                                key={index}
-                                className="flex flex-col hover:bg-secondary-300 px-2 py-1 cursor-pointer rounded ml-2"
-                                title={JSON.stringify(item)}
-                                onClick={() => {
-                                  CATEGORY_ACTIONS[category](
-                                    {
-                                      nodes: results[category].nodes.includes(item) ? [item] : [],
-                                      edges: results[category].edges.includes(item) ? [item] : [],
-                                    },
-                                    dispatch,
-                                  );
-                                }}
-                              >
-                                <div className="font-bold text-sm">
-                                  {item?.key?.slice(0, 18) || item?.id?.slice(0, 18) || Object.values(item)?.[0]?.slice(0, 18)}
-                                </div>
-                                <div className="font-light text-secondary-800 text-xs">{JSON.stringify(item).substring(0, 40)}...</div>
-                              </div>
-                            ))}
-                        </div>
-                      );
-                    } else return <></>;
-                  })
-                )}
-              </div>
-            )}
-          </div>
-        )}
-      </div>
-    </div>
-  );
-}
diff --git a/apps/web/src/components/onboarding/onboarding.tsx b/apps/web/src/components/onboarding/onboarding.tsx
index e7526d3f8..d811f1df2 100644
--- a/apps/web/src/components/onboarding/onboarding.tsx
+++ b/apps/web/src/components/onboarding/onboarding.tsx
@@ -11,7 +11,7 @@ interface OnboardingState {
   stepIndex?: number;
 }
 
-export default function Onboarding({}) {
+export function Onboarding({}) {
   const location = useLocation();
   const auth = useAuthorizationCache();
   const [showWalkthrough, setShowWalkthrough] = useState<boolean>(false);
diff --git a/apps/web/src/components/onboarding/use-cases/types.tsx b/apps/web/src/components/onboarding/use-cases/types.ts
similarity index 100%
rename from apps/web/src/components/onboarding/use-cases/types.tsx
rename to apps/web/src/components/onboarding/use-cases/types.ts
diff --git a/apps/web/src/main.css b/apps/web/src/main.css
index 3f399b3f9..b05311668 100644
--- a/apps/web/src/main.css
+++ b/apps/web/src/main.css
@@ -16,7 +16,7 @@ html * {
 
 html,
 body {
-  @apply font-sans bg-light text-dark;
+  @apply font-sans bg-secondary-50 text-dark;
 }
 
 .panel {
diff --git a/libs/config/tailwind.config.js b/libs/config/tailwind.config.js
index 05385a971..a6e1334de 100644
--- a/libs/config/tailwind.config.js
+++ b/libs/config/tailwind.config.js
@@ -37,6 +37,9 @@ export default {
       mono: ['Roboto Mono', ...defaultTheme.fontFamily.mono],
     },
     extend: {
+      borderColor: {
+        DEFAULT: 'hsl(var(--clr-sec--200) / <alpha-value>)',
+      },
       colors: tailwindColors,
       animation: {
         openmenu: 'openmenu 0.3s ease-out',
diff --git a/libs/shared/lib/components/Dialog.tsx b/libs/shared/lib/components/Dialog.tsx
index bec6280cd..75781e135 100644
--- a/libs/shared/lib/components/Dialog.tsx
+++ b/libs/shared/lib/components/Dialog.tsx
@@ -16,13 +16,10 @@ export const Dialog = (props: DialogProps) => {
   }, [props.open]);
 
   return (
-    <dialog className={"modal"} ref={ref} onClose={() => props.onClose()}>
-      <form method="dialog" className={"modal-box card flex gap-4 " + (props?.className ? props?.className : "")}>
+    <dialog className={'fixed inset-0 z-10 overflow-y-auto rounded p-4 bg-light border'} ref={ref} onClose={() => props.onClose()}>
+      <form method="dialog" className={'flex flex-col gap-4 ' + (props?.className ? props?.className : '')}>
         {props.children}
       </form>
-      <form method="dialog" className="modal-backdrop">
-        <button>close</button>
-      </form>
     </dialog>
   );
 };
diff --git a/libs/shared/lib/components/Resizable.tsx b/libs/shared/lib/components/Resizable.tsx
index 522f011b6..18069c8db 100644
--- a/libs/shared/lib/components/Resizable.tsx
+++ b/libs/shared/lib/components/Resizable.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useRef } from 'react';
+import React, { useEffect, useRef, useState } from 'react';
 
 type Props = {
   children: React.ReactNode;
@@ -7,32 +7,59 @@ type Props = {
   horizontal: boolean;
   divisorSize: number;
   defaultProportion?: number;
+  classNameLeft?: string;
+  classNameRight?: string;
 };
 
 function convertRemToPixels(rem: number) {
   return rem * parseFloat(getComputedStyle(document.documentElement).fontSize);
 }
 
-export const Resizable = ({ children, className, style, horizontal, divisorSize, defaultProportion, ...props }: Props) => {
+export const Resizable = ({
+  children,
+  className,
+  style,
+  horizontal,
+  divisorSize,
+  defaultProportion,
+  classNameLeft,
+  classNameRight,
+  ...props
+}: Props) => {
   const ref = useRef<HTMLDivElement>(null);
   const children2 = children as React.ReactElement[];
   const [firstSize, setFirstSize] = React.useState<number>(0);
   const [secondSize, setSecondSize] = React.useState<number>(0);
   const [dragging, setDragging] = React.useState<boolean>(false);
+  const [windowSize, setWindowSize] = useState({ width: window.innerWidth, height: window.innerHeight });
+
+  useEffect(() => {
+    const handleResize = () => {
+      setWindowSize({ width: window.innerWidth, height: window.innerHeight });
+    };
+
+    window.addEventListener('resize', handleResize);
+
+    return () => {
+      window.removeEventListener('resize', handleResize);
+    };
+  }, []);
+
+  // Store the current proportion of the first area
+  const [currentProportion, setCurrentProportion] = useState(defaultProportion || 0.5);
 
   useEffect(() => {
     if (ref.current) {
       const rect = ref.current.getBoundingClientRect();
-      const _defaultProportion = defaultProportion || 0.5;
       if (horizontal) {
-        setFirstSize(rect.width * _defaultProportion - divisorSize);
-        setSecondSize(rect.width * (1 / _defaultProportion) - divisorSize);
+        setFirstSize((rect.width - divisorSize) * currentProportion);
+        setSecondSize((rect.width - divisorSize) * (1 - currentProportion));
       } else {
-        setFirstSize(rect.height * _defaultProportion - divisorSize);
-        setSecondSize(rect.height * (1 / _defaultProportion) - divisorSize);
+        setFirstSize((rect.height - divisorSize) * currentProportion);
+        setSecondSize((rect.height - divisorSize) * (1 - currentProportion));
       }
     }
-  }, [ref.current]);
+  }, [ref.current, windowSize]);
 
   function onMouseDown(e: React.MouseEvent<HTMLDivElement, MouseEvent>) {
     setDragging(true);
@@ -42,15 +69,27 @@ export const Resizable = ({ children, className, style, horizontal, divisorSize,
     setDragging(false);
     window.removeEventListener('mouseup', onMouseUp);
   };
+
   function onMouseMove(e: React.MouseEvent<HTMLDivElement, MouseEvent>) {
     if (dragging) {
-      if (horizontal && ref.current) {
+      if (ref.current) {
         const rect = ref.current.getBoundingClientRect();
-        setFirstSize(e.clientX);
-        setSecondSize(rect.width - e.clientX);
-      } else {
-        setFirstSize(e.clientY);
-        setSecondSize(window.innerHeight - e.clientY);
+        const relativeX = e.clientX - rect.left;
+        const relativeY = e.clientY - rect.top;
+        const minSizeX = 16;
+        const minSizeY = 28;
+
+        if (horizontal) {
+          const newFirstSize = Math.max(minSizeX, relativeX);
+          setFirstSize(newFirstSize);
+          setSecondSize(Math.max(minSizeX, rect.width - relativeX));
+          setCurrentProportion(newFirstSize / rect.width);
+        } else {
+          const newFirstSize = Math.max(minSizeY, relativeY);
+          setFirstSize(newFirstSize);
+          setSecondSize(Math.max(minSizeY, rect.height - relativeY));
+          setCurrentProportion(newFirstSize / rect.height);
+        }
       }
     }
   }
@@ -65,17 +104,28 @@ export const Resizable = ({ children, className, style, horizontal, divisorSize,
     setDragging(false);
   }
 
+  if (!children2[0]) return children2[1];
+  if (!children2[1]) return children2[0];
+
   return (
     <>
       {dragging && <div className="absolute top-0 left-0 w-screen h-screen z-10 cursor-grabbing" onMouseMove={onMouseMove}></div>}
-      <div className={` w-full h-full flex ${horizontal ? 'flex-row' : 'flex-col'} ${className}`} style={style} {...props} ref={ref}>
+      <div
+        className={`w-full h-full flex ${horizontal ? 'flex-row' : 'flex-col'} ${className !== undefined ? className : ''} `}
+        style={style}
+        {...props}
+        ref={ref}
+      >
         {firstSize > 0 && (
           <>
-            <div className="h-full w-full" style={horizontal ? { maxWidth: firstSize } : { maxHeight: firstSize }}>
+            <div
+              className={'h-full w-full' + (classNameLeft !== undefined ? classNameLeft : '')}
+              style={horizontal ? { maxWidth: firstSize } : { maxHeight: firstSize }}
+            >
               {children2[0]}
             </div>
             <div
-              className={' ' + (horizontal ? 'cursor-col-resize' : 'cursor-row-resize')}
+              className={' ' + (horizontal ? 'cursor-col-resize' : 'cursor-row-resize') + (dragging ? ' bg-primary-200' : '')}
               style={horizontal ? { minWidth: divisorSize } : { minHeight: divisorSize }}
               onMouseDown={onMouseDown}
               onTouchStart={onTouchStart}
@@ -83,7 +133,10 @@ export const Resizable = ({ children, className, style, horizontal, divisorSize,
               onTouchEnd={onTouchEnd}
               onTouchCancel={onTouchCancel}
             ></div>
-            <div className="h-full w-full" style={horizontal ? { maxWidth: secondSize } : { maxHeight: secondSize }}>
+            <div
+              className={'h-full w-full' + (classNameRight !== undefined ? classNameRight : '')}
+              style={horizontal ? { maxWidth: secondSize } : { maxHeight: secondSize }}
+            >
               {children2[1]}
             </div>
           </>
diff --git a/libs/shared/lib/components/buttons/buttons.module.scss b/libs/shared/lib/components/buttons/buttons.module.scss
index eae142ad9..ec502e7d7 100644
--- a/libs/shared/lib/components/buttons/buttons.module.scss
+++ b/libs/shared/lib/components/buttons/buttons.module.scss
@@ -42,7 +42,9 @@
     @apply cursor-not-allowed;
   }
 }
-
+.btn-icon-only {
+  line-height: 1;
+}
 .btn-lg {
   @apply text-lg h-10 gap-1.5;
   &.btn-icon-only {
@@ -67,6 +69,12 @@
     @apply w-6;
   }
 }
+.btn-2xs {
+  @apply text-2xs h-4 gap-0.5;
+  &.btn-icon-only {
+    @apply w-4 p-0;
+  }
+}
 
 .btn-primary {
   --btn-color: var(--clr-pri--600);
diff --git a/libs/shared/lib/components/buttons/buttons.module.scss.d.ts b/libs/shared/lib/components/buttons/buttons.module.scss.d.ts
index 090a2928f..83aafa791 100644
--- a/libs/shared/lib/components/buttons/buttons.module.scss.d.ts
+++ b/libs/shared/lib/components/buttons/buttons.module.scss.d.ts
@@ -1,10 +1,11 @@
 declare const classNames: {
   readonly btn: 'btn';
-  readonly 'btn-lg': 'btn-lg';
   readonly 'btn-icon-only': 'btn-icon-only';
+  readonly 'btn-lg': 'btn-lg';
   readonly 'btn-md': 'btn-md';
   readonly 'btn-sm': 'btn-sm';
   readonly 'btn-xs': 'btn-xs';
+  readonly 'btn-2xs': 'btn-2xs';
   readonly 'btn-primary': 'btn-primary';
   readonly 'btn-secondary': 'btn-secondary';
   readonly 'btn-danger': 'btn-danger';
diff --git a/libs/shared/lib/components/buttons/index.tsx b/libs/shared/lib/components/buttons/index.tsx
index c98e59fda..04c2fad2c 100644
--- a/libs/shared/lib/components/buttons/index.tsx
+++ b/libs/shared/lib/components/buttons/index.tsx
@@ -6,7 +6,7 @@ import { forwardRef } from 'react';
 type ButtonProps = {
   type?: 'primary' | 'secondary' | 'danger';
   variant?: 'solid' | 'outline' | 'ghost';
-  size?: 'xs' | 'sm' | 'md' | 'lg';
+  size?: '2xs' | 'xs' | 'sm' | 'md' | 'lg';
   label?: string;
   rounded?: boolean;
   disabled?: boolean;
@@ -17,6 +17,7 @@ type ButtonProps = {
   ariaLabel?: string;
   children?: React.ReactNode;
   additionalClasses?: string;
+  notAButton?: boolean;
 };
 
 export const Button = React.forwardRef<HTMLButtonElement, ButtonProps & React.HTMLAttributes<HTMLButtonElement>>(
@@ -35,6 +36,7 @@ export const Button = React.forwardRef<HTMLButtonElement, ButtonProps & React.HT
       ariaLabel,
       additionalClasses,
       children,
+      notAButton,
       ...props
     },
     forwardRef,
@@ -76,6 +78,10 @@ export const Button = React.forwardRef<HTMLButtonElement, ButtonProps & React.HT
     let iconSize: Sizes = 24;
 
     switch (size) {
+      case '2xs':
+        sizeClass = styles['btn-2xs'];
+        iconSize = 12;
+        break;
       case 'xs':
         sizeClass = styles['btn-xs'];
         iconSize = 16;
@@ -100,6 +106,14 @@ export const Button = React.forwardRef<HTMLButtonElement, ButtonProps & React.HT
 
     const iconOnlyClass = iconComponent && !label && !children ? styles['btn-icon-only'] : '';
 
+    if (notAButton)
+      return (
+        <div
+          className={`${styles.btn} ${typeClass} ${variantClass} ${sizeClass} ${blockClass} ${roundedClass} ${iconOnlyClass} ${additionalClasses}`}
+        >
+          {icon}
+        </div>
+      );
     return (
       <button
         className={`${styles.btn} ${typeClass} ${variantClass} ${sizeClass} ${blockClass} ${roundedClass} ${iconOnlyClass} ${additionalClasses}`}
diff --git a/libs/shared/lib/components/color-mode/index.tsx b/libs/shared/lib/components/color-mode/index.tsx
index 97abb3e04..6b43428c1 100644
--- a/libs/shared/lib/components/color-mode/index.tsx
+++ b/libs/shared/lib/components/color-mode/index.tsx
@@ -45,9 +45,9 @@ const ColorMode = () => {
     <TooltipProvider delayDuration={0}>
       <Tooltip>
         <TooltipTrigger asChild>
-          <Button variant="ghost" iconComponent={iconComponent} onClick={toggleTheme} />
+          <Button variant="ghost" size="sm" iconComponent={iconComponent} onClick={toggleTheme} />
         </TooltipTrigger>
-        <TooltipContent side={'bottom'}>
+        <TooltipContent side={'right'}>
           <p>{`Switch to ${theme === 'dark-mode' ? 'light' : 'dark'}-mode`}</p>
         </TooltipContent>
       </Tooltip>
diff --git a/libs/shared/lib/components/controls/index.tsx b/libs/shared/lib/components/controls/index.tsx
index 92fc2cc4c..3660df5a1 100644
--- a/libs/shared/lib/components/controls/index.tsx
+++ b/libs/shared/lib/components/controls/index.tsx
@@ -4,6 +4,6 @@ type Props = {
   children: ReactNode;
 };
 
-export default function ControlContainer({ children }: Props) {
+export function ControlContainer({ children }: Props) {
   return <div className="top-4 right-4 flex flex-row-reverse justify-between z-50">{children}</div>;
 }
diff --git a/libs/shared/lib/components/dropdowns/dropdowns.module.scss b/libs/shared/lib/components/dropdowns/dropdowns.module.scss
index a564d157f..8d45e1520 100644
--- a/libs/shared/lib/components/dropdowns/dropdowns.module.scss
+++ b/libs/shared/lib/components/dropdowns/dropdowns.module.scss
@@ -8,7 +8,7 @@
 .dropdown-container {
   width: inherit;
   max-width: 100%;
-  @apply absolute z-10 mt-2 origin-top-right rounded-sm shadow-lg border border-secondary-200;
+  @apply absolute z-10 mt-2 origin-top-right rounded-sm shadow-lg border border-secondary-200 truncate;
   ul {
     //todo: color
     @apply divide-y;
diff --git a/libs/shared/lib/components/dropdowns/index.tsx b/libs/shared/lib/components/dropdowns/index.tsx
index 96ec000e5..54cfd4bab 100644
--- a/libs/shared/lib/components/dropdowns/index.tsx
+++ b/libs/shared/lib/components/dropdowns/index.tsx
@@ -1,5 +1,7 @@
 import React, { useState, useEffect, useRef, ReactNode } from 'react';
 import styles from './dropdowns.module.scss';
+import Icon from '../icon';
+import { ArrowDropDown } from '@mui/icons-material';
 
 type DropdownContainerProps = {
   children: ReactNode;
@@ -9,11 +11,11 @@ type DropdownContainerProps = {
 export const DropdownContainer = React.forwardRef<HTMLDivElement, DropdownContainerProps>(
   ({ children, className }, ref: React.ForwardedRef<HTMLDivElement>) => {
     return (
-      <div className={`border-1 border-secondary-800  relative inline-block text-left ${className && className}`} ref={ref}>
+      <div className={`relative inline-block text-left ${className && className}`} ref={ref}>
         {children}
       </div>
     );
-  }
+  },
 );
 
 type DropdownButtonProps = {
@@ -24,21 +26,18 @@ type DropdownButtonProps = {
 };
 
 export function DropdownButton({ title, onClick, size, disabled }: DropdownButtonProps) {
+  const paddingClass = size === 'xs' ? 'py-1' : size === 'sm' ? 'px-1 py-1' : size === 'md' ? 'px-2 py-1' : 'px-4 py-2';
+  const textSizeClass = size === 'xs' ? 'text-xs' : size === 'sm' ? 'text-sm' : size === 'md' ? 'text-base' : 'text-lg';
+
   return (
     <>
       <button
-        className="inline-flex w-full justify-between items-center gap-x-1.5 rounded bg-light px-3 py-2 text-secondary-900 shadow-sm ring-1 ring-inset ring-secondary-300 hover:bg-secondary-50 disabled:bg-secondary-100 disabled:cursor-not-allowed disabled:text-secondary-400"
+        className={`inline-flex border w-full justify-between items-center gap-x-1.5 rounded bg-light ${textSizeClass} ${paddingClass} text-secondary-900 shadow-sm hover:bg-secondary-50 disabled:bg-secondary-100 disabled:cursor-not-allowed disabled:text-secondary-400 pl-1 truncate`}
         onClick={onClick}
         disabled={disabled}
       >
         <span className={`text-${size}`}>{title}</span>
-        <svg className="-mr-1 h-5 w-5 text-secondary-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
-          <path
-            fillRule="evenodd"
-            d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z"
-            clipRule="evenodd"
-          />
-        </svg>
+        <Icon component={<ArrowDropDown />} size={16} />
       </button>
     </>
   );
diff --git a/libs/shared/lib/components/icon/icon.stories.tsx b/libs/shared/lib/components/icon/icon.stories.tsx
index 1b506cf2e..b57f7c09e 100644
--- a/libs/shared/lib/components/icon/icon.stories.tsx
+++ b/libs/shared/lib/components/icon/icon.stories.tsx
@@ -2,10 +2,9 @@ import { StoryObj, Meta } from '@storybook/react';
 import Icon from '../icon';
 import { ArrowBack, DeleteOutline, KeyboardArrowLeft, Settings } from '@mui/icons-material';
 
-export default {
+const Component: Meta<typeof Icon> = {
   title: 'Components/Icon',
   component: Icon,
-  decorators: [(Story) => <div className="p-5">{Story()}</div>],
   argTypes: {
     component: {
       control: 'select',
@@ -16,14 +15,14 @@ export default {
       options: [16, 20, 24, 28, 32, 40],
     },
   },
-} as Meta;
-type Story = StoryObj<typeof Icon>;
+  decorators: [(Story) => <div className="p-5">{Story()}</div>],
+};
 
-const BaseIcon: Story = {
-  args: {
-    name: 'ArrowBack',
-    size: 24,
-  },
+export default Component;
+type Story = StoryObj<typeof Component>;
+
+export const BaseIcon: Story = (args: any) => {
+  return <Icon component={<ArrowBack />} size={24} {...args} />;
 };
 
-export const Default = { ...BaseIcon };
+BaseIcon.args = {};
diff --git a/libs/shared/lib/components/icon/index.tsx b/libs/shared/lib/components/icon/index.tsx
index 68950afb5..4a4c74652 100644
--- a/libs/shared/lib/components/icon/index.tsx
+++ b/libs/shared/lib/components/icon/index.tsx
@@ -1,7 +1,7 @@
 import React, { ReactElement } from 'react';
 import { SVGProps } from 'react';
 
-export type Sizes = 14 | 16 | 20 | 24 | 28 | 32 | 40;
+export type Sizes = 12 | 14 | 16 | 20 | 24 | 28 | 32 | 40;
 export type IconProps = SVGProps<SVGSVGElement> & {
   component: ReactElement<any>;
   size?: Sizes;
diff --git a/libs/shared/lib/components/inputs/index.tsx b/libs/shared/lib/components/inputs/index.tsx
index e52a53dd7..2ef371c0c 100644
--- a/libs/shared/lib/components/inputs/index.tsx
+++ b/libs/shared/lib/components/inputs/index.tsx
@@ -31,6 +31,21 @@ type TextProps = {
   onChange?: (value: string) => void;
 };
 
+type NumberProps = {
+  label: string;
+  type: 'number';
+  placeholder?: string;
+  value: number;
+  required?: boolean;
+  errorText?: string;
+  visible?: boolean;
+  disabled?: boolean;
+  tooltip?: string;
+  info?: string;
+  validate?: (value: any) => boolean;
+  onChange?: (value: number) => void;
+};
+
 type CheckboxProps = {
   label?: string;
   type: 'checkbox';
@@ -63,6 +78,7 @@ type DropdownProps = {
   value: string | number | undefined;
   type: 'dropdown';
   options: any;
+  size?: 'xs' | 'sm' | 'md' | 'xl';
   tooltip?: string;
   onChange?: (value: string | number) => void;
   required?: boolean;
@@ -70,9 +86,9 @@ type DropdownProps = {
   disabled?: boolean;
 };
 
-export type InputProps = TextProps | SliderProps | CheckboxProps | DropdownProps | RadioProps | BooleanProps;
+export type InputProps = TextProps | SliderProps | CheckboxProps | DropdownProps | RadioProps | BooleanProps | NumberProps;
 
-const Input = (props: InputProps) => {
+export const Input = (props: InputProps) => {
   switch (props.type) {
     case 'slider':
       return <SliderInput {...(props as SliderProps)} />;
@@ -86,6 +102,8 @@ const Input = (props: InputProps) => {
       return <RadioInput {...(props as RadioProps)} />;
     case 'boolean':
       return <BooleanInput {...(props as BooleanProps)} />;
+    case 'number':
+      return <NumberInput {...(props as NumberProps)} />;
     default:
       return null;
   }
@@ -167,6 +185,52 @@ export const TextInput = ({
   );
 };
 
+export const NumberInput = ({
+  label,
+  placeholder,
+  value = 0,
+  required = false,
+  visible = true,
+  errorText,
+  validate,
+  disabled = false,
+  onChange,
+  tooltip,
+  info,
+}: NumberProps) => {
+  const [isValid, setIsValid] = React.useState<boolean>(true);
+
+  return (
+    <div data-tip={tooltip || null} className={'form-control w-full' + (tooltip ? ' tooltip' : '')}>
+      <label className="label">
+        <span className={`text-sm font-medium text-secondary-700 ${required && "after:content-['*'] after:ml-0.5 after:text-danger-500"}`}>
+          {label}
+        </span>
+        {required && isValid ? null : <span className="label-text-alt text-error">{errorText}</span>}
+        {info && <Info tooltip={info} side={'left'} />}
+      </label>
+      <input
+        type="number"
+        placeholder={placeholder}
+        className={`px-3 py-2 bg-light border border-secondary-300 placeholder-secondary-400 focus:outline-none block w-full sm:text-sm focus:ring-1 ${
+          isValid ? '' : 'input-error'
+        }`}
+        value={value.toString()}
+        onChange={(e) => {
+          if (required && validate) {
+            setIsValid(validate(e.target.value));
+          }
+          if (onChange) {
+            onChange(Number(e.target.value));
+          }
+        }}
+        required={required}
+        disabled={disabled}
+      />
+    </div>
+  );
+};
+
 export const RadioInput = ({ label, value, options, onChange, tooltip }: RadioProps) => {
   return (
     <div data-tip={tooltip || null} className={tooltip ? 'tooltip' : ''}>
@@ -226,7 +290,7 @@ export const BooleanInput = ({ label, value, onChange, tooltip }: BooleanProps)
   return (
     <div data-tip={tooltip || null} className={tooltip ? 'tooltip' : ''}>
       <label className={`label cursor-pointer w-fit gap-2 px-0 py-1`}>
-        <span className="label-text">{label}</span>
+        <span className="text-sm">{label}</span>
         <input
           type="checkbox"
           checked={value}
@@ -242,7 +306,17 @@ export const BooleanInput = ({ label, value, onChange, tooltip }: BooleanProps)
   );
 };
 
-export const DropDownInput = ({ label, value, options, onChange, required = false, tooltip, disabled = false, info }: DropdownProps) => {
+export const DropDownInput = ({
+  label,
+  value,
+  options,
+  onChange,
+  required = false,
+  tooltip,
+  size = 'sm',
+  disabled = false,
+  info,
+}: DropdownProps) => {
   const dropdownRef = React.useRef<HTMLDivElement>(null);
   const [isDropdownOpen, setIsDropdownOpen] = React.useState<boolean>(false);
 
@@ -273,6 +347,7 @@ export const DropDownInput = ({ label, value, options, onChange, required = fals
       <DropdownContainer className="w-full" ref={dropdownRef}>
         <DropdownButton
           title={value}
+          size={size}
           disabled={disabled}
           onClick={(e) => {
             e.stopPropagation();
@@ -302,5 +377,3 @@ export const DropDownInput = ({ label, value, options, onChange, required = fals
     </div>
   );
 };
-
-export default Input;
diff --git a/libs/shared/lib/components/inputs/number.stories.tsx b/libs/shared/lib/components/inputs/number.stories.tsx
new file mode 100644
index 000000000..e31f0c745
--- /dev/null
+++ b/libs/shared/lib/components/inputs/number.stories.tsx
@@ -0,0 +1,36 @@
+import React from 'react';
+import type { Meta, StoryObj } from '@storybook/react';
+import { NumberInput } from '.';
+
+const Component: Meta<typeof NumberInput> = {
+  title: 'Components/Inputs',
+  component: NumberInput,
+  argTypes: { onChange: {} },
+  decorators: [(Story) => <div className="w-52 m-5">{Story()}</div>],
+};
+
+export default Component;
+type Story = StoryObj<typeof Component>;
+
+export const NumberInputStory: Story = {
+  args: {
+    type: 'number',
+    label: 'Number input',
+    placeholder: 'Put here a number',
+    required: true,
+    onChange: (value) => {},
+  },
+};
+
+export const RequiredNumberInputStory: Story = {
+  args: {
+    type: 'number',
+    label: 'Number input',
+    placeholder: 'Put here a number',
+    errorText: 'This field is required',
+    validate: (value) => {
+      return value.length > 0;
+    },
+    onChange: (value) => {},
+  },
+};
diff --git a/libs/shared/lib/components/inputs/overview.mdx b/libs/shared/lib/components/inputs/overview.mdx
index 2682f0b10..8f26649d2 100644
--- a/libs/shared/lib/components/inputs/overview.mdx
+++ b/libs/shared/lib/components/inputs/overview.mdx
@@ -1,5 +1,5 @@
 import { Meta } from '@storybook/blocks';
-import Input from '.'; // Adjust the import path as needed
+import { Input } from '.'; // Adjust the import path as needed
 
 export const components = {
   Input,
diff --git a/libs/shared/lib/vis/configuration/encodings/selectors/axis.stories.tsx b/libs/shared/lib/components/selectors/axis.stories.tsx
similarity index 100%
rename from libs/shared/lib/vis/configuration/encodings/selectors/axis.stories.tsx
rename to libs/shared/lib/components/selectors/axis.stories.tsx
diff --git a/libs/shared/lib/vis/configuration/encodings/selectors/axis.tsx b/libs/shared/lib/components/selectors/axis.tsx
similarity index 66%
rename from libs/shared/lib/vis/configuration/encodings/selectors/axis.tsx
rename to libs/shared/lib/components/selectors/axis.tsx
index bd987f71d..0415ad71d 100644
--- a/libs/shared/lib/vis/configuration/encodings/selectors/axis.tsx
+++ b/libs/shared/lib/components/selectors/axis.tsx
@@ -1,6 +1,6 @@
 import React from 'react';
-import Input from '@graphpolaris/shared/lib/components/inputs';
-import { SelectorProps } from '../encodings.types';
+import { Input } from '@graphpolaris/shared/lib/components/inputs';
+import { SelectorProps } from './encodings.types';
 
 export default function Axis({ marking, onChange }: SelectorProps) {
   return (
diff --git a/libs/shared/lib/vis/configuration/encodings/selectors/color.stories.tsx b/libs/shared/lib/components/selectors/color.stories.tsx
similarity index 100%
rename from libs/shared/lib/vis/configuration/encodings/selectors/color.stories.tsx
rename to libs/shared/lib/components/selectors/color.stories.tsx
diff --git a/libs/shared/lib/vis/configuration/encodings/selectors/color.tsx b/libs/shared/lib/components/selectors/color.tsx
similarity index 83%
rename from libs/shared/lib/vis/configuration/encodings/selectors/color.tsx
rename to libs/shared/lib/components/selectors/color.tsx
index e67a6059e..a1daab8da 100644
--- a/libs/shared/lib/vis/configuration/encodings/selectors/color.tsx
+++ b/libs/shared/lib/components/selectors/color.tsx
@@ -1,7 +1,7 @@
 import React, { useState } from 'react';
-import { SelectorProps } from '../encodings.types';
+import { SelectorProps } from './encodings.types';
 import DropdownColorLegend from '@graphpolaris/shared/lib/components/colorComponents/colorDropdown';
-import Input from '@graphpolaris/shared/lib/components/inputs';
+import { Input } from '@graphpolaris/shared/lib/components/inputs';
 
 export default function Color({ marking, onChange, statistics, dimension }: SelectorProps) {
   const [colors, setColors] = useState<any>(null);
diff --git a/libs/shared/lib/vis/configuration/encodings/encodings.types.ts b/libs/shared/lib/components/selectors/encodings.types.ts
similarity index 94%
rename from libs/shared/lib/vis/configuration/encodings/encodings.types.ts
rename to libs/shared/lib/components/selectors/encodings.types.ts
index 6b1b367b6..38ee8f0df 100644
--- a/libs/shared/lib/vis/configuration/encodings/encodings.types.ts
+++ b/libs/shared/lib/components/selectors/encodings.types.ts
@@ -1,5 +1,5 @@
 import { DimensionType } from '@graphpolaris/shared/lib/schema';
-import { EncodingSelector } from './selectors';
+import { EncodingSelector } from '.';
 import { ElementStats } from '@graphpolaris/shared/lib/data-access/statistics';
 
 export type SelectorType = keyof typeof EncodingSelector;
diff --git a/libs/shared/lib/vis/configuration/encodings/selectors/index.ts b/libs/shared/lib/components/selectors/index.ts
similarity index 100%
rename from libs/shared/lib/vis/configuration/encodings/selectors/index.ts
rename to libs/shared/lib/components/selectors/index.ts
diff --git a/libs/shared/lib/vis/configuration/encodings/selectors/opacity.stories.tsx b/libs/shared/lib/components/selectors/opacity.stories.tsx
similarity index 100%
rename from libs/shared/lib/vis/configuration/encodings/selectors/opacity.stories.tsx
rename to libs/shared/lib/components/selectors/opacity.stories.tsx
diff --git a/libs/shared/lib/vis/configuration/encodings/selectors/opacity.tsx b/libs/shared/lib/components/selectors/opacity.tsx
similarity index 82%
rename from libs/shared/lib/vis/configuration/encodings/selectors/opacity.tsx
rename to libs/shared/lib/components/selectors/opacity.tsx
index 2d16f8a76..3d69051c3 100644
--- a/libs/shared/lib/vis/configuration/encodings/selectors/opacity.tsx
+++ b/libs/shared/lib/components/selectors/opacity.tsx
@@ -1,6 +1,6 @@
 import React, { useState } from 'react';
-import Input from '@graphpolaris/shared/lib/components/inputs';
-import { SelectorProps } from '../encodings.types';
+import { Input } from '@graphpolaris/shared/lib/components/inputs';
+import { SelectorProps } from './encodings.types';
 
 export default function Opacity({ marking, onChange, statistics, dimension }: SelectorProps) {
   const [custom, setCustom] = useState<boolean>(false);
diff --git a/libs/shared/lib/vis/configuration/encodings/selectors/shape.stories.tsx b/libs/shared/lib/components/selectors/shape.stories.tsx
similarity index 100%
rename from libs/shared/lib/vis/configuration/encodings/selectors/shape.stories.tsx
rename to libs/shared/lib/components/selectors/shape.stories.tsx
diff --git a/libs/shared/lib/vis/configuration/encodings/selectors/shape.tsx b/libs/shared/lib/components/selectors/shape.tsx
similarity index 74%
rename from libs/shared/lib/vis/configuration/encodings/selectors/shape.tsx
rename to libs/shared/lib/components/selectors/shape.tsx
index 1f0b38809..9238fc83e 100644
--- a/libs/shared/lib/vis/configuration/encodings/selectors/shape.tsx
+++ b/libs/shared/lib/components/selectors/shape.tsx
@@ -1,5 +1,5 @@
 import React from 'react';
-import { SelectorProps } from '../encodings.types';
+import { SelectorProps } from './encodings.types';
 
 export default function Shape({ marking, onChange, statistics, dimension }: SelectorProps) {
   return <div>shape</div>;
diff --git a/libs/shared/lib/vis/configuration/encodings/selectors/size.stories.tsx b/libs/shared/lib/components/selectors/size.stories.tsx
similarity index 100%
rename from libs/shared/lib/vis/configuration/encodings/selectors/size.stories.tsx
rename to libs/shared/lib/components/selectors/size.stories.tsx
diff --git a/libs/shared/lib/vis/configuration/encodings/selectors/size.tsx b/libs/shared/lib/components/selectors/size.tsx
similarity index 81%
rename from libs/shared/lib/vis/configuration/encodings/selectors/size.tsx
rename to libs/shared/lib/components/selectors/size.tsx
index e5f68f47b..4b74a1bf0 100644
--- a/libs/shared/lib/vis/configuration/encodings/selectors/size.tsx
+++ b/libs/shared/lib/components/selectors/size.tsx
@@ -1,6 +1,6 @@
 import React, { useState } from 'react';
-import Input from '@graphpolaris/shared/lib/components/inputs';
-import { SelectorProps } from '../encodings.types';
+import { Input } from '@graphpolaris/shared/lib/components/inputs';
+import { SelectorProps } from './encodings.types';
 
 export default function Size({ marking, onChange, statistics, dimension }: SelectorProps) {
   const [item, setItem] = useState<string>('');
diff --git a/libs/shared/lib/components/tooltip/index.tsx b/libs/shared/lib/components/tooltip/index.tsx
index 79e5bfe88..4d3d7c991 100644
--- a/libs/shared/lib/components/tooltip/index.tsx
+++ b/libs/shared/lib/components/tooltip/index.tsx
@@ -55,51 +55,3 @@ const TooltipContent = React.forwardRef<
 TooltipContent.displayName = TooltipPrimitive.Content.displayName;
 
 export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
-
-// Old Tooltip
-
-export type TooltipProps2 = {
-  position?: 'top' | 'bottom' | 'left' | 'right';
-  children: ReactNode;
-  tooltip: string;
-  disabled?: boolean;
-};
-export default function Tooltip2({ position = 'bottom', children, tooltip, disabled = false }: TooltipProps2) {
-  return (
-    <div className="group relative cursor-pointer">
-      <div className="">{children}</div>
-      {!disabled && (
-        <div className="z-50">
-          <span
-            className={`absolute hidden group-hover:inline-block bg-neutral-900 text-white text-xs p-2 whitespace-nowrap rounded ${
-              position === 'top' ? 'left-1/2 -translate-x-1/2 bottom-[calc(100%+5px)]' : ''
-            } ${position === 'bottom' ? 'left-1/2 -translate-x-1/2 top-[calc(100%+5px)]' : ''} ${
-              position === 'left' ? 'top-1/2 -translate-y-1/2 right-[calc(100%+5px)]' : ''
-            } ${position === 'right' ? 'top-1/2 -translate-y-1/2 left-[calc(100%+5px)]' : ''} `}
-          >
-            {tooltip}
-          </span>
-          <span
-            className={`absolute hidden group-hover:inline-block border-[6px] ${
-              position === 'top'
-                ? 'left-1/2 -translate-x-1/2 bottom-full border-l-transparent border-r-transparent border-b-0 border-t-neutral-900'
-                : ''
-            } ${
-              position === 'bottom'
-                ? 'left-1/2 -translate-x-1/2 top-full border-l-transparent border-r-transparent border-t-0 border-b-neutral-900'
-                : ''
-            } ${
-              position === 'left'
-                ? 'top-1/2 -translate-y-1/2 right-full border-t-transparent border-b-transparent border-r-0 border-l-neutral-900'
-                : ''
-            } ${
-              position === 'right'
-                ? 'top-1/2 -translate-y-1/2 left-full border-t-transparent border-b-transparent border-l-0 border-r-neutral-900'
-                : ''
-            } `}
-          ></span>
-        </div>
-      )}
-    </div>
-  );
-}
diff --git a/libs/shared/lib/data-access/store/graphQueryResultSlice.ts b/libs/shared/lib/data-access/store/graphQueryResultSlice.ts
index 5372882d4..62df2ef32 100755
--- a/libs/shared/lib/data-access/store/graphQueryResultSlice.ts
+++ b/libs/shared/lib/data-access/store/graphQueryResultSlice.ts
@@ -63,68 +63,72 @@ export const initialState: GraphQueryResult = {
   queryingBackend: false,
 };
 
+export const graphQueryBackend2graphQuery = (payload: GraphQueryResultFromBackend) => {
+  // Only keep one node and one edge per id. This is also done in the backend, but we do it here as well to be sure.
+  const nodeIDs = new Set(payload.nodes.map((node) => node.id));
+  const edgeIDs = new Set(payload.edges.map((edge) => edge.id));
+  let nodes = [...nodeIDs].map((nodeID) => payload.nodes.find((node) => node.id === nodeID) as unknown as Node);
+  let edges = [...edgeIDs].map((edgeID) => payload.edges.find((edge) => edge.id === edgeID) as unknown as Edge);
+
+  const metaData: GraphMetaData = {
+    nodes: { labels: [], count: nodes.length, types: {} },
+    edges: { labels: [], count: edges.length, types: {} },
+  };
+
+  nodes = nodes.map((node) => {
+    let _node = { ...node };
+    // TODO!: only works for neo4j
+    let nodeType: string = node.id.split('/')[0];
+    let innerLabels = node?.attributes?.labels as string[];
+
+    if (innerLabels?.length > 0) nodeType = innerLabels[0] as string;
+    if (!metaData.nodes.labels.includes(nodeType)) metaData.nodes.labels?.push(nodeType);
+    if (!metaData.nodes.types[nodeType]) metaData.nodes.types[nodeType] = { count: 0, attributes: {} };
+    metaData.nodes.types[nodeType].count++;
+
+    Object.entries(_node.attributes).forEach(([attributeId, attributeValue]) => {
+      if (!metaData.nodes.types[nodeType].attributes[attributeId]) {
+        const dimension = getDimension(attributeValue);
+        metaData.nodes.types[nodeType].attributes[attributeId] = { dimension, values: [], statistics: {} };
+      }
+      metaData.nodes.types[nodeType].attributes[attributeId].values?.push(attributeValue);
+    });
+
+    _node.label = nodeType;
+    return _node;
+  });
+
+  edges = edges.map((edge) => {
+    let _edge = { ...edge };
+    // TODO!: only works for neo4j
+    let edgeType: string = edge.id.split('/')[0];
+
+    if (!_edge.id.includes('/')) edgeType = edge.attributes.Type as string;
+    if (!metaData.edges.labels?.includes(edgeType)) metaData.edges.labels?.push(edgeType);
+    if (!metaData.edges.types[edgeType]) metaData.edges.types[edgeType] = { count: 0, attributes: {} };
+    metaData.edges.types[edgeType].count++;
+
+    Object.entries(_edge.attributes).forEach(([attributeId, attributeValue]) => {
+      if (!metaData.edges.types[edgeType].attributes[attributeId]) {
+        const dimension = getDimension(attributeValue);
+        metaData.edges.types[edgeType].attributes[attributeId] = { dimension, values: [], statistics: {} };
+      }
+      metaData.edges.types[edgeType].attributes[attributeId].values?.push(attributeValue);
+    });
+
+    _edge.label = edgeType;
+    return _edge;
+  });
+  return { metaData: extractStatistics(metaData), nodes, edges };
+};
+
 export const graphQueryResultSlice = createSlice({
   name: 'graphQueryResult',
   initialState,
   reducers: {
     setNewGraphQueryResult: (state, action: PayloadAction<GraphQueryResultFromBackendPayload>) => {
       const payload = action.payload.result.payload;
-
-      // Only keep one node and one edge per id. This is also done in the backend, but we do it here as well to be sure.
-      const nodeIDs = new Set(payload.nodes.map((node) => node.id));
-      const edgeIDs = new Set(payload.edges.map((edge) => edge.id));
-      let nodes = [...nodeIDs].map((nodeID) => payload.nodes.find((node) => node.id === nodeID) as unknown as Node);
-      let edges = [...edgeIDs].map((edgeID) => payload.edges.find((edge) => edge.id === edgeID) as unknown as Edge);
-
-      const metaData: GraphMetaData = {
-        nodes: { labels: [], count: nodes.length, types: {} },
-        edges: { labels: [], count: edges.length, types: {} },
-      };
-
-      nodes = nodes.map((node) => {
-        let _node = { ...node };
-        // TODO!: only works for neo4j
-        let nodeType: string = node.id.split('/')[0];
-        let innerLabels = node?.attributes?.labels as string[];
-
-        if (innerLabels?.length > 0) nodeType = innerLabels[0] as string;
-        if (!metaData.nodes.labels.includes(nodeType)) metaData.nodes.labels?.push(nodeType);
-        if (!metaData.nodes.types[nodeType]) metaData.nodes.types[nodeType] = { count: 0, attributes: {} };
-        metaData.nodes.types[nodeType].count++;
-
-        Object.entries(_node.attributes).forEach(([attributeId, attributeValue]) => {
-          if (!metaData.nodes.types[nodeType].attributes[attributeId]) {
-            const dimension = getDimension(attributeValue);
-            metaData.nodes.types[nodeType].attributes[attributeId] = { dimension, values: [], statistics: {} };
-          }
-          metaData.nodes.types[nodeType].attributes[attributeId].values?.push(attributeValue);
-        });
-
-        _node.label = nodeType;
-        return _node;
-      });
-
-      edges = edges.map((edge) => {
-        let _edge = { ...edge };
-        // TODO!: only works for neo4j
-        let edgeType: string = edge.id.split('/')[0];
-
-        if (!_edge.id.includes('/')) edgeType = edge.attributes.Type as string;
-        if (!metaData.edges.labels?.includes(edgeType)) metaData.edges.labels?.push(edgeType);
-        if (!metaData.edges.types[edgeType]) metaData.edges.types[edgeType] = { count: 0, attributes: {} };
-        metaData.edges.types[edgeType].count++;
-
-        Object.entries(_edge.attributes).forEach(([attributeId, attributeValue]) => {
-          if (!metaData.edges.types[edgeType].attributes[attributeId]) {
-            const dimension = getDimension(attributeValue);
-            metaData.edges.types[edgeType].attributes[attributeId] = { dimension, values: [], statistics: {} };
-          }
-          metaData.edges.types[edgeType].attributes[attributeId].values?.push(attributeValue);
-        });
-
-        _edge.label = edgeType;
-        return _edge;
-      });
+      const { metaData, nodes, edges } = graphQueryBackend2graphQuery(payload);
 
       // Assign new state
       state.metaData = extractStatistics(metaData);
diff --git a/libs/shared/lib/data-access/store/interactionSlice.ts b/libs/shared/lib/data-access/store/interactionSlice.ts
new file mode 100644
index 000000000..89d18d410
--- /dev/null
+++ b/libs/shared/lib/data-access/store/interactionSlice.ts
@@ -0,0 +1,35 @@
+import { createSlice, PayloadAction } from '@reduxjs/toolkit';
+import type { RootState } from './store';
+
+export type HoverType = { [id: string]: any };
+
+export type SelectType = { [id: string]: any };
+
+// Define the initial state using that type
+export type InteractionsType = {
+  hover: HoverType | undefined;
+  select: SelectType | undefined;
+};
+
+export const initialState: InteractionsType = {
+  hover: {},
+  select: {},
+};
+
+export const interactionSlice = createSlice({
+  name: 'interaction',
+  // `createSlice` will infer the state type from the `initialState` argument
+  initialState,
+  reducers: {
+    addHover: (state, action: PayloadAction<HoverType | undefined>) => {
+      state.hover = action.payload;
+    },
+    addSelect: (state, action: PayloadAction<SelectType | undefined>) => {
+      state.select = action.payload;
+    },
+  },
+});
+
+export const { addHover, addSelect } = interactionSlice.actions;
+
+export default interactionSlice.reducer;
diff --git a/libs/shared/lib/data-access/store/visualizationSlice.ts b/libs/shared/lib/data-access/store/visualizationSlice.ts
index 4cb0d79e4..217118a0e 100644
--- a/libs/shared/lib/data-access/store/visualizationSlice.ts
+++ b/libs/shared/lib/data-access/store/visualizationSlice.ts
@@ -1,46 +1,28 @@
-import { createSelector, createSlice, PayloadAction } from '@reduxjs/toolkit';
+import { createSlice, PayloadAction } from '@reduxjs/toolkit';
 import type { RootState } from './store';
-import { globalConfigTypes, VisualizationConfiguration } from '../../vis/types';
+import { VisualizationConfiguration } from '../../vis/common';
 import { isEqual } from 'lodash-es';
-import { EncodingTypes } from '../../vis/configuration/encodings';
-import { SettingTypes } from '../../vis/configuration/settings';
-import { InteractionTypes } from '../../vis/configuration/interactions';
 
 export type VisStateSettings = {
-  general: globalConfigTypes;
   [id: string]: VisualizationConfiguration;
 };
 export type VisState = {
   activeVisualization?: string;
-  settings: VisStateSettings;
+  openVisualizations: VisStateSettings;
 };
 
 export const initialState: VisState = {
-  activeVisualization: 'NodeLinkVis',
-  settings: {
-    general: {},
-  },
+  // activeVisualization: 'NodeLinkVis',
+  openVisualizations: {},
 };
 
 export const visualizationSlice = createSlice({
   name: 'visualization',
   initialState,
   reducers: {
-    addVisualization: (
-      state,
-      action: PayloadAction<{
-        id: string;
-        settings: SettingTypes;
-        encodings: EncodingTypes;
-        interactions: InteractionTypes;
-      }>,
-    ) => {
-      const { id, settings, encodings, interactions } = action.payload;
-      state.settings[id] = { settings, encodings, interactions };
-    },
     removeVisualization: (state, action: PayloadAction<string>) => {
-      if (state.settings[action.payload]) {
-        delete state.settings[action.payload];
+      if (state.openVisualizations[action.payload]) {
+        delete state.openVisualizations[action.payload];
       }
     },
     setActiveVisualization: (state, action: PayloadAction<string>) => {
@@ -49,21 +31,23 @@ export const visualizationSlice = createSlice({
     setVisualizationState: (state, action: PayloadAction<VisState>) => {
       if (action.payload.activeVisualization && !isEqual(action.payload, state)) {
         state.activeVisualization = action.payload.activeVisualization;
-        state.settings = action.payload.settings;
+        state.openVisualizations = action.payload.openVisualizations || {};
       }
     },
-    updateConfiguration: (state, action: PayloadAction<any>) => {
-      const { general, visualization } = action.payload;
-      state.settings.general = general;
-      if (state.activeVisualization) state.settings[state.activeVisualization] = visualization;
+    updateVisualization: (state, action: PayloadAction<{ id: string; settings: any }>) => {
+      const { id, settings } = action.payload;
+      state.openVisualizations[id] = settings;
+    },
+    reorderVisState: (state, action: PayloadAction<{ [id: string]: VisualizationConfiguration }>) => {
+      state.openVisualizations = action.payload;
     },
   },
 });
 
-export const { addVisualization, removeVisualization, setActiveVisualization, setVisualizationState, updateConfiguration } =
+export const { removeVisualization, setActiveVisualization, setVisualizationState, updateVisualization, reorderVisState } =
   visualizationSlice.actions;
 
 export const visualizationState = (state: RootState) => state.visualize;
-export const visualizationAllSettings = (state: RootState) => state.visualize.settings;
+export const visualizationAllSettings = (state: RootState) => state.visualize.openVisualizations;
 
 export default visualizationSlice.reducer;
diff --git a/libs/shared/lib/data-access/theme/colorPaletteConfigSlice.ts b/libs/shared/lib/data-access/theme/colorPaletteConfigSlice.ts
index f8c83ebf1..70132ebb4 100644
--- a/libs/shared/lib/data-access/theme/colorPaletteConfigSlice.ts
+++ b/libs/shared/lib/data-access/theme/colorPaletteConfigSlice.ts
@@ -1,6 +1,6 @@
 /** Extra properties that are not present in the default PaletteOptions of mui. For autocompletion */
 export interface ExtraColorsForMui5 {
-  /** Colors that can be used for data visualisation, e.g. nodes, edges */
+  /** Colors that can be used for data visualization, e.g. nodes, edges */
   dataPointColors: string[];
 
   nodes: Array<string>;
diff --git a/libs/shared/lib/querybuilder/panel/querybuilder.tsx b/libs/shared/lib/querybuilder/panel/querybuilder.tsx
index a594becbc..1491281f2 100644
--- a/libs/shared/lib/querybuilder/panel/querybuilder.tsx
+++ b/libs/shared/lib/querybuilder/panel/querybuilder.tsx
@@ -26,13 +26,13 @@ import ReactFlow, {
 } from 'reactflow';
 import { Dialog } from '../../components/Dialog';
 import { Button } from '../../components/buttons';
-import ControlContainer from '../../components/controls';
+import { ControlContainer } from '../../components/controls';
 import { addError } from '../../data-access/store/configSlice';
 import { toSchemaGraphology } from '../../data-access/store/schemaSlice';
 import { LayoutFactory } from '../../graph-layout';
 import { AllLogicMap, QueryElementTypes, createReactFlowElements, isLogicHandle, toHandleData } from '../model';
 import { ConnectionDragLine, ConnectionLine, EntityFlowElement, RelationPill } from '../pills';
-import LogicPill from '../pills/customFlowPills/logicpill/logicpill';
+import { LogicPill } from '../pills/customFlowPills/logicpill/logicpill';
 import { dragPillStarted, movePillTo } from '../pills/dragging/dragPill';
 import styles from './querybuilder.module.scss';
 import { QueryBuilderLogicPillsPanel } from './querysidepanel/queryBuilderLogicPillsPanel';
@@ -434,137 +434,141 @@ export const QueryBuilderInner = (props: QueryBuilderProps) => {
   }, [queryBuilderSettings]);
 
   return (
-    <div ref={reactFlowWrapper} className="h-full w-full">
+    <div ref={reactFlowWrapper} className="h-full w-full flex flex-col">
       <QuerySettingsDialog open={toggleSettings === 'settings'} onClose={() => setToggleSettings(undefined)} />
       <QueryMLDialog open={toggleSettings === 'ml'} onClose={() => setToggleSettings(undefined)} />
 
-      <div className="relative flex items-center justify-between z-[2] py-0 px-2 bg-secondary-100  border-b border-secondary-200">
-        <h1 className="text-xs font-semibold text-secondary-800">Query builder</h1>
-        <ControlContainer>
-          <TooltipProvider delayDuration={0}>
-            <Tooltip>
-              <TooltipTrigger asChild>
-                <Button type="secondary" variant="ghost" size="xs" iconComponent={<Fullscreen />} onClick={fitView} />
-              </TooltipTrigger>
-              <TooltipContent side={'bottom'}>
-                <p>Fit to screen</p>
-              </TooltipContent>
-            </Tooltip>
-            <Tooltip>
-              <TooltipTrigger asChild>
-                <Button type="secondary" variant="ghost" size="xs" iconComponent={<Delete />} onClick={() => clearAllNodes()} />
-              </TooltipTrigger>
-              <TooltipContent side={'bottom'}>
-                <p>Clear query panel</p>
-              </TooltipContent>
-            </Tooltip>
-            <Tooltip>
-              <TooltipTrigger asChild>
-                <Button
-                  type="secondary"
-                  variant="ghost"
-                  size="xs"
-                  iconComponent={<CameraAlt />}
-                  onClick={(event) => {
-                    event.stopPropagation();
-                  }}
-                />
-              </TooltipTrigger>
-              <TooltipContent side={'bottom'}>
-                <p>Capture screen</p>
-              </TooltipContent>
-            </Tooltip>
-            <Tooltip>
-              <TooltipTrigger asChild>
-                <Button
-                  type="secondary"
-                  variant="ghost"
-                  size="xs"
-                  iconComponent={<ImportExport />}
-                  onClick={(event) => {
-                    event.stopPropagation();
-                    applyLayout();
-                  }}
-                />
-              </TooltipTrigger>
-              <TooltipContent side={'bottom'}>
-                <p>Layouts</p>
-              </TooltipContent>
-            </Tooltip>
-            <Tooltip>
-              <TooltipTrigger asChild>
-                <Button
-                  type="secondary"
-                  variant="ghost"
-                  size="xs"
-                  iconComponent={<Settings />}
-                  additionalClasses="query-settings"
-                  onClick={(event) => {
-                    event.stopPropagation();
-                    if (toggleSettings === 'settings') setToggleSettings(undefined);
-                    else setToggleSettings('settings');
-                  }}
-                />
-              </TooltipTrigger>
-              <TooltipContent side={'bottom'} disabled={toggleSettings === 'settings'}>
-                <p>Query builder settings</p>
-              </TooltipContent>
-            </Tooltip>
-            <Tooltip>
-              <TooltipTrigger asChild>
-                <Button
-                  type="secondary"
-                  variant="ghost"
-                  size="xs"
-                  iconComponent={<Cached />}
-                  onClick={(event) => {
-                    event.stopPropagation();
-                    if (props.onRunQuery) props.onRunQuery();
-                  }}
-                />
-              </TooltipTrigger>
-              <TooltipContent side={'bottom'}>
-                <p>Rerun query</p>
-              </TooltipContent>
-            </Tooltip>
-            <Tooltip>
-              <TooltipTrigger asChild>
-                <Button
-                  type="secondary"
-                  variant="ghost"
-                  size="xs"
-                  iconComponent={<Difference />}
-                  onClick={(event) => {
-                    event.stopPropagation();
-                    if (toggleSettings === 'logic') setToggleSettings(undefined);
-                    else setToggleSettings('logic');
-                  }}
-                />
-              </TooltipTrigger>
-              <TooltipContent side={'bottom'} disabled={toggleSettings === 'logic'}>
-                <p>Logic settings</p>
-              </TooltipContent>
-            </Tooltip>
-            <Tooltip>
-              <TooltipTrigger asChild>
-                <Button
-                  type="secondary"
-                  variant="ghost"
-                  size="xs"
-                  iconComponent={<Lightbulb />}
-                  onClick={(event) => {
-                    event.stopPropagation();
-                    if (toggleSettings === 'ml') setToggleSettings(undefined);
-                    else setToggleSettings('ml');
-                  }}
-                />
-              </TooltipTrigger>
-              <TooltipContent side={'bottom'} disabled={toggleSettings === 'ml'}>
-                <p>Machine learning</p>
-              </TooltipContent>
-            </Tooltip>
-          </TooltipProvider>
-        </ControlContainer>
+      <div className="sticky shrink-0 top-0 flex items-stretch justify-between h-7 bg-secondary-100 border-b border-secondary-200 max-w-full">
+        <div className="flex items-center">
+          <h1 className="text-xs font-semibold text-secondary-600 px-2 truncate">Query builder</h1>
+        </div>
+        <div className="shrink-0 sticky right-0 px-0.5 ml-auto items-center flex">
+          <ControlContainer>
+            <TooltipProvider delayDuration={0}>
+              <Tooltip>
+                <TooltipTrigger asChild>
+                  <Button type="secondary" variant="ghost" size="xs" iconComponent={<Fullscreen />} onClick={fitView} />
+                </TooltipTrigger>
+                <TooltipContent side={'top'}>
+                  <p>Fit to screen</p>
+                </TooltipContent>
+              </Tooltip>
+              <Tooltip>
+                <TooltipTrigger asChild>
+                  <Button type="secondary" variant="ghost" size="xs" iconComponent={<Delete />} onClick={() => clearAllNodes()} />
+                </TooltipTrigger>
+                <TooltipContent side={'top'}>
+                  <p>Clear query panel</p>
+                </TooltipContent>
+              </Tooltip>
+              <Tooltip>
+                <TooltipTrigger asChild>
+                  <Button
+                    type="secondary"
+                    variant="ghost"
+                    size="xs"
+                    iconComponent={<CameraAlt />}
+                    onClick={(event) => {
+                      event.stopPropagation();
+                    }}
+                  />
+                </TooltipTrigger>
+                <TooltipContent side={'top'}>
+                  <p>Capture screen</p>
+                </TooltipContent>
+              </Tooltip>
+              <Tooltip>
+                <TooltipTrigger asChild>
+                  <Button
+                    type="secondary"
+                    variant="ghost"
+                    size="xs"
+                    iconComponent={<ImportExport />}
+                    onClick={(event) => {
+                      event.stopPropagation();
+                      applyLayout();
+                    }}
+                  />
+                </TooltipTrigger>
+                <TooltipContent side={'top'}>
+                  <p>Layouts</p>
+                </TooltipContent>
+              </Tooltip>
+              <Tooltip>
+                <TooltipTrigger asChild>
+                  <Button
+                    type="secondary"
+                    variant="ghost"
+                    size="xs"
+                    iconComponent={<Settings />}
+                    additionalClasses="query-settings"
+                    onClick={(event) => {
+                      event.stopPropagation();
+                      if (toggleSettings === 'settings') setToggleSettings(undefined);
+                      else setToggleSettings('settings');
+                    }}
+                  />
+                </TooltipTrigger>
+                <TooltipContent side={'top'} disabled={toggleSettings === 'settings'}>
+                  <p>Query builder settings</p>
+                </TooltipContent>
+              </Tooltip>
+              <Tooltip>
+                <TooltipTrigger asChild>
+                  <Button
+                    type="secondary"
+                    variant="ghost"
+                    size="xs"
+                    iconComponent={<Cached />}
+                    onClick={(event) => {
+                      event.stopPropagation();
+                      if (props.onRunQuery) props.onRunQuery();
+                    }}
+                  />
+                </TooltipTrigger>
+                <TooltipContent side={'top'}>
+                  <p>Rerun query</p>
+                </TooltipContent>
+              </Tooltip>
+              <Tooltip>
+                <TooltipTrigger asChild>
+                  <Button
+                    type="secondary"
+                    variant="ghost"
+                    size="xs"
+                    iconComponent={<Difference />}
+                    onClick={(event) => {
+                      event.stopPropagation();
+                      if (toggleSettings === 'logic') setToggleSettings(undefined);
+                      else setToggleSettings('logic');
+                    }}
+                  />
+                </TooltipTrigger>
+                <TooltipContent side={'top'} disabled={toggleSettings === 'logic'}>
+                  <p>Logic settings</p>
+                </TooltipContent>
+              </Tooltip>
+              <Tooltip>
+                <TooltipTrigger asChild>
+                  <Button
+                    type="secondary"
+                    variant="ghost"
+                    size="xs"
+                    iconComponent={<Lightbulb />}
+                    onClick={(event) => {
+                      event.stopPropagation();
+                      if (toggleSettings === 'ml') setToggleSettings(undefined);
+                      else setToggleSettings('ml');
+                    }}
+                  />
+                </TooltipTrigger>
+                <TooltipContent side={'top'} disabled={toggleSettings === 'ml'}>
+                  <p>Machine learning</p>
+                </TooltipContent>
+              </Tooltip>
+            </TooltipProvider>
+          </ControlContainer>
+        </div>
       </div>
 
       <Dialog
@@ -652,7 +656,7 @@ export const QueryBuilderInner = (props: QueryBuilderProps) => {
 
 export const QueryBuilder = (props: QueryBuilderProps) => {
   return (
-    <div className="query-panel flex w-full h-full">
+    <div className="query-panel flex w-full h-full border bg-light">
       <ReactFlowProvider>
         <QueryBuilderInner {...props} />
       </ReactFlowProvider>
diff --git a/libs/shared/lib/querybuilder/panel/querysidepanel/queryMLDialog.tsx b/libs/shared/lib/querybuilder/panel/querysidepanel/queryMLDialog.tsx
index a7a98076e..0c409aa29 100644
--- a/libs/shared/lib/querybuilder/panel/querysidepanel/queryMLDialog.tsx
+++ b/libs/shared/lib/querybuilder/panel/querysidepanel/queryMLDialog.tsx
@@ -8,6 +8,7 @@ import {
   setShortestPathEnabled,
 } from '@graphpolaris/shared/lib/data-access/store/mlSlice';
 import { FormDiv, FormCard, FormBody, FormTitle, FormHBar } from '@graphpolaris/shared/lib/components/forms';
+import { Input } from '@graphpolaris/shared/lib/components/inputs';
 
 type QueryMLDialogProps = DialogProps;
 
@@ -28,27 +29,22 @@ export const QueryMLDialog = React.forwardRef<HTMLDivElement, QueryMLDialogProps
               <FormTitle title="Machine Learning Options" onClose={props.onClose} />
               <FormHBar />
 
-              <div className="form-control px-5">
-                <label className="label cursor-pointer gap-2 w-fit">
-                  <input
-                    type="checkbox"
-                    checked={ml.linkPrediction.enabled}
-                    className="checkbox checkbox-sm"
-                    onChange={(e) => dispatch(setLinkPredictionEnabled(e.target.checked))}
-                  />
-                  <span className="label-text">Link Prediction</span>
-                </label>
+              <div className="px-5">
+                <Input
+                  type="boolean"
+                  label="Link Prediction"
+                  value={ml.linkPrediction.enabled}
+                  onChange={() => dispatch(setLinkPredictionEnabled(!ml.linkPrediction.enabled))}
+                />
                 {ml.linkPrediction.enabled && ml.linkPrediction.result && <span># of predictions: {ml.linkPrediction.result.length}</span>}
                 {ml.linkPrediction.enabled && !ml.linkPrediction.result && <span>Loading...</span>}
-                <label className="label cursor-pointer gap-2 w-fit">
-                  <input
-                    type="checkbox"
-                    checked={ml.centrality.enabled}
-                    className="checkbox checkbox-sm"
-                    onChange={(e) => dispatch(setCentralityEnabled(e.target.checked))}
-                  />
-                  <span className="label-text">Centrality</span>
-                </label>
+
+                <Input
+                  type="boolean"
+                  label="Centrality"
+                  value={ml.centrality.enabled}
+                  onChange={() => dispatch(setCentralityEnabled(!ml.centrality.enabled))}
+                />
                 {ml.centrality.enabled && Object.values(ml.centrality.result).length > 0 && (
                   <span>
                     sum of centers:
@@ -58,28 +54,24 @@ export const QueryMLDialog = React.forwardRef<HTMLDivElement, QueryMLDialogProps
                   </span>
                 )}
                 {ml.centrality.enabled && Object.values(ml.centrality.result).length === 0 && <span>No Centers Found</span>}
-                <label className="label cursor-pointer gap-2 w-fit">
-                  <input
-                    type="checkbox"
-                    checked={ml.communityDetection.enabled}
-                    className="checkbox checkbox-sm"
-                    onChange={(e) => dispatch(setCommunityDetectionEnabled(e.target.checked))}
-                  />
-                  <span className="label-text">Community Detection</span>
-                </label>
+
+                <Input
+                  type="boolean"
+                  label="Community detection"
+                  value={ml.communityDetection.enabled}
+                  onChange={() => dispatch(setCommunityDetectionEnabled(!ml.communityDetection.enabled))}
+                />
                 {ml.communityDetection.enabled && ml.communityDetection.result && (
                   <span># of communities: {ml.communityDetection.result.length}</span>
                 )}
                 {ml.communityDetection.enabled && !ml.communityDetection.result && <span>Loading...</span>}
-                <label className="label cursor-pointer gap-2 w-fit">
-                  <input
-                    type="checkbox"
-                    checked={ml.shortestPath.enabled}
-                    className="checkbox checkbox-sm"
-                    onChange={(e) => dispatch(setShortestPathEnabled(e.target.checked))}
-                  />
-                  <span className="label-text">Shortest Path</span>
-                </label>
+
+                <Input
+                  type="boolean"
+                  label="Shortest path"
+                  value={ml.shortestPath.enabled}
+                  onChange={() => dispatch(setShortestPathEnabled(!ml.shortestPath.enabled))}
+                />
                 {ml.shortestPath.enabled && ml.shortestPath.result?.length > 0 && <span># of hops: {ml.shortestPath.result.length}</span>}
                 {ml.shortestPath.enabled && !ml.shortestPath.srcNode && <span>Please select source node</span>}
                 {ml.shortestPath.enabled && ml.shortestPath.srcNode && !ml.shortestPath.trtNode && <span>Please select target node</span>}
diff --git a/libs/shared/lib/querybuilder/panel/querysidepanel/querySettingsDialog.tsx b/libs/shared/lib/querybuilder/panel/querysidepanel/querySettingsDialog.tsx
index bddfd287a..b5103ac70 100644
--- a/libs/shared/lib/querybuilder/panel/querysidepanel/querySettingsDialog.tsx
+++ b/libs/shared/lib/querybuilder/panel/querysidepanel/querySettingsDialog.tsx
@@ -6,7 +6,7 @@ import { QueryBuilderSettings, setQuerybuilderSettings } from '../../../data-acc
 import { addWarning } from '../../../data-access/store/configSlice';
 import { FormActions, FormBody, FormCard, FormControl, FormDiv, FormHBar, FormTitle } from '../../../components/forms';
 import { Layouts } from '@graphpolaris/shared/lib/graph-layout';
-import Input from '@graphpolaris/shared/lib/components/inputs';
+import { Input } from '@graphpolaris/shared/lib/components/inputs';
 
 type QuerySettingsDialogProps = DialogProps;
 
diff --git a/libs/shared/lib/querybuilder/pills/customFlowPills/entitypill/entitypill.tsx b/libs/shared/lib/querybuilder/pills/customFlowPills/entitypill/entitypill.tsx
index d0ec8779a..7953484ba 100644
--- a/libs/shared/lib/querybuilder/pills/customFlowPills/entitypill/entitypill.tsx
+++ b/libs/shared/lib/querybuilder/pills/customFlowPills/entitypill/entitypill.tsx
@@ -65,7 +65,9 @@ export const EntityFlowElement = React.memo((node: SchemaReactflowEntityNode) =>
             // outerClassName={'!bg-blue-700 !rounded-none'}
             className={'!bg-accent-700'}
           />
-          <div className="text-center py-1">{data.name}</div>
+          <div className="">
+            <div className="text-center py-1">{data.name}</div>
+          </div>
           {data?.attributes && (
             <PillDropdown
               node={node}
diff --git a/libs/shared/lib/querybuilder/pills/customFlowPills/logicpill/logicpill.tsx b/libs/shared/lib/querybuilder/pills/customFlowPills/logicpill/logicpill.tsx
index 0a5e0b884..bb3ec3096 100644
--- a/libs/shared/lib/querybuilder/pills/customFlowPills/logicpill/logicpill.tsx
+++ b/libs/shared/lib/querybuilder/pills/customFlowPills/logicpill/logicpill.tsx
@@ -21,7 +21,7 @@ import { LogicInput } from './logicInput';
  * Component to render an entity flow element
  * @param param0 Data of the flow element.
  */
-export default function LogicPill(node: SchemaReactflowLogicNode) {
+export function LogicPill(node: SchemaReactflowLogicNode) {
   const dispatch = useAppDispatch();
   const data = node.data;
   const logic = data.logic;
diff --git a/libs/shared/lib/schema/panel/index.ts b/libs/shared/lib/schema/panel/index.ts
index c25be6796..e27a6e2f5 100644
--- a/libs/shared/lib/schema/panel/index.ts
+++ b/libs/shared/lib/schema/panel/index.ts
@@ -1,4 +1 @@
 export * from './schema';
-
-import Schema from './schema';
-export default Schema;
diff --git a/libs/shared/lib/schema/panel/schema.stories.tsx b/libs/shared/lib/schema/panel/schema.stories.tsx
index 61457bbf4..051acd2f7 100644
--- a/libs/shared/lib/schema/panel/schema.stories.tsx
+++ b/libs/shared/lib/schema/panel/schema.stories.tsx
@@ -1,12 +1,12 @@
 import React from 'react';
-import { Meta, Story, ComponentStory } from '@storybook/react';
+import { Meta } from '@storybook/react';
 
 import { SchemaUtils } from '@graphpolaris/shared/lib/schema/schema-utils';
 import { schemaSlice, setSchema } from '@graphpolaris/shared/lib/data-access/store';
 
 import { configureStore } from '@reduxjs/toolkit';
 import { Provider } from 'react-redux';
-import Schema from './schema';
+import { Schema } from './schema';
 
 import {
   movieSchemaRaw,
diff --git a/libs/shared/lib/schema/panel/schema.tsx b/libs/shared/lib/schema/panel/schema.tsx
index 4e47cd9e3..b396083e7 100644
--- a/libs/shared/lib/schema/panel/schema.tsx
+++ b/libs/shared/lib/schema/panel/schema.tsx
@@ -1,22 +1,16 @@
+import React, { useEffect, useMemo, useRef, useState } from 'react';
 import { SmartBezierEdge, SmartStepEdge, SmartStraightEdge } from '@tisoap/react-flow-smart-edge';
-
-import { useEffect, useMemo, useRef, useState } from 'react';
 import ReactFlow, { Edge, Node, ReactFlowInstance, ReactFlowProvider, useEdgesState, useNodesState } from 'reactflow';
-
 import 'reactflow/dist/style.css';
-
 import { Button } from '../../components/buttons';
-import ControlContainer from '../../components/controls';
-import { useSchemaGraph, useSchemaSettings, useSearchResultSchema, useSessionCache, wsGetStates, wsSchemaRequest } from '../../data-access';
+import { useSchemaGraph, useSchemaSettings, useSearchResultSchema } from '../../data-access';
 import { toSchemaGraphology } from '../../data-access/store/schemaSlice';
-import NodeEdge from '../pills/edges/node-edge';
-import SelfEdge from '../pills/edges/self-edge';
+import { NodeEdge } from '../pills/edges/node-edge';
+import { SelfEdge } from '../pills/edges/self-edge';
 import { EntityNode } from '../pills/nodes/entity/entity-node';
 import { RelationNode } from '../pills/nodes/relation/relation-node';
 import { SchemaDialog } from './schemaDialog';
-import { Fullscreen, Cached, Settings } from '@mui/icons-material';
-import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../components/tooltip';
-import React from 'react';
+import { KeyboardArrowDown, KeyboardArrowRight } from '@mui/icons-material';
 import { AlgorithmToLayoutProvider, AllLayoutAlgorithms, LayoutFactory } from '../../graph-layout';
 import { ConnectionLine, ConnectionDragLine } from '../../querybuilder';
 import { schemaExpandRelation, schemaGraphology2Reactflow } from '../schema-utils';
@@ -44,7 +38,6 @@ const edgeTypes = {
 };
 
 export const Schema = (props: Props) => {
-  const session = useSessionCache();
   const settings = useSchemaSettings();
   const searchResults = useSearchResultSchema();
   const [toggleSchemaSettings, setToggleSchemaSettings] = useState(false);
@@ -52,6 +45,7 @@ export const Schema = (props: Props) => {
   const [edges, setEdges, onEdgesChange] = useEdgesState([] as Edge[]);
   const [firstUserConnection, setFirstUserConnection] = useState<boolean>(true);
   const [auth, setAuth] = useState(props.auth);
+  const [expanded, setExpanded] = useState<boolean>(false);
 
   const reactFlowInstanceRef = useRef<ReactFlowInstance | null>(null);
   const reactFlowRef = useRef<HTMLDivElement>(null);
@@ -91,6 +85,7 @@ export const Schema = (props: Props) => {
     updateLayout();
     const expandedSchema = schemaExpandRelation(schemaGraphology);
     const bounds = reactFlowRef.current?.getBoundingClientRect();
+
     const xy = bounds ? { x1: 50, x2: bounds.width - 50, y1: 50, y2: bounds.height - 200 } : { x1: 0, x2: 500, y1: 0, y2: 1000 };
     await layout.current?.layout(expandedSchema, xy);
     const schemaFlow = schemaGraphology2Reactflow(expandedSchema, settings.connectionType, settings.animatedEdges);
@@ -113,87 +108,50 @@ export const Schema = (props: Props) => {
   }, [searchResults]);
 
   return (
-    <div className="schema-panel w-full h-full">
-      <SchemaDialog open={toggleSchemaSettings} onClose={() => setToggleSchemaSettings(false)} />
-      <div className="relative flex items-center justify-between z-[2] py-0 px-2 bg-secondary-100  border-b border-secondary-200">
-        <h1 className="text-xs font-semibold text-secondary-800">Schema</h1>
-        <ControlContainer>
-          <TooltipProvider delayDuration={0}>
-            <Tooltip>
-              <TooltipTrigger asChild>
-                <Button type="secondary" variant="ghost" size="xs" iconComponent={<Fullscreen />} onClick={fitView} />
-              </TooltipTrigger>
-              <TooltipContent side={'bottom'}>
-                <p>Fit to screen</p>
-              </TooltipContent>
-            </Tooltip>
-            <Tooltip>
-              <TooltipTrigger asChild>
-                <Button
-                  type="secondary"
-                  variant="ghost"
-                  size="xs"
-                  iconComponent={<Cached />}
-                  onClick={(e) => {
-                    e.stopPropagation();
-                    if (session.currentSaveState) wsSchemaRequest(session.currentSaveState);
-                    else wsGetStates();
-                  }}
-                />
-              </TooltipTrigger>
-              <TooltipContent side={'bottom'}>
-                <p>Refresh schema</p>
-              </TooltipContent>
-            </Tooltip>
-            <Tooltip>
-              <TooltipTrigger asChild>
-                <Button
-                  type="secondary"
-                  variant="ghost"
-                  size="xs"
-                  iconComponent={<Settings />}
-                  additionalClasses="schema-settings"
-                  onClick={(e) => {
-                    e.stopPropagation();
-                    setToggleSchemaSettings(!toggleSchemaSettings);
-                  }}
-                />
-              </TooltipTrigger>
-              <TooltipContent side={'bottom'} disabled={toggleSchemaSettings}>
-                <p>Schema settings</p>
-              </TooltipContent>
-            </Tooltip>
-          </TooltipProvider>
-        </ControlContainer>
-      </div>
+    <div className="schema-panel w-full h-full flex flex-col justify-between" ref={reactFlowRef}>
       {nodes.length === 0 ? (
         <p className="text-sm">No Elements</p>
       ) : (
         <ReactFlowProvider>
-          <div className="h-[calc(100%-.8rem)] w-full" ref={reactFlowRef}>
-            <ReactFlow
-              snapGrid={[10, 10]}
-              snapToGrid
-              onlyRenderVisibleElements={false}
-              nodesDraggable={true}
-              nodeTypes={nodeTypes}
-              edgeTypes={edgeTypes}
-              connectionLineComponent={ConnectionDragLine}
-              onNodesChange={onNodesChange}
-              onEdgesChange={onEdgesChange}
-              nodes={nodes}
-              edges={edges}
-              onInit={(reactFlowInstance) => {
-                reactFlowInstanceRef.current = reactFlowInstance;
-                onInit(reactFlowInstance);
-              }}
-              proOptions={{ hideAttribution: true }}
-            ></ReactFlow>
-          </div>
+          <ReactFlow
+            snapGrid={[10, 10]}
+            snapToGrid
+            onlyRenderVisibleElements={false}
+            nodesDraggable={true}
+            nodeTypes={nodeTypes}
+            edgeTypes={edgeTypes}
+            connectionLineComponent={ConnectionDragLine}
+            onNodesChange={onNodesChange}
+            onEdgesChange={onEdgesChange}
+            nodes={nodes}
+            edges={edges}
+            onInit={(reactFlowInstance) => {
+              reactFlowInstanceRef.current = reactFlowInstance;
+              onInit(reactFlowInstance);
+            }}
+            proOptions={{ hideAttribution: true }}
+          ></ReactFlow>
         </ReactFlowProvider>
       )}
+      <div>
+        <div
+          className="w-full py-0 px-2 bg-secondary-50 cursor-pointer border-y flex items-center gap-1"
+          onClick={() => setExpanded(!expanded)}
+        >
+          <Button
+            size="xs"
+            variant="ghost"
+            iconComponent={expanded ? <KeyboardArrowDown /> : <KeyboardArrowRight />}
+            onClick={() => setExpanded(!expanded)}
+          />
+          <span className="text-xs font-semibold text-secondary-600 truncate">Schema settings</span>
+        </div>
+        {expanded && (
+          <div className="h-full w-full overflow-y-auto">
+            <SchemaDialog open={toggleSchemaSettings} onClose={() => setToggleSchemaSettings(false)} />
+          </div>
+        )}
+      </div>
     </div>
   );
 };
-
-export default Schema;
diff --git a/libs/shared/lib/schema/panel/schemaDialog.tsx b/libs/shared/lib/schema/panel/schemaDialog.tsx
index 644be97cd..3a4313d25 100644
--- a/libs/shared/lib/schema/panel/schemaDialog.tsx
+++ b/libs/shared/lib/schema/panel/schemaDialog.tsx
@@ -5,7 +5,7 @@ import { useAppDispatch, useSchemaSettings } from '../../data-access';
 import { SchemaSettings, setSchemaSettings } from '../../data-access/store/schemaSlice';
 import { FormActions, FormBody, FormCard, FormControl, FormHBar, FormTitle, FormDiv } from '../../components/forms';
 import { Layouts } from '../../graph-layout';
-import Input from '../../components/inputs';
+import { Input } from '../../components/inputs';
 
 export const SchemaDialog = (props: DialogProps) => {
   const settings = useSchemaSettings();
@@ -22,59 +22,50 @@ export const SchemaDialog = (props: DialogProps) => {
   }
 
   return (
-    <>
-      {props.open && (
-        <FormDiv hAnchor="left">
-          <FormCard>
-            <FormBody
-              onSubmit={(e) => {
-                e.preventDefault();
-                submit();
-              }}
-            >
-              <FormTitle title="Schema Settings" onClose={props.onClose} />
-              <FormHBar />
-              <FormControl>
-                <Input
-                  type="dropdown"
-                  label="Type of Connection"
-                  value={state.connectionType}
-                  options={['Default', 'Step', 'Straight', 'Bezier']}
-                  onChange={(value: string | number) => {
-                    setState({ ...state, connectionType: value as any });
-                  }}
-                />
-              </FormControl>
-              <FormHBar />
-              <FormControl>
-                <Input
-                  type="boolean"
-                  value={state.animatedEdges}
-                  label="Animated Edges"
-                  onChange={(value: boolean) => {
-                    setState({ ...state, animatedEdges: value as any });
-                  }}
-                />
-              </FormControl>
-              <FormHBar />
-              <FormControl>
-                <Input
-                  type="dropdown"
-                  label="Layout Type"
-                  value={state.layoutName}
-                  options={Object.values(Layouts)}
-                  onChange={(value: string | number) => {
-                    setState({ ...state, layoutName: value as any });
-                  }}
-                />
-              </FormControl>
-              <FormHBar />
+    <form
+      className="w-full"
+      onSubmit={(e) => {
+        e.preventDefault();
+        submit();
+      }}
+    >
+      <FormControl>
+        <Input
+          type="dropdown"
+          label="Type of Connection"
+          value={state.connectionType}
+          options={['Default', 'Step', 'Straight', 'Bezier']}
+          onChange={(value: string | number) => {
+            setState({ ...state, connectionType: value as any });
+          }}
+        />
+      </FormControl>
+      <FormHBar />
+      <FormControl>
+        <Input
+          type="boolean"
+          value={state.animatedEdges}
+          label="Animated Edges"
+          onChange={(value: boolean) => {
+            setState({ ...state, animatedEdges: value as any });
+          }}
+        />
+      </FormControl>
+      <FormHBar />
+      <FormControl>
+        <Input
+          type="dropdown"
+          label="Layout Type"
+          value={state.layoutName}
+          options={Object.values(Layouts)}
+          onChange={(value: string | number) => {
+            setState({ ...state, layoutName: value as any });
+          }}
+        />
+      </FormControl>
+      <FormHBar />
 
-              <FormActions onClose={props.onClose} />
-            </FormBody>
-          </FormCard>
-        </FormDiv>
-      )}
-    </>
+      <FormActions onClose={props.onClose} />
+    </form>
   );
 };
diff --git a/libs/shared/lib/schema/pills/edges/node-edge.tsx b/libs/shared/lib/schema/pills/edges/node-edge.tsx
index 691c78f0e..c24b0c9df 100644
--- a/libs/shared/lib/schema/pills/edges/node-edge.tsx
+++ b/libs/shared/lib/schema/pills/edges/node-edge.tsx
@@ -16,7 +16,7 @@ import { getCenter } from '../../schema-utils';
  * It has a path that is altered depending on the algorithm in the SchemaViewModelImpl.
  * @param EdgeProps All the data that is stored inside of the React Flow edge.
  */
-export default function NodeEdge({
+export function NodeEdge({
   id,
   source,
   target,
diff --git a/libs/shared/lib/schema/pills/edges/self-edge.tsx b/libs/shared/lib/schema/pills/edges/self-edge.tsx
index d0c1b217f..2b011d7cf 100644
--- a/libs/shared/lib/schema/pills/edges/self-edge.tsx
+++ b/libs/shared/lib/schema/pills/edges/self-edge.tsx
@@ -17,7 +17,7 @@ import { EdgeProps, getMarkerEnd } from 'reactflow';
  * It has a path that is altered depending on the algorithm in the SchemaViewModelImpl.
  * @param EdgeProps All the data that is stored inside of the React Flow edge.
  */
-export default function SelfEdge({
+export function SelfEdge({
   id,
   source,
   target,
diff --git a/libs/shared/lib/schema/pills/nodes/popup/attribute-analytics-popup-menu.tsx b/libs/shared/lib/schema/pills/nodes/popup/attribute-analytics-popup-menu.tsx
index e8755e486..fa5325917 100644
--- a/libs/shared/lib/schema/pills/nodes/popup/attribute-analytics-popup-menu.tsx
+++ b/libs/shared/lib/schema/pills/nodes/popup/attribute-analytics-popup-menu.tsx
@@ -47,7 +47,7 @@ export const AttributeAnalyticsPopupMenu = ({ data }: NodeProps<AttributeAnalyti
   //         </AccordionDetails>
   //         <AccordionDetails className="accordionDetails">
   //           <div className="attributeButtons">
-  //             <span>See visualisation</span>
+  //             <span>See visualization</span>
   //             <span className="rightSideValue">
   //               <Visibility className="visualisationEye" />
   //             </span>
diff --git a/libs/shared/lib/schema/pills/nodes/popup/popupmenus/attribute-analytics-popup-menu.tsx b/libs/shared/lib/schema/pills/nodes/popup/popupmenus/attribute-analytics-popup-menu.tsx
index 5ef056983..97eade305 100644
--- a/libs/shared/lib/schema/pills/nodes/popup/popupmenus/attribute-analytics-popup-menu.tsx
+++ b/libs/shared/lib/schema/pills/nodes/popup/popupmenus/attribute-analytics-popup-menu.tsx
@@ -58,7 +58,7 @@ export const AttributeAnalyticsPopupMenu = ({ data }: NodeProps<AttributeAnalyti
   //           </AccordionDetails>
   //           <AccordionDetails className="accordionDetails">
   //             <div className="attributeButtons">
-  //               <span>See visualisation</span>
+  //               <span>See visualization</span>
   //               <span className="rightSideValue">
   //                 <Visibility className="visualisationEye" />
   //               </span>
diff --git a/libs/shared/lib/schema/schema-utils/flow-utils.ts b/libs/shared/lib/schema/schema-utils/flow-utils.ts
index 284fb7a10..ba4dd9699 100644
--- a/libs/shared/lib/schema/schema-utils/flow-utils.ts
+++ b/libs/shared/lib/schema/schema-utils/flow-utils.ts
@@ -4,7 +4,7 @@
  * © Copyright Utrecht University (Department of Information and Computing Sciences)
  */
 import { Position } from 'reactflow';
-import { BoundingBox } from '../../vis/shared/Types'; // TODO: MOVE ELSEWHERE
+import { BoundingBox } from '../../vis/common'; // TODO: MOVE ELSEWHERE
 
 /** This is the interface to get the center of an edge */
 export interface GetCenterParams {
diff --git a/libs/shared/lib/sidebar/index.tsx b/libs/shared/lib/sidebar/index.tsx
new file mode 100644
index 000000000..6b2a03c0c
--- /dev/null
+++ b/libs/shared/lib/sidebar/index.tsx
@@ -0,0 +1,55 @@
+import React, { useState } from 'react';
+import { Button, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../components';
+import { Fullscreen, Schema as SchemaIcon, Search as SearchIcon } from '@mui/icons-material';
+import ColorMode from '../components/color-mode';
+
+export type SideNavTab = 'Schema' | 'Search' | undefined;
+const tabs: Array<{
+  name: SideNavTab;
+  icon: JSX.Element;
+}> = [
+  {
+    name: 'Search',
+    icon: <SearchIcon />,
+  },
+  { name: 'Schema', icon: <SchemaIcon /> },
+];
+
+export function Sidebar({ onTab }: { onTab: (tab: SideNavTab) => void }) {
+  const [tab, setTab] = useState<SideNavTab>('Schema');
+
+  return (
+    <div className="side-bar w-fit h-full flex shrink">
+      <TooltipProvider delayDuration={100}>
+        <div className="w-11 flex flex-col items-center">
+          {tabs.map((t) => (
+            <Tooltip key={t.name}>
+              <TooltipTrigger asChild>
+                <Button
+                  type="secondary"
+                  variant="ghost"
+                  size="sm"
+                  iconComponent={t.icon}
+                  onClick={() => {
+                    if (tab === t.name) {
+                      onTab(undefined);
+                      setTab(undefined);
+                    } else {
+                      onTab(t.name);
+                      setTab(t.name);
+                    }
+                  }}
+                  additionalClasses={tab === t.name ? 'bg-secondary-100' : ''}
+                />
+              </TooltipTrigger>
+              <TooltipContent side={'right'}>{t.name}</TooltipContent>
+            </Tooltip>
+          ))}
+          <div className="mt-auto mb-2">
+            <ColorMode />
+          </div>
+        </div>
+      </TooltipProvider>
+    </div>
+  );
+}
diff --git a/libs/shared/lib/sidebar/search/searchbar.tsx b/libs/shared/lib/sidebar/search/searchbar.tsx
new file mode 100644
index 000000000..837085911
--- /dev/null
+++ b/libs/shared/lib/sidebar/search/searchbar.tsx
@@ -0,0 +1,182 @@
+import React, { useRef, useState, useEffect } from 'react';
+import {
+  AppDispatch,
+  useAppDispatch,
+  useGraphQueryResult,
+  useQuerybuilderGraph,
+  useRecentSearches,
+  useSchemaGraph,
+  useSearchResult,
+} from '../../data-access';
+import { QueryMultiGraph } from '../../querybuilder';
+import {
+  CATEGORY_KEYS,
+  addRecentSearch,
+  addSearchResultData,
+  addSearchResultQueryBuilder,
+  addSearchResultSchema,
+} from '../../data-access/store/searchResultSlice';
+import { filterData } from './similarity';
+
+const SIMILARITY_THRESHOLD = 0.7;
+
+const CATEGORY_ACTIONS: {
+  [key in CATEGORY_KEYS]: (payload: { nodes: Record<string, any>[]; edges: Record<string, any>[] }, dispatch: AppDispatch) => void;
+} = {
+  data: (payload: { nodes: Record<string, any>[]; edges: Record<string, any>[] }, dispatch: AppDispatch) => {
+    dispatch(addSearchResultData(payload));
+  },
+  schema: (payload: { nodes: Record<string, any>[]; edges: Record<string, any>[] }, dispatch: AppDispatch) => {
+    dispatch(addSearchResultSchema(payload));
+  },
+  querybuilder: (payload: { nodes: Record<string, any>[]; edges: Record<string, any>[] }, dispatch: AppDispatch) => {
+    dispatch(addSearchResultQueryBuilder(payload));
+  },
+};
+
+const SEARCH_CATEGORIES: CATEGORY_KEYS[] = Object.keys(CATEGORY_ACTIONS) as CATEGORY_KEYS[];
+
+export function Searchbar() {
+  const inputRef = useRef<HTMLInputElement>(null);
+  const [search, setSearch] = useState<string>('');
+  const searchbarRef = useRef<HTMLDivElement>(null);
+  const dispatch = useAppDispatch();
+  const results = useSearchResult();
+  const recentSearches = useRecentSearches();
+  const schema = useSchemaGraph();
+  const graphData = useGraphQueryResult();
+  const querybuilderData = useQuerybuilderGraph();
+
+  const dataSources: {
+    [key: string]: { nodes: Record<string, any>[]; edges: Record<string, any>[] };
+  } = {
+    data: graphData,
+    schema: schema,
+    querybuilder: querybuilderData as QueryMultiGraph,
+  };
+
+  useEffect(() => {
+    const handleKeyPress = (event: KeyboardEvent) => {
+      if (event.key === 'Enter') {
+        if (search !== '') {
+          dispatch(addRecentSearch(search));
+        }
+      }
+    };
+    window.addEventListener('keydown', handleKeyPress);
+    return () => window.removeEventListener('keydown', handleKeyPress);
+  }, [search]);
+
+  useEffect(() => {
+    handleSearch();
+  }, [search]);
+
+  const handleSearch = () => {
+    let query = search.toLowerCase();
+    const categories = search.match(/@[^ ]+/g);
+
+    if (categories) {
+      categories.map((category) => {
+        query = query.replace(category, '').trim();
+        const cat = category.substring(1);
+
+        if (cat in CATEGORY_ACTIONS) {
+          const categoryAction = CATEGORY_ACTIONS[cat as CATEGORY_KEYS];
+          const data = dataSources[cat];
+
+          const payload = {
+            nodes: filterData(query, data.nodes, SIMILARITY_THRESHOLD),
+            edges: filterData(query, data.edges, SIMILARITY_THRESHOLD),
+          };
+          categoryAction(payload, dispatch);
+        }
+      });
+    } else {
+      for (const category of SEARCH_CATEGORIES) {
+        const categoryAction = CATEGORY_ACTIONS[category];
+        const data = dataSources[category];
+
+        const payload = {
+          nodes: filterData(query, data.nodes, SIMILARITY_THRESHOLD),
+          edges: filterData(query, data.edges, SIMILARITY_THRESHOLD),
+        };
+
+        categoryAction(payload, dispatch);
+      }
+    }
+  };
+
+  return (
+    <div className="flex flex-col w-full p-2">
+      <div className="w-full">
+        <input
+          type="text"
+          ref={inputRef}
+          value={search}
+          onChange={(e) => setSearch(e.target.value)}
+          id="input-group-search"
+          className="block w-full p-2 ps-2 text-sm text-secondary-900 border border-secondary-300 rounded bg-secondary-50 focus:ring-blue-500 focus:border-blue-500 focus:ring-0"
+          placeholder="Search database"
+        ></input>
+      </div>
+      <div>
+        {recentSearches.length !== 0 && (
+          <div className="px-3 pb-3">
+            <p className="text-sm">Recent searches</p>
+            {recentSearches.slice(0, 3).map((term) => (
+              <p key={term} className="ml-1 text-sm text-secondary-500 cursor-pointer" onClick={() => setSearch(term)}>
+                {term}
+              </p>
+            ))}
+          </div>
+        )}
+        {search !== '' && (
+          <div className="z-10 w-full overflow-y-auto scroll h-full px-2 pb-2">
+            {SEARCH_CATEGORIES.every((category) => results[category].nodes.length === 0 && results[category].edges.length === 0) ? (
+              <div className="ml-1 text-sm">
+                <p className="text-secondary-500">Found no matches...</p>
+              </div>
+            ) : (
+              SEARCH_CATEGORIES.map((category, index) => {
+                if (results[category].nodes.length > 0 || results[category].edges.length > 0) {
+                  return (
+                    <div key={index}>
+                      <div className="flex justify-between p-2 text-lg">
+                        <p className="font-bold text-sm">{category.charAt(0).toUpperCase() + category.slice(1)}</p>
+                        <p className="font-bold text-sm">{results[category].nodes.length + results[category].edges.length} results</p>
+                      </div>
+                      <div className="h-[1px] w-full bg-secondary-200"></div>
+                      {Object.values(Object.values(results[category]))
+                        .flat()
+                        .map((item, index) => (
+                          <div
+                            key={index}
+                            className="flex flex-col hover:bg-secondary-300 px-2 py-1 cursor-pointer rounded ml-2"
+                            title={JSON.stringify(item)}
+                            onClick={() => {
+                              CATEGORY_ACTIONS[category](
+                                {
+                                  nodes: results[category].nodes.includes(item) ? [item] : [],
+                                  edges: results[category].edges.includes(item) ? [item] : [],
+                                },
+                                dispatch,
+                              );
+                            }}
+                          >
+                            <div className="font-bold text-sm">
+                              {item?.key?.slice(0, 18) || item?.id?.slice(0, 18) || Object.values(item)?.[0]?.slice(0, 18)}
+                            </div>
+                            <div className="font-light text-secondary-800 text-xs">{JSON.stringify(item).substring(0, 40)}...</div>
+                          </div>
+                        ))}
+                    </div>
+                  );
+                } else return <></>;
+              })
+            )}
+          </div>
+        )}
+      </div>
+    </div>
+  );
+}
diff --git a/apps/web/src/components/navbar/search/similarity.ts b/libs/shared/lib/sidebar/search/similarity.ts
similarity index 96%
rename from apps/web/src/components/navbar/search/similarity.ts
rename to libs/shared/lib/sidebar/search/similarity.ts
index a5714c0aa..a6e0a9378 100644
--- a/apps/web/src/components/navbar/search/similarity.ts
+++ b/libs/shared/lib/sidebar/search/similarity.ts
@@ -30,7 +30,7 @@ const matches = (query: string, object: Record<string, any>): number => {
   return highestScore;
 };
 
-const jaroSimilarity = (s1: string, s2: string) => {
+export const jaroSimilarity = (s1: string, s2: string) => {
   if (s1 == s2) return 1.0;
 
   const len1 = s1.length;
diff --git a/libs/shared/lib/vis/common/index.ts b/libs/shared/lib/vis/common/index.ts
new file mode 100644
index 000000000..fcb073fef
--- /dev/null
+++ b/libs/shared/lib/vis/common/index.ts
@@ -0,0 +1 @@
+export * from './types';
diff --git a/libs/shared/lib/vis/shared/Types.tsx b/libs/shared/lib/vis/common/types.ts
similarity index 61%
rename from libs/shared/lib/vis/shared/Types.tsx
rename to libs/shared/lib/vis/common/types.ts
index 186166281..52e1513b2 100644
--- a/libs/shared/lib/vis/shared/Types.tsx
+++ b/libs/shared/lib/vis/common/types.ts
@@ -1,87 +1,73 @@
-/**
- * This program has been developed by students from the bachelor Computer Science at
- * Utrecht University within the Software Project course.
- * © Copyright Utrecht University (Department of Information and Computing Sciences)
- */
+import { GraphQueryResult } from '../../data-access/store/graphQueryResultSlice';
+import { ML } from '../../data-access/store/mlSlice';
+import { SchemaGraph } from '../../schema';
+import type { AppDispatch } from '../../data-access';
+import { FC } from 'react';
+import { Visualizations } from '../hooks';
 import { Edge, Node } from 'reactflow';
 
-/**
- * List of schema elements for react flow
- */
+export type VisualizationConfiguration = { [id: string]: any };
+
+export type VISComponentType = {
+  displayName: keyof typeof Visualizations;
+  component: FC<any>;
+  settings: FC<any>;
+  configuration: { [id: string]: any };
+};
+
+export type VisualizationPropTypes = {
+  data: GraphQueryResult;
+  schema: SchemaGraph;
+  ml: ML;
+  configuration: VisualizationConfiguration;
+  dispatch: AppDispatch;
+  handleHover: (val: any) => void;
+  handleSelect: (val: any) => void;
+};
+
 export type SchemaElements = {
   nodes: Node[];
   edges: Edge[];
   selfEdges: Edge[];
 };
 
-/**
- * Point that has an x and y coordinate
- */
 export interface Point {
   x: number;
   y: number;
 }
 
-/**
- * Bounding box described by a top left and bottom right coordinate
- */
 export interface BoundingBox {
   topLeft: Point;
   bottomRight: Point;
 }
 
-/**
- * Typing for the Node Quality data of an entity.
- * It is used for the Node quality analytics and will be displayed in the corresponding popup.
- */
 export interface NodeQualityDataForEntities {
   nodeCount: number;
   attributeNullCount: number;
   notConnectedNodeCount: number;
-
   isAttributeDataIn: boolean; // is true when the data to display has arrived
-
-  // for user interactions
   onClickCloseButton: () => void;
 }
 
-/**
- * Typing for the Node Quality data of a relation.
- * It is used for the Node quality analytics and will be displayed in the corresponding popup.
- */
 export interface NodeQualityDataForRelations {
   nodeCount: number;
   attributeNullCount: number;
-  // from-entity node --relation--> to-entity node
   fromRatio: number; // the ratio of from-entity nodes to nodes that have this relation
   toRatio: number; // the ratio of to-entity nodes to nodes that have this relation
-
   isAttributeDataIn: boolean; // is true when the data to display has arrived
-
-  // for user interactions
   onClickCloseButton: () => void;
 }
 
-/**
- * Typing for the Node Quality popup of an entity or relation node.
- */
 export interface NodeQualityPopupNode extends Node {
   data: NodeQualityDataForEntities | NodeQualityDataForRelations;
   nodeID: string; //ID of the node for which the popup is
 }
 
-/**
- * Typing for the attribute analytics popup menu data of an entity or relation.
- */
 export interface AttributeAnalyticsData {
   nodeType: NodeType;
   nodeID: string;
   attributes: AttributeWithData[];
-  // nullAmount: number;
-
   isAttributeDataIn: boolean; // is true when the data to display has arrived
-
-  // for user interactions
   onClickCloseButton: () => void;
   onClickPlaceInQueryBuilderButton: (name: string, type: string) => void;
   searchForAttributes: (id: string, searchbarValue: string) => void;
@@ -89,7 +75,6 @@ export interface AttributeAnalyticsData {
   applyAttributeFilters: (id: string, category: AttributeCategory, predicate: string, percentage: number) => void;
 }
 
-/** All possible options of categories of an attribute */
 export enum AttributeCategory {
   categorical = 'Categorical',
   numerical = 'Numerical',
@@ -97,21 +82,16 @@ export enum AttributeCategory {
   undefined = 'undefined',
 }
 
-/** All possible options of node-types */
 export enum NodeType {
   entity = 'entity',
   relation = 'relation',
 }
 
-/**
- * Typing for the attribute analytics popup menu of entity or relation nodes
- */
 export interface AttributeAnalyticsPopupMenuNode extends Node {
   nodeID: string; //ID of the node for which the popup is
   data: AttributeAnalyticsData;
 }
 
-/** Typing of the attributes which are stored in the popup menu's */
 export type AttributeWithData = {
   attribute: any;
   category: AttributeCategory;
diff --git a/libs/shared/lib/vis/components/bar.tsx b/libs/shared/lib/vis/components/bar.tsx
new file mode 100644
index 000000000..409690202
--- /dev/null
+++ b/libs/shared/lib/vis/components/bar.tsx
@@ -0,0 +1,112 @@
+import React from 'react';
+import { Button, Icon } from '../../components';
+import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../components/tooltip';
+import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
+import { Add, Close, Fullscreen } from '@mui/icons-material';
+import { ControlContainer } from '../../components/controls';
+import { Visualizations } from '../hooks';
+import { VisualizationManagerType } from '../hooks';
+
+type Props = {
+  manager: VisualizationManagerType;
+  fullSize: () => void;
+};
+
+export default function VisualizationBar({ manager, fullSize }: Props) {
+  const handleDragStart = (e: React.DragEvent<HTMLDivElement>, visId: string) => {
+    e.dataTransfer.setData('text/plain', visId);
+  };
+
+  const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {
+    e.preventDefault();
+  };
+
+  const handleDrop = (e: React.DragEvent<HTMLDivElement>, dropVisId: string) => {
+    e.preventDefault();
+    const draggedVisId = e.dataTransfer.getData('text/plain');
+    manager.reorderVisualizations({ draggedVisId, dropVisId });
+    manager.changeActive(draggedVisId);
+  };
+
+  return (
+    <div className="sticky shrink-0 top-0 flex items-stretch justify-between h-7 bg-secondary-100 border-b border-secondary-200 max-w-full">
+      <div className="flex items-center">
+        <h1 className="text-xs font-semibold text-secondary-600 px-2 truncate">Visualization</h1>
+      </div>
+      <div className="items-center shrink-0 px-0.5">
+        <DropdownMenu.Root>
+          <DropdownMenu.Trigger>
+            <TooltipProvider delayDuration={0}>
+              <Tooltip>
+                <TooltipTrigger asChild>
+                  <Button type="secondary" variant="ghost" size="xs" iconComponent={<Add />} onClick={() => {}} />
+                </TooltipTrigger>
+                <TooltipContent side={'top'}>
+                  <p>Add visualization</p>
+                </TooltipContent>
+              </Tooltip>
+            </TooltipProvider>
+          </DropdownMenu.Trigger>
+          <DropdownMenu.Portal>
+            <DropdownMenu.Content className="bg-light p-1 rounded border">
+              {Object.keys(Visualizations).map((key) => (
+                <DropdownMenu.Item
+                  key={key}
+                  className="text-sm px-2 py-1 rounded cursor-pointer hover:bg-secondary-200"
+                  onClick={(e) => {
+                    manager.changeActive(key);
+                  }}
+                >
+                  {key}
+                </DropdownMenu.Item>
+              ))}
+            </DropdownMenu.Content>
+          </DropdownMenu.Portal>
+        </DropdownMenu.Root>
+      </div>
+      <div className="flex items-stretch divide-x divide-secondary-200 border-x border-secondary-200 overflow-x-auto -my-px">
+        {manager.tabs.map((visId: string) => {
+          const isActive = manager.activeVisualization === visId;
+          return (
+            <div
+              key={visId}
+              className={`flex items-center pl-2 pr-1 gap-1 cursor-pointer relative border-secondary-200 before:content-[''] before:absolute before:left-0 before:bottom-0 before:h-[2px] before:w-full ${isActive && 'before:bg-primary-500'} ${!isActive && 'before:bg-transparent hover:before:bg-secondary-300 hover:bg-secondary-200'}`}
+              onClick={() => manager.changeActive(visId)}
+              onDragStart={(e) => handleDragStart(e, visId)}
+              onDragOver={(e) => handleDragOver(e)}
+              onDrop={(e) => handleDrop(e, visId)}
+              draggable
+            >
+              <p className={`text-xs text-secondary-500 font-semibold ${isActive && 'text-secondary-950'}`}>{visId}</p>
+              <Button
+                type="secondary"
+                variant="ghost"
+                rounded
+                size="2xs"
+                iconComponent={<Close />}
+                onClick={(e) => {
+                  e.stopPropagation();
+                  manager.deleteVisualization(visId);
+                }}
+              />
+            </div>
+          );
+        })}
+      </div>
+      <div className="shrink-0 sticky right-0 px-0.5 ml-auto items-center flex">
+        <ControlContainer>
+          <TooltipProvider delayDuration={0}>
+            <Tooltip>
+              <TooltipTrigger asChild>
+                <Button type="secondary" variant="ghost" size="xs" iconComponent={<Fullscreen />} onClick={fullSize} />
+              </TooltipTrigger>
+              <TooltipContent side={'top'}>
+                <p>Full screen</p>
+              </TooltipContent>
+            </Tooltip>
+          </TooltipProvider>
+        </ControlContainer>
+      </div>
+    </div>
+  );
+}
diff --git a/libs/shared/lib/vis/components/config/components.tsx b/libs/shared/lib/vis/components/config/components.tsx
new file mode 100644
index 000000000..842f508ce
--- /dev/null
+++ b/libs/shared/lib/vis/components/config/components.tsx
@@ -0,0 +1,24 @@
+import React, { ReactNode } from 'react';
+
+type SettingsContainerProps = {
+  children: ReactNode;
+};
+
+export function SettingsContainer({ children }: SettingsContainerProps) {
+  return <div className="">{children}</div>;
+}
+
+type SettingsHeaderProps = {
+  name: string;
+  icon?: ReactNode;
+  onClickIcon?: () => void;
+};
+
+export function SettingsHeader({ name, icon, onClickIcon }: SettingsHeaderProps) {
+  return (
+    <div className="flex justify-between items-center">
+      <span className="text-xs font-bold">{name}</span>
+      {icon && icon}
+    </div>
+  );
+}
diff --git a/libs/shared/lib/vis/components/config/index.tsx b/libs/shared/lib/vis/components/config/index.tsx
new file mode 100644
index 000000000..2f98579c7
--- /dev/null
+++ b/libs/shared/lib/vis/components/config/index.tsx
@@ -0,0 +1,2 @@
+export { ConfigPanel } from './panel';
+export { SettingsContainer, SettingsHeader } from './components';
diff --git a/libs/shared/lib/vis/components/config/panel.tsx b/libs/shared/lib/vis/components/config/panel.tsx
new file mode 100644
index 000000000..722e241fb
--- /dev/null
+++ b/libs/shared/lib/vis/components/config/panel.tsx
@@ -0,0 +1,86 @@
+import React from 'react';
+import { Button, Icon } from '../../../components';
+import { Delete, Person } from '@mui/icons-material';
+import { Input } from '../../../components/inputs';
+import { VISUALIZATION_TYPES } from '../../hooks';
+import { VisualizationManagerType } from '../../hooks';
+import { SettingsHeader } from './components';
+import { useSessionCache } from '../../../data-access';
+
+type Props = {
+  manager: VisualizationManagerType;
+};
+
+export function ConfigPanel({ manager }: Props) {
+  const session = useSessionCache();
+
+  const buildInfo = import.meta.env.GRAPHPOLARIS_VERSION;
+
+  return (
+    <div className="flex flex-col w-full">
+      {manager.activeVisualization ? (
+        <>
+          <div className="border-b py-2">
+            <div className="flex justify-between items-center px-4 py-2">
+              <span className="text-xs font-bold">Visualization</span>
+              <Button
+                type="secondary"
+                variant="ghost"
+                size="xs"
+                iconComponent={<Delete />}
+                onClick={() => {
+                  if (manager.activeVisualization) manager.deleteVisualization(manager.activeVisualization);
+                }}
+              />
+            </div>
+            <div className="flex justify-between items-center px-4 py-1">
+              <span className="text-xs font-normal">Type</span>
+              <div className="w-36">
+                <Input type="dropdown" size="xs" options={VISUALIZATION_TYPES} value={manager.activeVisualization} onChange={() => {}} />
+              </div>
+            </div>
+            <div className="flex justify-between items-center px-4 py-1">
+              <span className="text-xs font-normal">Name</span>
+              <input type="text" className="border rouded text-xs w-36" value={manager.activeVisualization} onChange={() => {}} />
+            </div>
+          </div>
+          {manager.activeVisualization && (
+            <div className="border-b p-4">
+              <SettingsHeader name="Configuration" />
+              {manager.renderSettings()}
+            </div>
+          )}
+        </>
+      ) : (
+        <div>
+          {session && session.currentSaveState && (
+            <div className="flex flex-col p-4 border-b">
+              <span className="text-sm font-bold">Connection details</span>
+              <span className="text-xs">Database: {session.saveStates[session.currentSaveState].name}</span>
+              <span className="text-xs">Port: {session.saveStates[session.currentSaveState].db.port}</span>
+              <span className="text-xs">Protocol: {session.saveStates[session.currentSaveState].db.protocol}</span>
+            </div>
+          )}
+        </div>
+      )}
+
+      {buildInfo === 'dev' && (
+        <div className="mt-auto p-2 bg-light">
+          <Button
+            type="primary"
+            variant="outline"
+            size="xs"
+            label="Report an issue"
+            onClick={() =>
+              window.open(
+                'https://app.asana.com/-/login?u=https%3A%2F%2Fform.asana.com%2F%3Fk%3D2QEC88Dl7ETs2wYYWjkMXg%26d%3D1206648675960041&error=01',
+                '_blank',
+              )
+            }
+            additionalClasses="block w-full"
+          />
+        </div>
+      )}
+    </div>
+  );
+}
diff --git a/libs/shared/lib/vis/components/panel.tsx b/libs/shared/lib/vis/components/panel.tsx
new file mode 100644
index 000000000..8e5653c19
--- /dev/null
+++ b/libs/shared/lib/vis/components/panel.tsx
@@ -0,0 +1,30 @@
+import React, { useMemo } from 'react';
+import { useGraphQueryResult, useQuerybuilderGraph } from '@graphpolaris/shared/lib/data-access';
+import VisualizationBar from './bar';
+import { VisualizationManagerType } from '../hooks';
+import { Recommender, NoData, Querying } from '../views';
+
+export const VisualizationPanel = ({ manager, fullSize }: { manager: VisualizationManagerType; fullSize: () => void }) => {
+  const query = useQuerybuilderGraph();
+  const graphQueryResult = useGraphQueryResult();
+
+  const renderContent = useMemo(() => {
+    if (graphQueryResult.queryingBackend) {
+      return <Querying />;
+    } else if (graphQueryResult.nodes.length === 0) {
+      return <NoData dataAvailable={query.nodes.length > 0} />;
+    } else if (manager.tabs.length === 0) {
+      return <Recommender onClick={(id: string) => manager.changeActive(id)} />;
+    }
+    return <div className="w-full h-full flex">{manager.renderComponent()}</div>;
+  }, [graphQueryResult, manager]);
+
+  return (
+    <div className="vis-panel h-full w-full flex flex-col border bg-light">
+      <VisualizationBar manager={manager} fullSize={fullSize} />
+      <div className="grow overflow-y-auto" style={graphQueryResult.nodes.length === 0 ? { overflow: 'hidden' } : {}}>
+        {renderContent}
+      </div>
+    </div>
+  );
+};
diff --git a/libs/shared/lib/vis/configuration/advanced/advanced.tsx b/libs/shared/lib/vis/configuration/advanced/advanced.tsx
deleted file mode 100644
index 287aa679a..000000000
--- a/libs/shared/lib/vis/configuration/advanced/advanced.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import React from 'react';
-import ReactJSONView from 'react-json-view';
-import { Configuration, PanelProps } from '../panel/panel.types';
-
-interface AdvancedPanelProps extends PanelProps {
-  state: Configuration;
-  update: (configType: string, key: string, value: any) => void; // Adjusted type for update function
-}
-
-export default function AdvancedPanel({ state, update }: AdvancedPanelProps) {
-  return (
-    state && (
-      <div className="m-2">
-        <ReactJSONView
-          src={state}
-          name={false}
-          collapsed={1}
-          quotesOnKeys={false}
-          displayDataTypes={false}
-          onEdit={(v) => update('', '', v.updated_src)}
-        />
-      </div>
-    )
-  );
-}
diff --git a/libs/shared/lib/vis/configuration/advanced/index.ts b/libs/shared/lib/vis/configuration/advanced/index.ts
deleted file mode 100644
index a7584d4b2..000000000
--- a/libs/shared/lib/vis/configuration/advanced/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default as AdvancedPanel } from './advanced';
diff --git a/libs/shared/lib/vis/configuration/encodings/accessor.tsx b/libs/shared/lib/vis/configuration/encodings/accessor.tsx
deleted file mode 100644
index 63db7d674..000000000
--- a/libs/shared/lib/vis/configuration/encodings/accessor.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import Input from '@graphpolaris/shared/lib/components/inputs';
-import { useGraphQueryResultMeta } from '@graphpolaris/shared/lib/data-access';
-import { DimensionType } from '@graphpolaris/shared/lib/schema';
-import { CompressedElement } from '@graphpolaris/shared/lib/data-access/statistics';
-
-type Props = {
-  value: string | undefined;
-  onChange: (val: string | number) => void;
-  element: 'node' | 'edge';
-  dimension?: DimensionType[];
-  disabled?: boolean;
-};
-
-const extractAttributesByDimension = (summaryGraph: CompressedElement, dimensions: DimensionType[]): string[] => {
-  const selectedAttributes: { [label: string]: string[] } = {};
-
-  Object.keys(summaryGraph.types).map((label) => {
-    selectedAttributes[label] = [];
-    Object.keys(summaryGraph.types[label].attributes).map((attribute) => {
-      const dim: DimensionType = summaryGraph.types[label]?.attributes[attribute].dimension as DimensionType;
-      dimensions.includes(dim) && selectedAttributes[label].push(attribute);
-    });
-  });
-
-  let commonAttributes: Set<string> = new Set();
-  Object.values(selectedAttributes).forEach((attributes) => {
-    if (commonAttributes.size === 0) {
-      commonAttributes = new Set(attributes);
-    } else {
-      commonAttributes = new Set([...commonAttributes].filter((attr) => attributes.includes(attr)));
-    }
-  });
-
-  return commonAttributes ? Array.from(commonAttributes) : [];
-};
-
-export default function Accessor({ value, onChange, element, dimension, disabled = false }: Props) {
-  const resultStatistics = useGraphQueryResultMeta();
-  const [options, setOptions] = useState<string[]>([]);
-  const [loading, setLoading] = useState<boolean>(true);
-
-  useEffect(() => {
-    setLoading(Object.keys(resultStatistics.nodes.types).length === 0 && Object.keys(resultStatistics.edges.types).length === 0);
-  }, [resultStatistics]);
-
-  useEffect(() => {
-    if (!loading) {
-      setOptions(extractAttributesByDimension(resultStatistics[element === 'node' ? 'nodes' : 'edges'], dimension || ['categorical']));
-      disabled = true;
-    } else {
-      disabled = false;
-    }
-  }, [resultStatistics, loading, element, dimension]);
-
-  return (
-    <div className="mb-2">
-      <Input type="dropdown" value={value} onChange={(val: string | number) => onChange(val)} options={options} disabled={disabled} />
-    </div>
-  );
-}
diff --git a/libs/shared/lib/vis/configuration/encodings/encoding.tsx b/libs/shared/lib/vis/configuration/encodings/encoding.tsx
deleted file mode 100644
index 96acc27ec..000000000
--- a/libs/shared/lib/vis/configuration/encodings/encoding.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-import React, { useState } from 'react';
-import Accessor from './accessor';
-import Info from '@graphpolaris/shared/lib/components/info';
-import Selector from './selector';
-import { PanelProps } from '../panel/panel.types';
-
-export default function EncodingPanel({ state, update }: PanelProps) {
-  const [encodingUpdates, setEncodingUpdates] = useState<{
-    [id: string]: {
-      marking: any;
-      accessorPath: string;
-    };
-  }>({});
-
-  const updateEncoding = (encoding: string, val: any, type: 'accessorPath' | 'marking') => {
-    setEncodingUpdates((prevState) => {
-      if (prevState) {
-        return {
-          ...prevState,
-          [encoding]: {
-            ...(prevState[encoding] || {}),
-            [type]: val,
-          },
-        };
-      } else {
-        return prevState;
-      }
-    });
-  };
-
-  return (
-    state && (
-      <div>
-        {Object.keys(state).map((key) => {
-          const item = state[key];
-          const value = encodingUpdates[key] ? encodingUpdates[key] : { marking: undefined, accessorPath: undefined };
-
-          return (
-            <div key={key} className="bg-secondary-50 p-2 m-1">
-              <div className="flex items-center justify-between">
-                <h1 className="text-xs">{item.label ? item.label : key}</h1>
-                {item.description && <Info tooltip={item.description} />}
-              </div>
-              <Accessor
-                value={value.accessorPath}
-                onChange={(value: string | number) => updateEncoding(key, value, 'accessorPath')}
-                // onChange={(value: string | number) => update(key, { ...state[key], accessorPath: value })}
-                element={item.element}
-                dimension={item.dimension ?? []}
-              />
-              {value.accessorPath && (
-                <Selector
-                  key={key}
-                  selectorType={item.selector}
-                  elementType={item.element}
-                  marking={value.marking}
-                  onChange={(value: any) => updateEncoding(key, value, 'marking')}
-                  accessorPath={value.accessorPath}
-                />
-              )}
-            </div>
-          );
-        })}
-      </div>
-    )
-  );
-}
diff --git a/libs/shared/lib/vis/configuration/encodings/index.ts b/libs/shared/lib/vis/configuration/encodings/index.ts
deleted file mode 100644
index 056c6ae4d..000000000
--- a/libs/shared/lib/vis/configuration/encodings/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export type { Encoding, EncodingTypes, EncodingProps } from './encodings.types';
-export { default as EncodingPanel } from './encoding';
diff --git a/libs/shared/lib/vis/configuration/encodings/selector.tsx b/libs/shared/lib/vis/configuration/encodings/selector.tsx
deleted file mode 100644
index cc8e31c3c..000000000
--- a/libs/shared/lib/vis/configuration/encodings/selector.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import { EncodingSelector } from './selectors';
-import { useGraphQueryResultMeta } from '@graphpolaris/shared/lib/data-access';
-import { ElementType } from './encodings.types';
-import { DimensionType } from '@graphpolaris/shared/lib/schema';
-
-type Props = {
-  selectorType: keyof typeof EncodingSelector;
-  marking: any;
-  elementType: ElementType;
-  onChange: (val: any) => void;
-  accessorPath: string;
-};
-
-export default function Selector({ selectorType, elementType, marking, onChange, accessorPath }: Props) {
-  const graphStatistics = useGraphQueryResultMeta();
-  const SelectorComponent = EncodingSelector[selectorType];
-  const [statistics, setStatistics] = useState<any>();
-  const [dimension, setDimension] = useState<DimensionType>('categorical');
-
-  useEffect(() => {
-    const group = graphStatistics[elementType === 'node' ? 'nodes' : 'edges'];
-
-    const combinedValues = Array.from(
-      new Set(
-        Object.keys(group.types).flatMap((label) => {
-          const obj = group.types[label].attributes[accessorPath];
-          const { dimension } = obj;
-          setDimension(dimension);
-
-          if (dimension === 'categorical') {
-            const { values } = obj;
-            return values || [];
-          } else if (dimension === 'numerical') {
-            console.log(obj);
-            const { min, max } = obj.statistics;
-            return [min, max];
-          } else if (dimension === 'temporal') {
-            const { minDate, maxDate } = obj.statistics;
-            return [minDate, maxDate];
-          } else if (dimension === 'spatial') {
-            const { boundingBox } = obj.statistics;
-            return boundingBox;
-          }
-          return [];
-        }),
-      ),
-    );
-
-    setStatistics(combinedValues);
-  }, [accessorPath]);
-
-  return <SelectorComponent marking={marking} onChange={onChange} dimension={dimension} statistics={statistics} />;
-}
diff --git a/libs/shared/lib/vis/configuration/index.ts b/libs/shared/lib/vis/configuration/index.ts
deleted file mode 100644
index 3ded492f1..000000000
--- a/libs/shared/lib/vis/configuration/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default as VisualizationDialog } from './panel/panel';
diff --git a/libs/shared/lib/vis/configuration/interactions/index.ts b/libs/shared/lib/vis/configuration/interactions/index.ts
deleted file mode 100644
index 61687e06e..000000000
--- a/libs/shared/lib/vis/configuration/interactions/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export type { Interaction, InteractionTypes, InteractionProps } from './interaction.types';
-export { default as InteractionPanel } from './interaction';
diff --git a/libs/shared/lib/vis/configuration/interactions/interaction.tsx b/libs/shared/lib/vis/configuration/interactions/interaction.tsx
deleted file mode 100644
index 5d25826eb..000000000
--- a/libs/shared/lib/vis/configuration/interactions/interaction.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import React from 'react';
-import { PanelProps } from '../panel/panel.types';
-
-export default function InteractionPanel({ state, update }: PanelProps) {
-  return (
-    state && (
-      <div>
-        <p>Interaction settings</p>
-      </div>
-    )
-  );
-}
diff --git a/libs/shared/lib/vis/configuration/interactions/interaction.types.ts b/libs/shared/lib/vis/configuration/interactions/interaction.types.ts
deleted file mode 100644
index bb81b4909..000000000
--- a/libs/shared/lib/vis/configuration/interactions/interaction.types.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { InputProps } from '@graphpolaris/shared/lib/components/inputs';
-
-export type Interaction = InputProps & { condition?: (config: Record<string, any>) => boolean };
-
-export type InteractionTypes = { [id: string]: Interaction };
-
-export type InteractionProps = { [K in keyof InteractionTypes]?: any };
diff --git a/libs/shared/lib/vis/configuration/panel/panel-header.tsx b/libs/shared/lib/vis/configuration/panel/panel-header.tsx
deleted file mode 100644
index f28390360..000000000
--- a/libs/shared/lib/vis/configuration/panel/panel-header.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import React from 'react';
-import { FormTitle } from '@graphpolaris/shared/lib/components/forms';
-import { AutoAwesome, CandlestickChart, LockOpen, Settings } from '@mui/icons-material';
-import { useVisualization } from '@graphpolaris/shared/lib/data-access';
-import PanelItem from './panel-item';
-
-type Props = {
-  onClose: any;
-  activeTab: number;
-  setActiveTab: any;
-};
-
-export default function PanelHeader({ onClose, activeTab, setActiveTab }: Props) {
-  const vis = useVisualization();
-
-  let encodingsExist: boolean = !!vis.settings[vis.activeVisualization || '']?.encodings || false;
-  let settingsExist: boolean = !!vis.settings[vis.activeVisualization || '']?.settings || false;
-  let interactionsExist: boolean = !!vis.settings[vis.activeVisualization || '']?.interactions || false;
-
-  return (
-    <div className="flex flex-col pt-2 bg-secondary-100">
-      <FormTitle title="Settings" onClose={onClose} />
-      <ul className="flex flex-wrap pt-4 pl-5 text-sm font-medium text-center text-gray-500 dark:text-gray-400">
-        {encodingsExist && (
-          <PanelItem active={activeTab === 0} onClick={() => setActiveTab(0)} icon={<AutoAwesome />} tooltip="Encodings" />
-        )}
-        {settingsExist && <PanelItem active={activeTab === 1} onClick={() => setActiveTab(1)} icon={<Settings />} tooltip="Settings" />}
-        {interactionsExist && (
-          <PanelItem active={activeTab === 2} onClick={() => setActiveTab(2)} icon={<CandlestickChart />} tooltip="Interactions" />
-        )}
-        {(settingsExist || encodingsExist || interactionsExist) && (
-          <PanelItem active={activeTab === 3} onClick={() => setActiveTab(3)} icon={<LockOpen />} tooltip="Advanced" />
-        )}
-      </ul>
-    </div>
-  );
-}
diff --git a/libs/shared/lib/vis/configuration/panel/panel-item.tsx b/libs/shared/lib/vis/configuration/panel/panel-item.tsx
deleted file mode 100644
index 05623c8f0..000000000
--- a/libs/shared/lib/vis/configuration/panel/panel-item.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import React from 'react';
-import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@graphpolaris/shared/lib/components/tooltip';
-
-type PanelItemProps = {
-  active: boolean;
-  onClick: () => void;
-  icon: JSX.Element;
-  tooltip: string;
-};
-
-export default function PanelItem({ active, onClick, icon, tooltip }: PanelItemProps) {
-  return (
-    <li
-      className={`me-2 inline-block bg-secondary-100 cursor-pointer ${active && 'border-b-2 border-primary-200 text-primary-200'}`}
-      onClick={onClick}
-    >
-      <TooltipProvider delayDuration={0}>
-        <Tooltip>
-          <TooltipTrigger>{icon}</TooltipTrigger>
-          <TooltipContent side={'top'}>
-            <p>{tooltip}</p>
-          </TooltipContent>
-        </Tooltip>
-      </TooltipProvider>
-    </li>
-  );
-}
diff --git a/libs/shared/lib/vis/configuration/panel/panel.tsx b/libs/shared/lib/vis/configuration/panel/panel.tsx
deleted file mode 100644
index 62ea4bca2..000000000
--- a/libs/shared/lib/vis/configuration/panel/panel.tsx
+++ /dev/null
@@ -1,82 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import { FormActions, FormBody, FormCard, FormDiv, FormHBar } from '@graphpolaris/shared/lib/components/forms';
-import { DialogProps } from '@graphpolaris/shared/lib/components/Dialog';
-import PanelHeader from './panel-header';
-import { SettingsPanel } from '../settings';
-import { AdvancedPanel } from '../advanced';
-import { EncodingPanel } from '../encodings';
-import { InteractionPanel } from '../interactions';
-import { useAppDispatch, useVisualization } from '@graphpolaris/shared/lib/data-access';
-import { updateConfiguration } from '@graphpolaris/shared/lib/data-access/store/visualizationSlice';
-import { ConfigTypes, Configuration } from './panel.types';
-
-export default function VisualizationDialog(props: DialogProps) {
-  const dispatch = useAppDispatch();
-  const vis = useVisualization();
-  const [activeTab, setActiveTab] = useState<number>(1);
-  const [configuration, setConfiguration] = useState<Configuration>({});
-
-  useEffect(() => {
-    if (vis.activeVisualization) {
-      setConfiguration({
-        general: vis.settings.general ?? {},
-        settings: vis.settings[vis.activeVisualization]?.settings ?? {},
-        encodings: vis.settings[vis.activeVisualization]?.encodings ?? {},
-        interactions: vis.settings[vis.activeVisualization]?.interactions ?? {},
-      });
-    }
-  }, [vis]);
-
-  const handlePanelUpdate = (configType: ConfigTypes, key: string, value: any) => {
-    if (configType === 'configuration') {
-      setConfiguration(value);
-    } else {
-      setConfiguration((prevState) => ({
-        ...prevState,
-        [configType]: {
-          [key]: value,
-          ...prevState[configType],
-        },
-      }));
-    }
-  };
-
-  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
-    e.preventDefault();
-    dispatch(updateConfiguration(configuration));
-    props.onClose();
-  };
-
-  return (
-    <>
-      {props.open && (
-        <FormDiv>
-          <FormCard>
-            <FormBody onSubmit={handleSubmit}>
-              <PanelHeader onClose={props.onClose} activeTab={activeTab} setActiveTab={setActiveTab} />
-              {activeTab === 0 && (
-                <EncodingPanel state={configuration.encodings} update={(key, value) => handlePanelUpdate('encodings', key, value)} />
-              )}
-              {activeTab === 1 && (
-                <SettingsPanel
-                  state={{ general: configuration.general, settings: configuration.settings }}
-                  update={(configType, key, value) => handlePanelUpdate(configType, key, value)}
-                />
-              )}
-              {activeTab === 2 && (
-                <InteractionPanel
-                  state={configuration.interactions}
-                  update={(key, value) => handlePanelUpdate('interactions', key, value)}
-                />
-              )}
-              {activeTab === 3 && <AdvancedPanel state={configuration} update={(value) => handlePanelUpdate('configuration', '', value)} />}
-
-              <FormHBar />
-              <FormActions onClose={props.onClose} />
-            </FormBody>
-          </FormCard>
-        </FormDiv>
-      )}
-    </>
-  );
-}
diff --git a/libs/shared/lib/vis/configuration/panel/panel.types.ts b/libs/shared/lib/vis/configuration/panel/panel.types.ts
deleted file mode 100644
index 46edb5748..000000000
--- a/libs/shared/lib/vis/configuration/panel/panel.types.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-export type ConfigTypes = 'configuration' | 'general' | 'settings' | 'encodings' | 'interactions';
-
-export type PanelProps = {
-  state: any;
-  update: (configType: ConfigTypes, key: string, value: any) => void;
-};
-
-export type Configuration = {
-  general?: any;
-  settings?: any;
-  encodings?: any;
-  interactions?: any;
-};
diff --git a/libs/shared/lib/vis/configuration/settings/index.ts b/libs/shared/lib/vis/configuration/settings/index.ts
deleted file mode 100644
index 825e0031f..000000000
--- a/libs/shared/lib/vis/configuration/settings/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export type { Setting, SettingTypes, SettingProps } from './settings.types';
-export { default as SettingsPanel } from './settings';
diff --git a/libs/shared/lib/vis/configuration/settings/settings.tsx b/libs/shared/lib/vis/configuration/settings/settings.tsx
deleted file mode 100644
index 1255476dc..000000000
--- a/libs/shared/lib/vis/configuration/settings/settings.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-import React from 'react';
-import { FormControl } from '@graphpolaris/shared/lib/components/forms';
-import Input from '@graphpolaris/shared/lib/components/inputs';
-import { PanelProps } from '../panel/panel.types';
-
-export default function SettingsPanel({ state, update }: PanelProps) {
-  return (
-    state && (
-      <div>
-        <div>
-          {Object.keys(state?.general).map((key) => (
-            <FormControl key={key}>
-              <Input
-                {...state.general[key]}
-                value={state.general[key]?.value as any}
-                onChange={(value: any) => update('general', key, { ...state[key].general, value: value })}
-              />
-            </FormControl>
-          ))}
-        </div>
-
-        <div>
-          {Object.keys(state?.settings).map((key) => {
-            const currentSetting = state.settings[key];
-            const shouldShowSetting = currentSetting.condition ? currentSetting.condition?.(state.settings) : true;
-            return (
-              shouldShowSetting && (
-                <div key={key} className="bg-secondary-50 p-2 m-2">
-                  <FormControl>
-                    <Input
-                      {...state.settings[key]}
-                      value={state.settings[key]?.value as any}
-                      onChange={(value: any) => update('settings', key, { ...state.settings[key], value: value })}
-                    />
-                  </FormControl>
-                </div>
-              )
-            );
-          })}
-        </div>
-      </div>
-    )
-  );
-}
diff --git a/libs/shared/lib/vis/configuration/settings/settings.types.ts b/libs/shared/lib/vis/configuration/settings/settings.types.ts
deleted file mode 100644
index 9c93ba813..000000000
--- a/libs/shared/lib/vis/configuration/settings/settings.types.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { InputProps } from '@graphpolaris/shared/lib/components/inputs';
-
-export type Setting = InputProps & {
-  condition?: (config: Record<string, any>) => boolean;
-  description?: string;
-};
-
-export type SettingTypes = { [id: string]: Setting };
-
-export type SettingProps = { [K in keyof SettingTypes]: any };
diff --git a/libs/shared/lib/vis/hooks/hooks.types.ts b/libs/shared/lib/vis/hooks/hooks.types.ts
new file mode 100644
index 000000000..fca458010
--- /dev/null
+++ b/libs/shared/lib/vis/hooks/hooks.types.ts
@@ -0,0 +1,12 @@
+import React from 'react';
+
+export type VisualizationManagerType = {
+  renderComponent: () => React.ReactNode;
+  renderSettings: () => React.ReactNode;
+  activeVisualization: string | undefined;
+  activeType: string | undefined;
+  tabs: string[];
+  changeActive: (id: string) => void;
+  reorderVisualizations: (args: { draggedVisId: string; dropVisId: string }) => void;
+  deleteVisualization: (id: string) => void;
+};
diff --git a/libs/shared/lib/vis/hooks/index.ts b/libs/shared/lib/vis/hooks/index.ts
new file mode 100644
index 000000000..bfd4ddd04
--- /dev/null
+++ b/libs/shared/lib/vis/hooks/index.ts
@@ -0,0 +1,2 @@
+export { useVisualizationManager, Visualizations, VISUALIZATION_TYPES } from './useVisualizationManager';
+export type { VisualizationManagerType } from './hooks.types';
diff --git a/libs/shared/lib/vis/hooks/useVisualizationManager.tsx b/libs/shared/lib/vis/hooks/useVisualizationManager.tsx
new file mode 100644
index 000000000..b79925468
--- /dev/null
+++ b/libs/shared/lib/vis/hooks/useVisualizationManager.tsx
@@ -0,0 +1,154 @@
+import React, { useState, useMemo, useEffect, Suspense } from 'react';
+import { VISComponentType, VisualizationConfiguration } from '../common';
+import {
+  removeVisualization,
+  reorderVisState,
+  setActiveVisualization,
+  updateVisualization,
+} from '../../data-access/store/visualizationSlice';
+import {
+  useAppDispatch,
+  useGraphQueryResult,
+  useGraphQueryResultMeta,
+  useML,
+  useSchemaGraph,
+  useSessionCache,
+  useVisualization,
+} from '../../data-access';
+import { VisualizationManagerType } from '../hooks';
+import { HoverType, SelectType, addHover, addSelect } from '../../data-access/store/interactionSlice';
+
+export const Visualizations: Record<string, Function> = {
+  TableVis: () => import('../visualizations/tablevis/tablevis'),
+  PaohVis: () => import('../visualizations/paohvis/paohvis'),
+  RawJSONVis: () => import('../visualizations/rawjsonvis/rawjsonvis'),
+  NodeLinkVis: () => import('../visualizations/nodelinkvis/nodelinkvis'),
+  MatrixVis: () => import('../visualizations/matrixvis/matrixvis'),
+  SemanticSubstratesVis: () => import('../visualizations/semanticsubstratesvis/semanticsubstratesvis'),
+  // MapVis: () => import('../visualizations/mapvis/mapvis'),
+};
+
+export const VISUALIZATION_TYPES: string[] = Object.keys(Visualizations);
+
+export const useVisualizationManager = (): VisualizationManagerType => {
+  const dispatch = useAppDispatch();
+  const session = useSessionCache();
+  const ml = useML();
+  const schema = useSchemaGraph();
+  const graphQueryResult = useGraphQueryResult();
+  const meta = useGraphQueryResultMeta();
+  const { activeVisualization, openVisualizations } = useVisualization();
+
+  const [configuration, setConfiguration] = useState<any>();
+  const [visualization, setVisualization] = useState<VISComponentType>();
+  const [selected, setSelected] = useState<any>();
+  const activeType = useMemo(
+    () => (activeVisualization ? openVisualizations[activeVisualization]?.displayName : undefined),
+    [openVisualizations, activeVisualization],
+  );
+  const tabs = useMemo(() => (Object.keys(openVisualizations).length ? Object.keys(openVisualizations) : []), [openVisualizations]);
+
+  useEffect(() => {
+    loadVisualization();
+  }, [activeVisualization]);
+
+  const loadVisualization = async () => {
+    if (activeVisualization && Visualizations[activeVisualization]) {
+      const componentModule = await Visualizations[activeVisualization]();
+      const component = componentModule.default;
+
+      if (!(activeVisualization in Object.keys(openVisualizations))) {
+        // Visualization doesn't yet exist so add its configuration
+        const configuration = component.configuration;
+        dispatch(updateVisualization({ id: activeVisualization, settings: configuration }));
+        setConfiguration(configuration);
+      } else {
+        setConfiguration(openVisualizations[activeVisualization]);
+      }
+
+      setVisualization(component);
+    }
+  };
+
+  const changeActive = (id: string) => {
+    dispatch(setActiveVisualization(id));
+  };
+
+  const deleteVisualization = (id: string) => {
+    dispatch(removeVisualization(id));
+    if (Object.keys(openVisualizations).length > 0) {
+      const newActive = tabs.find((v: string) => id !== v);
+      changeActive(newActive || '');
+    }
+  };
+
+  const reorderVisualizations = ({ draggedVisId, dropVisId }: { draggedVisId: string; dropVisId: string }) => {
+    const settingsCopy = { ...openVisualizations };
+    const keys = Object.keys(settingsCopy);
+    const draggedIndex = keys.indexOf(draggedVisId);
+    const dropIndex = keys.indexOf(dropVisId);
+
+    if (draggedIndex !== -1 && dropIndex !== -1) {
+      keys.splice(dropIndex, 0, draggedVisId);
+      const newSettings: { [id: string]: VisualizationConfiguration } = {};
+      keys.forEach((key) => {
+        newSettings[key] = settingsCopy[key];
+      });
+
+      dispatch(reorderVisState(newSettings));
+    }
+  };
+
+  const handleHover = (item: HoverType | undefined) => {
+    dispatch(addHover(item));
+  };
+
+  const handleSelect = (item: SelectType | undefined) => {
+    dispatch(addSelect(item));
+  };
+
+  const updateSettings = (newSettings: any) => {
+    if (activeVisualization) {
+      const updatedSettings = { ...configuration, ...newSettings };
+      setConfiguration(updatedSettings);
+      dispatch(updateVisualization({ id: activeVisualization, settings: updatedSettings }));
+    }
+  };
+
+  const renderSettings = () => {
+    return (
+      visualization?.settings &&
+      configuration && <visualization.settings configuration={configuration} graph={meta} updateSettings={updateSettings} />
+    );
+  };
+
+  // TODO: we should remove the renderable part of this useFunction into its own component, since this here is an anti-pattern
+  const renderComponent = () => {
+    return (
+      <Suspense fallback={<div>Loading...</div>}>
+        {visualization?.component && configuration && (
+          <visualization.component
+            data={graphQueryResult}
+            schema={schema}
+            ml={ml}
+            configuration={configuration}
+            dispatch={dispatch}
+            handleHover={handleHover}
+            handleSelect={handleSelect}
+          />
+        )}
+      </Suspense>
+    );
+  };
+
+  return {
+    renderComponent,
+    renderSettings,
+    activeVisualization,
+    activeType,
+    tabs,
+    changeActive,
+    reorderVisualizations,
+    deleteVisualization,
+  };
+};
diff --git a/libs/shared/lib/vis/index.ts b/libs/shared/lib/vis/index.ts
index 92ed4302d..ac473812c 100644
--- a/libs/shared/lib/vis/index.ts
+++ b/libs/shared/lib/vis/index.ts
@@ -1 +1 @@
-export * from './visualizationPanel';
+export * from './components/panel';
diff --git a/libs/shared/lib/vis/shared/AttributeDataType.test.tsx b/libs/shared/lib/vis/shared/AttributeDataType.test.tsx
deleted file mode 100644
index 43f9fe1b4..000000000
--- a/libs/shared/lib/vis/shared/AttributeDataType.test.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-import { assert, describe, expect, it } from 'vitest';
-
-import { isAttributeDataEntity } from './AttributeDataType';
-
-describe('AttributeDataType', () => {
-  it('true', () => {
-    expect(true).toEqual(true);
-  });
-});
-
-// /**
-//  * This program has been developed by students from the bachelor Computer Science at
-//  * Utrecht University within the Software Project course.
-//  * © Copyright Utrecht University (Department of Information and Computing Sciences)
-//  */
-//
-// import { isAttributeDataEntity, isAttributeDataRelation } from './AttributeDataType';
-// import {
-//   mockAttributeDataNLDifferentTypes1,
-//   mockAttributeDataNLDifferentTypes2,
-//   mockAttributeDataNLDifferentTypes3,
-//   mockAttributeDataNLEdge1,
-//   mockAttributeDataNLInvalidLengthNumerical,
-//   mockAttributeDataNLInvalidType,
-//   mockAttributeDataNLNode1,
-//   mockAttributeDataNLNode1AttributeArrayIsNoArray,
-//   mockAttributeDataNLUniqueCategoricalValuesIsNoArray,
-//   mockAttributeDataNLUniqueCategoricalValuesLengthIsZero,
-// } from '@graphpolaris/shared/lib/mock-data/schema/MockAttributeDataBatchedNL';
-//
-// describe('AttributeDataType', () => {
-//   it('should return true for a valid attributeData object with an entity', () => {
-//     expect(isAttributeDataEntity(mockAttributeDataNLNode1)).toEqual(true);
-//   });
-//
-//   it('should return true for a valid attributeData object with an relation', () => {
-//     expect(isAttributeDataRelation(mockAttributeDataNLEdge1)).toEqual(true);
-//   });
-//
-//   it('should return false if the attributes array is no array', () => {
-//     expect(isAttributeDataEntity(mockAttributeDataNLNode1AttributeArrayIsNoArray)).toEqual(false);
-//   });
-//
-//   it('should return false if the unique-categorical-values array is no array', () => {
-//     expect(isAttributeDataEntity(mockAttributeDataNLUniqueCategoricalValuesIsNoArray)).toEqual(
-//       false,
-//     );
-//   });
-//
-//   it('should return false if the unique-categorical-values array has length 0, while having "Categorical" type', () => {
-//     expect(isAttributeDataEntity(mockAttributeDataNLUniqueCategoricalValuesLengthIsZero)).toEqual(
-//       false,
-//     );
-//   });
-//
-//   it('should return false if the unique-categorical-values have different types', () => {
-//     expect(isAttributeDataEntity(mockAttributeDataNLDifferentTypes1)).toEqual(false);
-//     expect(isAttributeDataEntity(mockAttributeDataNLDifferentTypes2)).toEqual(false);
-//     expect(isAttributeDataEntity(mockAttributeDataNLDifferentTypes3)).toEqual(false);
-//   });
-//
-//   it('should return false if the unique-categorical-values array has an element with an invalid type', () => {
-//     expect(isAttributeDataEntity(mockAttributeDataNLInvalidType)).toEqual(false);
-//   });
-//
-//   it('should return false if the unique-categorical-values array contains an element while the category is not "Categorical', () => {
-//     expect(isAttributeDataEntity(mockAttributeDataNLInvalidLengthNumerical)).toEqual(false);
-//   });
-// });
diff --git a/libs/shared/lib/vis/shared/AttributeDataType.tsx b/libs/shared/lib/vis/shared/AttributeDataType.tsx
deleted file mode 100644
index 2ba60eea0..000000000
--- a/libs/shared/lib/vis/shared/AttributeDataType.tsx
+++ /dev/null
@@ -1,119 +0,0 @@
-/**
- * This program has been developed by students from the bachelor Computer Science at
- * Utrecht University within the Software Project course.
- * © Copyright Utrecht University (Department of Information and Computing Sciences)
- */
-import { AttributeData, AttributeFromAttributeData } from './InputDataTypes';
-
-/**
- * Checks if an object has all the properties of an attributeData type. If true, the object will be casted to attributeDataType
- * @param {any} object The object to check if it is an attributeData object.
- * @returns If true, the object is a of type attributeDataType.
- */
-export function isAttributeDataEntity(object: any): object is AttributeData {
-  if (
-    typeof object === 'object' &&
-    'id' in object &&
-    object.id != undefined &&
-    'length' in object &&
-    object.length != undefined &&
-    'connectedRatio' in object &&
-    object.connectedRatio != undefined &&
-    'summedNullAmount' in object &&
-    object.summedNullAmount != undefined &&
-    'attributes' in object &&
-    object.attributes != undefined
-  ) {
-    // Check the structure of a node.
-    return (
-      typeof object.id == 'string' &&
-      typeof object.length == 'number' &&
-      typeof object.connectedRatio == 'number' &&
-      typeof object.summedNullAmount == 'number' &&
-      isAttributeArray(object.attributes)
-    );
-  }
-  return false;
-}
-
-/**
- * Checks if an object has all the properties of an attributeData type. If true, the object will be casted to attributeDataType
- * @param {any} object The object to check if it is an attributeData object.
- * @returns If true, the object is a of type attributeDataType.
- */
-export function isAttributeDataRelation(object: any): object is AttributeData {
-  if (
-    typeof object === 'object' &&
-    'id' in object &&
-    object.id != undefined &&
-    'length' in object &&
-    object.length != undefined &&
-    'fromRatio' in object &&
-    object.fromRatio != undefined &&
-    'toRatio' in object &&
-    object.toRatio != undefined &&
-    'summedNullAmount' in object &&
-    object.summedNullAmount != undefined &&
-    'attributes' in object &&
-    object.attributes != undefined
-  ) {
-    // Check the structure of a edge.
-    return (
-      typeof object.id == 'string' &&
-      typeof object.length == 'number' &&
-      typeof object.fromRatio == 'number' &&
-      typeof object.toRatio == 'number' &&
-      typeof object.summedNullAmount == 'number' &&
-      isAttributeArray(object.attributes)
-    );
-  }
-  return false;
-}
-/**
- * Checks if an object has the correct structure of an attribute from AttributeData.
- * @param {any} object The object to check.
- * @returns If true, the object has the correct structure of an attribute from AttributeData.
- */
-function isAttributeArray(object: any): object is AttributeFromAttributeData[] {
-  if (!Array.isArray(object)) return false;
-
-  return object.every(
-    (attribute: AttributeFromAttributeData) =>
-      typeof attribute.name == 'string' &&
-      ['Categorical', 'Numerical', 'Other'].includes(attribute.type) &&
-      typeof attribute.nullAmount == 'number' &&
-      isCorrectUniqueCategoricalValues(attribute)
-  );
-}
-
-/**
- * Checks whether uniqueCategoricalValues has the correct values.
- * @param attribute The attribute that contains the array (possibly null) with all unique values of the categories.
- * @returns If true, uniqueCategoricalValues is or null, or has an array with values of the same type.
- */
-function isCorrectUniqueCategoricalValues(attribute: any): attribute is AttributeFromAttributeData {
-  const uniqueCategoricalValues = attribute.uniqueCategoricalValues;
-
-  // Check if uniqueCategoricalValues is an array.
-  if (!Array.isArray(uniqueCategoricalValues)) return false;
-
-  // Check if uniqueCategoricalValues.type is Categorical.
-  if (attribute.type === 'Categorical') {
-    // If true, it has to have a length bigger than 0.
-    if (uniqueCategoricalValues.length == 0) return false;
-
-    // All types in the array has to be the same.
-    if (typeof uniqueCategoricalValues[0] == 'string') {
-      return uniqueCategoricalValues.every((value: any) => typeof value == 'string');
-    } else if (typeof uniqueCategoricalValues[0] == 'number') {
-      return uniqueCategoricalValues.every((value: any) => typeof value == 'number');
-    } else if (typeof uniqueCategoricalValues[0] == 'boolean') {
-      return uniqueCategoricalValues.every((value: any) => typeof value == 'boolean');
-    } else return false;
-  }
-  // If the type is Numerical or Other (the two remaining), check if the length of the array is 0.
-  else {
-    if (uniqueCategoricalValues.length == 0) return true;
-    else return false;
-  }
-}
diff --git a/libs/shared/lib/vis/shared/InputDataTypes.tsx b/libs/shared/lib/vis/shared/InputDataTypes.tsx
deleted file mode 100644
index 4d97b6529..000000000
--- a/libs/shared/lib/vis/shared/InputDataTypes.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * This program has been developed by students from the bachelor Computer Science at
- * Utrecht University within the Software Project course.
- * © Copyright Utrecht University (Department of Information and Computing Sciences)
- */
-import { SchemaAttribute } from '../../schema';
-import { AttributeCategory } from './Types';
-
-/** Node type, consist of a name and a list of attributes */
-export type Node = {
-  name: string;
-  attributes: SchemaAttribute[];
-};
-
-/** Edge type, consist of a name, start point, end point and a list of attributes */
-export type Edge = {
-  name: string;
-  to: string;
-  from: string;
-  collection: string;
-  attributes: SchemaAttribute[];
-};
-
-/** Type of the attribute-data, which could be either of a node (entity) or an edge (relation) */
-export type AttributeData = NodeAttributeData | EdgeAttributeData;
-
-/** Type for a node containing all attribute-data */
-export type NodeAttributeData = {
-  id: string;
-  attributes: AttributeFromAttributeData[];
-  length: number;
-  connectedRatio: number;
-  summedNullAmount: number;
-};
-
-/** Type for an edge containing all attribute-data */
-export type EdgeAttributeData = {
-  id: string;
-  attributes: AttributeFromAttributeData[];
-  length: number;
-  fromRatio: number;
-  toRatio: number;
-  summedNullAmount: number;
-};
-
-/** Type for an attribute of a node or an edge, containing attribute-data */
-export type AttributeFromAttributeData = {
-  name: string;
-  type: AttributeCategory;
-  nullAmount: number;
-  uniqueCategoricalValues: null | string[] | number[] | boolean[];
-};
diff --git a/libs/shared/lib/vis/shared/SchemaResultType.test.tsx b/libs/shared/lib/vis/shared/SchemaResultType.test.tsx
deleted file mode 100644
index cb08d75ad..000000000
--- a/libs/shared/lib/vis/shared/SchemaResultType.test.tsx
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * This program has been developed by students from the bachelor Computer Science at
- * Utrecht University within the Software Project course.
- * © Copyright Utrecht University (Department of Information and Computing Sciences)
- */
-import { assert, describe, expect, it } from 'vitest';
-import { isSchemaResult } from './SchemaResultType';
-
-/** Testsuite to test the schema result checker */
-describe('isSchemaResult', () => {
-  it('should return true for a valid schema object', () => {
-    const schema: any = {
-      nodes: [],
-      edges: [],
-    };
-    expect(isSchemaResult(schema)).toBe(true);
-
-    schema.nodes.push({
-      name: 'hoi',
-      attributes: [{ name: 'attr', type: 'string' }],
-    });
-    schema.edges.push({
-      name: 'edge',
-      from: '1',
-      to: '2',
-      collection: 'flights',
-      attributes: [],
-    });
-    expect(isSchemaResult(schema)).toBe(true);
-
-    schema.TEST = 2;
-    expect(isSchemaResult(schema)).toBe(true);
-  });
-
-  it('should return false for an invalid schema object', () => {
-    const schema: any = {
-      nodes: [],
-      edges: [],
-    };
-    expect(isSchemaResult(schema)).toBe(true);
-
-    schema.edges = 2;
-    expect(isSchemaResult(schema)).toBe(false);
-
-    schema.edges = [
-      {
-        name: 'test',
-        from: '2',
-        TO: '2',
-        collection: 'flights',
-        attributes: [],
-      },
-    ];
-    expect(isSchemaResult(schema)).toBe(false);
-
-    schema.edges = [
-      {
-        name: 'test',
-        from: '2',
-        to: '2',
-        collection: 'flights',
-        attributes: 2,
-      },
-    ];
-    expect(isSchemaResult(schema)).toBe(false);
-
-    schema.edges = [
-      {
-        name: 'test',
-        from: '2',
-        to: '2',
-        collection: 'flights',
-        attributes: [
-          { name: 'attr', type: 'text' },
-          { name: 'attr', type: 'ff at 20' },
-        ],
-      },
-    ];
-    expect(isSchemaResult(schema)).toBe(false);
-
-    // It should return false for incomplete schema
-    const onlyNodes: any = { nodes: [] };
-    const onlyEdges: any = { egdes: [] };
-    expect(isSchemaResult(onlyNodes)).toEqual(false);
-    expect(isSchemaResult(onlyEdges)).toEqual(false);
-  });
-});
diff --git a/libs/shared/lib/vis/shared/SchemaResultType.tsx b/libs/shared/lib/vis/shared/SchemaResultType.tsx
deleted file mode 100644
index 804ed3f9c..000000000
--- a/libs/shared/lib/vis/shared/SchemaResultType.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * This program has been developed by students from the bachelor Computer Science at
- * Utrecht University within the Software Project course.
- * © Copyright Utrecht University (Department of Information and Computing Sciences)
- */
-
-/**
- * Checks if an object has all the properties of a schema result. If true, the object will be casted to SchemaResultType
- * @param {any} object The object to check if it is a SchemaResult object.
- * @returns If true, the object is a of type SchemaResultType.
- * @deprecated //TODO remove
- */
-export function isSchemaResult(object: any): object is any {
-  if (typeof object === 'object' && 'nodes' in object && object.nodes != undefined && 'edges' in object && object.edges != undefined) {
-    if (!Array.isArray(object.nodes) || !Array.isArray(object.edges)) return false;
-
-    // Check the structure of all nodes
-    const validNodes = object.nodes.every((node: any) => typeof node.name == 'string' && isAttributeArray(node.attributes));
-
-    // Check the structure of all edges
-    const validEdges = object.edges.every(
-      (edge: any) =>
-        typeof edge.name == 'string' &&
-        typeof edge.collection == 'string' &&
-        typeof edge.from == 'string' &&
-        typeof edge.to == 'string' &&
-        isAttributeArray(edge.attributes)
-    );
-    return validNodes && validEdges;
-  }
-  return false;
-}
-
-/**
- * Checks if an object has the structure of a SchemaAttribute.
- * @param {any} object The object to check.
- * @returns If true, the object has the structure of SchemaAttribute type.
- * @deprecated //TODO remove
- */
-function isAttributeArray(object: any): object is any[] {
-  if (!Array.isArray(object)) {
-    return false;
-  }
-
-  return object.every((attribute) => typeof attribute.name == 'string' && ['string', 'int', 'bool', 'float'].includes(attribute.type));
-}
diff --git a/libs/shared/lib/vis/shared/VisConfigPanel/ArrowRightIcon.svg b/libs/shared/lib/vis/shared/VisConfigPanel/ArrowRightIcon.svg
deleted file mode 100644
index 0b775d11e..000000000
--- a/libs/shared/lib/vis/shared/VisConfigPanel/ArrowRightIcon.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22"><defs><clipPath><path fill="#00f" fill-opacity=".514" d="m-7 1024.36h34v34h-34z"/></clipPath><clipPath><path fill="#aade87" fill-opacity=".472" d="m-6 1028.36h32v32h-32z"/></clipPath></defs><path d="m345.44 248.29l-194.29 194.28c-12.359 12.365-32.397 12.365-44.75 0-12.354-12.354-12.354-32.391 0-44.744l171.91-171.91-171.91-171.9c-12.354-12.359-12.354-32.394 0-44.748 12.354-12.359 32.391-12.359 44.75 0l194.29 194.28c6.177 6.18 9.262 14.271 9.262 22.366 0 8.099-3.091 16.196-9.267 22.373" transform="matrix(.03541-.00013.00013.03541 2.98 3.02)" fill="#4d4d4d"/></svg>
\ No newline at end of file
diff --git a/libs/shared/lib/vis/shared/VisConfigPanel/QuestionMarkIcon.svg b/libs/shared/lib/vis/shared/VisConfigPanel/QuestionMarkIcon.svg
deleted file mode 100644
index 75c116bed..000000000
--- a/libs/shared/lib/vis/shared/VisConfigPanel/QuestionMarkIcon.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<svg id="svg2" xmlns="http://www.w3.org/2000/svg" width="17" height="17" viewBox="0 0 200 200" version="1.0">
- <g id="layer1">
-  <path id="path2413" d="m100 0c-55.2 0-100 44.8-100 100-5.0495e-15 55.2 44.8 100 100 100s100-44.8 100-100-44.8-100-100-100zm0 12.812c48.13 0 87.19 39.058 87.19 87.188s-39.06 87.19-87.19 87.19-87.188-39.06-87.188-87.19 39.058-87.188 87.188-87.188zm1.47 21.25c-5.45 0.03-10.653 0.737-15.282 2.063-4.699 1.346-9.126 3.484-12.876 6.219-3.238 2.362-6.333 5.391-8.687 8.531-4.159 5.549-6.461 11.651-7.063 18.687-0.04 0.468-0.07 0.868-0.062 0.876 0.016 0.016 21.702 2.687 21.812 2.687 0.053 0 0.113-0.234 0.282-0.937 1.941-8.085 5.486-13.521 10.968-16.813 4.32-2.594 9.808-3.612 15.778-2.969 2.74 0.295 5.21 0.96 7.38 2 2.71 1.301 5.18 3.361 6.94 5.813 1.54 2.156 2.46 4.584 2.75 7.312 0.08 0.759 0.05 2.48-0.03 3.219-0.23 1.826-0.7 3.378-1.5 4.969-0.81 1.597-1.48 2.514-2.76 3.812-2.03 2.077-5.18 4.829-10.78 9.407-3.6 2.944-6.04 5.156-8.12 7.343-4.943 5.179-7.191 9.069-8.564 14.719-0.905 3.72-1.256 7.55-1.156 13.19 0.025 1.4 0.062 2.73 0.062 2.97v0.43h21.598l0.03-2.4c0.03-3.27 0.21-5.37 0.56-7.41 0.57-3.27 1.43-5 3.94-7.81 1.6-1.8 3.7-3.76 6.93-6.47 4.77-3.991 8.11-6.99 11.26-10.125 4.91-4.907 7.46-8.26 9.28-12.187 1.43-3.092 2.22-6.166 2.46-9.532 0.06-0.816 0.07-3.03 0-3.968-0.45-7.043-3.1-13.253-8.15-19.032-0.8-0.909-2.78-2.887-3.72-3.718-4.96-4.394-10.69-7.353-17.56-9.094-4.19-1.062-8.23-1.6-13.35-1.75-0.78-0.023-1.59-0.036-2.37-0.032zm-10.908 103.6v22h21.998v-22h-21.998z"/>
- </g>
-</svg>
\ No newline at end of file
diff --git a/libs/shared/lib/vis/shared/VisConfigPanel/VisConfigPanel.module.scss.d.ts b/libs/shared/lib/vis/shared/VisConfigPanel/VisConfigPanel.module.scss.d.ts
deleted file mode 100644
index 5099a5d37..000000000
--- a/libs/shared/lib/vis/shared/VisConfigPanel/VisConfigPanel.module.scss.d.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-declare const classNames: {
-  readonly expandButtonSize: 'expandButtonSize';
-  readonly container: 'container';
-  readonly expandButton: 'expandButton';
-  readonly arrowLeft: 'arrowLeft';
-  readonly childrenContainer: 'childrenContainer';
-  readonly children: 'children';
-};
-export = classNames;
diff --git a/libs/shared/lib/vis/types.ts b/libs/shared/lib/vis/types.ts
deleted file mode 100644
index cf79a63d5..000000000
--- a/libs/shared/lib/vis/types.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import { GraphQueryResult } from '../data-access/store/graphQueryResultSlice';
-import { ML } from '../data-access/store/mlSlice';
-import { SchemaGraph } from '../schema';
-import type { AppDispatch } from '../data-access';
-import { InputProps } from '../components/inputs';
-import { FC } from 'react';
-import { EncodingProps, EncodingTypes } from './configuration/encodings';
-import { SettingProps, SettingTypes } from './configuration/settings';
-import { InteractionProps, InteractionTypes } from './configuration/interactions';
-import { Visualizations } from './visualizationManager';
-
-export type globalConfigTypes = { [id: string]: InputProps };
-
-export type globalConfigPropTypes = { [K in keyof globalConfigTypes]: any };
-
-export type VisualizationConfiguration = {
-  settings?: SettingTypes;
-  encodings?: EncodingTypes;
-  interactions?: InteractionTypes;
-};
-
-export type VISComponentType = {
-  displayName: keyof typeof Visualizations;
-  VIS: FC<any>;
-  settings?: SettingTypes;
-  encodings?: EncodingTypes;
-  interactions?: InteractionTypes;
-};
-
-export type VisualizationPropTypes = {
-  data: GraphQueryResult;
-  schema: SchemaGraph;
-  ml: ML;
-  dispatch: AppDispatch;
-  globalConfig: globalConfigPropTypes;
-  settings: SettingProps;
-  encodings?: EncodingProps;
-  interactions?: InteractionProps;
-};
diff --git a/libs/shared/lib/vis/views/index.tsx b/libs/shared/lib/vis/views/index.tsx
new file mode 100644
index 000000000..de85438c8
--- /dev/null
+++ b/libs/shared/lib/vis/views/index.tsx
@@ -0,0 +1,3 @@
+export { NoData } from './noData';
+export { Recommender } from './recommender';
+export { Querying } from './querying';
diff --git a/libs/shared/lib/vis/views/noData.tsx b/libs/shared/lib/vis/views/noData.tsx
new file mode 100644
index 000000000..fafa7b810
--- /dev/null
+++ b/libs/shared/lib/vis/views/noData.tsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import { Button } from '../../components';
+import { InfoOutlined } from '@mui/icons-material';
+
+type Props = { dataAvailable: boolean };
+
+export function NoData({ dataAvailable }: Props) {
+  return (
+    <div className="flex justify-center items-center h-full">
+      <div className="max-w-lg mx-auto text-left">
+        <p className="text-xl font-normal text-secondary-600">No data available to be shown</p>
+        {dataAvailable ? (
+          <p>Query resulted in empty dataset</p>
+        ) : (
+          <div>
+            <p>Query for data to visualize</p>
+            <Button
+              type="primary"
+              variant="outline"
+              label="Learn how to query data"
+              size="sm"
+              iconComponent={<InfoOutlined />}
+              onClick={() => window.open('https://graphpolaris.com', '_blank')}
+            />
+          </div>
+        )}
+      </div>
+    </div>
+  );
+}
diff --git a/libs/shared/lib/vis/views/querying.tsx b/libs/shared/lib/vis/views/querying.tsx
new file mode 100644
index 000000000..d466a33ae
--- /dev/null
+++ b/libs/shared/lib/vis/views/querying.tsx
@@ -0,0 +1,10 @@
+import React from 'react';
+import { LoadingSpinner } from '../../components';
+
+export function Querying() {
+  return (
+    <div className="w-full h-full flex flex-col items-center justify-center overflow-hidden">
+      <LoadingSpinner>Querying backend...</LoadingSpinner>
+    </div>
+  );
+}
diff --git a/libs/shared/lib/vis/views/recommender.tsx b/libs/shared/lib/vis/views/recommender.tsx
new file mode 100644
index 000000000..1bc681b19
--- /dev/null
+++ b/libs/shared/lib/vis/views/recommender.tsx
@@ -0,0 +1,38 @@
+import React from 'react';
+import Info from '../../components/info';
+
+type Props = { onClick: (id: string) => void };
+
+const options = {
+  TableVis: '',
+  NodeLinkVis: '',
+  PaohVis: '',
+  SemanticSubstratesVis: '',
+  MatrixVis: '',
+};
+
+export function Recommender({ onClick }: Props) {
+  return (
+    <div className="p-4">
+      <span className="text-md font-thin">Select a visualization</span>
+      <div className="grid grid-cols-3 gap-4">
+        {Object.entries(options).map(([name, image]) => (
+          <div
+            key={name}
+            className="p-4 cursor-pointer border hover:bg-secondary-100"
+            onClick={(e) => {
+              e.preventDefault();
+              onClick(name);
+            }}
+          >
+            <div className="flex items-center justify-between">
+              <span className="text-sm font-semibold">{name}</span>
+              <Info tooltip="Here an explanation" side="top" />
+            </div>
+            {/* <image src={image} /> */}
+          </div>
+        ))}
+      </div>
+    </div>
+  );
+}
diff --git a/libs/shared/lib/vis/visualizationManager.tsx b/libs/shared/lib/vis/visualizationManager.tsx
deleted file mode 100644
index 12b474b33..000000000
--- a/libs/shared/lib/vis/visualizationManager.tsx
+++ /dev/null
@@ -1,103 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import { useAppDispatch } from '@graphpolaris/shared/lib/data-access';
-import { addVisualization } from '../data-access/store/visualizationSlice';
-import { useGraphQueryResult, useML, useSchemaGraph, useVisualization } from '@graphpolaris/shared/lib/data-access/store/hooks';
-import { VISComponentType, globalConfigPropTypes } from './types';
-
-export const Visualizations: Record<string, Function> = {
-  TableVis: () => import('./visualizations/tablevis/tablevis'),
-  PaohVis: () => import('./visualizations/paohvis/paohvis'),
-  RawJSONVis: () => import('./visualizations/rawjsonvis/rawjsonvis'),
-  NodeLinkVis: () => import('./visualizations/nodelinkvis/nodelinkvis'),
-  // MapVis: () => import('./visualizations/mapvis/mapvis'),
-  MatrixVis: () => import('./visualizations/matrixvis/matrixvis'),
-  SemSubstrVis: () => import('./visualizations/semanticsubstratesvis/semanticsubstratesvis'),
-};
-
-export const VisualizationManager = () => {
-  const dispatch = useAppDispatch();
-  const vis = useVisualization();
-  const graphQueryResult = useGraphQueryResult();
-  const schema = useSchemaGraph();
-  const ml = useML();
-
-  const [visualizationComponent, setVisualizationComponent] = useState<VISComponentType>();
-
-  useEffect(() => {
-    if (vis.activeVisualization && vis.activeVisualization in Visualizations) {
-      Visualizations[vis.activeVisualization]().then((r: any) => {
-        setVisualizationComponent(r.default);
-      });
-    }
-  }, [vis.activeVisualization]);
-
-  useEffect(() => {
-    if (visualizationComponent) {
-      const { displayName, settings = {}, encodings = {}, interactions = {} } = visualizationComponent;
-      dispatch(addVisualization({ id: displayName, settings, encodings, interactions }));
-    }
-  }, [visualizationComponent]);
-
-  if (!visualizationComponent) {
-    return <></>;
-  }
-
-  const globalConfig: globalConfigPropTypes = vis.settings.general
-    ? Object.keys(vis.settings.general).reduce((propsObject, val) => {
-        return {
-          ...propsObject,
-          [val]: vis.settings.general[val].value,
-        };
-      }, {})
-    : {};
-
-  let visSettings = {};
-  let visEncodings = {};
-  let visInteractions = {};
-
-  if (vis.activeVisualization && vis.settings[vis.activeVisualization]) {
-    const activeVisSettings = vis.settings[vis.activeVisualization]?.settings;
-    const activeVisEncodings = vis.settings[vis.activeVisualization]?.encodings;
-    const activeVisInteractions = vis.settings[vis.activeVisualization]?.interactions;
-
-    visSettings = Object.keys(activeVisSettings ?? {}).reduce((propsObject, val) => {
-      return {
-        ...propsObject,
-        [val]: activeVisSettings?.[val]?.value,
-      };
-    }, {});
-
-    visEncodings = Object.keys(activeVisEncodings ?? {}).reduce((propsObject, val) => {
-      return {
-        ...propsObject,
-        [val]: activeVisEncodings?.[val]?.marking,
-      };
-    }, {});
-
-    visInteractions = Object.keys(activeVisInteractions ?? {}).reduce((propsObject, val) => {
-      return {
-        ...propsObject,
-        [val]: activeVisInteractions?.[val]?.value,
-      };
-    }, {});
-  }
-
-  try {
-    return (
-      vis.activeVisualization && (
-        <visualizationComponent.VIS
-          data={graphQueryResult}
-          schema={schema}
-          ml={ml}
-          dispatch={dispatch}
-          globalConfig={globalConfig}
-          settings={visSettings}
-          encodings={visEncodings}
-          interactions={visInteractions}
-        />
-      )
-    );
-  } catch (error) {
-    return <div className="w-full h-full flex items-center justify-center">Something went wrong in the visualization component.</div>;
-  }
-};
diff --git a/libs/shared/lib/vis/visualizationPanel.tsx b/libs/shared/lib/vis/visualizationPanel.tsx
deleted file mode 100644
index 7a42403af..000000000
--- a/libs/shared/lib/vis/visualizationPanel.tsx
+++ /dev/null
@@ -1,110 +0,0 @@
-import React, { useState, useRef, useEffect } from 'react';
-import { useAppDispatch, useGraphQueryResult, useQuerybuilderGraph, useVisualization } from '@graphpolaris/shared/lib/data-access';
-import { LoadingSpinner } from '@graphpolaris/shared/lib/components/LoadingSpinner';
-import { setActiveVisualization } from '@graphpolaris/shared/lib/data-access/store/visualizationSlice';
-import { DropdownItem, DropdownItemContainer } from '@graphpolaris/shared/lib/components/dropdowns';
-import ControlContainer from '@graphpolaris/shared/lib/components/controls';
-import { Button } from '@graphpolaris/shared/lib/components/buttons';
-
-import { VisualizationDialog } from './configuration';
-import { Settings as SettingsIcon, Apps as AppsIcon, Fullscreen } from '@mui/icons-material';
-import { VisualizationManager, Visualizations } from './visualizationManager';
-import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../components/tooltip';
-
-export const VisualizationPanel = () => {
-  const graphQueryResult = useGraphQueryResult();
-  const query = useQuerybuilderGraph();
-  const dispatch = useAppDispatch();
-  const vis = useVisualization();
-  const [visDropdownOpen, setVisDropdownOpen] = useState<boolean>(false);
-  const [showVisSettings, setShowVisSettings] = useState<boolean>(false);
-  const visDropdownRef = useRef<HTMLDivElement>(null);
-
-  useEffect(() => {
-    const handleClickOutside = (event: MouseEvent) => {
-      if (visDropdownRef.current && !visDropdownRef.current.contains(event.target as Node)) {
-        setVisDropdownOpen(false);
-      }
-    };
-    if (visDropdownOpen) document.addEventListener('mousedown', handleClickOutside);
-    return () => {
-      document.removeEventListener('mousedown', handleClickOutside);
-    };
-  }, [visDropdownOpen]);
-
-  return (
-    <div className="vis-panel h-full w-full overflow-y-auto" style={graphQueryResult.nodes.length === 0 ? { overflow: 'hidden' } : {}}>
-      <VisualizationDialog open={showVisSettings} onClose={() => setShowVisSettings(false)} />
-      <div className="sticky top-0 flex items-center justify-between z-[2] py-0 px-2 bg-secondary-100  border-b border-secondary-200">
-        <h1 className="text-xs font-semibold text-secondary-800">{vis.activeVisualization} visualization</h1>
-        <ControlContainer>
-          <TooltipProvider delayDuration={0}>
-            <Tooltip disabled={showVisSettings}>
-              <TooltipTrigger asChild>
-                <Button
-                  type="secondary"
-                  variant="ghost"
-                  size="xs"
-                  iconComponent={<SettingsIcon />}
-                  onClick={() => {
-                    // TODO
-                    // setShowVisSettings(!showVisSettings);
-                  }}
-                />
-              </TooltipTrigger>
-              <TooltipContent side={'bottom'} disabled={showVisSettings}>
-                <p>Visualization settings</p>
-              </TooltipContent>
-            </Tooltip>
-            <Tooltip>
-              <TooltipTrigger asChild>
-                <Button
-                  type="secondary"
-                  variant="ghost"
-                  size="xs"
-                  iconComponent={<AppsIcon />}
-                  onClick={() => {
-                    setVisDropdownOpen(!visDropdownOpen);
-                  }}
-                />
-              </TooltipTrigger>
-              <TooltipContent side={'bottom'} disabled={visDropdownOpen}>
-                <p>Change visualization</p>
-              </TooltipContent>
-            </Tooltip>
-          </TooltipProvider>
-
-          {visDropdownOpen && (
-            <div ref={visDropdownRef}>
-              <DropdownItemContainer align="top-6 right-6">
-                {Object.keys(Visualizations).map((key) => (
-                  <DropdownItem
-                    key={key}
-                    value={key}
-                    onClick={() => {
-                      setVisDropdownOpen(false);
-                      dispatch(setActiveVisualization(key));
-                    }}
-                  />
-                ))}
-              </DropdownItemContainer>
-            </div>
-          )}
-        </ControlContainer>
-      </div>
-
-      {graphQueryResult.queryingBackend ? (
-        <div className="w-full h-full flex flex-col items-center justify-center overflow-hidden">
-          <LoadingSpinner>Querying backend...</LoadingSpinner>
-        </div>
-      ) : graphQueryResult.nodes.length === 0 ? (
-        <div className="w-full h-full flex flex-col items-center justify-center">
-          <p>No data available to be shown</p>
-          {query.nodes.length > 0 ? <p>Query resulted in empty dataset</p> : <p>Query for data to visualize</p>}
-        </div>
-      ) : (
-        <VisualizationManager />
-      )}
-    </div>
-  );
-};
diff --git a/libs/shared/lib/vis/visualizations/mapvis/archive/geovis/types.tsx b/libs/shared/lib/vis/visualizations/mapvis/archive/geovis/types.ts
similarity index 100%
rename from libs/shared/lib/vis/visualizations/mapvis/archive/geovis/types.tsx
rename to libs/shared/lib/vis/visualizations/mapvis/archive/geovis/types.ts
diff --git a/libs/shared/lib/vis/visualizations/mapvis/components/FilterMenu.tsx b/libs/shared/lib/vis/visualizations/mapvis/components/FilterMenu.tsx
index 6cb870b9d..1b1fb98cd 100644
--- a/libs/shared/lib/vis/visualizations/mapvis/components/FilterMenu.tsx
+++ b/libs/shared/lib/vis/visualizations/mapvis/components/FilterMenu.tsx
@@ -1,6 +1,6 @@
 import React from 'react';
 import { Close, ExpandLess, ExpandMore, PlayArrow } from '@mui/icons-material';
-import { GraphType } from '../Types';
+import { GraphType } from '../types';
 
 type Props = {
   graph: GraphType;
diff --git a/libs/shared/lib/vis/visualizations/mapvis/components/LayerPanel.tsx b/libs/shared/lib/vis/visualizations/mapvis/components/LayerPanel.tsx
index af8342ed0..6a5d57b2c 100644
--- a/libs/shared/lib/vis/visualizations/mapvis/components/LayerPanel.tsx
+++ b/libs/shared/lib/vis/visualizations/mapvis/components/LayerPanel.tsx
@@ -1,6 +1,6 @@
 import React from 'react';
 import { layerTypes } from '../layers';
-import { Layer } from '../Types';
+import { Layer } from '../types';
 import { makeLayer } from '../utlis';
 
 type Props = {
diff --git a/libs/shared/lib/vis/visualizations/mapvis/components/MapPanel.tsx b/libs/shared/lib/vis/visualizations/mapvis/components/MapPanel.tsx
index 877464ba4..dbf41b61d 100644
--- a/libs/shared/lib/vis/visualizations/mapvis/components/MapPanel.tsx
+++ b/libs/shared/lib/vis/visualizations/mapvis/components/MapPanel.tsx
@@ -3,7 +3,7 @@ import DeckGL from '@deck.gl/react/typed';
 import { FlyToInterpolator, MapView, WebMercatorViewport } from '@deck.gl/core/typed';
 import { createBaseMap } from './BaseMap';
 import FilterMenu from './FilterMenu';
-import { GraphType, Layer } from '../Types';
+import { GraphType, Layer } from '../types';
 import { SelectionLayer } from '@nebula.gl/layers';
 import SelectedMenu from './SelectedMenu';
 import SecondaryMenu from './SecondaryMenu';
@@ -39,7 +39,7 @@ export function MapPanel({ graph, layers, showFilter, setShowFilter }: Props) {
         [minLon, minLat],
         [maxLon, maxLat],
       ],
-      { padding: 20 }
+      { padding: 20 },
     );
     const { zoom, longitude, latitude } = viewportWebMercator;
     return { zoom, longitude, latitude };
diff --git a/libs/shared/lib/vis/visualizations/mapvis/graphModel.tsx b/libs/shared/lib/vis/visualizations/mapvis/graphModel.tsx
index 4e86887ee..73464a385 100644
--- a/libs/shared/lib/vis/visualizations/mapvis/graphModel.tsx
+++ b/libs/shared/lib/vis/visualizations/mapvis/graphModel.tsx
@@ -1,4 +1,4 @@
-import { GraphType, Node, Edge, Coordinate } from './Types';
+import { GraphType, Node, Edge, Coordinate } from './types';
 
 export default class GraphModel implements GraphType {
   nodeMap: { [id: string]: Node };
diff --git a/libs/shared/lib/vis/visualizations/mapvis/layers/choropleth-layer/ChoroplethLayer.tsx b/libs/shared/lib/vis/visualizations/mapvis/layers/choropleth-layer/ChoroplethLayer.tsx
index bd72091c9..bc2f56d98 100644
--- a/libs/shared/lib/vis/visualizations/mapvis/layers/choropleth-layer/ChoroplethLayer.tsx
+++ b/libs/shared/lib/vis/visualizations/mapvis/layers/choropleth-layer/ChoroplethLayer.tsx
@@ -5,7 +5,7 @@ import { getDistance } from '../../utlis';
 import * as d3 from 'd3';
 import ChoroplethOptions from './ChoroplethOptions';
 import { europeData, usaData, worldData, netherlands } from '../../../../../mock-data/geo-json';
-import { Edge, Node, LayerProps, GeoJSONData } from '../../Types';
+import { Edge, Node, LayerProps, GeoJSONData } from '../../types';
 
 export const circumferencesMap = {
   netherlands: netherlands,
@@ -129,7 +129,7 @@ export class ChoroplethLayer extends CompositeLayer<LayerProps> {
           feature.properties.nodes.push(node.id);
           const nIncomingEdges: number = node.connectedEdges.filter((edge: string) => this.props.graph.getEdge(edge).to === node.id).length;
           const nOutgoingEdges: number = node.connectedEdges.filter(
-            (edge: string) => this.props.graph.getEdge(edge).from === node.id
+            (edge: string) => this.props.graph.getEdge(edge).from === node.id,
           ).length;
 
           feature.properties.incomingEdges =
@@ -144,10 +144,10 @@ export class ChoroplethLayer extends CompositeLayer<LayerProps> {
               township.properties.nodes = township.properties.nodes ?? [];
               township.properties.nodes.push(node.id);
               const nIncomingEdges: number = node.connectedEdges.filter(
-                (edge: string) => this.props.graph.getEdge(edge).to === node.id
+                (edge: string) => this.props.graph.getEdge(edge).to === node.id,
               ).length;
               const nOutgoingEdges: number = node.connectedEdges.filter(
-                (edge: string) => this.props.graph.getEdge(edge).from === node.id
+                (edge: string) => this.props.graph.getEdge(edge).from === node.id,
               ).length;
 
               township.properties.incomingEdges =
@@ -204,7 +204,7 @@ export class ChoroplethLayer extends CompositeLayer<LayerProps> {
                 getTargetPosition: (d: any) => graph.getNodeLocation(d.to),
                 getSourceColor: (d: any) => [220, 220, 220],
                 getTargetColor: (d: any) => [220, 220, 220],
-              })
+              }),
             ),
             new ScatterplotLayer(
               this.getSubLayerProps({
@@ -219,7 +219,7 @@ export class ChoroplethLayer extends CompositeLayer<LayerProps> {
                 getFillColor: (d: any) => [0, 0, 0],
                 getRadius: (d: any) => 1,
                 getPosition: (d: any) => graph.getNodeLocation(d.to),
-              })
+              }),
             ),
           ]);
         }
@@ -247,7 +247,7 @@ export class ChoroplethLayer extends CompositeLayer<LayerProps> {
                 getTargetPosition: (d: any) => graph.getNodeLocation(d.to),
                 getSourceColor: (d: any) => [220, 220, 220],
                 getTargetColor: (d: any) => [220, 220, 220],
-              })
+              }),
             ),
             new ScatterplotLayer(
               this.getSubLayerProps({
@@ -262,7 +262,7 @@ export class ChoroplethLayer extends CompositeLayer<LayerProps> {
                 getFillColor: (d: any) => [0, 0, 0],
                 getRadius: (d: any) => 1,
                 getPosition: (d: any) => graph.getNodeLocation(d.to),
-              })
+              }),
             ),
           ]);
         }
@@ -287,8 +287,8 @@ export class ChoroplethLayer extends CompositeLayer<LayerProps> {
             getLineWidth: (d: any) => 1,
             getLineColor: (d: any) => [220, 220, 220],
             getFillColor: (d: any) => this.getColor(d),
-          })
-        )
+          }),
+        ),
       );
     });
 
diff --git a/libs/shared/lib/vis/visualizations/mapvis/layers/edge-arc-layer/EdgeArcLayer.tsx b/libs/shared/lib/vis/visualizations/mapvis/layers/edge-arc-layer/EdgeArcLayer.tsx
index 619bd86ca..9d84fc006 100644
--- a/libs/shared/lib/vis/visualizations/mapvis/layers/edge-arc-layer/EdgeArcLayer.tsx
+++ b/libs/shared/lib/vis/visualizations/mapvis/layers/edge-arc-layer/EdgeArcLayer.tsx
@@ -5,7 +5,7 @@ import ArcLayerOptions from './ArcLayerOptions';
 import * as d3 from 'd3';
 import { getProperty } from '../../utlis';
 import { BrushingExtension } from '@deck.gl/extensions/typed';
-import { Edge, LayerProps } from '../../Types';
+import { Edge, LayerProps } from '../../types';
 
 export const EdgeArcLayerConfig = {
   width: {
diff --git a/libs/shared/lib/vis/visualizations/mapvis/layers/edge-layer/EdgeLayer.tsx b/libs/shared/lib/vis/visualizations/mapvis/layers/edge-layer/EdgeLayer.tsx
index c1b6a533c..65f5178b5 100644
--- a/libs/shared/lib/vis/visualizations/mapvis/layers/edge-layer/EdgeLayer.tsx
+++ b/libs/shared/lib/vis/visualizations/mapvis/layers/edge-layer/EdgeLayer.tsx
@@ -5,7 +5,7 @@ import EdgeOptions from './EdgeOptions';
 import * as d3 from 'd3';
 import { getDistance, getProperty } from '../../utlis';
 import { BrushingExtension } from '@deck.gl/extensions/typed';
-import { Edge, LayerProps } from '../../Types';
+import { Edge, LayerProps } from '../../types';
 
 export const EdgeLayerConfig = {
   width: {
@@ -156,7 +156,7 @@ export class EdgeLayer extends CompositeLayer<LayerProps> {
           ...edge,
           path: [this.props.graph.getNodeLocation(edge.from), this.props.graph.getNodeLocation(edge.to)],
         };
-      })
+      }),
     );
 
     console.log('displayed edges', edges);
diff --git a/libs/shared/lib/vis/visualizations/mapvis/layers/heatmap-layer/HeatLayer.tsx b/libs/shared/lib/vis/visualizations/mapvis/layers/heatmap-layer/HeatLayer.tsx
index ce2f50693..06494eda4 100644
--- a/libs/shared/lib/vis/visualizations/mapvis/layers/heatmap-layer/HeatLayer.tsx
+++ b/libs/shared/lib/vis/visualizations/mapvis/layers/heatmap-layer/HeatLayer.tsx
@@ -3,7 +3,7 @@ import { CompositeLayer, HeatmapLayer } from 'deck.gl/typed';
 import HeatLayerOptions from './HeatLayerOptions';
 import * as d3 from 'd3';
 import { getDistance, getProperty } from '../../utlis';
-import { Edge, LayerProps } from '../../Types';
+import { Edge, LayerProps } from '../../types';
 
 /*
 Potential use cases:
@@ -94,8 +94,8 @@ export class HeatLayer extends CompositeLayer<LayerProps> {
                 : graph.getEdges().map((edge: Edge) => graph.getNode(edge.to)),
             getPosition: (d: any) => [d.attributes.long, d.attributes.lat],
             aggregation: 'SUM',
-          })
-        )
+          }),
+        ),
       );
     } else if (config.type === 'distance') {
       layers.push(
@@ -114,8 +114,8 @@ export class HeatLayer extends CompositeLayer<LayerProps> {
             getPosition: (d: any) => [d.attributes.long, d.attributes.lat],
             getWeight: (d: any) => d.distance,
             aggregation: 'MEAN',
-          })
-        )
+          }),
+        ),
       );
     } else if (config.type === 'attribute') {
       console.log('attribute');
@@ -129,8 +129,8 @@ export class HeatLayer extends CompositeLayer<LayerProps> {
               return 1;
             },
             aggregation: 'SUM',
-          })
-        )
+          }),
+        ),
       );
     } else if (config.type === 'path') {
       layers.push(
@@ -142,12 +142,12 @@ export class HeatLayer extends CompositeLayer<LayerProps> {
                   ...edge,
                   path: [this.props.graph.getNodeLocation(edge.from), this.props.graph.getNodeLocation(edge.to)],
                 };
-              })
+              }),
             ).flatMap((edge) => edge.path),
             getPosition: (d: any) => d,
             aggregation: 'SUM',
-          })
-        )
+          }),
+        ),
       );
     }
 
diff --git a/libs/shared/lib/vis/visualizations/mapvis/layers/icon-layer/IconLayer.tsx b/libs/shared/lib/vis/visualizations/mapvis/layers/icon-layer/IconLayer.tsx
index 3aad1baf2..7c0623022 100644
--- a/libs/shared/lib/vis/visualizations/mapvis/layers/icon-layer/IconLayer.tsx
+++ b/libs/shared/lib/vis/visualizations/mapvis/layers/icon-layer/IconLayer.tsx
@@ -4,7 +4,7 @@ import { IconLayer } from '@deck.gl/layers/typed';
 import { getProperty } from '../../utlis';
 import * as d3 from 'd3';
 import IconOptions from './IconOptions';
-import { LayerProps } from '../../Types';
+import { LayerProps } from '../../types';
 
 // TODO: Make icons based on node property
 
@@ -43,7 +43,7 @@ export class NodeIconLayer extends CompositeLayer<LayerProps> {
         getPosition: (d: any) => [d.attributes.long, d.attributes.lat],
         getSize: (d: any) => 5,
         getColor: (d: any) => [Math.sqrt(d.exits), 140, 0],
-      })
+      }),
     );
   }
 }
diff --git a/libs/shared/lib/vis/visualizations/mapvis/layers/node-layer/NodeLayer.tsx b/libs/shared/lib/vis/visualizations/mapvis/layers/node-layer/NodeLayer.tsx
index 50ec26226..73c0cc4d4 100644
--- a/libs/shared/lib/vis/visualizations/mapvis/layers/node-layer/NodeLayer.tsx
+++ b/libs/shared/lib/vis/visualizations/mapvis/layers/node-layer/NodeLayer.tsx
@@ -4,7 +4,7 @@ import { ScatterplotLayer } from '@deck.gl/layers/typed';
 import { getProperty } from '../../utlis';
 import * as d3 from 'd3';
 import NodeOptions from './NodeOptions';
-import { Node, LayerProps } from '../../Types';
+import { Node, LayerProps } from '../../types';
 
 export const NodeLayerConfig = {
   colisionFilter: true,
diff --git a/libs/shared/lib/vis/visualizations/mapvis/layers/nodelink-layer/NodeLinkLayer.tsx b/libs/shared/lib/vis/visualizations/mapvis/layers/nodelink-layer/NodeLinkLayer.tsx
index bf2e7b214..19b497c79 100644
--- a/libs/shared/lib/vis/visualizations/mapvis/layers/nodelink-layer/NodeLinkLayer.tsx
+++ b/libs/shared/lib/vis/visualizations/mapvis/layers/nodelink-layer/NodeLinkLayer.tsx
@@ -4,7 +4,7 @@ import { IconLayer, LineLayer, TextLayer } from '@deck.gl/layers/typed';
 import NodeLinkOptions from './NodeLinkOptions';
 import { createIcon } from './shapeFactory';
 import { getProperty } from '../../utlis';
-import { Edge, Node, LayerProps } from '../../Types';
+import { Edge, Node, LayerProps } from '../../types';
 
 export const NodeLinkConfig = {
   showLabels: false,
@@ -63,8 +63,8 @@ export class NodeLinkLayer extends CompositeLayer<LayerProps> {
             };
           },
           mask: true,
-        })
-      )
+        }),
+      ),
     );
 
     if (this.props.selected.length > 0) {
@@ -94,7 +94,7 @@ export class NodeLinkLayer extends CompositeLayer<LayerProps> {
             },
             mask: true,
             getColor: (d: any) => [200, 140, 0],
-          })
+          }),
         ),
         new IconLayer(
           this.getSubLayerProps({
@@ -117,7 +117,7 @@ export class NodeLinkLayer extends CompositeLayer<LayerProps> {
             },
             mask: true,
             getColor: (d: any) => [200, 140, 0],
-          })
+          }),
         ),
         new LineLayer(
           this.getSubLayerProps({
@@ -128,7 +128,7 @@ export class NodeLinkLayer extends CompositeLayer<LayerProps> {
             getSourcePosition: (d: any) => graph.getNodeLocation(d.from),
             getTargetPosition: (d: any) => graph.getNodeLocation(d.to),
             getColor: (d: any) => [0, 0, 0],
-          })
+          }),
         ),
         new TextLayer(
           this.getSubLayerProps({
@@ -142,7 +142,7 @@ export class NodeLinkLayer extends CompositeLayer<LayerProps> {
             background: true,
             getBackgroundColor: [255, 125, 0],
             getPixelOffset: [10, 10],
-          })
+          }),
         ),
         new TextLayer(
           this.getSubLayerProps({
@@ -155,7 +155,7 @@ export class NodeLinkLayer extends CompositeLayer<LayerProps> {
             getAlignmentBaseline: 'top',
             background: true,
             getPixelOffset: [10, 10],
-          })
+          }),
         ),
       ]);
     }
@@ -171,8 +171,8 @@ export class NodeLinkLayer extends CompositeLayer<LayerProps> {
             getSourcePosition: (d: any) => graph.getNodeLocation(d.from),
             getTargetPosition: (d: any) => graph.getNodeLocation(d.to),
             getColor: (d: any) => [0, 0, 0],
-          })
-        )
+          }),
+        ),
       );
     }
 
diff --git a/libs/shared/lib/vis/visualizations/mapvis/mapvis.stories.tsx b/libs/shared/lib/vis/visualizations/mapvis/mapvis.stories.tsx
index e3194bdbf..a89ba6db0 100644
--- a/libs/shared/lib/vis/visualizations/mapvis/mapvis.stories.tsx
+++ b/libs/shared/lib/vis/visualizations/mapvis/mapvis.stories.tsx
@@ -1,21 +1,23 @@
 import React from 'react';
 import { Meta } from '@storybook/react';
-import { VisualizationPanel } from '../../visualizationPanel';
 import { Provider } from 'react-redux';
 import { configureStore } from '@reduxjs/toolkit';
-import {
-  setNewGraphQueryResult,
-  graphQueryResultSlice,
-  querybuilderSlice,
-  schemaSlice,
-  visualizationSlice,
-} from '../../../data-access/store';
+import { graphQueryResultSlice, querybuilderSlice, schemaSlice, visualizationSlice } from '../../../data-access/store';
 import { mockMobilityQueryResult, bigMockQueryResults } from '../../../mock-data';
-import { setActiveVisualization } from '@graphpolaris/shared/lib/data-access/store/visualizationSlice';
+import { MapComponent } from './mapvis';
 
-const Component: Meta<typeof VisualizationPanel> = {
+const Mockstore = configureStore({
+  reducer: {
+    schema: schemaSlice.reducer,
+    graphQueryResult: graphQueryResultSlice.reducer,
+    visualize: visualizationSlice.reducer,
+    querybuilder: querybuilderSlice.reducer,
+  },
+});
+
+const Component: Meta<typeof MapComponent.component> = {
   title: 'Visualizations/MapVis',
-  component: VisualizationPanel,
+  component: MapComponent.component,
   decorators: [
     (story) => (
       <Provider store={Mockstore}>
@@ -32,28 +34,15 @@ const Component: Meta<typeof VisualizationPanel> = {
   ],
 };
 
-const Mockstore = configureStore({
-  reducer: {
-    schema: schemaSlice.reducer,
-    graphQueryResult: graphQueryResultSlice.reducer,
-    visualize: visualizationSlice.reducer,
-    querybuilder: querybuilderSlice.reducer,
-  },
-});
-
 export const DutchVehicleTheft = {
-  play: async () => {
-    const dispatch = Mockstore.dispatch;
-    dispatch(setNewGraphQueryResult({ queryID: '1', result: { type: 'nodelink', payload: mockMobilityQueryResult } }));
-    dispatch(setActiveVisualization('MapVis'));
+  args: {
+    data: mockMobilityQueryResult,
   },
 };
 
 export const AmericanFlights = {
-  play: async () => {
-    const dispatch = Mockstore.dispatch;
-    dispatch(setNewGraphQueryResult({ queryID: '1', result: { type: 'nodelink', payload: bigMockQueryResults } }));
-    dispatch(setActiveVisualization('MapVis'));
+  args: {
+    data: bigMockQueryResults,
   },
 };
 
diff --git a/libs/shared/lib/vis/visualizations/mapvis/mapvis.tsx b/libs/shared/lib/vis/visualizations/mapvis/mapvis.tsx
index 20d218005..0562b8118 100644
--- a/libs/shared/lib/vis/visualizations/mapvis/mapvis.tsx
+++ b/libs/shared/lib/vis/visualizations/mapvis/mapvis.tsx
@@ -1,12 +1,15 @@
 import React from 'react';
 import { MapPanel, LayerPanel } from './components';
 import GraphModel from './graphModel';
-import { GraphType, Layer } from './Types';
-import { VISComponentType, VisualizationPropTypes } from '../../types';
+import { GraphType, Layer } from './types';
+import { VISComponentType, VisualizationPropTypes } from '../../common';
+import { GraphMetaData } from '@graphpolaris/shared/lib/data-access/statistics';
 
 export type MapProps = {};
 
-export default function MapVis({ data, schema, settings }: VisualizationPropTypes) {
+const configuration: MapProps = {};
+
+export default function MapVis({ data }: VisualizationPropTypes) {
   const [layers, setLayers] = React.useState<Layer[]>([]);
   const [showFilter, setShowFilter] = React.useState<boolean>(false);
 
@@ -31,8 +34,21 @@ export default function MapVis({ data, schema, settings }: VisualizationPropType
   );
 }
 
+const MapSettings = ({
+  configuration,
+  graph,
+  updateSettings,
+}: {
+  configuration: MapProps;
+  graph: GraphMetaData;
+  updateSettings: (val: any) => void;
+}) => {
+  return <div>To be implemented</div>;
+};
+
 export const MapComponent: VISComponentType = {
-  displayName: 'Map',
-  VIS: MapVis,
-  settings: {},
+  displayName: 'MapVis',
+  component: MapVis,
+  settings: MapSettings,
+  configuration: configuration,
 };
diff --git a/libs/shared/lib/vis/visualizations/mapvis/Types.tsx b/libs/shared/lib/vis/visualizations/mapvis/types.ts
similarity index 100%
rename from libs/shared/lib/vis/visualizations/mapvis/Types.tsx
rename to libs/shared/lib/vis/visualizations/mapvis/types.ts
diff --git a/libs/shared/lib/vis/visualizations/mapvis/utlis.tsx b/libs/shared/lib/vis/visualizations/mapvis/utlis.tsx
index 23ee31499..8f5e38de3 100644
--- a/libs/shared/lib/vis/visualizations/mapvis/utlis.tsx
+++ b/libs/shared/lib/vis/visualizations/mapvis/utlis.tsx
@@ -1,4 +1,4 @@
-import { Coordinate, Layer } from './Types';
+import { Coordinate, Layer } from './types';
 import { layerTypes } from './layers';
 import { Layer as DeckLayer } from '@deck.gl/core/typed';
 
diff --git a/libs/shared/lib/vis/visualizations/matrixvis/components/MatrixPixi.tsx b/libs/shared/lib/vis/visualizations/matrixvis/components/MatrixPixi.tsx
index 5c48d1f27..1eddd255b 100644
--- a/libs/shared/lib/vis/visualizations/matrixvis/components/MatrixPixi.tsx
+++ b/libs/shared/lib/vis/visualizations/matrixvis/components/MatrixPixi.tsx
@@ -16,15 +16,15 @@ import {
   Texture,
 } from 'pixi.js';
 import { useEffect, useRef, useState } from 'react';
-import { LinkType, NodeType } from '../Types';
+import { LinkType, NodeType } from '../types';
 import { NLPopup } from './MatrixPopup';
 
 import { Actions, Interpolations } from 'pixi-actions';
 
 import Color from 'color';
-import { SettingTypes } from '../../../configuration/settings';
 import { createColumn } from './ColumnGraphicsComponent';
 import { ReorderingManager } from './ReorderingManager';
+import { VisualizationConfiguration } from '../../../common';
 
 type Props = {
   // onClick: (node: NodeType, pos: IPointData) => void;
@@ -34,7 +34,7 @@ type Props = {
   currentShortestPathEdges?: LinkType[];
   highlightedLinks?: LinkType[];
   graph?: GraphQueryResult;
-  localConfig: SettingTypes;
+  configuration: VisualizationConfiguration;
 };
 
 const app = new Application({ background: 0xffffff, antialias: true, autoDensity: true, eventMode: 'auto' });
@@ -108,7 +108,6 @@ export const MatrixPixi = (props: Props) => {
   }, [ref]);
 
   useEffect(() => {
-    console.log('graph change');
     // console.log('graph changed', props.graph, ref.current, ref.current.children.length > 0, imperative.current);
     if (props.graph && ref.current && ref.current.children.length > 0) {
       if (!isSetup.current) setup();
@@ -117,12 +116,11 @@ export const MatrixPixi = (props: Props) => {
   }, [props.graph]);
 
   useEffect(() => {
-    console.log('config change');
     // console.log('graph changed', props.graph, ref.current, ref.current.children.length > 0, imperative.current);
     if (props.graph && ref.current && ref.current.children.length > 0) {
       setup();
     }
-  }, [props.localConfig]);
+  }, [props.configuration]);
 
   // TODO implement search results
   // useEffect(() => {
@@ -145,7 +143,7 @@ export const MatrixPixi = (props: Props) => {
 
   function onButtonDown(event: FederatedPointerEvent) {
     console.log(
-      event.currentTarget
+      event.currentTarget,
       // graph.nodes.find((node) => node.id === event.currentTarget.name)
     );
   }
@@ -200,7 +198,6 @@ export const MatrixPixi = (props: Props) => {
       col.alpha = 0.25;
     });
 
-    // console.log(event.currentTarget);
     const edgesForThisColumn = props.graph.edges.filter((edge) => {
       return edge.from === currentNode.id || edge.to === currentNode.id;
     });
@@ -231,7 +228,7 @@ export const MatrixPixi = (props: Props) => {
 
     if (columnTextPositions.length !== columnPositions.length)
       throw new Error(
-        'columnTextPositions and columnPositions have different length ' + columnTextPositions.length + ' / ' + columnPositions.length
+        'columnTextPositions and columnPositions have different length ' + columnTextPositions.length + ' / ' + columnPositions.length,
       );
 
     for (let i = 0; i < columns.length; i++) {
@@ -257,7 +254,7 @@ export const MatrixPixi = (props: Props) => {
     rowOrder: string[],
     colorScale: any,
     cellWidth: number,
-    cellHeight: number
+    cellHeight: number,
   ) => {
     const rows = rowsContainer.children;
     let rowPositions: Point[] = [];
@@ -278,7 +275,6 @@ export const MatrixPixi = (props: Props) => {
     }
 
     const colOrder = columnsContainer.children.map((col) => col.name) as string[];
-    console.log('colOrder', colOrder);
     if (!colOrder) throw new Error('colOrder is undefined');
     columnsContainer.removeChildren();
     setupColumns(edges, colOrder, rowOrder);
@@ -306,18 +302,18 @@ export const MatrixPixi = (props: Props) => {
     viewport.current.addChild(columnsContainer);
     viewport.current.addChild(rowsContainer);
 
-    const groupByType = props.graph.nodes.reduce((group: any, node: Node) => {
-      if (!group[node.label]) group[node.label] = [];
-      group[node.label].push(node);
-      return group;
-    }, {} as { [key: string]: Node[] });
+    const groupByType = props.graph.nodes.reduce(
+      (group: any, node: Node) => {
+        if (!group[node.label]) group[node.label] = [];
+        group[node.label].push(node);
+        return group;
+      },
+      {} as { [key: string]: Node[] },
+    );
 
     // order groupByType by size
     const ordered = Object.entries(groupByType).sort((a: any[], b: any[]) => b[1].length - a[1].length);
 
-    // console.log('ordered', ordered);
-    // console.log('edges', props.graph.edges);
-
     let cols = [] as Node[];
     let rows = [] as Node[];
     if (ordered.length == 2) {
@@ -348,9 +344,7 @@ export const MatrixPixi = (props: Props) => {
     config.cellWidth = Math.max((size?.width || 1000) / props.graph.nodes.length, (size?.height || 1000) / props.graph.nodes.length);
     config.cellHeight = config.cellWidth;
 
-    // console.log('currentColumnOrder', columnOrder);
-
-    setupVisualizationEncodingMapping(props.localConfig);
+    setupVisualizationEncodingMapping(props.configuration);
 
     setupColumns(props.graph.edges, columnOrder, rowOrder);
     setupColumnLegend(columnOrder);
@@ -359,7 +353,7 @@ export const MatrixPixi = (props: Props) => {
     setupRowLegend(rows, rowOrder);
     setupRowInteractivity(cols, rows, rowOrder, d3.scaleOrdinal(d3.schemeCategory10));
 
-    console.log('setup matrixvis with graph:', props.graph);
+    console.debug('setup matrixvis with graph:', props.graph);
 
     // activate plugins
     viewport.current.drag().pinch().wheel().animate({}).decelerate({ friction: 0.75 });
@@ -369,7 +363,7 @@ export const MatrixPixi = (props: Props) => {
     isSetup.current = true;
   };
 
-  const setupVisualizationEncodingMapping = (localConfig: SettingTypes) => {
+  const setupVisualizationEncodingMapping = (configuration: VisualizationConfiguration) => {
     if (!props.graph) throw new Error('Graph is undefined; cannot setup matrix');
     const visMapping = []; // TODO type
 
@@ -381,7 +375,7 @@ export const MatrixPixi = (props: Props) => {
     const adjacenyScale = d3.scaleLinear([colorNeutral, tailwindColors.entity.DEFAULT]);
     visMapping.push({
       attribute: 'adjacency',
-      encoding: localConfig.marks,
+      encoding: configuration.marks,
       colorScale: adjacenyScale,
       renderFunction: function (i: number, color: ColorSource, gfxContext: Graphics) {
         gfxContext.beginFill(color, 1);
@@ -440,7 +434,6 @@ export const MatrixPixi = (props: Props) => {
       const edgesForThisColumn = edges.filter((edge) => {
         return edge.from === oneColumn.name || edge.to === oneColumn.name;
       });
-      // console.log('edgesForThisColumn', oneColumn.name, edgesForThisColumn);
 
       const col = createColumn(rowOrder, edgesForThisColumn, config.visMapping, config.cellWidth, config.cellHeight);
       oneColumn.addChild(col);
@@ -468,7 +461,6 @@ export const MatrixPixi = (props: Props) => {
   };
 
   const setupColumnLegend = (columnOrder: string[]) => {
-    // console.log('setupColumnLegend');
     // columnAxisContainer.removeChildren();
     columnAxisContainer.position.set(config.textOffsetX, 0);
     for (let j = 0; j < columnOrder.length; j++) {
diff --git a/libs/shared/lib/vis/visualizations/matrixvis/components/MatrixPopup.tsx b/libs/shared/lib/vis/visualizations/matrixvis/components/MatrixPopup.tsx
index cab6d5b29..ae0cf66b5 100644
--- a/libs/shared/lib/vis/visualizations/matrixvis/components/MatrixPopup.tsx
+++ b/libs/shared/lib/vis/visualizations/matrixvis/components/MatrixPopup.tsx
@@ -1,5 +1,5 @@
 import { IPointData } from 'pixi.js';
-import { NodeType } from '../Types';
+import { NodeType } from '../types';
 
 export type NodelinkPopupProps = {
   data: { node: NodeType; pos: IPointData };
diff --git a/libs/shared/lib/vis/visualizations/matrixvis/components/ReorderingManager.tsx b/libs/shared/lib/vis/visualizations/matrixvis/components/ReorderingManager.tsx
index ae69d44e2..da0119c11 100644
--- a/libs/shared/lib/vis/visualizations/matrixvis/components/ReorderingManager.tsx
+++ b/libs/shared/lib/vis/visualizations/matrixvis/components/ReorderingManager.tsx
@@ -110,7 +110,7 @@ export class ReorderingManager {
           ...node,
           index: 0,
           weight: 0,
-        } as any)
+        }) as any,
     );
 
     const nodes = columnOrder.map((id) => nodesTemp.find((node) => node.id === id));
@@ -190,7 +190,6 @@ export class ReorderingManager {
   };
 
   public reorderMatrix = (orderingname = 'leafordering', columnOrder: string[], rowOrder: string[]) => {
-    console.log('reorderMatrix', orderingname);
     switch (orderingname.toLowerCase()) {
       case 'leafordering': {
         return this.computeLeaforder(columnOrder, rowOrder);
diff --git a/libs/shared/lib/vis/visualizations/matrixvis/matrix.stories.tsx b/libs/shared/lib/vis/visualizations/matrixvis/matrix.stories.tsx
index f6d1db554..5fdecb241 100644
--- a/libs/shared/lib/vis/visualizations/matrixvis/matrix.stories.tsx
+++ b/libs/shared/lib/vis/visualizations/matrixvis/matrix.stories.tsx
@@ -3,7 +3,7 @@ import { Meta } from '@storybook/react';
 import { configureStore } from '@reduxjs/toolkit';
 import { Provider } from 'react-redux';
 import { big2ndChamberQueryResult, smallFlightsQueryResults, mockLargeQueryResults } from '../../../mock-data';
-import { VisualizationPanel } from '../../visualizationPanel';
+import { VisualizationPanel } from '../../components/panel';
 
 import {
   setNewGraphQueryResult,
@@ -17,10 +17,11 @@ import {
 import { SchemaUtils } from '../../../schema/schema-utils';
 import { simpleSchemaAirportRaw } from '../../../mock-data/schema/simpleAirportRaw';
 import { setActiveVisualization } from '@graphpolaris/shared/lib/data-access/store/visualizationSlice';
+import MatrixVisComponent from './matrixvis';
 
-const Component: Meta<typeof VisualizationPanel> = {
+const Component: Meta<typeof MatrixVisComponent.component> = {
   title: 'Visualizations/MatrixVis',
-  component: VisualizationPanel,
+  component: MatrixVisComponent.component,
   decorators: [
     (story) => (
       <Provider store={Mockstore}>
@@ -49,75 +50,55 @@ const Mockstore: any = configureStore({
 export const TestWithData = {
   layout: 'fullscreen',
   args: {
-    loading: false,
+    data: {
+      nodes: [
+        { id: 'agent/007', attributes: { name: 'Daniel Craig' } },
+        { id: 'villain', attributes: { name: 'Le Chiffre' } },
+      ],
+      edges: [{ id: 'escape/escape', from: 'agent/007', to: 'villain', attributes: { name: 'Escape' } }],
+    },
+    ml: {},
+    configuration: MatrixVisComponent.configuration,
   },
   play: async () => {
-    const dispatch = Mockstore.dispatch;
-    const schema = SchemaUtils.schemaBackend2Graphology(simpleSchemaAirportRaw);
-    dispatch(setSchema(schema.export()));
-    dispatch(
-      setNewGraphQueryResult({
-        queryID: '1',
-        result: {
-          type: 'nodelink',
-          payload: {
-            nodes: [
-              { id: 'agent/007', attributes: { name: 'Daniel Craig' } },
-              { id: 'villain', attributes: { name: 'Le Chiffre' } },
-            ],
-            edges: [{ id: 'escape/escape', from: 'agent/007', to: 'villain', attributes: { name: 'Escape' } }],
-          },
-        },
-      }),
-    );
-    dispatch(setActiveVisualization('MatrixVis'));
+    // const dispatch = Mockstore.dispatch;
+    // const schema = SchemaUtils.schemaBackend2Graphology(simpleSchemaAirportRaw);
+    // dispatch(setSchema(schema.export()));
   },
 };
 
 export const TestWithNoData = {
-  args: { loading: false },
-  play: async () => {
-    const dispatch = Mockstore.dispatch;
-    dispatch(
-      setNewGraphQueryResult({
-        queryID: '1',
-        result: {
-          type: 'nodelink',
-          payload: {
-            nodes: [],
-            edges: [],
-          },
-        },
-      }),
-    );
-    dispatch(setActiveVisualization('MatrixVis'));
+  args: {
+    data: {
+      nodes: [],
+      edges: [],
+    },
+    ml: {},
+    configuration: MatrixVisComponent.configuration,
   },
 };
 
 export const TestWithBig2ndChamber = {
-  args: { loading: false },
-  play: async () => {
-    const dispatch = Mockstore.dispatch;
-    dispatch(setNewGraphQueryResult({ queryID: '1', result: { type: 'nodelink', payload: big2ndChamberQueryResult } }));
-    dispatch(setActiveVisualization('MatrixVis'));
+  args: {
+    data: big2ndChamberQueryResult,
+    ml: {},
+    configuration: MatrixVisComponent.configuration,
   },
 };
 
 export const TestWithSmallFlights = {
-  args: { loading: false },
-  play: async () => {
-    const dispatch = Mockstore.dispatch;
-    dispatch(setNewGraphQueryResult({ queryID: '1', result: { type: 'nodelink', payload: smallFlightsQueryResults } }));
-    dispatch(setActiveVisualization('MatrixVis'));
+  args: {
+    data: smallFlightsQueryResults,
+    ml: {},
+    configuration: MatrixVisComponent.configuration,
   },
 };
 
 export const TestWithLargeQueryResult = {
-  args: { loading: false },
-  play: async () => {
-    const dispatch = Mockstore.dispatch;
-    dispatch(setNewGraphQueryResult({ queryID: '1', result: { type: 'nodelink', payload: mockLargeQueryResults } }));
-    dispatch(setActiveVisualization('MatrixVis'));
+  args: {
+    data: mockLargeQueryResults,
+    ml: {},
+    configuration: MatrixVisComponent.configuration,
   },
 };
 
diff --git a/libs/shared/lib/vis/visualizations/matrixvis/matrixvis.tsx b/libs/shared/lib/vis/visualizations/matrixvis/matrixvis.tsx
index 911a5fbae..b5ee7fe95 100644
--- a/libs/shared/lib/vis/visualizations/matrixvis/matrixvis.tsx
+++ b/libs/shared/lib/vis/visualizations/matrixvis/matrixvis.tsx
@@ -1,11 +1,25 @@
 import React, { useEffect, useRef, useState } from 'react';
 import { useImmer } from 'use-immer';
 import { GraphQueryResult } from '../../../data-access/store';
-import { LinkType, NodeType } from './Types';
+import { LinkType, NodeType } from './types';
 import { MatrixPixi } from './components/MatrixPixi';
-import { VisualizationPropTypes, VISComponentType } from '../../types';
+import { VisualizationPropTypes, VISComponentType } from '../../common';
+import { Input } from '@graphpolaris/shared/lib/components/inputs';
+import { GraphMetaData } from '@graphpolaris/shared/lib/data-access/statistics';
+import { SettingsContainer } from '@graphpolaris/shared/lib/vis/components/config';
+import { dataColors, tailwindColors } from 'config';
 
-export const MatrixVis = React.memo(({ data, ml, settings }: VisualizationPropTypes) => {
+export interface MatrixVisProps {
+  marks: string;
+  color: string;
+}
+
+const configuration: MatrixVisProps = {
+  marks: 'rect',
+  color: 'blue',
+};
+
+export const MatrixVis = React.memo(({ data, ml, configuration }: VisualizationPropTypes) => {
   const ref = useRef<HTMLDivElement>(null);
   const [graph, setGraph] = useImmer<GraphQueryResult | undefined>(undefined);
   const [highlightNodes, setHighlightNodes] = useState<NodeType[]>([]);
@@ -20,25 +34,47 @@ export const MatrixVis = React.memo(({ data, ml, settings }: VisualizationPropTy
   return (
     <>
       <div className="h-full w-full overflow-hidden" ref={ref}>
-        <MatrixPixi graph={graph} highlightNodes={highlightNodes} highlightedLinks={highlightedLinks} localConfig={settings} />
+        <MatrixPixi graph={graph} highlightNodes={highlightNodes} highlightedLinks={highlightedLinks} configuration={configuration} />
       </div>
     </>
   );
 });
 
-const displayName = 'MatrixVis';
+const MatrixSettings = ({
+  configuration,
+  graph,
+  updateSettings,
+}: {
+  configuration: MatrixVisProps;
+  graph: GraphMetaData;
+  updateSettings: (val: any) => void;
+}) => {
+  return (
+    <SettingsContainer>
+      <Input
+        type="dropdown"
+        label="Configure marks"
+        value={configuration.marks}
+        options={['rect', 'circle']}
+        onChange={(val) => updateSettings({ marks: val })}
+      />
+
+      <Input
+        type="dropdown"
+        label="Color"
+        value={configuration.color}
+        options={['blue', 'green']}
+        onChange={(val) => updateSettings({ color: val })}
+      />
+    </SettingsContainer>
+  );
+};
 
 export const MatrixVisComponent: VISComponentType = {
-  displayName: displayName,
-  VIS: MatrixVis,
-  settings: {
-    marks: {
-      type: 'dropdown',
-      options: ['rect', 'circle'],
-      value: 'rect',
-      label: 'Configure Marks',
-    },
-  },
+  displayName: 'MatrixVis',
+  component: MatrixVis,
+  settings: MatrixSettings,
+  configuration: configuration,
 };
 
 export default MatrixVisComponent;
diff --git a/libs/shared/lib/vis/visualizations/matrixvis/Types.tsx b/libs/shared/lib/vis/visualizations/matrixvis/types.ts
similarity index 92%
rename from libs/shared/lib/vis/visualizations/matrixvis/Types.tsx
rename to libs/shared/lib/vis/visualizations/matrixvis/types.ts
index 4103fa516..c8f6bec1d 100644
--- a/libs/shared/lib/vis/visualizations/matrixvis/Types.tsx
+++ b/libs/shared/lib/vis/visualizations/matrixvis/types.ts
@@ -76,17 +76,17 @@ export type TypeNode = {
   name: string; //Collection name
   attributes: string[]; //attributes. This includes all attributes found in the collection
   type: number | undefined; //number that represents collection of node, for colorscheme
-  visualisations: Visualisation[]; //The way to visualize attributes of this Node kind
+  visualisations: Visualization[]; //The way to visualize attributes of this Node kind
 };
 
 export type CommunityDetectionNode = {
   cluster: number; //group as used by colouring scheme
 };
 
-/**Visualisation holds the visualisation method for an attribute */
-export type Visualisation = {
+/**Visualization holds the visualization method for an attribute */
+export type Visualization = {
   attribute: string; //attribute type      (e.g. 'age')
-  vis: string; //visualisation type  (e.g. 'radius')
+  vis: string; //visualization type  (e.g. 'radius')
 };
 
 /** possible colors to pick from*/
diff --git a/libs/shared/lib/vis/visualizations/nodelinkvis/components/NLMachineLearning.tsx b/libs/shared/lib/vis/visualizations/nodelinkvis/components/NLMachineLearning.tsx
index 7f51d9148..6ac50ebe2 100644
--- a/libs/shared/lib/vis/visualizations/nodelinkvis/components/NLMachineLearning.tsx
+++ b/libs/shared/lib/vis/visualizations/nodelinkvis/components/NLMachineLearning.tsx
@@ -1,6 +1,4 @@
 import { useState } from 'react';
-import { AttributeData, NodeAttributeData } from '../../../shared/InputDataTypes';
-import { AttributeCategory } from '../../../shared/Types';
 import { GraphType, LinkType, NodeType } from '../types';
 import { ML } from '../../../../data-access/store/mlSlice';
 
diff --git a/libs/shared/lib/vis/visualizations/nodelinkvis/components/NLPixi.tsx b/libs/shared/lib/vis/visualizations/nodelinkvis/components/NLPixi.tsx
index df4e62737..983a2713d 100644
--- a/libs/shared/lib/vis/visualizations/nodelinkvis/components/NLPixi.tsx
+++ b/libs/shared/lib/vis/visualizations/nodelinkvis/components/NLPixi.tsx
@@ -9,12 +9,14 @@ import { NLPopup } from './NLPopup';
 import { hslStringToHex, nodeColor } from './utils';
 import { CytoscapeLayout, GraphologyLayout, LayoutFactory, Layouts } from '../../../../graph-layout';
 import { MultiGraph } from 'graphology';
+import { VisualizationConfiguration } from '../../../common';
 
 type Props = {
   onClick: (node: NodeType, pos: IPointData) => void;
   // onHover: (data: { node: NodeType; pos: IPointData }) => void;
   // onUnHover: (data: { node: NodeType; pos: IPointData }) => void;
   highlightNodes: NodeType[];
+  configuration: VisualizationConfiguration;
   currentShortestPathEdges?: LinkType[];
   highlightedLinks?: LinkType[];
   graph?: GraphType;
@@ -398,7 +400,6 @@ export const NLPixi = (props: Props) => {
 
   useEffect(() => {
     if (props.graph && ref.current && ref.current.children.length > 0 && imperative.current) {
-      console.log(props.graph);
       if (isSetup.current === false) setup();
       else update(false);
     }
diff --git a/libs/shared/lib/vis/visualizations/nodelinkvis/nodelinkvis.stories.tsx b/libs/shared/lib/vis/visualizations/nodelinkvis/nodelinkvis.stories.tsx
index 72719dc5a..a19fe1e7f 100644
--- a/libs/shared/lib/vis/visualizations/nodelinkvis/nodelinkvis.stories.tsx
+++ b/libs/shared/lib/vis/visualizations/nodelinkvis/nodelinkvis.stories.tsx
@@ -1,13 +1,6 @@
 import React from 'react';
 import { Meta } from '@storybook/react';
-import { VisualizationPanel } from '../../visualizationPanel';
-import {
-  setNewGraphQueryResult,
-  graphQueryResultSlice,
-  querybuilderSlice,
-  schemaSlice,
-  visualizationSlice,
-} from '../../../data-access/store';
+import { graphQueryResultSlice, querybuilderSlice, schemaSlice, visualizationSlice } from '../../../data-access/store';
 import { configureStore } from '@reduxjs/toolkit';
 import { Provider } from 'react-redux';
 import {
@@ -17,11 +10,20 @@ import {
   recommendationPersonActedInMovieQueryResultPayload,
   slackReactionToThreadedMessageQueryResultPayload,
 } from '../../../mock-data';
-import { setActiveVisualization } from '@graphpolaris/shared/lib/data-access/store/visualizationSlice';
+import { NodeLinkComponent } from './nodelinkvis';
 
-const Component: Meta<typeof VisualizationPanel> = {
+const Mockstore = configureStore({
+  reducer: {
+    schema: schemaSlice.reducer,
+    graphQueryResult: graphQueryResultSlice.reducer,
+    visualize: visualizationSlice.reducer,
+    querybuilder: querybuilderSlice.reducer,
+  },
+});
+
+const Component: Meta<typeof NodeLinkComponent.component> = {
   title: 'Visualizations/NodeLinkVis',
-  component: VisualizationPanel,
+  component: NodeLinkComponent.component,
   decorators: [
     (story) => (
       <Provider store={Mockstore}>
@@ -38,127 +40,93 @@ const Component: Meta<typeof VisualizationPanel> = {
   ],
 };
 
-const Mockstore = configureStore({
-  reducer: {
-    schema: schemaSlice.reducer,
-    graphQueryResult: graphQueryResultSlice.reducer,
-    visualize: visualizationSlice.reducer,
-    querybuilder: querybuilderSlice.reducer,
-  },
-});
-
 export const TestWithData = {
-  layout: 'fullscreen',
-  play: async () => {
-    const dispatch = Mockstore.dispatch;
-
-    dispatch(
-      setNewGraphQueryResult({
-        queryID: '1',
-        result: {
-          type: 'nodelink',
-          payload: {
-            nodes: [
-              { id: 'agent/007', attributes: { name: 'Daniel Craig' } },
-              { id: 'villain', attributes: { name: 'Le Chiffre' } },
-            ],
-            edges: [{ id: 'escape/escape', from: 'agent/007', to: 'villain', attributes: { name: 'Escape' } }],
-          },
-        },
-      }),
-    );
-    dispatch(setActiveVisualization('NodeLinkVis'));
+  args: {
+    data: {
+      nodes: [
+        { id: 'agent/007', attributes: { name: 'Daniel Craig' } },
+        { id: 'villain', attributes: { name: 'Le Chiffre' } },
+      ],
+      edges: [{ id: 'escape/escape', from: 'agent/007', to: 'villain', attributes: { name: 'Escape' } }],
+    },
+    ml: {},
+    configuration: NodeLinkComponent.configuration,
+    dispatch: () => {},
   },
 };
 
 export const TestWithDoubleArchData = {
-  layout: 'fullscreen',
-  play: async () => {
-    const dispatch = Mockstore.dispatch;
-
-    dispatch(
-      setNewGraphQueryResult({
-        queryID: '1',
-        result: {
-          type: 'nodelink',
-          payload: {
-            nodes: [
-              { id: 'agent/007', attributes: { name: 'Daniel Craig' } },
-              { id: 'villain', attributes: { name: 'Le Chiffre' } },
-            ],
-            edges: [
-              { id: 'escape/escape', from: 'agent/007', to: 'villain', attributes: { name: 'Escape' } },
-              { id: 'escape/escape', to: 'agent/007', from: 'villain', attributes: { name: 'Escape' } },
-            ],
-          },
-        },
-      }),
-    );
-    dispatch(setActiveVisualization(Visualizations.NodeLink));
+  args: {
+    data: {
+      nodes: [
+        { id: 'agent/007', attributes: { name: 'Daniel Craig' } },
+        { id: 'villain', attributes: { name: 'Le Chiffre' } },
+      ],
+      edges: [
+        { id: 'escape/escape', from: 'agent/007', to: 'villain', attributes: { name: 'Escape' } },
+        { id: 'escape/escape', to: 'agent/007', from: 'villain', attributes: { name: 'Escape' } },
+      ],
+    },
+    ml: {},
+    configuration: NodeLinkComponent.configuration,
+    dispatch: () => {},
   },
 };
 
 export const TestWithNoData = {
-  args: { loading: false },
-  play: async () => {
-    const dispatch = Mockstore.dispatch;
-    dispatch(
-      setNewGraphQueryResult({
-        queryID: '1',
-        result: {
-          type: 'nodelink',
-          payload: {
-            nodes: [],
-            edges: [],
-          },
-        },
-      }),
-    );
-    dispatch(setActiveVisualization('NodeLinkVis'));
+  args: {
+    data: {
+      nodes: [],
+      edges: [],
+    },
+    ml: {},
+    configuration: NodeLinkComponent.configuration,
+    dispatch: () => {},
   },
 };
 
 export const TestWithBig2ndChamber = {
-  play: async () => {
-    const dispatch = Mockstore.dispatch;
-    dispatch(setNewGraphQueryResult({ queryID: '1', result: { type: 'nodelink', payload: big2ndChamberQueryResult } }));
-    dispatch(setActiveVisualization('NodeLinkVis'));
+  args: {
+    data: big2ndChamberQueryResult,
+    ml: {},
+    configuration: NodeLinkComponent.configuration,
+    dispatch: () => {},
   },
 };
 
 export const TestWithSmallFlights = {
-  args: { loading: false },
-  play: async () => {
-    const dispatch = Mockstore.dispatch;
-    dispatch(setNewGraphQueryResult({ queryID: '1', result: { type: 'nodelink', payload: smallFlightsQueryResults } }));
-    dispatch(setActiveVisualization('NodeLinkVis'));
+  args: {
+    data: smallFlightsQueryResults,
+    ml: {},
+    configuration: NodeLinkComponent.configuration,
+    dispatch: () => {},
   },
 };
 
 export const TestWithLargeQueryResult = {
-  args: { loading: false },
-  play: async () => {
-    const dispatch = Mockstore.dispatch;
-    dispatch(setNewGraphQueryResult({ queryID: '1', result: { type: 'nodelink', payload: mockLargeQueryResults } }));
-    dispatch(setActiveVisualization('NodeLinkVis'));
+  args: {
+    data: mockLargeQueryResults,
+    ml: {},
+    configuration: NodeLinkComponent.configuration,
+    dispatch: () => {},
   },
 };
 
 export const TestWithRecommendationPersonActedInMovieQueryResult = {
-  args: { loading: false },
-  play: async () => {
-    const dispatch = Mockstore.dispatch;
-    dispatch(setNewGraphQueryResult(recommendationPersonActedInMovieQueryResultPayload));
-    dispatch(setActiveVisualization(Visualizations.NodeLink));
+  args: {
+    data: recommendationPersonActedInMovieQueryResultPayload.result.payload,
+    ml: {},
+    configuration: NodeLinkComponent.configuration,
+    dispatch: () => {},
   },
 };
 
 export const TestWithSlackReactionToThreadedMessageQueryResult = {
-  args: { loading: false },
-  play: async () => {
-    const dispatch = Mockstore.dispatch;
-    dispatch(setNewGraphQueryResult(slackReactionToThreadedMessageQueryResultPayload));
-    dispatch(setActiveVisualization(Visualizations.NodeLink));
+  args: {
+    data: slackReactionToThreadedMessageQueryResultPayload.result.payload,
+    ml: {},
+    configuration: NodeLinkComponent.configuration,
+    dispatch: () => {},
   },
 };
 
diff --git a/libs/shared/lib/vis/visualizations/nodelinkvis/nodelinkvis.tsx b/libs/shared/lib/vis/visualizations/nodelinkvis/nodelinkvis.tsx
index f9a42c5d5..2af16aca3 100644
--- a/libs/shared/lib/vis/visualizations/nodelinkvis/nodelinkvis.tsx
+++ b/libs/shared/lib/vis/visualizations/nodelinkvis/nodelinkvis.tsx
@@ -4,10 +4,42 @@ import { NLPixi } from './components/NLPixi';
 import { parseQueryResult } from './components/query2NL';
 import { useImmer } from 'use-immer';
 import { ML, setShortestPathSource, setShortestPathTarget } from '../../../data-access/store/mlSlice';
-import { VisualizationPropTypes, VISComponentType } from '../../types';
 import { Layouts } from '../../../graph-layout/types';
+import { Input } from '@graphpolaris/shared/lib/components/inputs';
+import { GraphMetaData } from '@graphpolaris/shared/lib/data-access/statistics';
+import { SettingsContainer, SettingsHeader } from '@graphpolaris/shared/lib/vis/components/config';
+import { VISComponentType, VisualizationPropTypes } from '../../common';
 
-export const NodeLinkVis = React.memo(({ data, ml, dispatch, settings }: VisualizationPropTypes) => {
+export interface NodelinkVisProps {
+  layout: string;
+  showPopUpOnHover: boolean;
+  shapes: {
+    similar: boolean;
+    shape: 'circle' | 'rectangle';
+    shapeMap: { [id: string]: 'circle' | 'rectangle' } | undefined;
+  };
+  edges: {
+    width: {
+      similar: boolean;
+      width: number;
+    };
+  };
+}
+
+const configuration: NodelinkVisProps = {
+  layout: Layouts.FORCEATLAS2WEBWORKER as string,
+  showPopUpOnHover: true,
+  shapes: {
+    similar: true,
+    shape: 'circle',
+    shapeMap: undefined,
+  },
+  edges: {
+    width: { similar: true, width: 0.2 },
+  },
+};
+
+export const NodeLinkVis = React.memo(({ data, ml, dispatch, configuration }: VisualizationPropTypes) => {
   const ref = useRef<HTMLDivElement>(null);
   const [graph, setGraph] = useImmer<GraphType | undefined>(undefined);
   const [highlightNodes, setHighlightNodes] = useState<NodeType[]>([]);
@@ -58,58 +90,104 @@ export const NodeLinkVis = React.memo(({ data, ml, dispatch, settings }: Visuali
   return (
     <NLPixi
       graph={graph}
+      configuration={configuration}
       highlightNodes={highlightNodes}
       highlightedLinks={highlightedLinks}
       onClick={(node, pos) => {
         onClickedNode(node, ml);
       }}
-      layoutAlgorithm={settings.layout}
+      layoutAlgorithm={configuration.layout}
     />
   );
 });
 
+const NodelinkSettings = ({
+  configuration,
+  graph,
+  updateSettings,
+}: {
+  configuration: NodelinkVisProps;
+  graph: GraphMetaData;
+  updateSettings: (val: any) => void;
+}) => {
+  return (
+    <SettingsContainer>
+      <div className="mb-4">
+        <h1 className="text-sm font-bold">General</h1>
+        <Input
+          type="dropdown"
+          label="Layout"
+          value={configuration.layout}
+          options={Object.values(Layouts) as string[]}
+          onChange={(val) => updateSettings({ layout: val })}
+        />
+        <Input
+          type="boolean"
+          label="Show pop-up on hover"
+          value={configuration.showPopUpOnHover}
+          onChange={(val) => updateSettings({ showPopUpOnHover: val })}
+        />
+      </div>
+
+      <div className="mb-4">
+        <h1 className="text-sm font-bold">Nodes</h1>
+
+        <div>
+          <span className="text-xs font-semibold">Shape</span>
+          <Input
+            type="boolean"
+            label="Common shape?"
+            value={configuration.shapes.similar}
+            onChange={(val) => updateSettings({ shapes: { ...configuration.shapes, similar: val } })}
+          />
+          {configuration.shapes.similar ? (
+            <Input
+              type="dropdown"
+              label="Shape"
+              value={configuration.shapes.shape}
+              options={['Circle', 'Square']}
+              onChange={(val) => updateSettings({ shapes: { ...configuration.shapes, shape: val } })}
+            />
+          ) : (
+            <span>Map shapes to labels (to be implemented)</span>
+          )}
+        </div>
+
+        <div>
+          <span className="text-xs font-semibold">Color</span>
+        </div>
+      </div>
+
+      <div>
+        <h1 className="text-sm font-bold">Edges</h1>
+        <div>
+          <span className="text-xs font-semibold">Edge width</span>
+          <Input
+            type="boolean"
+            label="Common width"
+            value={configuration.edges.width.similar}
+            onChange={(val) => updateSettings({ edges: { ...configuration.edges, width: { ...configuration.edges.width, similar: val } } })}
+          />
+          <Input
+            type="slider"
+            label="Width"
+            value={configuration.edges.width.width}
+            onChange={(val) => updateSettings({ edges: { ...configuration.edges, width: { ...configuration.edges.width, width: val } } })}
+            min={0.1}
+            max={2}
+            step={0.1}
+          />
+        </div>
+      </div>
+    </SettingsContainer>
+  );
+};
+
 export const NodeLinkComponent: VISComponentType = {
   displayName: 'NodeLinkVis',
-  VIS: NodeLinkVis,
-  settings: {
-    layout: {
-      value: Layouts.FORCEATLAS2WEBWORKER as string,
-      type: 'dropdown',
-      label: 'Layout',
-      options: Object.values(Layouts) as string[],
-      description: 'Select a layout that is used for the visualization',
-    },
-  },
-  encodings: {
-    color: {
-      label: 'Node color',
-      element: 'node',
-      dimension: ['categorical', 'numerical'],
-      selector: 'Color',
-      description: 'Select a color for the nodes',
-    },
-    shape: {
-      label: 'Node shape',
-      element: 'node',
-      dimension: ['categorical'],
-      selector: 'Shape',
-      description: 'Select a shape for the nodes',
-    },
-    size: {
-      label: 'Node size',
-      element: 'node',
-      dimension: ['categorical'],
-      selector: 'Size',
-      description: 'Select a size for the nodes',
-    },
-  },
-  interactions: {
-    showPopUpOnHover: {
-      value: true,
-      type: 'boolean',
-      label: 'Show pop-up',
-    },
-  },
+  component: NodeLinkVis,
+  settings: NodelinkSettings,
+  configuration: configuration,
 };
 
 export default NodeLinkComponent;
diff --git a/libs/shared/lib/vis/visualizations/nodelinkvis/types.ts b/libs/shared/lib/vis/visualizations/nodelinkvis/types.ts
index 4103fa516..c8f6bec1d 100644
--- a/libs/shared/lib/vis/visualizations/nodelinkvis/types.ts
+++ b/libs/shared/lib/vis/visualizations/nodelinkvis/types.ts
@@ -76,17 +76,17 @@ export type TypeNode = {
   name: string; //Collection name
   attributes: string[]; //attributes. This includes all attributes found in the collection
   type: number | undefined; //number that represents collection of node, for colorscheme
-  visualisations: Visualisation[]; //The way to visualize attributes of this Node kind
+  visualisations: Visualization[]; //The way to visualize attributes of this Node kind
 };
 
 export type CommunityDetectionNode = {
   cluster: number; //group as used by colouring scheme
 };
 
-/**Visualisation holds the visualisation method for an attribute */
-export type Visualisation = {
+/**Visualization holds the visualization method for an attribute */
+export type Visualization = {
   attribute: string; //attribute type      (e.g. 'age')
-  vis: string; //visualisation type  (e.g. 'radius')
+  vis: string; //visualization type  (e.g. 'radius')
 };
 
 /** possible colors to pick from*/
diff --git a/libs/shared/lib/vis/visualizations/paohvis/components/HyperEdgesRange.tsx b/libs/shared/lib/vis/visualizations/paohvis/components/HyperEdgesRange.tsx
index c525b545e..5e9d44b05 100644
--- a/libs/shared/lib/vis/visualizations/paohvis/components/HyperEdgesRange.tsx
+++ b/libs/shared/lib/vis/visualizations/paohvis/components/HyperEdgesRange.tsx
@@ -10,7 +10,7 @@
  * See testing plan for more details.*/
 import { select } from 'd3';
 import React, { useEffect, useRef } from 'react';
-import { HyperEdgeI } from '../Types';
+import { HyperEdgeI } from '../types';
 import CustomLine from './CustomLine';
 
 type HyperEdgeRangeProps = {
diff --git a/libs/shared/lib/vis/visualizations/paohvis/components/MakePaohvisMenu.tsx b/libs/shared/lib/vis/visualizations/paohvis/components/MakePaohvisMenu.tsx
index 6ceac1573..142c374e2 100644
--- a/libs/shared/lib/vis/visualizations/paohvis/components/MakePaohvisMenu.tsx
+++ b/libs/shared/lib/vis/visualizations/paohvis/components/MakePaohvisMenu.tsx
@@ -8,7 +8,7 @@
 /* The comment above was added so the code coverage wouldn't count this file towards code coverage.
  * We do not test components/renderfunctions/styling files.
  * See testing plan for more details.*/
-import React, { ChangeEventHandler, ReactElement, useEffect, useMemo } from 'react';
+import React, { ReactElement, useEffect, useMemo } from 'react';
 import {
   Attribute,
   AttributeNames,
@@ -19,19 +19,22 @@ import {
   PaohvisNodeOrder,
   RelationsFromSchema,
   ValueType,
-} from '../Types';
+} from '../types';
 import { Sort } from '@mui/icons-material';
 import './MakePaohvisMenu.scss';
 import { useImmer } from 'use-immer';
-import { useGraphQueryResult, useSchemaGraph } from '@graphpolaris/shared/lib/data-access';
 import { calculateAttributesAndRelations, calculateAttributesFromRelation } from '../utils/utils';
-import calcEntitiesFromQueryResult from '../utils/CalcEntitiesFromQueryResult';
-import { isNodeLinkResult } from '../../../shared/ResultNodeLinkParserUseCase';
+import { calcEntitiesFromQueryResult } from '../utils/CalcEntitiesFromQueryResult';
+import { isNodeLinkResult } from '../utils/ResultNodeLinkParserUseCase';
 import { select } from 'd3';
 import { Button } from '../../../../components/buttons';
+import { GraphQueryResult } from '@graphpolaris/shared/lib/data-access';
+import { SchemaGraph } from '@graphpolaris/shared/lib/schema';
 
 /** The typing for the props of the Paohvis menu */
 type MakePaohvisMenuProps = {
+  graphQueryResult: GraphQueryResult;
+  schema: SchemaGraph;
   makePaohvis: (
     entityVertical: string,
     entityHorizontal: string,
@@ -66,10 +69,8 @@ type MakePaohvisMenuState = {
   attributeValue: string;
 };
 
-/** React component that renders a menu with input fields for adding a new Paohvis visualisation. */
+/** React component that renders a menu with input fields for adding a new Paohvis visualization. */
 export const MakePaohvisMenu = (props: MakePaohvisMenuProps) => {
-  const graphQueryResult = useGraphQueryResult();
-  const schema = useSchemaGraph();
   const [state, setState] = useImmer<MakePaohvisMenuState>({
     entityVertical: '',
     entityVerticalListed: '',
@@ -400,24 +401,24 @@ export const MakePaohvisMenu = (props: MakePaohvisMenuProps) => {
   useEffect(() => {
     resetConfig();
     setState((draft) => {
-      draft.entitiesFromSchema = calculateAttributesAndRelations(schema);
-      draft.relationsFromSchema = calculateAttributesFromRelation(schema);
+      draft.entitiesFromSchema = calculateAttributesAndRelations(props.schema);
+      draft.relationsFromSchema = calculateAttributesFromRelation(props.schema);
       return draft;
     });
-  }, [schema]);
+  }, [props.schema]);
 
   /** This method filters and makes a new Paohvis table. */
   useEffect(() => {
-    if (isNodeLinkResult(graphQueryResult)) {
+    if (isNodeLinkResult(props.graphQueryResult)) {
       resetConfig();
       setState((draft) => {
-        draft.entitiesFromQueryResult = calcEntitiesFromQueryResult(graphQueryResult);
+        draft.entitiesFromQueryResult = calcEntitiesFromQueryResult(props.graphQueryResult);
         return draft;
       });
     } else {
       console.error('Invalid query result!');
     }
-  }, [graphQueryResult]);
+  }, [props.graphQueryResult]);
 
   /** This resets the configuration. Should be called when the possible entities and relations change. */
   function resetConfig(): void {
@@ -571,5 +572,3 @@ export const MakePaohvisMenu = (props: MakePaohvisMenuProps) => {
     </div>
   );
 };
-
-export default MakePaohvisMenu;
diff --git a/libs/shared/lib/vis/visualizations/paohvis/components/PaohvisFilterComponent.tsx b/libs/shared/lib/vis/visualizations/paohvis/components/PaohvisFilterComponent.tsx
index 185651253..652f974b3 100644
--- a/libs/shared/lib/vis/visualizations/paohvis/components/PaohvisFilterComponent.tsx
+++ b/libs/shared/lib/vis/visualizations/paohvis/components/PaohvisFilterComponent.tsx
@@ -9,10 +9,10 @@
  * We do not test components/renderfunctions/styling files.
  * See testing plan for more details.*/
 import React, { ChangeEventHandler, ReactElement, useState, MouseEventHandler, useEffect, useMemo } from 'react';
-import { AttributeNames, FilterType } from '../Types';
+import { AttributeNames, FilterType } from '../types';
 import { useImmer } from 'use-immer';
 import { useGraphQueryResult, useSchemaGraph } from '@graphpolaris/shared/lib/data-access';
-import { isNodeLinkResult } from '../../../shared/ResultNodeLinkParserUseCase';
+import { isNodeLinkResult } from '../utils/ResultNodeLinkParserUseCase';
 import { calculateAttributesAndRelations, calculateAttributesFromRelation } from '../utils/utils';
 import { boolPredicates, numberPredicates, textPredicates } from '../models/FilterPredicates';
 import { style } from 'd3';
@@ -155,6 +155,11 @@ export const PaohvisFilterComponent = (props: PaohvisFilterProps) => {
   function onChangeCompareValue(event: React.ChangeEvent<HTMLInputElement>): void {
     setState((draft) => {
       draft.compareValue = event.target.value;
+      console.log(
+        containsFilterTargetChosenAttribute(draft.attributeNameAndType),
+        isPredicateValid(draft.predicate),
+        isCompareValueTypeValid(draft.compareValue),
+      );
 
       draft.isFilterButtonEnabled = isFilterConfigurationValid(draft);
       return draft;
diff --git a/libs/shared/lib/vis/visualizations/paohvis/paohvis.stories.tsx b/libs/shared/lib/vis/visualizations/paohvis/paohvis.stories.tsx
index 6b20d5245..b22021f6a 100644
--- a/libs/shared/lib/vis/visualizations/paohvis/paohvis.stories.tsx
+++ b/libs/shared/lib/vis/visualizations/paohvis/paohvis.stories.tsx
@@ -1,14 +1,7 @@
-import {
-  setNewGraphQueryResult,
-  graphQueryResultSlice,
-  querybuilderSlice,
-  schemaSlice,
-  setSchema,
-  visualizationSlice,
-} from '../../../data-access/store';
+import React from 'react';
+import { graphQueryResultSlice, querybuilderSlice, schemaSlice, setSchema, visualizationSlice } from '../../../data-access/store';
 import { configureStore } from '@reduxjs/toolkit';
 import { Meta } from '@storybook/react';
-import { VisualizationPanel } from '../../visualizationPanel';
 import { Provider } from 'react-redux';
 import { SchemaUtils } from '../../../schema/schema-utils';
 import {
@@ -20,11 +13,21 @@ import {
   mockRecommendationsActorMovie,
 } from '../../../mock-data';
 import { simpleSchemaAirportRaw } from '../../../mock-data/schema/simpleAirportRaw';
-import { setActiveVisualization } from '@graphpolaris/shared/lib/data-access/store/visualizationSlice';
+import PaohVisComponent from './paohvis';
+import { graphQueryBackend2graphQuery } from '@graphpolaris/shared/lib/data-access/store/graphQueryResultSlice';
+
+const Mockstore = configureStore({
+  reducer: {
+    schema: schemaSlice.reducer,
+    graphQueryResult: graphQueryResultSlice.reducer,
+    visualize: visualizationSlice.reducer,
+    querybuilder: querybuilderSlice.reducer,
+  },
+});
 
-const Component: Meta<typeof VisualizationPanel> = {
+const Component: Meta<typeof PaohVisComponent.component> = {
   title: 'Visualizations/Paohvis',
-  component: VisualizationPanel,
+  component: PaohVisComponent.component,
   decorators: [
     (story) => (
       <Provider store={Mockstore}>
@@ -41,19 +44,22 @@ const Component: Meta<typeof VisualizationPanel> = {
   ],
 };
 
-const Mockstore = configureStore({
-  reducer: {
-    schema: schemaSlice.reducer,
-    graphQueryResult: graphQueryResultSlice.reducer,
-    visualize: visualizationSlice.reducer,
-    querybuilder: querybuilderSlice.reducer,
-  },
-});
-
 export const TestWithData = {
-  play: async () => {
-    const dispatch = Mockstore.dispatch;
-    const schema = SchemaUtils.schemaBackend2Graphology({
+  args: {
+    data: graphQueryBackend2graphQuery({
+      nodes: [
+        { id: '1/a', label: 'a', attributes: { a: 's1' } },
+        { id: '1/b1', label: 'b1', attributes: { a: 's1' } },
+        { id: '1/b2', label: 'b2', attributes: { a: 's1' } },
+        { id: '1/b3', label: 'b3', attributes: { a: 's1' } },
+      ],
+      edges: [
+        { id: '1c/z1', label: 'z1', from: '1/b1', to: '1/a', attributes: { a: 's1' } },
+        { id: '1c/z2', label: 'z2', from: '1/a', to: '1/b1', attributes: { a: 's1' } },
+        { id: '1c/z3', label: 'z3', from: '1/b2', to: '1/b3', attributes: { a: 's2' } },
+      ],
+    }),
+    schema: SchemaUtils.schemaBackend2Graphology({
       nodes: [
         {
           name: '1',
@@ -70,73 +76,40 @@ export const TestWithData = {
           attributes: [{ name: 'a', type: 'string' }],
         },
       ],
-    });
-
-    dispatch(setSchema(schema.export()));
-    dispatch(
-      setNewGraphQueryResult({
-        queryID: '1',
-        result: {
-          type: 'nodelink',
-          payload: {
-            nodes: [
-              { id: '1/a', label: 'a', attributes: { a: 's1' } },
-              { id: '1/b1', label: 'b1', attributes: { a: 's1' } },
-              { id: '1/b2', label: 'b2', attributes: { a: 's1' } },
-              { id: '1/b3', label: 'b3', attributes: { a: 's1' } },
-            ],
-            edges: [
-              { id: '1c/z1', label: 'z1', from: '1/b1', to: '1/a', attributes: { a: 's1' } },
-              { id: '1c/z2', label: 'z2', from: '1/a', to: '1/b1', attributes: { a: 's1' } },
-              { id: '1c/z3', label: 'z3', from: '1/b2', to: '1/b3', attributes: { a: 's2' } },
-            ],
-          },
-        },
-      }),
-    );
-    dispatch(setActiveVisualization('PaohVis'));
+    }).export(),
+    configuration: PaohVisComponent.configuration,
   },
 };
 
 export const TestWithMarieBoucherSample = {
-  play: async () => {
-    const dispatch = Mockstore.dispatch;
-    const schema = SchemaUtils.schemaBackend2Graphology(marieBoucherSampleSchemaRaw);
-
-    dispatch(setSchema(schema.export()));
-    dispatch(setNewGraphQueryResult({ queryID: '1', result: { type: 'nodelink', payload: marieBoucherSample } }));
-    dispatch(setActiveVisualization('PaohVis'));
+  args: {
+    data: graphQueryBackend2graphQuery(marieBoucherSample),
+    schema: SchemaUtils.schemaBackend2Graphology(marieBoucherSampleSchemaRaw).export(),
+    configuration: PaohVisComponent.configuration,
   },
 };
 
 export const TestWithBig2ndChamber = {
-  play: async () => {
-    const dispatch = Mockstore.dispatch;
-    const schema = SchemaUtils.schemaBackend2Graphology(big2ndChamberSchemaRaw);
-    dispatch(setSchema(schema.export()));
-    dispatch(setNewGraphQueryResult({ queryID: '1', result: { type: 'nodelink', payload: big2ndChamberQueryResult } }));
-    dispatch(setActiveVisualization('PaohVis'));
+  args: {
+    data: graphQueryBackend2graphQuery(big2ndChamberQueryResult),
+    schema: SchemaUtils.schemaBackend2Graphology(big2ndChamberSchemaRaw).export(),
+    configuration: PaohVisComponent.configuration,
   },
 };
 
 export const TestWithAirport = {
-  play: async () => {
-    const dispatch = Mockstore.dispatch;
-    const schema = SchemaUtils.schemaBackend2Graphology(simpleSchemaAirportRaw);
-
-    dispatch(setSchema(schema.export()));
-    dispatch(setNewGraphQueryResult({ queryID: '1', result: { type: 'nodelink', payload: bigMockQueryResults } }));
-    dispatch(setActiveVisualization('PaohVis'));
+  args: {
+    data: graphQueryBackend2graphQuery(bigMockQueryResults),
+    schema: SchemaUtils.schemaBackend2Graphology(simpleSchemaAirportRaw).export(),
+    configuration: PaohVisComponent.configuration,
   },
 };
 
 export const TestWithRecommendationsActorMovie = {
-  play: async () => {
-    const dispatch = Mockstore.dispatch;
-    const schema = SchemaUtils.schemaBackend2Graphology(marieBoucherSampleSchemaRaw);
-    dispatch(setSchema(schema.export()));
-    dispatch(setNewGraphQueryResult({ queryID: '1', result: { type: 'nodelink', payload: mockRecommendationsActorMovie } }));
-    dispatch(setActiveVisualization('PaohVis'));
+  args: {
+    data: graphQueryBackend2graphQuery(mockRecommendationsActorMovie),
+    schema: SchemaUtils.schemaBackend2Graphology(marieBoucherSampleSchemaRaw).export(),
+    configuration: PaohVisComponent.configuration,
   },
 };
 
diff --git a/libs/shared/lib/vis/visualizations/paohvis/paohvis.tsx b/libs/shared/lib/vis/visualizations/paohvis/paohvis.tsx
index f889bee9d..f345bbe9e 100644
--- a/libs/shared/lib/vis/visualizations/paohvis/paohvis.tsx
+++ b/libs/shared/lib/vis/visualizations/paohvis/paohvis.tsx
@@ -1,6 +1,4 @@
 import { useEffect, useRef, useState, useMemo } from 'react';
-import SortByAlphaIcon from '@mui/icons-material/SortByAlpha';
-import SortIcon from '@mui/icons-material/Sort';
 import styles from './paohvis.module.scss';
 import {
   Attribute,
@@ -13,27 +11,23 @@ import {
   PaohvisNodeOrder,
   RelationsFromSchema,
   ValueType,
-} from './Types';
+} from './types';
 import { useImmer } from 'use-immer';
 
 import { getWidthOfText } from '../../../schema/schema-utils';
-import { useGraphQueryResult, useSchemaGraph } from '../../../data-access';
-import { isNodeLinkResult } from '../../shared/ResultNodeLinkParserUseCase';
-import { calculateAttributesAndRelations, calculateAttributesFromRelation, calcTextWidthAndStringText } from './utils/utils';
 import { processDataColumn } from './utils/processAttributes';
-import VisConfigPanelComponent from '../../shared/VisConfigPanel/VisConfigPanel';
-import { PaohvisFilterComponent } from './components/PaohvisFilterComponent';
-import { pointer, select, selectAll, scaleOrdinal } from 'd3';
+import { select, selectAll, scaleOrdinal } from 'd3';
 import { HyperEdgeRange } from './components/HyperEdgesRange';
-import ToPaohvisDataParserUseCase from './utils/ToPaohvisDataParserUsecase';
-import MakePaohvisMenu from './components/MakePaohvisMenu';
+import { ToPaohvisDataParserUseCase } from './utils/ToPaohvisDataParserUsecase';
+import { MakePaohvisMenu } from './components/MakePaohvisMenu';
 import { RowLabelColumn } from './components/RowLabelColumn';
-import { VISComponentType, VisualizationPropTypes } from '../../types';
 import { categoricalColors } from '../../../../../config/src/colors.js';
-import { NodeAttributes, Node } from '@graphpolaris/shared/lib/data-access/store/graphQueryResultSlice';
-import { SchemaAttributeTypes } from '@graphpolaris/shared/lib/schema';
-import { SchemaAttribute } from '../../../schema';
-import Graph, { MultiGraph } from 'graphology';
+import { GraphMetaData } from '@graphpolaris/shared/lib/data-access/statistics';
+import { SettingsContainer } from '@graphpolaris/shared/lib/vis/components/config';
+import { Input } from '@graphpolaris/shared/lib/components/inputs';
+import { VisualizationPropTypes, VISComponentType } from '../../common';
+import { isNodeLinkResult } from './utils/ResultNodeLinkParserUseCase';
+import { calculateAttributesAndRelations, calculateAttributesFromRelation, calcTextWidthAndStringText } from './utils/utils';
 
 type PaohvisViewModelState = {
   //rowHeight: number;
@@ -64,18 +58,22 @@ type PaohvisViewModelState = {
 };
 
 export type PaohVisProps = {
-  //rowHeight: number;
-  //hyperedgeColumnWidth: number;
-  //gapBetweenRanges: number;
-  //data?: PaohvisData;
+  rowHeight: number;
+  hyperedgeColumnWidth: number;
+  gapBetweenRanges: number;
+  data?: PaohvisData;
   showColor: boolean;
 };
 
-const displayName = 'PaohVis';
-export const PaohVis = ({ data, schema, settings }: VisualizationPropTypes) => {
-  //export const PaohVis = ({ settings }: VisualizationPropTypes<typeof displayName>) => {
+const configuration: PaohVisProps = {
+  rowHeight: 30,
+  hyperedgeColumnWidth: 20,
+  gapBetweenRanges: 5,
+  showColor: false,
+};
+
+export const PaohVis = ({ data, schema, configuration }: VisualizationPropTypes) => {
   const graphQueryResult = data;
-  //const schema = useSchemaGraph();
 
   const [isButtonPressed, setIsButtonPressed] = useState(false);
 
@@ -154,7 +152,7 @@ export const PaohVis = ({ data, schema, settings }: VisualizationPropTypes) => {
 
   useEffect(() => {
     //console.log(colorRowsRef.current);
-    if (settings.showColor) {
+    if (configuration.showColor) {
       selectAll('.rowsLabel')
         .select('rect')
         .data(colorRowsRef.current.vip)
@@ -181,7 +179,7 @@ export const PaohVis = ({ data, schema, settings }: VisualizationPropTypes) => {
     }
 
     //
-  }, [settings.showColor]);
+  }, [configuration.showColor]);
 
   // old props
   /*
@@ -484,13 +482,13 @@ export const PaohVis = ({ data, schema, settings }: VisualizationPropTypes) => {
   }
 
   /**
-   * Makes the new PAOHvis visualisation.
+   * Makes the new PAOHvis visualization.
    * @param {string} entityVertical This is the name of the vertical entity (so on the left).
    * @param {string} entityHorizontal This is the name of the horizontal entity (so at the top).
    * @param {string} relationName This is the (collection)-name of the relation.
    * @param {boolean} isEntityVerticalEqualToRelationFrom Tells if the vertical entity is the from or to of the relation.
    * @param {Attribute} chosenAttribute This is the attribute on which the PAOHvis must be grouped by.
-   * @param {PaohvisNodeOrder} nodeOrder Defines the sorting order of the PAOHvis visualisation.
+   * @param {PaohvisNodeOrder} nodeOrder Defines the sorting order of the PAOHvis visualization.
    */
   function onClickMakeButton(
     entityVertical: string,
@@ -660,9 +658,10 @@ export const PaohVis = ({ data, schema, settings }: VisualizationPropTypes) => {
   // RENDER
   //
   //
-  const hyperEdgeRanges = dataModel.hyperEdgeRanges; // hyperedges dataModelset
-  const rowLabelColumnWidth = dataModel.maxRowLabelWidth; // max width of the rows
-  const hyperedgeColumnWidth = props_hyperedgeColumnWidth; // column width from user defined
+
+  const hyperEdgeRanges = dataModel.hyperEdgeRanges;
+  const rowLabelColumnWidth = dataModel.maxRowLabelWidth;
+  const hyperedgeColumnWidth = configuration.hyperedgeColumnWidth;
 
   //calculate yOffset - hyperedges
   /*
@@ -692,7 +691,7 @@ export const PaohVis = ({ data, schema, settings }: VisualizationPropTypes) => {
       /*Math.cos(columnLabelAngleInRadians) * */
       getWidthOfText(hyperEdgeRange.rangeText, styles.tableFontFamily, styles.tableFontSize, styles.tableFontWeight);
 
-    const columnWidth = hyperEdgeRange.hyperEdges.length * hyperedgeColumnWidth + props_gapBetweenRanges * 3;
+    const columnWidth = hyperEdgeRange.hyperEdges.length * hyperedgeColumnWidth + configuration.gapBetweenRanges * 3;
     // new text compute
 
     tableWidth += columnWidth;
@@ -720,10 +719,10 @@ export const PaohVis = ({ data, schema, settings }: VisualizationPropTypes) => {
         colOffset={colOffset}
         xOffset={rowLabelColumnWidth}
         yOffset={yOffset}
-        rowHeight={props_rowHeight}
+        rowHeight={configuration.rowHeight}
         textBothMargins={0.1 * maxSizeTextColumns}
         hyperedgeColumnWidth={hyperedgeColumnWidth}
-        gapBetweenRanges={props_gapBetweenRanges}
+        gapBetweenRanges={configuration.gapBetweenRanges}
         onMouseEnter={onMouseEnterHyperEdge}
         onMouseLeave={onMouseLeaveHyperEdge}
       />,
@@ -731,10 +730,10 @@ export const PaohVis = ({ data, schema, settings }: VisualizationPropTypes) => {
     colOffset += hyperEdgeRange.hyperEdges.length;
   });
 
-  // returns the whole PAOHvis visualisation panel
+  // returns the whole PAOHvis visualization panel
   return (
     <div className={styles.container}>
-      <MakePaohvisMenu makePaohvis={onClickMakeButton} />
+      <MakePaohvisMenu makePaohvis={onClickMakeButton} graphQueryResult={graphQueryResult} schema={schema} />
       <div className="w-full h-full">
         <div className="w-full h-full">
           <div className="w-full h-full flex flex-row justify-center" ref={secondContainerRef}>
@@ -742,7 +741,7 @@ export const PaohVis = ({ data, schema, settings }: VisualizationPropTypes) => {
               ref={svgRef}
               style={{
                 width: tableWidthWithExtraColumnLabelWidth,
-                height: yOffset + (dataModel.rowLabels.length + 1) * props_rowHeight,
+                height: yOffset + (dataModel.rowLabels.length + 1) * configuration.rowHeight,
               }}
             >
               <RowLabelColumn
@@ -750,7 +749,7 @@ export const PaohVis = ({ data, schema, settings }: VisualizationPropTypes) => {
                 onMouseLeave={onMouseLeaveRow}
                 titles={dataModel.rowLabels}
                 width={rowLabelColumnWidth}
-                rowHeight={props_rowHeight}
+                rowHeight={configuration.rowHeight} // viewModel.rowHeight?
                 yOffset={yOffset}
               />
               {hyperEdgeRangeColumns}
@@ -761,75 +760,40 @@ export const PaohVis = ({ data, schema, settings }: VisualizationPropTypes) => {
     </div>
   );
 };
-/*
-const localConfigSchema: localConfigSchemaType = {
-  
-  showColor: {
-    value: false,
-    type: 'boolean',
-    label: 'Color rows!',
-  },
-  entitySelected: {
-    // data driven
-    value: '',
-    type: 'dropdown',
-    label: 'Entity:',
-    options: ['merchant'],
-  },
-  attributeSelected: {
-    // data driven. After select entity, it updates this one
-    value: '',
-    type: 'dropdown',
-    label: 'Attribute:',
-    options: ['no attribute', 'name: Entity', 'time: Relation'],
-  },
-  sortMethodSelected: {
-    // no data driven
-    value: '',
-    type: 'dropdown',
-    label: 'Sort by:',
-    options: ['Alphabetical', 'Degree (Amount of hyperedges)', 'By Group'],
-  },
-
-  sortMethodAscDscSelected: {
-    // no data driven. Depends on sortMethodSelected.
-    // if sortMethodSelected == "Alphabetical" this:
-
-    value: 'A-Z',
-    type: 'dropdown',
-    label: 'Short method:',
-    options: [<SortIcon />, <SortByAlphaIcon />],
-    // else: sortMethodSelected == "Degree" this:
-
-    value: 'A-Z',
-    type: 'dropdown',
-    label: 'Ascending/Descending:',
-    options: ['A-Z', 'Z-A'],
-
-  },
-  sortMethodRowsSelected: {
-    // Data driven. It should only appear when sortMethodSelected == Group
-    // Show categorical node's attribute. No limitation of nodes.
-    value: '',
-    type: 'dropdown',
-    label: 'Group By:',
-    options: ['city', 'country', 'state', 'name'],
-  },
-  colorRowsBySelected: {
-    // Data driven.
-    // Show categorical node's attribute with less categories than colors availabe.
-    value: '',
-    type: 'dropdown',
-    label: 'Color Rows by:',
-    options: ['city', 'country', 'state', 'name'],
-  },
-  
+
+const PaohSettings = ({
+  configuration,
+  graph,
+  updateSettings,
+}: {
+  configuration: PaohVisProps;
+  graph: GraphMetaData;
+  updateSettings: (val: any) => void;
+}) => {
+  return (
+    <SettingsContainer>
+      <Input type="number" label="Row height" value={configuration.rowHeight} onChange={(val) => updateSettings({ rowHeight: val })} />
+      <Input
+        type="number"
+        label="Hyper edge column width"
+        value={configuration.hyperedgeColumnWidth}
+        onChange={(val) => updateSettings({ hyperedgeColumnWidth: val })}
+      />
+      <Input
+        type="number"
+        label="Gap between ranges"
+        value={configuration.gapBetweenRanges}
+        onChange={(val) => updateSettings({ gapBetweenRanges: val })}
+      />
+    </SettingsContainer>
+  );
 };
-*/
+
 export const PaohVisComponent: VISComponentType = {
   displayName: 'PaohVis',
-  VIS: PaohVis,
-  settings: {},
+  component: PaohVis,
+  settings: PaohSettings,
+  configuration: configuration,
 };
 
 export default PaohVisComponent;
diff --git a/libs/shared/lib/vis/visualizations/paohvis/Types.tsx b/libs/shared/lib/vis/visualizations/paohvis/types.ts
similarity index 100%
rename from libs/shared/lib/vis/visualizations/paohvis/Types.tsx
rename to libs/shared/lib/vis/visualizations/paohvis/types.ts
diff --git a/libs/shared/lib/vis/visualizations/paohvis/utils/AttributesFilterUseCase.tsx b/libs/shared/lib/vis/visualizations/paohvis/utils/AttributesFilterUseCase.tsx
index 193c898cc..35cf2539c 100644
--- a/libs/shared/lib/vis/visualizations/paohvis/utils/AttributesFilterUseCase.tsx
+++ b/libs/shared/lib/vis/visualizations/paohvis/utils/AttributesFilterUseCase.tsx
@@ -4,8 +4,8 @@
  * © Copyright Utrecht University (Department of Information and Computing Sciences)
  */
 
-import { FilterInfo, PaohvisFilters } from '../Types';
-import { AxisType, isNotInGroup } from '../../../shared/ResultNodeLinkParserUseCase';
+import { FilterInfo, PaohvisFilters } from '../types';
+import { AxisType, isNotInGroup } from './ResultNodeLinkParserUseCase';
 import { boolPredicates, numberPredicates, textPredicates } from '../models/FilterPredicates';
 import { Edge, GraphQueryResult, Node } from '@graphpolaris/shared/lib/data-access';
 
diff --git a/libs/shared/lib/vis/visualizations/paohvis/utils/CalcEntitiesFromQueryResult.tsx b/libs/shared/lib/vis/visualizations/paohvis/utils/CalcEntitiesFromQueryResult.tsx
index c6988eab4..ff160f5c0 100644
--- a/libs/shared/lib/vis/visualizations/paohvis/utils/CalcEntitiesFromQueryResult.tsx
+++ b/libs/shared/lib/vis/visualizations/paohvis/utils/CalcEntitiesFromQueryResult.tsx
@@ -5,14 +5,14 @@
  */
 
 import { GraphQueryResult } from '@graphpolaris/shared/lib/data-access';
-import { getGroupName } from '../../../shared/ResultNodeLinkParserUseCase';
+import { getGroupName } from './ResultNodeLinkParserUseCase';
 
 /**
  * This calculates all entities from the query result.
  * @param {NodeLinkResultType} message This is the message with all the information about the entities and relations.
  * @returns {string[]} All names of the entities which are in the query result.
  */
-export default function calcEntitiesFromQueryResult(message: GraphQueryResult): string[] {
+export function calcEntitiesFromQueryResult(message: GraphQueryResult): string[] {
   const entityTypesFromQueryResult: string[] = [];
   message.nodes.forEach((node) => {
     const group = getGroupName(node);
diff --git a/libs/shared/lib/vis/visualizations/paohvis/utils/CalcEntityAttrAndRelNamesFromSchemaUseCase.tsx b/libs/shared/lib/vis/visualizations/paohvis/utils/CalcEntityAttrAndRelNamesFromSchemaUseCase.tsx
deleted file mode 100644
index b369cfa30..000000000
--- a/libs/shared/lib/vis/visualizations/paohvis/utils/CalcEntityAttrAndRelNamesFromSchemaUseCase.tsx
+++ /dev/null
@@ -1,130 +0,0 @@
-/**
- * This program has been developed by students from the bachelor Computer Science at
- * Utrecht University within the Software Project course.
- * © Copyright Utrecht University (Department of Information and Computing Sciences)
- */
-import { SchemaGraph, SchemaGraphologyEdge } from '@graphpolaris/shared/lib/schema';
-import { AttributeNames, EntitiesFromSchema, RelationsFromSchema } from '../Types';
-
-/** Use case for retrieving entity names, relation names and attribute names from a schema result. */
-export default class CalcEntityAttrAndRelNamesFromSchemaUseCase {
-  /**
-   * Takes a schema result and calculates all the entity names, and relation names and attribute names per entity.
-   * Used by PAOHvis to show all possible options to choose from when adding a new PAOHvis visualisation or when filtering.
-   * @param {SchemaResultType} schemaResult A new schema result from the backend.
-   * @returns {EntitiesFromSchema} All entity names, and relation names and attribute names per entity.
-   */
-  public static calculateAttributesAndRelations(schemaResult: SchemaGraph): EntitiesFromSchema {
-    const attributesPerEntity: Record<string, AttributeNames> = this.calculateAttributes(schemaResult);
-    const relationsPerEntity: Record<string, string[]> = this.calculateRelations(schemaResult);
-
-    return {
-      entityNames: schemaResult.nodes.filter((node) => node?.attributes?.name !== undefined).map((node) => node.attributes!.name),
-      attributesPerEntity,
-      relationsPerEntity,
-    };
-  }
-
-  /**
-   * Takes a schema result and calculates all the attribute names per entity.
-   * @param {SchemaResultType} schemaResult A new schema result from the backend.
-   * @returns {Record<string, AttributeNames>} All attribute names per entity.
-   */
-  public static calculateAttributes(schemaResult: SchemaGraph): Record<string, AttributeNames> {
-    const attributesPerEntity: Record<string, AttributeNames> = {};
-    // Go through each entity.
-    schemaResult.nodes.forEach((node) => {
-      if (node.attributes === undefined || node.attributes.name === undefined) {
-        console.error('ERROR: Node has no attributes/name.', node);
-        return;
-      }
-
-      // Extract the attribute names per datatype for each entity.
-      const textAttributeNames: string[] = [];
-      const boolAttributeNames: string[] = [];
-      const numberAttributeNames: string[] = [];
-      node.attributes.attributes.forEach((attr) => {
-        if (attr.type == 'string') textAttributeNames.push(attr.name);
-        else if (attr.type == 'int' || attr.type == 'float') numberAttributeNames.push(attr.name);
-        else boolAttributeNames.push(attr.name);
-      });
-
-      // Create a new object with the arrays with attribute names per datatype.
-      attributesPerEntity[node.attributes.name] = {
-        textAttributeNames,
-        boolAttributeNames,
-        numberAttributeNames,
-      };
-    });
-    return attributesPerEntity;
-  }
-
-  /**
-   * Takes a schema result and calculates all the relation names per entity.
-   * @param {SchemaResultType} schemaResult A new schema result from the backend.
-   * @returns {Record<string, AttributeNames>} All relation (from and to) names per entity.
-   */
-  public static calculateRelations(schemaResult: SchemaGraph): Record<string, string[]> {
-    const relationsPerEntity: Record<string, string[]> = {};
-    // Go through each relation.
-    schemaResult.edges.forEach((edge) => {
-      if (edge.attributes === undefined || edge.attributes.name === undefined) {
-        console.error('ERROR: Edge has no attributes/name.', edge);
-        return;
-      }
-
-      // Extract the from-node-name (collection name) from every relation.
-      if (relationsPerEntity[edge.attributes.from]) relationsPerEntity[edge.attributes.from].push(edge.attributes.collection);
-      else relationsPerEntity[edge.attributes.from] = [edge.attributes.collection];
-      // Extract the to-node-name (collection name) from every relation.
-      if (relationsPerEntity[edge.attributes.to]) relationsPerEntity[edge.attributes.to].push(edge.attributes.collection);
-      else relationsPerEntity[edge.attributes.to] = [edge.attributes.collection];
-    });
-    return relationsPerEntity;
-  }
-
-  /**
-   * Takes a schema result and calculates all the relation collection names, and relation names and attribute names per relation.
-   * Used by PAOHvis to show all possible options to choose from when adding a new PAOHvis visualisation or when filtering.
-   * @param {SchemaResultType} schemaResult A new schema result from the backend.
-   * @returns {EntitiesFromSchema} All entity names, and relation names and attribute names per entity.
-   */
-  public static calculateAttributesFromRelation(schemaResult: SchemaGraph): RelationsFromSchema {
-    const relationCollections: string[] = [];
-    const attributesPerRelation: Record<string, AttributeNames> = {};
-    const nameOfCollectionPerRelation: Record<string, string> = {};
-    // Go through each relation.
-    schemaResult.edges.forEach((edge) => {
-      if (edge.attributes === undefined || edge.attributes.name === undefined) {
-        console.error('ERROR: Edge has no attributes/name.', edge);
-        return;
-      }
-
-      if (!nameOfCollectionPerRelation[edge.attributes.collection]) {
-        relationCollections.push(edge.attributes.collection);
-        nameOfCollectionPerRelation[edge.attributes.collection] = `${edge.attributes.name}`;
-      }
-      // Extract the attribute names per datatype for each relation.
-      const textAttributeNames: string[] = [];
-      const boolAttributeNames: string[] = [];
-      const numberAttributeNames: string[] = [];
-      edge.attributes.attributes.forEach((attr: SchemaGraphologyEdge) => {
-        if (attr.type == 'string') textAttributeNames.push(attr.name);
-        else if (attr.type == 'int' || attr.type == 'float') numberAttributeNames.push(attr.name);
-        else boolAttributeNames.push(attr.name);
-      });
-
-      // Create a new object with the arrays with attribute names per datatype.
-      attributesPerRelation[edge.attributes.collection] = {
-        textAttributeNames,
-        boolAttributeNames,
-        numberAttributeNames,
-      };
-    });
-    return {
-      relationCollection: relationCollections,
-      relationNames: nameOfCollectionPerRelation,
-      attributesPerRelation: attributesPerRelation,
-    };
-  }
-}
diff --git a/libs/shared/lib/vis/shared/ResultNodeLinkParserUseCase.tsx b/libs/shared/lib/vis/visualizations/paohvis/utils/ResultNodeLinkParserUseCase.tsx
similarity index 73%
rename from libs/shared/lib/vis/shared/ResultNodeLinkParserUseCase.tsx
rename to libs/shared/lib/vis/visualizations/paohvis/utils/ResultNodeLinkParserUseCase.tsx
index 611d8d120..2af931efa 100644
--- a/libs/shared/lib/vis/shared/ResultNodeLinkParserUseCase.tsx
+++ b/libs/shared/lib/vis/visualizations/paohvis/utils/ResultNodeLinkParserUseCase.tsx
@@ -3,38 +3,8 @@
  * Utrecht University within the Software Project course.
  * © Copyright Utrecht University (Department of Information and Computing Sciences)
  */
-import { GraphType, LinkType, NodeType } from '../visualizations/nodelinkvis/types';
-import { Edge, Node, GraphQueryResult } from '../../data-access/store';
-import { ML } from '../../data-access/store/mlSlice';
-/** ResultNodeLinkParserUseCase implements methods to parse and translate websocket messages from the backend into a GraphType. */
-
-/**
- * This program has been developed by students from the bachelor Computer Science at
- * Utrecht University within the Software Project course.
- * © Copyright Utrecht University (Department of Information and Computing Sciences)
- */
-/** A node link data-type for a query result object from the backend. */
-// export type NodeLinkResultType = { DEPRECATED USE GraphQueryResult
-//   nodes: Node[];
-//   edges: Link[];
-//   mlEdges?: Link[];
-// };
-
-/** Typing for nodes and links in the node-link result. Nodes and links should always have an id and attributes. */
-// export interface AxisType {
-//   id: string;
-//   attributes: Record<string, any>;
-//   mldata?: Record<string, string[]> | number; // This is shortest path data . This name is needs to be changed together with backend TODO: Change this.
-// }
-
-/** Typing for a node in the node-link result */
-// export type Node = AxisType;
-
-/** Typing for a link in the node-link result */
-// export interface Link extends AxisType {
-//   from: string;
-//   to: string;
-// }
+import { GraphType, LinkType, NodeType } from '../../nodelinkvis/types';
+import { Edge, Node, GraphQueryResult } from '../../../../data-access/store';
 
 export type AxisType = Node | Edge;
 
diff --git a/libs/shared/lib/vis/visualizations/paohvis/utils/SortUseCase.tsx b/libs/shared/lib/vis/visualizations/paohvis/utils/SortUseCase.tsx
index 85686eca5..ef2aea133 100644
--- a/libs/shared/lib/vis/visualizations/paohvis/utils/SortUseCase.tsx
+++ b/libs/shared/lib/vis/visualizations/paohvis/utils/SortUseCase.tsx
@@ -4,7 +4,7 @@
  * © Copyright Utrecht University (Department of Information and Computing Sciences)
  */
 
-import { HyperEdgeI, HyperEdgeRange, NodeOrder, PaohvisNodeOrder, ValueType } from '../Types';
+import { HyperEdgeI, HyperEdgeRange, NodeOrder, PaohvisNodeOrder, ValueType } from '../types';
 import { Node } from '@graphpolaris/shared/lib/data-access';
 import { NodeAttributes } from '@graphpolaris/shared/lib/data-access/store/graphQueryResultSlice';
 
@@ -46,7 +46,7 @@ export default class SortUseCase {
    */
   private static sortHyperEdgeIndices(hyperEdgeRanges: HyperEdgeRange[]): void {
     hyperEdgeRanges.forEach((hyperEdgeRange) =>
-      hyperEdgeRange.hyperEdges.forEach((hyperEdge) => hyperEdge.indices.sort((n1, n2) => n1 - n2))
+      hyperEdgeRange.hyperEdges.forEach((hyperEdge) => hyperEdge.indices.sort((n1, n2) => n1 - n2)),
     );
   }
 
@@ -61,7 +61,7 @@ export default class SortUseCase {
     nodeOrder: PaohvisNodeOrder,
     nodes: Node[],
     hyperEdgeDegree: Record<string, number>,
-    entityVerticalListed: string
+    entityVerticalListed: string,
   ): void {
     switch (nodeOrder.orderBy) {
       //sort nodes on their degree (# number of hyperedges) (entities with most hyperedges first)
@@ -176,11 +176,14 @@ export default class SortUseCase {
 
   public static sortNodesByGroupAlphabetically(nodes: Node[], attributeSort: string): void {
     const groupBy = (array: Node[], keyFunc: (item: Node) => string) => {
-      return array.reduce((result, item) => {
-        const key = keyFunc(item);
-        (result[key] = result[key] || []).push(item);
-        return result;
-      }, {} as { [key: string]: Node[] });
+      return array.reduce(
+        (result, item) => {
+          const key = keyFunc(item);
+          (result[key] = result[key] || []).push(item);
+          return result;
+        },
+        {} as { [key: string]: Node[] },
+      );
     };
 
     // Groups nodes according attributeSort
diff --git a/libs/shared/lib/vis/visualizations/paohvis/utils/ToPaohvisDataParserUsecase.tsx b/libs/shared/lib/vis/visualizations/paohvis/utils/ToPaohvisDataParserUsecase.tsx
index 6004bbcc4..85f43afc2 100644
--- a/libs/shared/lib/vis/visualizations/paohvis/utils/ToPaohvisDataParserUsecase.tsx
+++ b/libs/shared/lib/vis/visualizations/paohvis/utils/ToPaohvisDataParserUsecase.tsx
@@ -4,12 +4,11 @@
  * © Copyright Utrecht University (Department of Information and Computing Sciences)
  */
 
-import { AxisType, getGroupName } from '../../../shared/ResultNodeLinkParserUseCase';
-import { Edge, GraphQueryResult, Node } from '@graphpolaris/shared/lib/data-access';
-import Graph, { MultiGraph } from 'graphology';
+import { getGroupName } from './ResultNodeLinkParserUseCase';
+import { GraphQueryResult, Node } from '@graphpolaris/shared/lib/data-access';
+import { MultiGraph } from 'graphology';
 
 import {
-  AttributeOrigin,
   HyperEdgeI,
   HyperEdgeRange,
   PaohvisAxisInfo,
@@ -19,24 +18,21 @@ import {
   PaohvisNodeOrder,
   Relation,
   ValueType,
-  GraphData,
   AugmentedEdgeAttributes,
   AugmentedNodeAttributesGraph,
   connectionFromTo,
-} from '../Types';
-import AttributeFilterUsecase, { filterUnusedEdges, getIds } from './AttributesFilterUseCase';
+} from '../types';
+import AttributeFilterUsecase, { getIds } from './AttributesFilterUseCase';
 import SortUseCase from './SortUseCase';
 import { getWidthOfText, getUniqueArrays, findConnectionsNodes, buildGraphology } from './utils';
 import style from '../paohvis.module.scss';
-import { ConstructionOutlined } from '@mui/icons-material';
-//import { CropLandscapeOutlined } from '@mui/icons-material';
 
 type Index = number;
 
 /**
  * This parser is used to parse the incoming query result to the format that's needed to make the Paohvis table.
  */
-export default class ToPaohvisDataParserUseCase {
+export class ToPaohvisDataParserUseCase {
   private queryResult: GraphQueryResult;
   private xAxisNodeGroup: string;
   private yAxisNodeGroup: string;
diff --git a/libs/shared/lib/vis/shared/VisConfigPanel/VisConfigPanel.module.scss b/libs/shared/lib/vis/visualizations/paohvis/utils/VisConfigPanel.module.scss
similarity index 97%
rename from libs/shared/lib/vis/shared/VisConfigPanel/VisConfigPanel.module.scss
rename to libs/shared/lib/vis/visualizations/paohvis/utils/VisConfigPanel.module.scss
index 4904ce9db..0b1171461 100644
--- a/libs/shared/lib/vis/shared/VisConfigPanel/VisConfigPanel.module.scss
+++ b/libs/shared/lib/vis/visualizations/paohvis/utils/VisConfigPanel.module.scss
@@ -21,7 +21,9 @@ $expandButtonSize: 13px;
   top: 0;
   background-color: #f0f0f0;
 
-  transition: right 0.2s, left 0.2s;
+  transition:
+    right 0.2s,
+    left 0.2s;
   z-index: 100;
 
   border-radius: 0 0 0 5px;
diff --git a/libs/shared/lib/vis/shared/VisConfigPanel/VisConfigPanel.tsx b/libs/shared/lib/vis/visualizations/paohvis/utils/VisConfigPanel.tsx
similarity index 62%
rename from libs/shared/lib/vis/shared/VisConfigPanel/VisConfigPanel.tsx
rename to libs/shared/lib/vis/visualizations/paohvis/utils/VisConfigPanel.tsx
index 4b52f9595..b0575f99e 100644
--- a/libs/shared/lib/vis/shared/VisConfigPanel/VisConfigPanel.tsx
+++ b/libs/shared/lib/vis/visualizations/paohvis/utils/VisConfigPanel.tsx
@@ -1,21 +1,6 @@
-/**
- * This program has been developed by students from the bachelor Computer Science at
- * Utrecht University within the Software Project course.
- * © Copyright Utrecht University (Department of Information and Computing Sciences)
- */
-
-/* istanbul ignore file */
-/* The comment above was added so the code coverage wouldn't count this file towards code coverage.
- * We do not test components/renderfunctions/styling files.
- * See testing plan for more details.*/
-
-/** A component for rendering a configuration panel to the right of the visualization. */
-
 import React, { useState } from 'react';
 import styles from './VisConfigPanel.module.scss';
 
-//TODO import { ReactComponent as ArrowRightSVG } from './ArrowRightIcon.svg';
-
 export default function VisConfigPanelComponent({
   width = 250,
   children,
diff --git a/libs/shared/lib/vis/visualizations/paohvis/utils/utils.tsx b/libs/shared/lib/vis/visualizations/paohvis/utils/utils.tsx
index 6871bbc67..277c62af7 100644
--- a/libs/shared/lib/vis/visualizations/paohvis/utils/utils.tsx
+++ b/libs/shared/lib/vis/visualizations/paohvis/utils/utils.tsx
@@ -1,5 +1,4 @@
-import { log } from 'console';
-import { SchemaAttribute, SchemaGraph, SchemaGraphologyEdge, SchemaGraphologyNode } from '../../../../schema';
+import { SchemaAttribute, SchemaGraph } from '../../../../schema';
 import {
   AttributeNames,
   EntitiesFromSchema,
@@ -8,12 +7,12 @@ import {
   idConnections,
   GraphData,
   AugmentedNodeAttributesGraph,
-} from '../Types';
-import Graph, { MultiGraph } from 'graphology';
+} from '../types';
+import { MultiGraph } from 'graphology';
 
 /**
  * Takes a schema result and calculates all the entity names, and relation names and attribute names per entity.
- * Used by PAOHvis to show all possible options to choose from when adding a new PAOHvis visualisation or when filtering.
+ * Used by PAOHvis to show all possible options to choose from when adding a new PAOHvis visualization or when filtering.
  * @param {SchemaResultType} schemaResult A new schema result from the backend.
  * @returns {EntitiesFromSchema} All entity names, and relation names and attribute names per entity.
  */
@@ -88,7 +87,7 @@ export function calculateRelations(schemaResult: SchemaGraph): Record<string, st
 
 /**
  * Takes a schema result and calculates all the relation collection names, and relation names and attribute names per relation.
- * Used by PAOHvis to show all possible options to choose from when adding a new PAOHvis visualisation or when filtering.
+ * Used by PAOHvis to show all possible options to choose from when adding a new PAOHvis visualization or when filtering.
  * @param {SchemaResultType} schemaResult A new schema result from the backend.
  * @returns {EntitiesFromSchema} All entity names, and relation names and attribute names per entity.
  */
diff --git a/libs/shared/lib/vis/visualizations/rawjsonvis/rawjsonvis.stories.tsx b/libs/shared/lib/vis/visualizations/rawjsonvis/rawjsonvis.stories.tsx
index b040c99c2..bdfc75c5b 100644
--- a/libs/shared/lib/vis/visualizations/rawjsonvis/rawjsonvis.stories.tsx
+++ b/libs/shared/lib/vis/visualizations/rawjsonvis/rawjsonvis.stories.tsx
@@ -1,23 +1,23 @@
 import React from 'react';
 import { Meta } from '@storybook/react';
-import { VisualizationPanel } from '../../visualizationPanel';
-import {
-  setNewGraphQueryResult,
-  graphQueryResultSlice,
-  querybuilderSlice,
-  resetGraphQueryResults,
-  schemaSlice,
-  store,
-  visualizationSlice,
-} from '../../../data-access/store';
+import { graphQueryResultSlice, querybuilderSlice, schemaSlice, visualizationSlice } from '../../../data-access/store';
 import { configureStore } from '@reduxjs/toolkit';
 import { Provider } from 'react-redux';
 import { mockLargeQueryResults } from '../../../mock-data/query-result';
-import { setActiveVisualization } from '@graphpolaris/shared/lib/data-access/store/visualizationSlice';
+import RawJSONComponent from './rawjsonvis';
 
-const Component: Meta<typeof VisualizationPanel> = {
+const Mockstore = configureStore({
+  reducer: {
+    schema: schemaSlice.reducer,
+    graphQueryResult: graphQueryResultSlice.reducer,
+    visualize: visualizationSlice.reducer,
+    querybuilder: querybuilderSlice.reducer,
+  },
+});
+
+const Component: Meta<typeof RawJSONComponent.component> = {
   title: 'Visualizations/RawJSONVIS',
-  component: VisualizationPanel,
+  component: RawJSONComponent.component,
   decorators: [
     (story) => (
       <Provider store={Mockstore}>
@@ -34,61 +34,33 @@ const Component: Meta<typeof VisualizationPanel> = {
   ],
 };
 
-const Mockstore = configureStore({
-  reducer: {
-    schema: schemaSlice.reducer,
-    graphQueryResult: graphQueryResultSlice.reducer,
-    visualize: visualizationSlice.reducer,
-    querybuilder: querybuilderSlice.reducer,
-  },
-});
-
 export const SimpleData = {
-  play: async () => {
-    const dispatch = Mockstore.dispatch;
-    dispatch(
-      setNewGraphQueryResult({
-        queryID: '1',
-        result: {
-          type: 'nodelink',
-          payload: {
-            nodes: [
-              { id: 'agent/007', attributes: { name: 'Daniel Craig' } },
-              { id: 'villain', attributes: { name: 'Le Chiffre' } },
-            ],
-            edges: [],
-          },
-        },
-      }),
-    );
-    dispatch(setActiveVisualization('RawJSONVis'));
+  args: {
+    data: {
+      nodes: [
+        { id: 'agent/007', attributes: { name: 'Daniel Craig' } },
+        { id: 'villain', attributes: { name: 'Le Chiffre' } },
+      ],
+      edges: [],
+    },
+    configuration: RawJSONComponent.configuration,
   },
 };
 
 export const LargeData = {
   args: {
-    loading: false,
-  },
-  play: async () => {
-    const dispatch = Mockstore.dispatch;
-    dispatch(
-      setNewGraphQueryResult({
-        queryID: '1',
-        result: {
-          type: 'nodelink',
-          payload: mockLargeQueryResults,
-        },
-      }),
-    );
-    dispatch(setActiveVisualization('RawJSONVis'));
+    data: mockLargeQueryResults,
+    configuration: RawJSONComponent.configuration,
   },
 };
 
 export const Empty = {
-  play: async () => {
-    const dispatch = store.dispatch;
-    dispatch(resetGraphQueryResults());
-    dispatch(setActiveVisualization('RawJSONVis'));
+  args: {
+    data: {
+      nodes: [],
+      edges: [],
+    },
+    configuration: RawJSONComponent.configuration,
   },
 };
 
diff --git a/libs/shared/lib/vis/visualizations/rawjsonvis/rawjsonvis.tsx b/libs/shared/lib/vis/visualizations/rawjsonvis/rawjsonvis.tsx
index f62cd2a94..fa8ec2355 100644
--- a/libs/shared/lib/vis/visualizations/rawjsonvis/rawjsonvis.tsx
+++ b/libs/shared/lib/vis/visualizations/rawjsonvis/rawjsonvis.tsx
@@ -1,32 +1,93 @@
 import React, { useEffect } from 'react';
 import ReactJSONView from 'react-json-view';
-import { VisualizationPropTypes, VISComponentType } from '../../types';
+import { VisualizationPropTypes, VISComponentType } from '../../common';
+import { GraphMetaData } from '@graphpolaris/shared/lib/data-access/statistics';
+import { SettingsContainer } from '@graphpolaris/shared/lib/vis/components/config';
+import { Input } from '@graphpolaris/shared/lib/components/inputs';
 
-export interface RawJSONVisProps {}
+export interface RawJSONVisProps {
+  showDataTypes: boolean;
+  showObjectSize: boolean;
+  enableClipboard: boolean;
+  theme: string;
+  iconStyle: string;
+}
 
-const displayName = 'RawJSONVis';
+const configuration: RawJSONVisProps = {
+  showDataTypes: false,
+  showObjectSize: false,
+  enableClipboard: false,
+  theme: 'bright:inverted',
+  iconStyle: 'circle',
+};
 
-export const RawJSONVis = React.memo(({ data }: VisualizationPropTypes) => {
+export const RawJSONVis = React.memo(({ data, configuration }: VisualizationPropTypes) => {
   return (
-    <div>
-      <div style={{ overflowY: 'auto' }}>
-        <div
-          style={{
-            marginTop: '50px',
-            paddingLeft: '30px',
-          }}
-          className="font-mono text-sm"
-        >
-          <ReactJSONView src={data} collapsed={1} quotesOnKeys={false} displayDataTypes={false} />
-        </div>
-      </div>
-    </div>
+    <ReactJSONView
+      src={data}
+      collapsed={1}
+      quotesOnKeys={false}
+      style={{ padding: '20px', flexGrow: 1 }}
+      theme={configuration.theme}
+      iconStyle={configuration.iconStyle}
+      displayDataTypes={configuration.displayDataTypes}
+      displayObjectSize={configuration.displayObjectSize}
+      enableClipboard={configuration.enableClipboard}
+    />
   );
 });
 
+const RawJSONSettings = ({
+  configuration,
+  graph,
+  updateSettings,
+}: {
+  configuration: RawJSONVisProps;
+  graph: GraphMetaData;
+  updateSettings: (val: any) => void;
+}) => {
+  return (
+    <SettingsContainer>
+      <Input
+        type="dropdown"
+        label="Select a theme"
+        value={configuration.theme}
+        options={['bright:inverted', 'monokai', 'ocean']}
+        onChange={(val) => updateSettings({ theme: val })}
+      />
+      <Input
+        type="dropdown"
+        label="Icon style"
+        value={configuration.iconStyle}
+        options={['circle', 'square', 'triangle']}
+        onChange={(val) => updateSettings({ iconStyle: val })}
+      />
+      {/* <Input
+        type="boolean"
+        label="Show data types"
+        value={configuration.showDataTypes}
+        onChange={(val) => updateSettings({ showDataTypes: val })}
+      />
+      <Input
+        type="boolean"
+        label="Show object size"
+        value={configuration.showObjectSize}
+        onChange={(val) => updateSettings({ showObjectSize: val })}
+      />
+      <Input
+        type="boolean"
+        label="Enable clipboard"
+        value={configuration.enableClipboard}
+        onChange={(val) => updateSettings({ enableClipboard: val })}
+      /> */}
+    </SettingsContainer>
+  );
+};
+
 export const RawJSONComponent: VISComponentType = {
   displayName: 'RawJSONVis',
-  VIS: RawJSONVis,
-  settings: {},
+  component: RawJSONVis,
+  settings: RawJSONSettings,
+  configuration: configuration,
 };
 export default RawJSONComponent;
diff --git a/libs/shared/lib/vis/visualizations/semanticsubstrates/subcomponents/OptimizedAutocomplete.tsx b/libs/shared/lib/vis/visualizations/semanticsubstrates/subcomponents/OptimizedAutocomplete.tsx
deleted file mode 100644
index 194a3bbf5..000000000
--- a/libs/shared/lib/vis/visualizations/semanticsubstrates/subcomponents/OptimizedAutocomplete.tsx
+++ /dev/null
@@ -1,94 +0,0 @@
-/**
- * This program has been developed by students from the bachelor Computer Science at
- * Utrecht University within the Software Project course.
- * © Copyright Utrecht University (Department of Information and Computing Sciences)
- */
-
-/* istanbul ignore file */
-/* The comment above was added so the code coverage wouldn't count this file towards code coverage.
- * We do not test components/renderfunctions/styling files.
- * See testing plan for more details.*/
-
-import React from 'react';
-import { VariableSizeList, ListChildComponentProps } from 'react-window';
-import styles from './OptimizedAutocomplete.module.scss';
-
-const LISTBOX_PADDING = 8; // px
-
-function renderRow(props: ListChildComponentProps) {
-  const { data, index, style } = props;
-  return React.cloneElement(data[index], {
-    style: {
-      ...style,
-      top: (style.top as number) + LISTBOX_PADDING,
-    },
-  });
-}
-
-const OuterElementContext = React.createContext({});
-
-const OuterElementType = React.forwardRef<HTMLDivElement>((props, ref) => {
-  const outerProps = React.useContext(OuterElementContext);
-  return <div ref={ref} {...props} {...outerProps} />;
-});
-
-function useResetCache(data: any) {
-  const ref = React.useRef<VariableSizeList>(null);
-  React.useEffect(() => {
-    if (ref.current != null) {
-      ref.current.resetAfterIndex(0, true);
-    }
-  }, [data]);
-  return ref;
-}
-
-// Adapter for react-window
-const ListboxComponent = React.forwardRef<HTMLDivElement>(function ListboxComponent(props: any, ref) {
-  const { children, ...other } = props;
-  const itemData = React.Children.toArray(children);
-  const itemCount = itemData.length;
-  const itemSize = 36;
-
-  return <div ref={ref}></div>;
-});
-
-const renderGroup = (params: any) => [<div key={params.key}>{params.group}</div>, params.children];
-
-type OptimizedAutocomplete = {
-  currentValue: string;
-  options: string[];
-  useMaterialStyle?: { label: string; helperText: string };
-  /** Called when the value of the input field changes. */
-  onChange?(value: string): void;
-  /** Called when the user leaves focus of the input field. */
-  onLeave?(value: string): void;
-};
-/** Renders the autocomplete input field with the given props. */
-export default function OptimizedAutocomplete(props: OptimizedAutocomplete) {
-  let newValue = props.currentValue;
-  console.log(props);
-
-  return (
-    <input
-      id="optimized-autocomplete"
-      style={{ width: 200 }}
-      className={styles.listbox}
-      // defaultValue={props.currentValue}
-      placeholder={props.currentValue}
-      // renderOption={(props, option, state) => <Typography noWrap>{option}</Typography>}
-      onChange={(e) => {
-        let value = e.target.value;
-        console.log(value);
-
-        newValue = value || '?';
-        if (props.onChange) props.onChange(newValue);
-      }}
-      onBlur={() => {
-        if (props.onLeave) props.onLeave(newValue);
-      }}
-      onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>): void => {
-        if (e.key == 'Enter' && props.onLeave) props.onLeave(newValue);
-      }}
-    />
-  );
-}
diff --git a/libs/shared/lib/vis/visualizations/semanticsubstratesvis/components/types.tsx b/libs/shared/lib/vis/visualizations/semanticsubstratesvis/components/types.ts
similarity index 100%
rename from libs/shared/lib/vis/visualizations/semanticsubstratesvis/components/types.tsx
rename to libs/shared/lib/vis/visualizations/semanticsubstratesvis/components/types.ts
diff --git a/libs/shared/lib/vis/visualizations/semanticsubstratesvis/semanticsubstratesvis.stories.tsx b/libs/shared/lib/vis/visualizations/semanticsubstratesvis/semanticsubstratesvis.stories.tsx
index 752304cb0..89b021f5f 100644
--- a/libs/shared/lib/vis/visualizations/semanticsubstratesvis/semanticsubstratesvis.stories.tsx
+++ b/libs/shared/lib/vis/visualizations/semanticsubstratesvis/semanticsubstratesvis.stories.tsx
@@ -1,16 +1,7 @@
 import React from 'react';
 import { Meta } from '@storybook/react';
-import { VisualizationPanel } from '../../visualizationPanel';
-import { SchemaUtils } from '../../../schema/schema-utils';
-
-import {
-  setNewGraphQueryResult,
-  graphQueryResultSlice,
-  querybuilderSlice,
-  schemaSlice,
-  setSchema,
-  visualizationSlice,
-} from '../../../data-access/store';
+import { SemSubstrVisComponent } from './semanticsubstratesvis';
+import { graphQueryResultSlice, querybuilderSlice, schemaSlice, visualizationSlice } from '../../../data-access/store';
 import { configureStore } from '@reduxjs/toolkit';
 import { Provider } from 'react-redux';
 import {
@@ -20,15 +11,20 @@ import {
   marieBoucherSampleSchemaRaw,
   big2ndChamberSchemaRaw,
 } from '../../../mock-data';
-import { setActiveVisualization } from '@graphpolaris/shared/lib/data-access/store/visualizationSlice';
+import { graphQueryBackend2graphQuery } from '@graphpolaris/shared/lib/data-access/store/graphQueryResultSlice';
+
+const Mockstore = configureStore({
+  reducer: {
+    schema: schemaSlice.reducer,
+    graphQueryResult: graphQueryResultSlice.reducer,
+    visualize: visualizationSlice.reducer,
+    querybuilder: querybuilderSlice.reducer,
+  },
+});
 
-const Component: Meta<typeof VisualizationPanel> = {
-  /* 👇 The title prop is optional.
-   * See https://storybook.js.org/docs/react/configure/overview#configure-story-loading
-   * to learn how to generate automatic titles
-   */
-  title: 'Visualizations/VisSemanticSubstrates',
-  component: VisualizationPanel,
+const Component: Meta<typeof SemSubstrVisComponent.component> = {
+  title: 'Visualizations/SemanticSubstrates',
+  component: SemSubstrVisComponent.component,
   decorators: [
     (story) => (
       <Provider store={Mockstore}>
@@ -45,42 +41,24 @@ const Component: Meta<typeof VisualizationPanel> = {
   ],
 };
 
-const Mockstore = configureStore({
-  reducer: {
-    schema: schemaSlice.reducer,
-    graphQueryResult: graphQueryResultSlice.reducer,
-    visualize: visualizationSlice.reducer,
-    querybuilder: querybuilderSlice.reducer,
-  },
-});
-
 export const TestWithBig2ndChamber = {
-  play: async () => {
-    const dispatch = Mockstore.dispatch;
-    const schema = SchemaUtils.schemaBackend2Graphology(big2ndChamberSchemaRaw);
-    dispatch(setSchema(schema.export()));
-    dispatch(setNewGraphQueryResult({ queryID: '1', result: { type: 'nodelink', payload: big2ndChamberQueryResult } }));
-    dispatch(setActiveVisualization('SemSubstrVis'));
+  args: {
+    data: graphQueryBackend2graphQuery(big2ndChamberQueryResult),
+    configuration: SemSubstrVisComponent.configuration,
   },
 };
 
 export const TestWithRecommendationsActorMovie = {
-  play: async () => {
-    const dispatch = Mockstore.dispatch;
-    const schema = SchemaUtils.schemaBackend2Graphology(marieBoucherSampleSchemaRaw);
-    dispatch(setSchema(schema.export()));
-    dispatch(setNewGraphQueryResult({ queryID: '1', result: { type: 'nodelink', payload: mockRecommendationsActorMovie } }));
-    dispatch(setActiveVisualization('SemSubstrVis'));
+  args: {
+    data: graphQueryBackend2graphQuery(mockRecommendationsActorMovie),
+    configuration: SemSubstrVisComponent.configuration,
   },
 };
 
 export const TestWithGOTcharacter2character = {
-  play: async () => {
-    const dispatch = Mockstore.dispatch;
-    const schema = SchemaUtils.schemaBackend2Graphology(marieBoucherSampleSchemaRaw);
-    dispatch(setSchema(schema.export()));
-    dispatch(setNewGraphQueryResult({ queryID: '1', result: { type: 'nodelink', payload: gotCharacter2Character } }));
-    dispatch(setActiveVisualization('SemSubstrVis'));
+  args: {
+    data: graphQueryBackend2graphQuery(gotCharacter2Character),
+    configuration: SemSubstrVisComponent.configuration,
   },
 };
 
diff --git a/libs/shared/lib/vis/visualizations/semanticsubstratesvis/semanticsubstratesvis.tsx b/libs/shared/lib/vis/visualizations/semanticsubstratesvis/semanticsubstratesvis.tsx
index 56bc0a031..8b73e3768 100644
--- a/libs/shared/lib/vis/visualizations/semanticsubstratesvis/semanticsubstratesvis.tsx
+++ b/libs/shared/lib/vis/visualizations/semanticsubstratesvis/semanticsubstratesvis.tsx
@@ -1,8 +1,10 @@
 import React, { useRef, useState, useMemo, useEffect } from 'react';
 import Scatterplot, { KeyedScatterplotProps } from './components/Scatterplot';
+import { GraphMetaData } from '@graphpolaris/shared/lib/data-access/statistics';
+import { SettingsContainer } from '@graphpolaris/shared/lib/vis/components/config';
 
 import { categoricalColors } from 'config/src/colors';
-import { VISComponentType, VisualizationPropTypes } from '../../types';
+import { VisualizationPropTypes, VISComponentType } from '../../common';
 import { findConnectionsNodes, getRegionData, setExtension, filterArray, getUniqueValues } from './components/utils';
 
 import { Node } from '@graphpolaris/shared/lib/data-access/store/graphQueryResultSlice';
@@ -24,15 +26,21 @@ import { MultiGraph } from 'graphology';
 import { select, selectAll, scaleOrdinal } from 'd3';
 
 import { buildGraphology, configVisualRegion, config, numColorsCategorical, marginAxis, isColorCircleFix } from './utils';
+import { Input } from '../../..';
 
 export type SemSubstrProps = {
   showColor: boolean;
 };
 
+const configuration: SemSubstrProps = {
+  showColor: true,
+};
+
 const displayName = 'SemSubstrVis';
-export const VisSemanticSubstrates = ({ data: graphQueryResult, schema, settings }: VisualizationPropTypes) => {
-  const nodes = graphQueryResult.nodes;
-  const edges = graphQueryResult.edges;
+
+export const VisSemanticSubstrates = ({ data, configuration }: VisualizationPropTypes) => {
+  const nodes = data.nodes;
+  const edges = data.edges;
 
   const divRef = useRef<HTMLDivElement>(null);
   const idEdges = useRef<string[][]>([]);
@@ -415,10 +423,27 @@ export const VisSemanticSubstrates = ({ data: graphQueryResult, schema, settings
   );
 };
 
+const SemSubstrSettings = ({
+  configuration,
+  graph,
+  updateSettings,
+}: {
+  configuration: SemSubstrProps;
+  graph: GraphMetaData;
+  updateSettings: (val: any) => void;
+}) => {
+  return (
+    <SettingsContainer>
+      <Input type="boolean" label="Show color" value={configuration.showColor} onChange={(val) => updateSettings({ showColor: val })} />
+    </SettingsContainer>
+  );
+};
+
 export const SemSubstrVisComponent: VISComponentType = {
   displayName: displayName,
-  VIS: VisSemanticSubstrates,
-  settings: {},
+  component: VisSemanticSubstrates,
+  settings: SemSubstrSettings,
+  configuration: configuration,
 };
 
 export default SemSubstrVisComponent;
diff --git a/libs/shared/lib/vis/visualizations/tablevis/components/Table.tsx b/libs/shared/lib/vis/visualizations/tablevis/components/Table.tsx
index c44740686..e5133ca74 100644
--- a/libs/shared/lib/vis/visualizations/tablevis/components/Table.tsx
+++ b/libs/shared/lib/vis/visualizations/tablevis/components/Table.tsx
@@ -16,6 +16,7 @@ export type TableProps = {
   data: AugmentedNodeAttributes[];
   itemsPerPage: number;
   showBarPlot: boolean;
+  showAttributes: string[];
 };
 type Data2RenderI = {
   name: string;
@@ -27,7 +28,7 @@ type Data2RenderI = {
 
 const THRESHOLD_WIDTH = 100;
 
-export const Table = ({ data, itemsPerPage, showBarPlot }: TableProps) => {
+export const Table = ({ data, itemsPerPage, showBarPlot, showAttributes }: TableProps) => {
   const maxUniqueValues = 29;
   const barPlotNumBins = 10;
   const fetchAttributes = 0;
@@ -42,9 +43,12 @@ export const Table = ({ data, itemsPerPage, showBarPlot }: TableProps) => {
     currentData: AugmentedNodeAttributes[];
   } | null>(null);
   const [data2Render, setData2Render] = useState<Data2RenderI[]>([]);
-  //const dataColumns = useMemo(() => Object.keys(data[0].attribute), [data]);
-
-  const dataColumns = useMemo(() => Object.keys(data[data.length > fetchAttributes ? fetchAttributes : 0].attribute), [data]);
+  const dataColumns = useMemo(() => {
+    if (showAttributes && showAttributes.length > 0) {
+      return showAttributes.filter((attr) => Object.keys(data[0].attribute).includes(attr));
+    }
+    return Object.keys(data[0].attribute);
+  }, [data, showAttributes]);
   const totalPages = Math.ceil(sortedData.length / itemsPerPage);
 
   const [columnWidths, setColumnWidths] = useState<number[]>([]);
diff --git a/libs/shared/lib/vis/visualizations/tablevis/tablevis.stories.tsx b/libs/shared/lib/vis/visualizations/tablevis/tablevis.stories.tsx
index 0b0c85d84..26488d4a2 100644
--- a/libs/shared/lib/vis/visualizations/tablevis/tablevis.stories.tsx
+++ b/libs/shared/lib/vis/visualizations/tablevis/tablevis.stories.tsx
@@ -1,14 +1,6 @@
 import React from 'react';
 import { Meta } from '@storybook/react';
-import { VisualizationPanel } from '../../visualizationPanel';
-import {
-  setNewGraphQueryResult,
-  graphQueryResultSlice,
-  querybuilderSlice,
-  schemaSlice,
-  setSchema,
-  visualizationSlice,
-} from '../../../data-access/store';
+import { graphQueryResultSlice, querybuilderSlice, schemaSlice, visualizationSlice } from '../../../data-access/store';
 import { configureStore } from '@reduxjs/toolkit';
 import { Provider } from 'react-redux';
 import {
@@ -18,14 +10,21 @@ import {
   typesMockQueryResults,
   typesMockSchemaRaw,
 } from '../../../mock-data';
-
-import { SchemaUtils } from '../../../schema/schema-utils';
 import { simpleSchemaAirportRaw } from '../../../mock-data/schema/simpleAirportRaw';
-import { setActiveVisualization } from '@graphpolaris/shared/lib/data-access/store/visualizationSlice';
+import TableComponent from './tablevis';
+
+const Mockstore = configureStore({
+  reducer: {
+    schema: schemaSlice.reducer,
+    graphQueryResult: graphQueryResultSlice.reducer,
+    visualize: visualizationSlice.reducer,
+    querybuilder: querybuilderSlice.reducer,
+  },
+});
 
-const Component: Meta<typeof VisualizationPanel> = {
+const Component: Meta<typeof TableComponent.component> = {
   title: 'Visualizations/TableVis',
-  component: VisualizationPanel,
+  component: TableComponent.component,
   decorators: [
     (story) => (
       <Provider store={Mockstore}>
@@ -42,45 +41,27 @@ const Component: Meta<typeof VisualizationPanel> = {
   ],
 };
 
-const Mockstore = configureStore({
-  reducer: {
-    schema: schemaSlice.reducer,
-    graphQueryResult: graphQueryResultSlice.reducer,
-    visualize: visualizationSlice.reducer,
-    querybuilder: querybuilderSlice.reducer,
-  },
-});
-
 export const TestWithAirport = {
-  play: async () => {
-    const dispatch = Mockstore.dispatch;
-    const schema = SchemaUtils.schemaBackend2Graphology(simpleSchemaAirportRaw);
-
-    dispatch(setSchema(schema.export()));
-    dispatch(setNewGraphQueryResult({ queryID: '1', result: { type: 'nodelink', payload: bigMockQueryResults } }));
-    dispatch(setActiveVisualization('TableVis'));
+  args: {
+    data: bigMockQueryResults,
+    schema: simpleSchemaAirportRaw,
+    configuration: TableComponent.configuration,
   },
 };
 
 export const TestWithBig2ndChamber = {
-  play: async () => {
-    const dispatch = Mockstore.dispatch;
-    const schema = SchemaUtils.schemaBackend2Graphology(big2ndChamberSchemaRaw);
-
-    dispatch(setSchema(schema.export()));
-    dispatch(setNewGraphQueryResult({ queryID: '1', result: { type: 'nodelink', payload: big2ndChamberQueryResult } }));
-    dispatch(setActiveVisualization('TableVis'));
+  args: {
+    data: big2ndChamberQueryResult,
+    schema: big2ndChamberSchemaRaw,
+    configuration: TableComponent.configuration,
   },
 };
 
 export const TestWithTypesMock = {
-  play: async () => {
-    const dispatch = Mockstore.dispatch;
-    const schema = SchemaUtils.schemaBackend2Graphology(typesMockSchemaRaw);
-
-    dispatch(setSchema(schema.export()));
-    dispatch(setNewGraphQueryResult({ queryID: '1', result: { type: 'nodelink', payload: typesMockQueryResults } }));
-    dispatch(setActiveVisualization('TableVis'));
+  args: {
+    data: typesMockQueryResults,
+    schema: typesMockSchemaRaw,
+    configuration: TableComponent.configuration,
   },
 };
 
diff --git a/libs/shared/lib/vis/visualizations/tablevis/tablevis.tsx b/libs/shared/lib/vis/visualizations/tablevis/tablevis.tsx
index f1cc8dac1..552b40db3 100644
--- a/libs/shared/lib/vis/visualizations/tablevis/tablevis.tsx
+++ b/libs/shared/lib/vis/visualizations/tablevis/tablevis.tsx
@@ -1,14 +1,24 @@
 import React, { useMemo, useRef } from 'react';
 import { Table, AugmentedNodeAttributes } from './components/Table';
 import { SchemaAttribute } from '../../../schema';
-import { VisualizationPropTypes, VISComponentType } from '../../types';
+import { VisualizationPropTypes, VISComponentType } from '../../common';
+import { Input } from '@graphpolaris/shared/lib/components/inputs';
+import { GraphMetaData } from '@graphpolaris/shared/lib/data-access/statistics';
+import { SettingsContainer } from '@graphpolaris/shared/lib/vis/components/config';
 
 export type TableProps = {
   showBarplot: boolean;
   itemsPerPage: number;
+  displayAttributes: string[];
 };
 
-export const TableVis = ({ data, schema, settings }: VisualizationPropTypes) => {
+const configuration: TableProps = {
+  itemsPerPage: 10,
+  showBarplot: false,
+  displayAttributes: [],
+};
+
+export const TableVis = ({ data, schema, configuration }: VisualizationPropTypes) => {
   const ref = useRef<HTMLDivElement>(null);
 
   const attributesArray = useMemo<AugmentedNodeAttributes[]>(
@@ -24,33 +34,85 @@ export const TableVis = ({ data, schema, settings }: VisualizationPropTypes) =>
           type: Object.fromEntries(types.map((t) => [t.name, t.type])),
         };
       }),
-    [data.nodes]
+    [data.nodes],
   );
 
   return (
     <div className="h-full w-full" ref={ref}>
       {attributesArray.length > 0 && (
-        <Table data={attributesArray} itemsPerPage={settings.itemsPerPage} showBarPlot={settings.showBarplot} />
+        <Table
+          data={attributesArray}
+          itemsPerPage={configuration.itemsPerPage}
+          showBarPlot={configuration.showBarplot}
+          showAttributes={configuration.displayAttributes}
+        />
       )}
     </div>
   );
 };
 
+const TableSettings = ({
+  configuration,
+  graph,
+  updateSettings,
+}: {
+  configuration: TableProps;
+  graph: GraphMetaData;
+  updateSettings: (val: any) => void;
+}) => {
+  const allAttributes: string[] = Object.keys(graph.nodes.types).reduce((acc: string[], label: string) => {
+    const labelAttributes = Object.keys(graph.nodes.types[label].attributes);
+    return acc.concat(labelAttributes);
+  }, []);
+
+  // Find the intersection of attributes across all nodes
+  const intersectionAttributes = allAttributes.filter((attr) => {
+    return Object.keys(graph.nodes.types).every((label) => {
+      return graph.nodes.types[label].attributes.hasOwnProperty(attr);
+    });
+  });
+
+  const uniqueIntersectionAttributes = Array.from(new Set(intersectionAttributes));
+
+  return (
+    <SettingsContainer>
+      <Input
+        type="dropdown"
+        label="Items per page"
+        value={configuration.itemsPerPage}
+        onChange={(val) => updateSettings({ itemsPerPage: val })}
+        options={[10, 25, 50, 100]}
+      />
+      <Input
+        type="boolean"
+        label="Show barplot"
+        value={configuration.showBarplot}
+        onChange={(val) => updateSettings({ showBarplot: val })}
+      />
+
+      <div>
+        <span className="text-sm">Attributes to display</span>
+        <div className="">
+          <Input
+            type="checkbox"
+            value={configuration.displayAttributes}
+            options={uniqueIntersectionAttributes}
+            onChange={(val: string[] | string) => {
+              const updatedVal = Array.isArray(val) ? val : [val];
+              updateSettings({ displayAttributes: updatedVal });
+            }}
+          />
+        </div>
+      </div>
+    </SettingsContainer>
+  );
+};
+
 export const TableComponent: VISComponentType = {
   displayName: 'TableVis',
-  VIS: TableVis,
-  settings: {
-    showBarplot: {
-      value: true,
-      type: 'boolean',
-      label: 'Show barplot',
-    },
-    itemsPerPage: {
-      value: 10,
-      type: 'dropdown',
-      label: 'Items per page',
-      options: [10, 20, 30],
-    },
-  },
+  component: TableVis,
+  settings: TableSettings,
+  configuration: configuration,
 };
+
 export default TableComponent;
diff --git a/libs/shared/package.json b/libs/shared/package.json
index bccd77823..aef1e4dc9 100644
--- a/libs/shared/package.json
+++ b/libs/shared/package.json
@@ -24,6 +24,7 @@
     "@mui/icons-material": "^5.15.13",
     "@nebula.gl/layers": "^1.0.4",
     "@pixi-essentials/cull": "^2.0.0",
+    "@radix-ui/react-dropdown-menu": "^2.0.6",
     "@radix-ui/react-tooltip": "^1.0.7",
     "@reactflow/node-resizer": "^2.2.9",
     "@reduxjs/toolkit": "^2.2.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index cce9a2689..8edaf1eed 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -244,6 +244,9 @@ importers:
       '@pixi-essentials/cull':
         specifier: ^2.0.0
         version: 2.0.0(@pixi/display@7.4.0)(@pixi/math@7.4.0)
+      '@radix-ui/react-dropdown-menu':
+        specifier: ^2.0.6
+        version: 2.0.6(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0)(react@18.2.0)
       '@radix-ui/react-tooltip':
         specifier: ^1.0.7
         version: 1.0.7(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0)(react@18.2.0)
@@ -5902,7 +5905,6 @@ packages:
       '@types/react-dom': 18.2.22
       react: 18.2.0
       react-dom: 18.2.0(react@18.2.0)
-    dev: true
 
   /@radix-ui/react-compose-refs@1.0.1(@types/react@18.2.65)(react@18.2.0):
     resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==}
@@ -5942,7 +5944,6 @@ packages:
       '@babel/runtime': 7.24.0
       '@types/react': 18.2.65
       react: 18.2.0
-    dev: true
 
   /@radix-ui/react-dismissable-layer@1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0)(react@18.2.0):
     resolution: {integrity: sha512-7UpBa/RKMoHJYjie1gkF1DlK8l1fdU/VKDpoS3rCCo8YBJR294GwcEHyxHw72yvphJ7ld0AXEcSLAzY2F/WyCg==}
@@ -5994,6 +5995,33 @@ packages:
       react-dom: 18.2.0(react@18.2.0)
     dev: false
 
+  /@radix-ui/react-dropdown-menu@2.0.6(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0)(react@18.2.0):
+    resolution: {integrity: sha512-i6TuFOoWmLWq+M/eCLGd/bQ2HfAX1RJgvrBQ6AQLmzfvsLdefxbWu8G9zczcPFfcSPehz9GcpF6K9QYreFV8hA==}
+    peerDependencies:
+      '@types/react': '*'
+      '@types/react-dom': '*'
+      react: ^16.8 || ^17.0 || ^18.0
+      react-dom: ^16.8 || ^17.0 || ^18.0
+    peerDependenciesMeta:
+      '@types/react':
+        optional: true
+      '@types/react-dom':
+        optional: true
+    dependencies:
+      '@babel/runtime': 7.24.0
+      '@radix-ui/primitive': 1.0.1
+      '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.65)(react@18.2.0)
+      '@radix-ui/react-context': 1.0.1(@types/react@18.2.65)(react@18.2.0)
+      '@radix-ui/react-id': 1.0.1(@types/react@18.2.65)(react@18.2.0)
+      '@radix-ui/react-menu': 2.0.6(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0)(react@18.2.0)
+      '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0)(react@18.2.0)
+      '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.65)(react@18.2.0)
+      '@types/react': 18.2.65
+      '@types/react-dom': 18.2.22
+      react: 18.2.0
+      react-dom: 18.2.0(react@18.2.0)
+    dev: false
+
   /@radix-ui/react-focus-guards@1.0.1(@types/react@18.2.65)(react@18.2.0):
     resolution: {integrity: sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==}
     peerDependencies:
@@ -6006,7 +6034,6 @@ packages:
       '@babel/runtime': 7.24.0
       '@types/react': 18.2.65
       react: 18.2.0
-    dev: true
 
   /@radix-ui/react-focus-scope@1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0)(react@18.2.0):
     resolution: {integrity: sha512-upXdPfqI4islj2CslyfUBNlaJCPybbqRHAi1KER7Isel9Q2AtSJ0zRBZv8mWQiFXD2nyAJ4BhC3yXgZ6kMBSrQ==}
@@ -6031,6 +6058,29 @@ packages:
       react-dom: 18.2.0(react@18.2.0)
     dev: true
 
+  /@radix-ui/react-focus-scope@1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0)(react@18.2.0):
+    resolution: {integrity: sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==}
+    peerDependencies:
+      '@types/react': '*'
+      '@types/react-dom': '*'
+      react: ^16.8 || ^17.0 || ^18.0
+      react-dom: ^16.8 || ^17.0 || ^18.0
+    peerDependenciesMeta:
+      '@types/react':
+        optional: true
+      '@types/react-dom':
+        optional: true
+    dependencies:
+      '@babel/runtime': 7.24.0
+      '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.65)(react@18.2.0)
+      '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0)(react@18.2.0)
+      '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.65)(react@18.2.0)
+      '@types/react': 18.2.65
+      '@types/react-dom': 18.2.22
+      react: 18.2.0
+      react-dom: 18.2.0(react@18.2.0)
+    dev: false
+
   /@radix-ui/react-id@1.0.1(@types/react@18.2.65)(react@18.2.0):
     resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==}
     peerDependencies:
@@ -6045,6 +6095,44 @@ packages:
       '@types/react': 18.2.65
       react: 18.2.0
 
+  /@radix-ui/react-menu@2.0.6(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0)(react@18.2.0):
+    resolution: {integrity: sha512-BVkFLS+bUC8HcImkRKPSiVumA1VPOOEC5WBMiT+QAVsPzW1FJzI9KnqgGxVDPBcql5xXrHkD3JOVoXWEXD8SYA==}
+    peerDependencies:
+      '@types/react': '*'
+      '@types/react-dom': '*'
+      react: ^16.8 || ^17.0 || ^18.0
+      react-dom: ^16.8 || ^17.0 || ^18.0
+    peerDependenciesMeta:
+      '@types/react':
+        optional: true
+      '@types/react-dom':
+        optional: true
+    dependencies:
+      '@babel/runtime': 7.24.0
+      '@radix-ui/primitive': 1.0.1
+      '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0)(react@18.2.0)
+      '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.65)(react@18.2.0)
+      '@radix-ui/react-context': 1.0.1(@types/react@18.2.65)(react@18.2.0)
+      '@radix-ui/react-direction': 1.0.1(@types/react@18.2.65)(react@18.2.0)
+      '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0)(react@18.2.0)
+      '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.65)(react@18.2.0)
+      '@radix-ui/react-focus-scope': 1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0)(react@18.2.0)
+      '@radix-ui/react-id': 1.0.1(@types/react@18.2.65)(react@18.2.0)
+      '@radix-ui/react-popper': 1.1.3(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0)(react@18.2.0)
+      '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0)(react@18.2.0)
+      '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0)(react@18.2.0)
+      '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0)(react@18.2.0)
+      '@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0)(react@18.2.0)
+      '@radix-ui/react-slot': 1.0.2(@types/react@18.2.65)(react@18.2.0)
+      '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.65)(react@18.2.0)
+      '@types/react': 18.2.65
+      '@types/react-dom': 18.2.22
+      aria-hidden: 1.2.3
+      react: 18.2.0
+      react-dom: 18.2.0(react@18.2.0)
+      react-remove-scroll: 2.5.5(@types/react@18.2.65)(react@18.2.0)
+    dev: false
+
   /@radix-ui/react-popper@1.1.2(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0)(react@18.2.0):
     resolution: {integrity: sha512-1CnGGfFi/bbqtJZZ0P/NQY20xdG3E0LALJaLUEoKwPLwl6PPPfbeiCqMVQnhoFRAxjJj4RpBRJzDmUgsex2tSg==}
     peerDependencies:
@@ -6216,7 +6304,6 @@ packages:
       '@types/react-dom': 18.2.22
       react: 18.2.0
       react-dom: 18.2.0(react@18.2.0)
-    dev: true
 
   /@radix-ui/react-select@1.2.2(@types/react-dom@18.2.22)(@types/react@18.2.65)(react-dom@18.2.0)(react@18.2.0):
     resolution: {integrity: sha512-zI7McXr8fNaSrUY9mZe4x/HC0jTLY9fWNhO1oLWYMQGDXuV4UCivIGTxwioSzO0ZCYX9iSLyWmAh/1TOmX3Cnw==}
@@ -9954,7 +10041,6 @@ packages:
     engines: {node: '>=10'}
     dependencies:
       tslib: 2.6.2
-    dev: true
 
   /aria-query@5.1.3:
     resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==}
@@ -10621,7 +10707,7 @@ packages:
     engines: {node: '>=10.0.0'}
     requiresBuild: true
     dependencies:
-      '@babel/runtime': 7.21.0
+      '@babel/runtime': 7.24.0
       '@types/raf': 3.4.0
       core-js: 3.36.0
       raf: 3.4.1
@@ -12135,7 +12221,6 @@ packages:
 
   /detect-node-es@1.1.0:
     resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==}
-    dev: true
 
   /detect-package-manager@2.0.1:
     resolution: {integrity: sha512-j/lJHyoLlWi6G1LDdLgvUtz60Zo5GEj+sVYtTVXnYLDPuzgC3llMxonXym9zIwhhUII8vjdw0LXxavpLqTbl1A==}
@@ -13796,7 +13881,6 @@ packages:
   /get-nonce@1.0.1:
     resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==}
     engines: {node: '>=6'}
-    dev: true
 
   /get-npm-tarball-url@2.1.0:
     resolution: {integrity: sha512-ro+DiMu5DXgRBabqXupW38h7WPZ9+Ad8UjwhvsmmN8w1sU7ab0nzAXvVZ4kqYg57OrqomRtJvepX5/xvFKNtjA==}
@@ -17875,7 +17959,7 @@ packages:
     peerDependencies:
       react: '>=16.13.1'
     dependencies:
-      '@babel/runtime': 7.21.0
+      '@babel/runtime': 7.24.0
       react: 18.2.0
     dev: true
 
@@ -18244,6 +18328,7 @@ packages:
   /react-remove-scroll-bar@2.3.5(@types/react@18.2.65)(react@18.2.0):
     resolution: {integrity: sha512-3cqjOqg6s0XbOjWvmasmqHch+RLxIEk2r/70rzGXuz3iIGQsQheEQyqYCBb5EECoD01Vo2SIbDqW4paLeLTASw==}
     engines: {node: '>=10'}
+    deprecated: please update to the following version as this contains a bug (https://github.com/theKashey/react-remove-scroll-bar/issues/57)
     peerDependencies:
       '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0
       react: ^16.8.0 || ^17.0.0 || ^18.0.0
@@ -18255,7 +18340,6 @@ packages:
       react: 18.2.0
       react-style-singleton: 2.2.1(@types/react@18.2.65)(react@18.2.0)
       tslib: 2.6.2
-    dev: true
 
   /react-remove-scroll@2.5.5(@types/react@18.2.65)(react@18.2.0):
     resolution: {integrity: sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==}
@@ -18274,7 +18358,6 @@ packages:
       tslib: 2.6.2
       use-callback-ref: 1.3.1(@types/react@18.2.65)(react@18.2.0)
       use-sidecar: 1.1.2(@types/react@18.2.65)(react@18.2.0)
-    dev: true
 
   /react-resizable@3.0.5(react-dom@18.2.0)(react@18.2.0):
     resolution: {integrity: sha512-vKpeHhI5OZvYn82kXOs1bC8aOXktGU5AmKAgaZS4F5JPburCtbmDPqE7Pzp+1kN4+Wb81LlF33VpGwWwtXem+w==}
@@ -18349,7 +18432,6 @@ packages:
       invariant: 2.2.4
       react: 18.2.0
       tslib: 2.6.2
-    dev: true
 
   /react-test-renderer@18.2.0(react@18.2.0):
     resolution: {integrity: sha512-JWD+aQ0lh2gvh4NM3bBM42Kx+XybOxCpgYK7F8ugAlpaTSnWsX+39Z4XkOykGZAHrjwwTZT3x3KxswVWxHPUqA==}
@@ -20807,7 +20889,6 @@ packages:
       '@types/react': 18.2.65
       react: 18.2.0
       tslib: 2.6.2
-    dev: true
 
   /use-composed-ref@1.3.0(react@18.2.0):
     resolution: {integrity: sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==}
@@ -20879,7 +20960,6 @@ packages:
       detect-node-es: 1.1.0
       react: 18.2.0
       tslib: 2.6.2
-    dev: true
 
   /use-sync-external-store@1.2.0(react@18.2.0):
     resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==}
-- 
GitLab