From 503feee785e90803494b34c300ebbd39712c45e8 Mon Sep 17 00:00:00 2001
From: 2427021 <s.a.vink@students.uu.nl>
Date: Sun, 24 Mar 2024 16:17:57 +0100
Subject: [PATCH] feat(visManager): improved manager

---
 .../data-access/store/visualizationSlice.ts   |  54 +++-----
 .../vis/configuration/advanced/advanced.tsx   |  25 ----
 .../lib/vis/configuration/advanced/index.ts   |   1 -
 .../vis/configuration/encodings/encoding.tsx  |  67 ----------
 .../lib/vis/configuration/encodings/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/manager.tsx               | 124 ++++++++++++++++++
 libs/shared/lib/vis/types.ts                  |  30 ++---
 libs/shared/lib/vis/visualizationManager.tsx  | 104 ---------------
 libs/shared/lib/vis/visualizationPanel.tsx    |  25 ++--
 .../lib/vis/visualizations/mapvis/mapvis.tsx  |  24 +++-
 .../visualizations/matrixvis/matrixvis.tsx    |  50 +++++--
 .../nodelinkvis/nodelinkvis.tsx               |  85 ++++++------
 .../vis/visualizations/paohvis/paohvis.tsx    |  46 +++++--
 .../visualizations/rawjsonvis/rawjsonvis.tsx  |  20 ++-
 .../vis/visualizations/tablevis/tablevis.tsx  |  59 ++++++---
 25 files changed, 351 insertions(+), 600 deletions(-)
 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/encoding.tsx
 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/manager.tsx
 delete mode 100644 libs/shared/lib/vis/visualizationManager.tsx

diff --git a/libs/shared/lib/data-access/store/visualizationSlice.ts b/libs/shared/lib/data-access/store/visualizationSlice.ts
index 4cb0d79e4..0a7d865bb 100644
--- a/libs/shared/lib/data-access/store/visualizationSlice.ts
+++ b/libs/shared/lib/data-access/store/visualizationSlice.ts
@@ -1,69 +1,49 @@
-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/types';
 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;
+  active?: string;
+  visualizations: VisStateSettings;
 };
 
 export const initialState: VisState = {
-  activeVisualization: 'NodeLinkVis',
-  settings: {
-    general: {},
-  },
+  active: 'NodeLinkVis',
+  visualizations: {},
 };
 
 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.visualizations[action.payload]) {
+        delete state.visualizations[action.payload];
       }
     },
     setActiveVisualization: (state, action: PayloadAction<string>) => {
-      state.activeVisualization = action.payload;
+      state.active = action.payload;
     },
     setVisualizationState: (state, action: PayloadAction<VisState>) => {
-      if (action.payload.activeVisualization && !isEqual(action.payload, state)) {
-        state.activeVisualization = action.payload.activeVisualization;
-        state.settings = action.payload.settings;
+      if (action.payload.active && !isEqual(action.payload, state)) {
+        state.active = action.payload.active;
+        state.visualizations = action.payload.visualizations;
       }
     },
-    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.visualizations[id] = settings;
     },
   },
 });
 
-export const { addVisualization, removeVisualization, setActiveVisualization, setVisualizationState, updateConfiguration } =
-  visualizationSlice.actions;
+export const { removeVisualization, setActiveVisualization, setVisualizationState, updateVisualization } = visualizationSlice.actions;
 
 export const visualizationState = (state: RootState) => state.visualize;
-export const visualizationAllSettings = (state: RootState) => state.visualize.settings;
+export const visualizationAllSettings = (state: RootState) => state.visualize.visualizations;
 
 export default visualizationSlice.reducer;
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/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
index 056c6ae4d..ea02a9951 100644
--- a/libs/shared/lib/vis/configuration/encodings/index.ts
+++ b/libs/shared/lib/vis/configuration/encodings/index.ts
@@ -1,2 +1 @@
 export type { Encoding, EncodingTypes, EncodingProps } from './encodings.types';
-export { default as EncodingPanel } from './encoding';
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/manager.tsx b/libs/shared/lib/vis/manager.tsx
new file mode 100644
index 000000000..8702e6519
--- /dev/null
+++ b/libs/shared/lib/vis/manager.tsx
@@ -0,0 +1,124 @@
+import React, { useState, useEffect } from 'react';
+import { VISComponentType } from './types';
+import { updateVisualization } from '../data-access/store/visualizationSlice';
+import { useAppDispatch, useGraphQueryResult, useGraphQueryResultMeta, useML, useSchemaGraph, useVisualization } from '../data-access';
+import { FormActions, FormBody, FormCard, FormDiv, FormHBar, FormTitle } from '../components';
+
+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'),
+};
+
+export const useVisualizationManager = () => {
+  const dispatch = useAppDispatch();
+  const ml = useML();
+  const schema = useSchemaGraph();
+  const graphQueryResult = useGraphQueryResult();
+  const meta = useGraphQueryResultMeta();
+  const { active, visualizations } = useVisualization();
+
+  const [configuration, setConfiguration] = useState<any>();
+  const [visualization, setVisualization] = useState<VISComponentType>();
+  const [settings, setSettings] = useState<any>(null);
+  const [settingsOpen, setSettingsOpen] = useState<boolean>(false);
+  const [hoverItem, setHoverItem] = useState<any>();
+  const [selected, setSelected] = useState<any>();
+
+  useEffect(() => {
+    loadVisualization();
+  }, [active]);
+
+  const loadVisualization = async () => {
+    if (active && Visualizations[active]) {
+      const componentModule = await Visualizations[active]();
+      const component = componentModule.default;
+      setVisualization(component);
+      setSettings(null);
+
+      if (!(active in Object.keys(visualizations))) {
+        // Visualization doesn't yet exist so add its configuration
+        const configuration = component.configuration;
+        updateSettings(configuration);
+      }
+
+      setConfiguration(visualizations[active]);
+    }
+  };
+
+  const handleHover = (item: any) => {
+    setHoverItem(item);
+  };
+
+  const handleSelect = (item: any) => {
+    setSelected(item);
+  };
+
+  const updateSettings = (newSettings: any) => {
+    if (active) {
+      const updatedSettings = { ...configuration, ...newSettings };
+      setSettings(updatedSettings);
+      dispatch(updateVisualization({ id: active, settings: updatedSettings }));
+    }
+  };
+
+  const openSettingsMenu = () => {
+    setSettingsOpen(!settingsOpen);
+  };
+
+  const renderSettings = () => {
+    return (
+      visualization?.settings &&
+      settings &&
+      settingsOpen && (
+        <FormDiv>
+          <FormCard>
+            <FormBody
+              onSubmit={(e) => {
+                e.preventDefault();
+                setSettingsOpen(false);
+              }}
+            >
+              <FormTitle title="Visualization settings" onClose={() => {}} />
+              <FormHBar />
+              <visualization.settings configuration={settings} graph={meta} updateSettings={updateSettings} />
+              <FormHBar />
+              <FormActions
+                onClose={() => {
+                  setSettingsOpen(false);
+                }}
+              />
+            </FormBody>
+          </FormCard>
+        </FormDiv>
+      )
+    );
+  };
+
+  const renderComponent = () => {
+    return (
+      visualization?.component &&
+      settings && (
+        <visualization.component
+          data={graphQueryResult}
+          schema={schema}
+          ml={ml}
+          settings={settings}
+          dispatch={dispatch}
+          handleHover={handleHover}
+          handleSelect={handleSelect}
+        />
+      )
+    );
+  };
+
+  return {
+    active,
+    renderComponent,
+    renderSettings,
+    openSettingsMenu,
+  };
+};
diff --git a/libs/shared/lib/vis/types.ts b/libs/shared/lib/vis/types.ts
index cf79a63d5..6f174b786 100644
--- a/libs/shared/lib/vis/types.ts
+++ b/libs/shared/lib/vis/types.ts
@@ -2,38 +2,24 @@ 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';
+import { Visualizations } from './manager';
 
-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 VisualizationConfiguration = { [id: string]: any };
 
 export type VISComponentType = {
   displayName: keyof typeof Visualizations;
-  VIS: FC<any>;
-  settings?: SettingTypes;
-  encodings?: EncodingTypes;
-  interactions?: InteractionTypes;
+  component: FC<any>;
+  settings: FC<any>;
+  configuration: { [id: string]: any };
 };
 
 export type VisualizationPropTypes = {
   data: GraphQueryResult;
   schema: SchemaGraph;
   ml: ML;
+  configuration: VisualizationConfiguration;
   dispatch: AppDispatch;
-  globalConfig: globalConfigPropTypes;
-  settings: SettingProps;
-  encodings?: EncodingProps;
-  interactions?: InteractionProps;
+  handleHover: (val: any) => void;
+  handleSelect: (val: any) => void;
 };
diff --git a/libs/shared/lib/vis/visualizationManager.tsx b/libs/shared/lib/vis/visualizationManager.tsx
deleted file mode 100644
index f9a963ddf..000000000
--- a/libs/shared/lib/vis/visualizationManager.tsx
+++ /dev/null
@@ -1,104 +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'),
-};
-
-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 && (
-        <div className="w-full h-full">
-          <visualizationComponent.VIS
-            data={graphQueryResult}
-            schema={schema}
-            ml={ml}
-            dispatch={dispatch}
-            globalConfig={globalConfig}
-            settings={visSettings}
-            encodings={visEncodings}
-            interactions={visInteractions}
-          />
-        </div>
-      )
-    );
-  } 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
index ab722fc2c..a2e6013a4 100644
--- a/libs/shared/lib/vis/visualizationPanel.tsx
+++ b/libs/shared/lib/vis/visualizationPanel.tsx
@@ -5,19 +5,17 @@ import { setActiveVisualization } from '@graphpolaris/shared/lib/data-access/sto
 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';
+import { useVisualizationManager, Visualizations } from './manager';
 
 export const VisualizationPanel = () => {
   const graphQueryResult = useGraphQueryResult();
   const query = useQuerybuilderGraph();
   const dispatch = useAppDispatch();
   const vis = useVisualization();
+  const manager = useVisualizationManager();
   const [visDropdownOpen, setVisDropdownOpen] = useState<boolean>(false);
-  const [showVisSettings, setShowVisSettings] = useState<boolean>(false);
   const visDropdownRef = useRef<HTMLDivElement>(null);
 
   useEffect(() => {
@@ -27,19 +25,17 @@ export const VisualizationPanel = () => {
       }
     };
     if (visDropdownOpen) document.addEventListener('mousedown', handleClickOutside);
-    return () => {
-      document.removeEventListener('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)} />
+      {manager.renderSettings()}
       <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>
+        <h1 className="text-xs font-semibold text-secondary-800">{vis.active} visualization</h1>
         <ControlContainer>
           <TooltipProvider delayDuration={0}>
-            <Tooltip disabled={showVisSettings}>
+            <Tooltip>
               <TooltipTrigger asChild>
                 <Button
                   type="secondary"
@@ -48,11 +44,11 @@ export const VisualizationPanel = () => {
                   iconComponent={<SettingsIcon />}
                   onClick={() => {
                     // TODO
-                    // setShowVisSettings(!showVisSettings);
+                    manager.openSettingsMenu();
                   }}
                 />
               </TooltipTrigger>
-              <TooltipContent side={'bottom'} disabled={showVisSettings}>
+              <TooltipContent side={'bottom'}>
                 <p>Visualization settings</p>
               </TooltipContent>
             </Tooltip>
@@ -92,7 +88,6 @@ export const VisualizationPanel = () => {
           )}
         </ControlContainer>
       </div>
-
       {graphQueryResult.queryingBackend ? (
         <div className="w-full h-full flex flex-col items-center justify-center overflow-hidden">
           <LoadingSpinner>Querying backend...</LoadingSpinner>
@@ -103,9 +98,7 @@ export const VisualizationPanel = () => {
           {query.nodes.length > 0 ? <p>Query resulted in empty dataset</p> : <p>Query for data to visualize</p>}
         </div>
       ) : (
-        <div className="w-full h-full">
-          <VisualizationManager />
-        </div>
+        <div className="w-full h-full">{manager.renderComponent()}</div>
       )}
     </div>
   );
diff --git a/libs/shared/lib/vis/visualizations/mapvis/mapvis.tsx b/libs/shared/lib/vis/visualizations/mapvis/mapvis.tsx
index 20d218005..d9f84a2cc 100644
--- a/libs/shared/lib/vis/visualizations/mapvis/mapvis.tsx
+++ b/libs/shared/lib/vis/visualizations/mapvis/mapvis.tsx
@@ -3,10 +3,13 @@ import { MapPanel, LayerPanel } from './components';
 import GraphModel from './graphModel';
 import { GraphType, Layer } from './Types';
 import { VISComponentType, VisualizationPropTypes } from '../../types';
+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/matrixvis/matrixvis.tsx b/libs/shared/lib/vis/visualizations/matrixvis/matrixvis.tsx
index 911a5fbae..86c3877bb 100644
--- a/libs/shared/lib/vis/visualizations/matrixvis/matrixvis.tsx
+++ b/libs/shared/lib/vis/visualizations/matrixvis/matrixvis.tsx
@@ -4,8 +4,18 @@ import { GraphQueryResult } from '../../../data-access/store';
 import { LinkType, NodeType } from './Types';
 import { MatrixPixi } from './components/MatrixPixi';
 import { VisualizationPropTypes, VISComponentType } from '../../types';
+import Input from '@graphpolaris/shared/lib/components/inputs';
+import { GraphMetaData } from '@graphpolaris/shared/lib/data-access/statistics';
 
-export const MatrixVis = React.memo(({ data, ml, settings }: VisualizationPropTypes) => {
+export interface MatrixVisProps {
+  marks: string;
+}
+
+const configuration: MatrixVisProps = {
+  marks: 'rect',
+};
+
+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 +30,39 @@ 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} localConfig={configuration} />
       </div>
     </>
   );
 });
 
-const displayName = 'MatrixVis';
+const MatrixSettings = ({
+  configuration,
+  graph,
+  updateSettings,
+}: {
+  configuration: MatrixVisProps;
+  graph: GraphMetaData;
+  updateSettings: (val: any) => void;
+}) => {
+  return (
+    <div>
+      <Input
+        type="dropdown"
+        label="Configure marks"
+        value={configuration.marks}
+        options={['rect', 'circle']}
+        onChange={(val) => updateSettings({ marks: val })}
+      />
+    </div>
+  );
+};
 
 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/nodelinkvis/nodelinkvis.tsx b/libs/shared/lib/vis/visualizations/nodelinkvis/nodelinkvis.tsx
index 6c86c681c..8d1d36db2 100644
--- a/libs/shared/lib/vis/visualizations/nodelinkvis/nodelinkvis.tsx
+++ b/libs/shared/lib/vis/visualizations/nodelinkvis/nodelinkvis.tsx
@@ -5,6 +5,18 @@ 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 Input from '@graphpolaris/shared/lib/components/inputs';
+import { GraphMetaData } from '@graphpolaris/shared/lib/data-access/statistics';
+
+export interface NodelinkVisProps {
+  layout: string;
+  showPopUpOnHover: boolean;
+}
+
+const configuration: NodelinkVisProps = {
+  layout: 'Force directed',
+  showPopUpOnHover: true,
+};
 
 export const NodeLinkVis = React.memo(({ data, ml, dispatch }: VisualizationPropTypes) => {
   const ref = useRef<HTMLDivElement>(null);
@@ -18,7 +30,7 @@ export const NodeLinkVis = React.memo(({ data, ml, dispatch }: VisualizationProp
         parseQueryResult(data, ml, {
           defaultX: (ref.current?.clientWidth || 1000) / 2,
           defaultY: (ref.current?.clientHeight || 1000) / 2,
-        })
+        }),
       );
     }
   }, [data, ml]);
@@ -70,48 +82,39 @@ export const NodeLinkVis = React.memo(({ data, ml, dispatch }: VisualizationProp
   );
 });
 
+const NodelinkSettings = ({
+  configuration,
+  graph,
+  updateSettings,
+}: {
+  configuration: NodelinkVisProps;
+  graph: GraphMetaData;
+  updateSettings: (val: any) => void;
+}) => {
+  return (
+    <div>
+      <Input
+        type="dropdown"
+        label="Layout"
+        value={configuration.layout}
+        options={['Force directed']}
+        onChange={(val) => updateSettings({ layout: val })}
+      />
+      <Input
+        type="boolean"
+        label="Show pop-up on hover"
+        value={configuration.showPopUpOnHover}
+        onChange={(val) => updateSettings({ showPopUpOnHover: val })}
+      />
+    </div>
+  );
+};
+
 export const NodeLinkComponent: VISComponentType = {
   displayName: 'NodeLinkVis',
-  VIS: NodeLinkVis,
-  settings: {
-    layout: {
-      value: 'Force directed',
-      type: 'dropdown',
-      label: 'Layout',
-      options: ['Force directed'],
-      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/paohvis/paohvis.tsx b/libs/shared/lib/vis/visualizations/paohvis/paohvis.tsx
index 90544d35d..d18c548ce 100644
--- a/libs/shared/lib/vis/visualizations/paohvis/paohvis.tsx
+++ b/libs/shared/lib/vis/visualizations/paohvis/paohvis.tsx
@@ -27,7 +27,8 @@ import { HyperEdgeRange } from './components/HyperEdgesRange';
 import ToPaohvisDataParserUseCase from './utils/ToPaohvisDataParserUsecase';
 import MakePaohvisMenu from './components/MakePaohvisMenu';
 import { RowLabelColumn } from './components/RowLabelColumn';
-import { VISComponentType } from '../../types';
+import { VISComponentType, VisualizationPropTypes } from '../../types';
+import { GraphMetaData } from '@graphpolaris/shared/lib/data-access/statistics';
 
 type PaohvisViewModelState = {
   rowHeight: number;
@@ -63,7 +64,13 @@ export type PaohVisProps = {
   data?: PaohvisData;
 };
 
-export const PaohVis = (props: PaohVisProps) => {
+const configuration: PaohVisProps = {
+  rowHeight: 30,
+  hyperedgeColumnWidth: 20,
+  gapBetweenRanges: 5,
+};
+
+export const PaohVis = ({ configuration }: VisualizationPropTypes) => {
   const svgRef = useRef<SVGSVGElement>(null);
   const graphQueryResult = useGraphQueryResult();
   const schema = useSchemaGraph();
@@ -132,7 +139,7 @@ export const PaohVis = (props: PaohVisProps) => {
     entityOrRelationType: string,
     attribute: string,
     predicate: string,
-    compareValue: string
+    compareValue: string,
   ): void {
     const attributeName: string = attribute.split(':')[0];
     const attributeType: string = attribute.split(':')[1];
@@ -373,7 +380,7 @@ export const PaohVis = (props: PaohVisProps) => {
     relationName: string,
     isEntityVerticalEqualToRelationFrom: boolean,
     chosenAttribute: Attribute,
-    nodeOrder: PaohvisNodeOrder
+    nodeOrder: PaohvisNodeOrder,
   ): void {
     setViewModel((draft) => {
       draft.entityVertical = entityVertical;
@@ -512,7 +519,7 @@ export const PaohVis = (props: PaohVisProps) => {
 
   const hyperEdgeRanges = data.hyperEdgeRanges;
   const rowLabelColumnWidth = data.maxRowLabelWidth;
-  const hyperedgeColumnWidth = props.hyperedgeColumnWidth;
+  const hyperedgeColumnWidth = configuration.hyperedgeColumnWidth;
 
   //calculate yOffset
   let maxColWidth = 0;
@@ -532,7 +539,7 @@ export const PaohVis = (props: PaohVisProps) => {
     const columnLabelWidth =
       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;
 
     tableWidth += columnWidth;
 
@@ -559,12 +566,12 @@ export const PaohVis = (props: PaohVisProps) => {
         colOffset={colOffset}
         xOffset={rowLabelColumnWidth}
         yOffset={yOffset}
-        rowHeight={props.rowHeight}
+        rowHeight={configuration.rowHeight}
         hyperedgeColumnWidth={hyperedgeColumnWidth}
-        gapBetweenRanges={props.gapBetweenRanges}
+        gapBetweenRanges={configuration.gapBetweenRanges}
         onMouseEnter={onMouseEnterHyperEdge}
         onMouseLeave={onMouseLeaveHyperEdge}
-      />
+      />,
     );
     colOffset += hyperEdgeRange.hyperEdges.length;
   });
@@ -591,7 +598,7 @@ export const PaohVis = (props: PaohVisProps) => {
               ref={svgRef}
               style={{
                 width: tableWidthWithExtraColumnLabelWidth,
-                height: yOffset + (data.rowLabels.length + 1) * props.rowHeight,
+                height: yOffset + (data.rowLabels.length + 1) * configuration.rowHeight,
               }}
             >
               <RowLabelColumn // render the PAOHvis itself
@@ -599,7 +606,7 @@ export const PaohVis = (props: PaohVisProps) => {
                 onMouseLeave={onMouseLeaveRow}
                 titles={data.rowLabels}
                 width={rowLabelColumnWidth}
-                rowHeight={props.rowHeight} // viewModel.rowHeight?
+                rowHeight={configuration.rowHeight} // viewModel.rowHeight?
                 yOffset={yOffset}
               />
               {hyperEdgeRangeColumns}
@@ -638,10 +645,23 @@ export const PaohVis = (props: PaohVisProps) => {
   );
 };
 
+const PaohSettings = ({
+  configuration,
+  graph,
+  updateSettings,
+}: {
+  configuration: PaohVisProps;
+  graph: GraphMetaData;
+  updateSettings: (val: any) => void;
+}) => {
+  return <div>To be implemented</div>;
+};
+
 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/rawjsonvis/rawjsonvis.tsx b/libs/shared/lib/vis/visualizations/rawjsonvis/rawjsonvis.tsx
index f62cd2a94..29d370bb7 100644
--- a/libs/shared/lib/vis/visualizations/rawjsonvis/rawjsonvis.tsx
+++ b/libs/shared/lib/vis/visualizations/rawjsonvis/rawjsonvis.tsx
@@ -1,10 +1,11 @@
 import React, { useEffect } from 'react';
 import ReactJSONView from 'react-json-view';
 import { VisualizationPropTypes, VISComponentType } from '../../types';
+import { GraphMetaData } from '@graphpolaris/shared/lib/data-access/statistics';
 
 export interface RawJSONVisProps {}
 
-const displayName = 'RawJSONVis';
+const configuration: RawJSONVisProps = {};
 
 export const RawJSONVis = React.memo(({ data }: VisualizationPropTypes) => {
   return (
@@ -24,9 +25,22 @@ export const RawJSONVis = React.memo(({ data }: VisualizationPropTypes) => {
   );
 });
 
+const RawJSONSettings = ({
+  configuration,
+  graph,
+  updateSettings,
+}: {
+  configuration: RawJSONVisProps;
+  graph: GraphMetaData;
+  updateSettings: (val: any) => void;
+}) => {
+  return <div>To be implemented</div>;
+};
+
 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/tablevis/tablevis.tsx b/libs/shared/lib/vis/visualizations/tablevis/tablevis.tsx
index f1cc8dac1..d740b4a7a 100644
--- a/libs/shared/lib/vis/visualizations/tablevis/tablevis.tsx
+++ b/libs/shared/lib/vis/visualizations/tablevis/tablevis.tsx
@@ -2,13 +2,20 @@ import React, { useMemo, useRef } from 'react';
 import { Table, AugmentedNodeAttributes } from './components/Table';
 import { SchemaAttribute } from '../../../schema';
 import { VisualizationPropTypes, VISComponentType } from '../../types';
+import Input from '@graphpolaris/shared/lib/components/inputs';
+import { GraphMetaData } from '@graphpolaris/shared/lib/data-access/statistics';
 
 export type TableProps = {
   showBarplot: boolean;
   itemsPerPage: number;
 };
 
-export const TableVis = ({ data, schema, settings }: VisualizationPropTypes) => {
+const configuration: TableProps = {
+  itemsPerPage: 10,
+  showBarplot: false,
+};
+
+export const TableVis = ({ data, schema, configuration }: VisualizationPropTypes) => {
   const ref = useRef<HTMLDivElement>(null);
 
   const attributesArray = useMemo<AugmentedNodeAttributes[]>(
@@ -24,33 +31,51 @@ 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} />
       )}
     </div>
   );
 };
 
+const TableSettings = ({
+  configuration,
+  graph,
+  updateSettings,
+}: {
+  configuration: TableProps;
+  graph: GraphMetaData;
+  updateSettings: (val: any) => void;
+}) => {
+  return (
+    <div>
+      <Input
+        type="dropdown"
+        label="Items per page"
+        value={configuration.itemsPerPage}
+        onChange={(val) => updateSettings({ itemsPerPage: val })}
+        options={[10, 20, 30]}
+      />
+      <Input
+        type="boolean"
+        label="Show barplot"
+        value={configuration.showBarplot}
+        onChange={(val) => updateSettings({ showBarplot: val })}
+      />
+    </div>
+  );
+};
+
 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;
-- 
GitLab