From 2c26f4edf45df0c2936a535a19b799d524cf5064 Mon Sep 17 00:00:00 2001
From: Michael Behrisch <m.behrisch@uu.nl>
Date: Tue, 15 Feb 2022 17:04:29 +0100
Subject: [PATCH] feat(vis-schema): :sparkles: introduces graph-layout library
 with various algorithms

This feature introduces @graphpolaris/shared/graph-layout with
four layouts (circular, noverlap, random, forceatlas2)

Shows how to apply layouts to graphology graphs in the schema.
---
 .vscode/launch.json                           |  22 +-
 apps/web-graphpolaris/.babelrc                |   4 +-
 apps/web-graphpolaris/src/app/app.tsx         |   5 +-
 .../src/components/schema/initial-elements.js | 121 ++++++++++
 .../src/components/schema/schema.stories.tsx  | 136 ++---------
 .../src/components/schema/schema.tsx          |  85 ++++---
 .../src/lib/schema-usecases.spec.ts           |  62 ++++-
 .../src/lib/schema-usecases.ts                |   7 +-
 .../shared/data-access/store/src/lib/hooks.ts |  12 +-
 .../store/src/lib/schemaSlice.spec.ts         |  64 ++----
 .../data-access/store/src/lib/schemaSlice.ts  |  31 ++-
 libs/shared/graph-layout/.babelrc             |   3 +
 libs/shared/graph-layout/.eslintrc.json       |  18 ++
 libs/shared/graph-layout/README.md            |   7 +
 libs/shared/graph-layout/jest.config.js       |  15 ++
 libs/shared/graph-layout/project.json         |  29 +++
 .../shared/graph-layout/src/factory/Layout.ts |  21 ++
 .../src/factory/cytoscape-layouts.ts          |  54 +++++
 .../src/factory/graphology-layouts.ts         | 169 ++++++++++++++
 .../factory/layout-creator-usecase.spec.ts    | 142 ++++++++++++
 .../src/factory/layout-creator-usecase.ts     |  77 +++++++
 libs/shared/graph-layout/src/factory/test.ts  |   0
 libs/shared/graph-layout/src/index.ts         |   6 +
 libs/shared/graph-layout/tsconfig.json        |  22 ++
 libs/shared/graph-layout/tsconfig.lib.json    |  11 +
 libs/shared/graph-layout/tsconfig.spec.json   |  19 ++
 package.json                                  |   3 +
 tsconfig.base.json                            |   4 +
 yarn.lock                                     | 212 +++++++++++++++++-
 29 files changed, 1146 insertions(+), 215 deletions(-)
 create mode 100644 apps/web-graphpolaris/src/components/schema/initial-elements.js
 create mode 100644 libs/shared/graph-layout/.babelrc
 create mode 100644 libs/shared/graph-layout/.eslintrc.json
 create mode 100644 libs/shared/graph-layout/README.md
 create mode 100644 libs/shared/graph-layout/jest.config.js
 create mode 100644 libs/shared/graph-layout/project.json
 create mode 100644 libs/shared/graph-layout/src/factory/Layout.ts
 create mode 100644 libs/shared/graph-layout/src/factory/cytoscape-layouts.ts
 create mode 100644 libs/shared/graph-layout/src/factory/graphology-layouts.ts
 create mode 100644 libs/shared/graph-layout/src/factory/layout-creator-usecase.spec.ts
 create mode 100644 libs/shared/graph-layout/src/factory/layout-creator-usecase.ts
 create mode 100644 libs/shared/graph-layout/src/factory/test.ts
 create mode 100644 libs/shared/graph-layout/src/index.ts
 create mode 100644 libs/shared/graph-layout/tsconfig.json
 create mode 100644 libs/shared/graph-layout/tsconfig.lib.json
 create mode 100644 libs/shared/graph-layout/tsconfig.spec.json

diff --git a/.vscode/launch.json b/.vscode/launch.json
index f73ba1c65..520ee6d53 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -14,12 +14,22 @@
       "port": 9229
     },
     {
-      // Requires the extension Debugger for Chrome: https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome
+      "name": "Run Storybook server",
+      "type": "node",
+      "request": "launch",
+      "protocol": "inspector",
+      "program": "${workspaceRoot}/node_modules/.bin/start-storybook",
+      "args": ["-p", "6006"],
+      "stopOnEntry": false,
+      "runtimeArgs": ["--nolazy"],
+      "sourceMaps": false
+    },
+    {
       "type": "chrome",
       "request": "launch",
-      "name": "Storybook Debug",
+      "name": "Launch Chrome for Storybook",
       "breakOnLoad": true,
-      "url": "http://localhost:4400/?path=/story/",
+      "url": "http://localhost:6006",
       "sourceMaps": true,
       "webRoot": "${workspaceFolder}",
       "sourceMapPathOverrides": {
@@ -29,5 +39,11 @@
         "webpack:///./~/*": "${webRoot}/node_modules/*"
       }
     }
+  ],
+  "compounds": [
+    {
+      "name": "Launch Storybook",
+      "configurations": ["Launch Chrome for Storybook", "Run Storybook server"]
+    }
   ]
 }
diff --git a/apps/web-graphpolaris/.babelrc b/apps/web-graphpolaris/.babelrc
index 61641ec8a..09947a5fd 100644
--- a/apps/web-graphpolaris/.babelrc
+++ b/apps/web-graphpolaris/.babelrc
@@ -5,7 +5,7 @@
       {
         "runtime": "automatic"
       }
-    ]
+    ],
   ],
-  "plugins": []
+  "plugins": ["@babel/plugin-syntax-flow"]
 }
diff --git a/apps/web-graphpolaris/src/app/app.tsx b/apps/web-graphpolaris/src/app/app.tsx
index e94971f9d..4b52a8ebc 100644
--- a/apps/web-graphpolaris/src/app/app.tsx
+++ b/apps/web-graphpolaris/src/app/app.tsx
@@ -11,6 +11,7 @@ import { RawJSONVis } from '../components/visualisations/rawjsonvis/rawjsonvis';
 import SemanticSubstrates from '../components/visualisations/semanticsubstrates/semanticsubstrates';
 import LoginScreen from '../components/login/loginScreen';
 import { OurThemeProvider } from '@graphpolaris/shared/data-access/theme';
+import Schema from '../components/schema/schema';
 
 function useIsAuthorized() {
   const [userAuthorized, setUserAuthorized] = useState(false);
@@ -51,7 +52,9 @@ export function App() {
           key="schema-panel"
           data-grid={{ x: 0, y: 0, w: 3, h: 30, maxW: 5, isDraggable: false }}
         >
-          <Panel content="Schema Panel" color="red"></Panel>
+          <Panel content="Schema Panel" color="red">
+            <Schema />
+          </Panel>
         </div>
         <div
           key="query-panel"
diff --git a/apps/web-graphpolaris/src/components/schema/initial-elements.js b/apps/web-graphpolaris/src/components/schema/initial-elements.js
new file mode 100644
index 000000000..09ea3488c
--- /dev/null
+++ b/apps/web-graphpolaris/src/components/schema/initial-elements.js
@@ -0,0 +1,121 @@
+import React from 'react';
+
+export default [
+  {
+    id: '1',
+    type: 'input',
+    data: { label: 'Node 1' },
+    position: { x: 250, y: 5 },
+  },
+  // you can also pass a React Node as a label
+  { id: '2', data: { label: <div>Node 2</div> }, position: { x: 100, y: 100 } },
+  { id: 'e1-2', source: '1', target: '2', animated: true },
+];
+
+// export default [
+//   {
+//     id: '1',
+//     type: 'input',
+//     data: {
+//       label: (
+//         <>
+//           Welcome to <strong>React Flow!</strong>
+//         </>
+//       ),
+//     },
+//     position: { x: 250, y: 0 },
+//   },
+//   {
+//     id: '2',
+//     data: {
+//       label: (
+//         <>
+//           This is a <strong>default node</strong>
+//         </>
+//       ),
+//     },
+//     position: { x: 100, y: 100 },
+//   },
+//   {
+//     id: '3',
+//     data: {
+//       label: (
+//         <>
+//           This one has a <strong>custom style</strong>
+//         </>
+//       ),
+//     },
+//     position: { x: 400, y: 100 },
+//     style: {
+//       background: '#D6D5E6',
+//       color: '#333',
+//       border: '1px solid #222138',
+//       width: 180,
+//     },
+//   },
+//   {
+//     id: '4',
+//     position: { x: 250, y: 200 },
+//     data: {
+//       label: 'Another default node',
+//     },
+//   },
+//   {
+//     id: '5',
+//     data: {
+//       label: 'Node id: 5',
+//     },
+//     position: { x: 250, y: 325 },
+//   },
+//   {
+//     id: '6',
+//     type: 'output',
+//     data: {
+//       label: (
+//         <>
+//           An <strong>output node</strong>
+//         </>
+//       ),
+//     },
+//     position: { x: 100, y: 480 },
+//   },
+//   {
+//     id: '7',
+//     type: 'output',
+//     data: { label: 'Another output node' },
+//     position: { x: 400, y: 450 },
+//   },
+//   { id: 'e1-2', source: '1', target: '2', label: 'this is an edge label' },
+//   { id: 'e1-3', source: '1', target: '3' },
+//   {
+//     id: 'e3-4',
+//     source: '3',
+//     target: '4',
+//     animated: true,
+//     label: 'animated edge',
+//   },
+//   {
+//     id: 'e4-5',
+//     source: '4',
+//     target: '5',
+//     // arrowHeadType: 'arrowclosed',
+//     label: 'edge with arrow head',
+//   },
+//   {
+//     id: 'e5-6',
+//     source: '5',
+//     target: '6',
+//     type: 'smoothstep',
+//     label: 'smooth step edge',
+//   },
+//   {
+//     id: 'e5-7',
+//     source: '5',
+//     target: '7',
+//     type: 'step',
+//     style: { stroke: '#f6ab6c' },
+//     label: 'a step edge',
+//     animated: true,
+//     labelStyle: { fill: '#f6ab6c', fontWeight: 700 },
+//   },
+// ];
diff --git a/apps/web-graphpolaris/src/components/schema/schema.stories.tsx b/apps/web-graphpolaris/src/components/schema/schema.stories.tsx
index 7441b44b9..a38499b13 100644
--- a/apps/web-graphpolaris/src/components/schema/schema.stories.tsx
+++ b/apps/web-graphpolaris/src/components/schema/schema.stories.tsx
@@ -1,10 +1,16 @@
+import { parseSchemaFromBackend } from '@graphpolaris/schema/schema-usecases';
 import {
-  // handleSchemaLayout,
-  parseSchemaFromBackend
-} from '@graphpolaris/schema/schema-usecases';
-import {
-  store
+  SchemaFromBackend,
+  schemaSlice,
+  setSchema,
+  store,
 } from '@graphpolaris/shared/data-access/store';
+import {
+  movieSchema,
+  northWindSchema,
+  twitterSchema,
+} from '@graphpolaris/shared/mock-data';
+import { configureStore } from '@reduxjs/toolkit';
 import { ComponentMeta, ComponentStory } from '@storybook/react';
 import React from 'react';
 import { Provider } from 'react-redux';
@@ -20,7 +26,7 @@ export default {
   decorators: [
     (story) => (
       <div style={{ padding: '3rem' }}>
-        <Provider store={store}>{story()}</Provider>
+        <Provider store={Mockstore}>{story()}</Provider>
       </div>
     ),
   ],
@@ -29,119 +35,15 @@ export default {
 const Template: ComponentStory<typeof Schema> = (args) => <Schema {...args} />;
 
 // // A super-simple mock of a redux store
-// const Mockstore = configureStore({
-//   reducer: {
-//     schema: schemaSlice,
-//   },
-// });
+const Mockstore = configureStore({
+  reducer: {
+    schema: schemaSlice.reducer,
+  },
+});
 
 export const TestWithSchema = Template.bind({});
 
 TestWithSchema.play = async () => {
-  const dispatch = store.dispatch;
-
-  const schema = parseSchemaFromBackend({
-    nodes: [
-      {
-        name: 'Thijs',
-        attributes: [],
-      },
-      {
-        name: 'Airport',
-        attributes: [
-          { name: 'city', type: 'string' },
-          { name: 'vip', type: 'bool' },
-          { name: 'state', type: 'string' },
-        ],
-      },
-      {
-        name: 'Airport2',
-        attributes: [
-          { name: 'city', type: 'string' },
-          { name: 'vip', type: 'bool' },
-          { name: 'state', type: 'string' },
-        ],
-      },
-      {
-        name: 'Plane',
-        attributes: [
-          { name: 'type', type: 'string' },
-          { name: 'maxFuelCapacity', type: 'int' },
-        ],
-      },
-      { name: 'Staff', attributes: [] },
-    ],
-    edges: [
-      {
-        name: 'Airport2:Airport',
-        from: 'Airport2',
-        to: 'Airport',
-        collection: 'flights',
-        attributes: [
-          { name: 'arrivalTime', type: 'int' },
-          { name: 'departureTime', type: 'int' },
-        ],
-      },
-      {
-        name: 'Airport:Staff',
-        from: 'Airport',
-        to: 'Staff',
-        collection: 'flights',
-        attributes: [{ name: 'salary', type: 'int' }],
-      },
-      {
-        name: 'Plane:Airport',
-        from: 'Plane',
-        to: 'Airport',
-        collection: 'flights',
-        attributes: [],
-      },
-      {
-        name: 'Airport:Thijs',
-        from: 'Airport',
-        to: 'Thijs',
-        collection: 'flights',
-        attributes: [{ name: 'hallo', type: 'string' }],
-      },
-      {
-        name: 'Thijs:Airport',
-        from: 'Thijs',
-        to: 'Airport',
-        collection: 'flights',
-        attributes: [{ name: 'hallo', type: 'string' }],
-      },
-      {
-        name: 'Staff:Plane',
-        from: 'Staff',
-        to: 'Plane',
-        collection: 'flights',
-        attributes: [{ name: 'hallo', type: 'string' }],
-      },
-      {
-        name: 'Staff:Airport2',
-        from: 'Staff',
-        to: 'Airport2',
-        collection: 'flights',
-        attributes: [{ name: 'hallo', type: 'string' }],
-      },
-      {
-        name: 'Airport2:Plane',
-        from: 'Airport2',
-        to: 'Plane',
-        collection: 'flights',
-        attributes: [{ name: 'hallo', type: 'string' }],
-      },
-
-      {
-        name: 'Airport:Airport',
-        from: 'Airport',
-        to: 'Airport',
-        collection: 'flights',
-        attributes: [{ name: 'test', type: 'string' }],
-      },
-    ],
-  });
-
-  //dispatch(setSchema(schema));
-  // handleSchemaLayout(schema);
+  const parsed = parseSchemaFromBackend(twitterSchema as SchemaFromBackend);
+  Mockstore.dispatch(setSchema(parsed.export()));
 };
diff --git a/apps/web-graphpolaris/src/components/schema/schema.tsx b/apps/web-graphpolaris/src/components/schema/schema.tsx
index 1023e2e3a..094621fb9 100644
--- a/apps/web-graphpolaris/src/components/schema/schema.tsx
+++ b/apps/web-graphpolaris/src/components/schema/schema.tsx
@@ -1,45 +1,63 @@
-import { useSchema } from '@graphpolaris/shared/data-access/store';
-//import { useEffect } from 'react';
-import ReactFlow from 'react-flow-renderer';
 import { createReactFlowElements } from '@graphpolaris/schema/schema-usecases';
+import {
+  useSchema,
+  useSchemaLayout,
+} from '@graphpolaris/shared/data-access/store';
+import {
+  AllLayoutAlgorithms,
+  LayoutFactory,
+} from '@graphpolaris/shared/graph-layout';
+import { Attributes } from 'graphology-types';
 import { useEffect, useState } from 'react';
+import ReactFlow, {
+  Node,
+  Edge,
+  Elements,
+  ReactFlowProvider,
+  FlowElement,
+} from 'react-flow-renderer';
 
 interface Props {
-  content: string;
+  // content: string;
 }
 
-const initialElements = [
-  {
-    id: '1',
-    type: 'input',
-    data: { label: 'Input Node' },
-    position: { x: 250, y: 25 },
-  },
-  {
-    id: '2',
-    data: { label: 'Another Node' },
-    position: { x: 100, y: 125 },
-  },
-];
+const onLoad = (reactFlowInstance: any) => {
+  setTimeout(() => reactFlowInstance.fitView(), 0);
+};
 
 const Schema = (props: Props) => {
+  const [elements, setElements] = useState([] as FlowElement[]);
+  // In case the schema is updated
   const dbschema = useSchema();
-  console.log(dbschema);
+  const schemaLayout = useSchemaLayout();
 
-  const flowElements = createReactFlowElements(dbschema);
-  console.log(flowElements);
+  useEffect(() => {
+    const layoutFactory = new LayoutFactory();
 
-  // const [dbschema, setSchema] = useState(useSchema());
+    // console.log('schema Layout', schemaLayout);
+    const layout = layoutFactory.createLayout(
+      // schemaLayout as AllLayoutAlgorithms
+      'Graphology_noverlap'
+    );
+    layout?.layout(dbschema);
 
-  // const [flowElements, setFlowElements] = useState(initialElements);
+    // dbschema.forEachNode((node, attr) => {
+    //   console.log('x', dbschema.getNodeAttribute(node, 'x'));
+    //   console.log('y', dbschema.getNodeAttribute(node, 'y'));
+    // });
 
-  // In case the schema is updated
-  // useEffect(() => {
-  //   const flowElements = createReactFlowElements(dbschema);
-  //   console.log('update schema useEffect');
-  // }, [dbschema]);
+    const flowElements = createReactFlowElements(dbschema);
+    setElements(flowElements);
+    console.log(
+      'update schema useEffect',
+      dbschema,
+      dbschema.order,
+      flowElements
+    );
+  }, [dbschema, schemaLayout]);
+
+  const graphStyles = { width: '100%', height: '500px' };
 
-  // console.log(dbschema);
   return (
     <div
       style={{
@@ -47,7 +65,16 @@ const Schema = (props: Props) => {
         height: '100%',
       }}
     >
-      <ReactFlow elements={createReactFlowElements(dbschema)} />
+      {elements.length == 0 && <p>DEBUG: No Elements</p>}
+      <ReactFlowProvider>
+        <ReactFlow elements={elements} style={graphStyles} onLoad={onLoad} />
+        {/* // onElementsRemove={onElementsRemove}
+        // onConnect={onConnect}
+        // 
+        snapToGrid={true}
+        snapGrid={[15, 15]}
+      ></ReactFlow> */}
+      </ReactFlowProvider>
     </div>
   );
 };
diff --git a/libs/schema/schema-usecases/src/lib/schema-usecases.spec.ts b/libs/schema/schema-usecases/src/lib/schema-usecases.spec.ts
index a466f3101..87156cb18 100644
--- a/libs/schema/schema-usecases/src/lib/schema-usecases.spec.ts
+++ b/libs/schema/schema-usecases/src/lib/schema-usecases.spec.ts
@@ -1,14 +1,19 @@
-import { SchemaFromBackend } from '@graphpolaris/shared/data-access/store';
+import {
+  SchemaFromBackend,
+  setSchema,
+} from '@graphpolaris/shared/data-access/store';
 import { MultiGraph } from 'graphology';
-import { parse } from 'path/posix';
-import { parseSchemaFromBackend } from '..';
 import { Attributes } from 'graphology-types';
 import {
   movieSchema,
   northWindSchema,
   simpleSchema,
   twitterSchema,
-} from 'libs/shared/mock-data/src';
+} from '@graphpolaris/shared/mock-data';
+import { parseSchemaFromBackend } from '..';
+
+import { store } from '@graphpolaris/shared/data-access/store';
+import { LayoutFactory } from '@graphpolaris/shared/graph-layout';
 
 describe('SchemaUsecases', () => {
   test.each([
@@ -67,4 +72,53 @@ describe('SchemaUsecases', () => {
     expect(data).toBeDefined();
     expect(data.nodes).toBeDefined();
   });
+
+  test.each([
+    { data: simpleSchema },
+    { data: movieSchema },
+    { data: northWindSchema },
+    { data: twitterSchema },
+  ])('should load my test json $data', ({ data }) => {
+    const dispatch = store.dispatch;
+
+    const parsed = parseSchemaFromBackend(data as SchemaFromBackend);
+    dispatch(setSchema(parsed.export()));
+
+    const state = store.getState();
+    const schema = state.schema.graphologySerialized;
+    expect(schema);
+    const graphReloaded = MultiGraph.from(schema);
+
+    expect(graphReloaded).toStrictEqual(parsed);
+  });
+
+  test.each([
+    { data: simpleSchema },
+    { data: movieSchema },
+    { data: northWindSchema },
+    { data: twitterSchema },
+  ])('should layout schema', ({ data }) => {
+    const parsed = parseSchemaFromBackend(data as SchemaFromBackend);
+    expect(parsed).toBeDefined();
+
+    const layout = store.getState().schema.schemaLayout;
+    expect(layout);
+
+    // const carFactory = new CarFactory();
+    const layouter = new LayoutFactory();
+
+    const layoutAlgorithm = layouter.createLayout('Graphology_noverlap');
+    layoutAlgorithm?.layout(parsed);
+
+    // const carFactory = new CarFactory();
+
+    // const carModels: AllCarModels[] = ['BMW_coupe', 'Audi_q4', 'Audi_etron', 'BMW_i4'];
+
+    // const cars = carModels.map(model => carFactory.createCar(model)?.drive());
+
+    // const audi = carFactory.createCar('Audi_etron');
+    // const bmw = carFactory.createCar('BMW_coupe');
+
+    // audi?.specialAudiFunction();
+  });
 });
diff --git a/libs/schema/schema-usecases/src/lib/schema-usecases.ts b/libs/schema/schema-usecases/src/lib/schema-usecases.ts
index ea3fdc0fa..04dcbd855 100644
--- a/libs/schema/schema-usecases/src/lib/schema-usecases.ts
+++ b/libs/schema/schema-usecases/src/lib/schema-usecases.ts
@@ -1,8 +1,11 @@
 import Graph, { MultiGraph } from 'graphology';
 // import cytoscape from 'cytoscape'; // eslint-disable-line
-import { setSchema, store } from '@graphpolaris/shared/data-access/store';
+import {
+  setSchema,
+  store,
+  SchemaFromBackend,
+} from '@graphpolaris/shared/data-access/store';
 import { Elements, Node, Edge } from 'react-flow-renderer';
-import { SchemaFromBackend } from '@graphpolaris/shared/data-access/store';
 import { Attributes } from 'graphology-types';
 
 type CytoNode = {
diff --git a/libs/shared/data-access/store/src/lib/hooks.ts b/libs/shared/data-access/store/src/lib/hooks.ts
index df0faef46..0d4265931 100644
--- a/libs/shared/data-access/store/src/lib/hooks.ts
+++ b/libs/shared/data-access/store/src/lib/hooks.ts
@@ -1,6 +1,6 @@
 import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
 import { selectGraphQueryResult } from './graphQueryResultSlice';
-import { selectSchema } from './schemaSlice';
+import { selectSchema, selectSchemaLayout } from './schemaSlice';
 import type { RootState, AppDispatch } from './store';
 
 // Use throughout your app instead of plain `useDispatch` and `useSelector`
@@ -10,5 +10,13 @@ export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
 // Gives the graphQueryResult from the store
 export const useGraphQueryResult = () => useAppSelector(selectGraphQueryResult);
 
-// Gives the schema form the store (as a graphology object)
+/**
+ * 
+ Gives the schema form the store (as a graphology object)
+ *  */
 export const useSchema = () => useAppSelector(selectSchema);
+
+/**
+ *  Gives the schema form the store (as a enumeration of existing layout algorithms)
+ *  */
+export const useSchemaLayout = () => useAppSelector(selectSchemaLayout);
diff --git a/libs/shared/data-access/store/src/lib/schemaSlice.spec.ts b/libs/shared/data-access/store/src/lib/schemaSlice.spec.ts
index 3a6b17a52..b0da5d51f 100644
--- a/libs/shared/data-access/store/src/lib/schemaSlice.spec.ts
+++ b/libs/shared/data-access/store/src/lib/schemaSlice.spec.ts
@@ -5,6 +5,13 @@ import reducer, { selectSchema, setSchema, initialState } from './schemaSlice';
 // import { deleteBook, updateBook, addNewBook } from '../redux/bookSlice';
 import { store } from './store';
 
+import {
+  movieSchema,
+  northWindSchema,
+  simpleSchema,
+  twitterSchema,
+} from '@graphpolaris/shared/mock-data';
+
 describe('SchemaSlice Tests', () => {
   it('should make a graphology graph', () => {
     const graph = new MultiGraph({ allowSelfLoops: true });
@@ -31,7 +38,7 @@ describe('SchemaSlice Tests', () => {
     expect(initialState);
   });
 
-  it('should return the initial state', () => {
+  it('state should return the initial state', () => {
     let state = store.getState();
 
     const schema = state.schema;
@@ -43,52 +50,19 @@ describe('SchemaSlice Tests', () => {
     // console.log(initialState);
     expect(graph);
   });
-
-  //   it('should handle a todo being added to an empty list', () => {
-  //     let state = store.getState().schema;
-  //     let schema = useSchema();
-
-  //     // const unchangedBook = state.bookList.find((book) => book.id === '1');
-  //     // expect(unchangedBook?.title).toBe('1984');
-  //     // expect(unchangedBook?.author).toBe('George Orwell');
-
-  //     // store.dispatch(updateBook({ id: '1', title: '1985', author: 'George Bush' }));
-  //     // state = store.getState().book;
-  //     // let changeBook = state.bookList.find((book) => book.id === '1');
-  //     // expect(changeBook?.title).toBe('1985');
-  //     // expect(changeBook?.author).toBe('George Bush');
-
-  //     // store.dispatch(
-  //     //     updateBook({ id: '1', title: '1984', author: 'George Orwell' })
-  //     // );
-  //     // state = store.getState().book;
-  //     // const backToUnchangedBook = state.bookList.find((book) => book.id === '1');
-
-  //     // expect(backToUnchangedBook).toEqual(unchangedBook);
-  //     // ]);
-  //   });
 });
 
-// test('Deletes a book from list with id', () => {
-//   let state = store.getState().book;
-//   const initialBookCount = state.bookList.length;
+test.each([
+  { data: simpleSchema },
+  { data: movieSchema },
+  { data: northWindSchema },
+  { data: twitterSchema },
+])('store and retrieve', ({ data }) => {
 
-//   store.dispatch(deleteBook({ id: '1' }));
-//   state = store.getState().book;
+  let state = store.getState();
 
-//   expect(state.bookList.length).toBeLessThan(initialBookCount); // Checking if new length smaller than inital length, which is 3
-// });
+  const schema = state.schema;
+  expect(schema);
 
-// test('Adds a new book', () => {
-//   let state = store.getState().book;
-//   const initialBookCount = state.bookList.length;
-
-//   store.dispatch(
-//     addNewBook({ id: '4', author: 'Tester', title: 'Testers manual' })
-//   );
-//   state = store.getState().book;
-//   const newlyAddedBook = state.bookList.find((book) => book.id === '4');
-//   expect(newlyAddedBook?.author).toBe('Tester');
-//   expect(newlyAddedBook?.title).toBe('Testers manual');
-//   expect(state.bookList.length).toBeGreaterThan(initialBookCount);
-// });
+  expect(data).toBeDefined();
+});
diff --git a/libs/shared/data-access/store/src/lib/schemaSlice.ts b/libs/shared/data-access/store/src/lib/schemaSlice.ts
index eb8fdb562..686cec2ee 100644
--- a/libs/shared/data-access/store/src/lib/schemaSlice.ts
+++ b/libs/shared/data-access/store/src/lib/schemaSlice.ts
@@ -1,6 +1,9 @@
 import { createSlice, PayloadAction } from '@reduxjs/toolkit';
 import type { RootState } from './store';
-import Graph, { MultiGraph } from 'graphology';
+import { MultiGraph } from 'graphology';
+import { SerializedGraph } from 'graphology-types';
+import { AllLayoutAlgorithms } from '@graphpolaris/shared/graph-layout';
+import { Graphology } from 'libs/shared/graph-layout/src/factory/graphology-layouts';
 
 /*************** schema format from the backend *************** */
 // TODO: should probably not live here
@@ -35,6 +38,7 @@ export type Edge = {
 // Define the initial state using that type
 export const initialState = {
   graphologySerialized: new MultiGraph().export(),
+  schemaLayout: 'Graphology_noverlap',
 };
 
 export const schemaSlice = createSlice({
@@ -42,12 +46,10 @@ export const schemaSlice = createSlice({
   // `createSlice` will infer the state type from the `initialState` argument
   initialState,
   reducers: {
-    setSchema: (state, action: PayloadAction<Graph>) => {
-      console.log('setSchema', action);
-
-      state.graphologySerialized = action.payload.export();
+    setSchema: (state, action: PayloadAction<SerializedGraph>) => {
+      // console.log('setSchema in schemaslice', action);
+      state.graphologySerialized = action.payload;
     },
-
     readInSchemaFromBackend: (
       state,
       action: PayloadAction<SchemaFromBackend>
@@ -89,13 +91,26 @@ export const schemaSlice = createSlice({
 
       state.graphologySerialized = schema.export();
     },
+    setGraphLayout: (state, action: PayloadAction<AllLayoutAlgorithms>) => {
+      state.schemaLayout = action.payload;
+    },
   },
 });
 
 export const { readInSchemaFromBackend, setSchema } = schemaSlice.actions;
 
-// Select the schema and convert it to a graphology object
+/**
+ * Select the schema and convert it to a graphology object
+ * */
 export const selectSchema = (state: RootState) =>
-  Graph.from(state.schema.graphologySerialized);
+  MultiGraph.from(state.schema.graphologySerialized).copy();
+
+/**
+ * selects the SchemaLayout enum
+ * @param {GraphLayout} state
+ * @returns {GraphLayout} enum of type GraphLayout
+ */
+export const selectSchemaLayout = (state: RootState) =>
+  state.schema.schemaLayout;
 
 export default schemaSlice.reducer;
diff --git a/libs/shared/graph-layout/.babelrc b/libs/shared/graph-layout/.babelrc
new file mode 100644
index 000000000..0cae4a9a8
--- /dev/null
+++ b/libs/shared/graph-layout/.babelrc
@@ -0,0 +1,3 @@
+{
+  "presets": ["@nrwl/web/babel"]
+}
diff --git a/libs/shared/graph-layout/.eslintrc.json b/libs/shared/graph-layout/.eslintrc.json
new file mode 100644
index 000000000..3456be9b9
--- /dev/null
+++ b/libs/shared/graph-layout/.eslintrc.json
@@ -0,0 +1,18 @@
+{
+  "extends": ["../../../.eslintrc.json"],
+  "ignorePatterns": ["!**/*"],
+  "overrides": [
+    {
+      "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
+      "rules": {}
+    },
+    {
+      "files": ["*.ts", "*.tsx"],
+      "rules": {}
+    },
+    {
+      "files": ["*.js", "*.jsx"],
+      "rules": {}
+    }
+  ]
+}
diff --git a/libs/shared/graph-layout/README.md b/libs/shared/graph-layout/README.md
new file mode 100644
index 000000000..b7f37ef4a
--- /dev/null
+++ b/libs/shared/graph-layout/README.md
@@ -0,0 +1,7 @@
+# shared-graph-layout 
+
+This library was generated with [Nx](https://nx.dev).
+
+## Running unit tests
+
+Run `nx test shared-graph-layout` to execute the unit tests via [Jest](https://jestjs.io).
diff --git a/libs/shared/graph-layout/jest.config.js b/libs/shared/graph-layout/jest.config.js
new file mode 100644
index 000000000..489b3c0e0
--- /dev/null
+++ b/libs/shared/graph-layout/jest.config.js
@@ -0,0 +1,15 @@
+module.exports = {
+  displayName: 'shared-graph-layout',
+  preset: '../../../jest.preset.js',
+  globals: {
+    'ts-jest': {
+      tsconfig: '<rootDir>/tsconfig.spec.json',
+    },
+  },
+  transform: {
+    '^.+\\.[tj]s$': 'ts-jest',
+  },
+  moduleFileExtensions: ['ts', 'js', 'html'],
+  coverageDirectory: '../../../coverage/libs/shared/graph-layout',
+  testEnvironment: 'jsdom',
+};
diff --git a/libs/shared/graph-layout/project.json b/libs/shared/graph-layout/project.json
new file mode 100644
index 000000000..b9148c494
--- /dev/null
+++ b/libs/shared/graph-layout/project.json
@@ -0,0 +1,29 @@
+{
+  "root": "libs/shared/graph-layout",
+  "sourceRoot": "libs/shared/graph-layout/src",
+  "projectType": "library",
+  "targets": {
+    "lint": {
+      "executor": "@nrwl/linter:eslint",
+      "outputs": ["{options.outputFile}"],
+      "options": {
+        "lintFilePatterns": ["libs/shared/graph-layout/**/*.ts"]
+      }
+    },
+    "test": {
+      "executor": "@nrwl/jest:jest",
+      "outputs": ["coverage/libs/shared/graph-layout"],
+      "options": {
+        "jestConfig": "libs/shared/graph-layout/jest.config.js",
+        "passWithNoTests": true
+      }
+    },
+    "version": {
+      "executor": "@jscutlery/semver:version",
+      "options": {
+        "commitMessageFormat": "chore(${projectName}): release version ${version}"
+      }
+    }
+  },
+  "tags": []
+}
diff --git a/libs/shared/graph-layout/src/factory/Layout.ts b/libs/shared/graph-layout/src/factory/Layout.ts
new file mode 100644
index 000000000..06f4da35e
--- /dev/null
+++ b/libs/shared/graph-layout/src/factory/Layout.ts
@@ -0,0 +1,21 @@
+import Graph from 'graphology';
+import { Providers, LayoutAlgorithm } from './layout-creator-usecase';
+
+/**
+ * This is our Product
+ */
+
+export abstract class Layout<provider extends Providers> {
+  constructor(
+    public provider: provider,
+    public algorithm: LayoutAlgorithm<provider>
+  ) {
+    console.log(
+      `Created the following Layout: ${provider} - ${this.algorithm}`
+    );
+  }
+
+  public layout(graph: Graph) {
+    console.log(`${this.provider} [${this.algorithm}] layouting now`);
+  }
+}
diff --git a/libs/shared/graph-layout/src/factory/cytoscape-layouts.ts b/libs/shared/graph-layout/src/factory/cytoscape-layouts.ts
new file mode 100644
index 000000000..ce7800a50
--- /dev/null
+++ b/libs/shared/graph-layout/src/factory/cytoscape-layouts.ts
@@ -0,0 +1,54 @@
+import { Layout } from './Layout';
+import { ILayoutFactory, LayoutAlgorithm } from './layout-creator-usecase';
+
+export type CytoscapeProvider = 'Cytoscape';
+
+export type CytoscapeLayoutAlgorithms =
+  | `${CytoscapeProvider}_coupe`
+  | `${CytoscapeProvider}_i4`;
+
+/**
+ * This is a ConcreteCreator
+ */
+export class CytoscapeFactory
+  implements ILayoutFactory<CytoscapeLayoutAlgorithms>
+{
+  createLayout(LayoutAlgorithm: CytoscapeLayoutAlgorithms): Cytoscape | null {
+    switch (LayoutAlgorithm) {
+      case 'Cytoscape_coupe':
+        return new CytoscapeCoupe();
+      case 'Cytoscape_i4':
+        return new CytoscapeI4();
+      default:
+        return null;
+    }
+  }
+}
+
+export abstract class Cytoscape extends Layout<CytoscapeProvider> {
+  constructor(public override algorithm: LayoutAlgorithm<CytoscapeProvider>) {
+    super('Cytoscape', algorithm);
+  }
+
+  public specialCytoscapeFunction() {
+    console.log('Only Cytoscape Layouts can do this.');
+  }
+}
+
+/**
+ * This is a ConcreteProduct
+ */
+class CytoscapeI4 extends Cytoscape {
+  constructor() {
+    super('Cytoscape_i4');
+  }
+}
+
+/**
+ * This is a ConcreteProduct
+ */
+class CytoscapeCoupe extends Cytoscape {
+  constructor() {
+    super('Cytoscape_coupe');
+  }
+}
diff --git a/libs/shared/graph-layout/src/factory/graphology-layouts.ts b/libs/shared/graph-layout/src/factory/graphology-layouts.ts
new file mode 100644
index 000000000..ce9976091
--- /dev/null
+++ b/libs/shared/graph-layout/src/factory/graphology-layouts.ts
@@ -0,0 +1,169 @@
+import Graph from 'graphology';
+import { circular, random } from 'graphology-layout';
+import forceAtlas2, {
+  ForceAtlas2Settings,
+} from 'graphology-layout-forceatlas2';
+import noverlap from 'graphology-layout-noverlap';
+import { RandomLayoutOptions } from 'graphology-layout/random';
+import { NoverlapSettings } from 'graphology-library/layout-noverlap';
+import { Attributes } from 'graphology-types';
+import { Layout } from './Layout';
+import { ILayoutFactory, LayoutAlgorithm } from './layout-creator-usecase';
+
+export type GraphologyProvider = 'Graphology';
+
+export type GraphologyLayoutAlgorithms =
+  | `${GraphologyProvider}_circular`
+  | `${GraphologyProvider}_random`
+  | `${GraphologyProvider}_noverlap`
+  | `${GraphologyProvider}_forceAtlas2`;
+
+/**
+ * This is a ConcreteCreator
+ */
+export class GraphologyFactory
+  implements ILayoutFactory<GraphologyLayoutAlgorithms>
+{
+  createLayout(layoutAlgorithm: GraphologyLayoutAlgorithms): Graphology | null {
+    switch (layoutAlgorithm) {
+      case 'Graphology_random':
+        return new GraphologyRandom();
+      case 'Graphology_circular':
+        return new GraphologyCircular();
+      case 'Graphology_noverlap':
+        return new GraphologyNoverlap();
+      case 'Graphology_forceAtlas2':
+        return new GraphologyForceAtlas2();
+      default:
+        return null;
+    }
+  }
+}
+
+export abstract class Graphology extends Layout<GraphologyProvider> {
+  height: number = 100;
+  width: number = 100;
+  constructor(public override algorithm: LayoutAlgorithm<GraphologyProvider>) {
+    super('Graphology', algorithm);
+    this.setDimensions(100, 200);
+  }
+
+  public specialGraphologyFunction() {
+    // graph.forEachNode((node, attr) => {
+    //   graph.setNodeAttribute(node, 'x', 0);
+    //   graph.setNodeAttribute(node, 'y', 0);
+    // });
+  }
+
+  public setDimensions(width = 100, height = 100) {
+    this.width = width;
+    this.height = height;
+  }
+}
+
+/**
+ * This is a ConcreteProduct
+ */
+export class GraphologyCircular extends Graphology {
+  constructor() {
+    super('Graphology_circular');
+  }
+
+  public override layout(
+    graph: Graph<Attributes, Attributes, Attributes>
+  ): void {
+    // To directly assign the positions to the nodes:
+    circular.assign(graph, {
+      scale: 100,
+    });
+  }
+}
+
+const DEFAULT_RANDOM_SETTINGS: RandomLayoutOptions = {
+  scale: 250,
+};
+/**
+ * This is a ConcreteProduct
+ */
+export class GraphologyRandom extends Graphology {
+  constructor() {
+    super('Graphology_random');
+  }
+
+  public override layout(
+    graph: Graph<Attributes, Attributes, Attributes>
+  ): void {
+    // const positions = random(graph);
+
+    // To directly assign the positions to the nodes:
+    random.assign(graph, DEFAULT_RANDOM_SETTINGS);
+  }
+}
+
+const DEFAULT_NOVERLAP_SETTINGS: NoverlapSettings = {
+  margin: 40,
+  ratio: 40,
+  // gridSize: 50,
+
+  // gridSize ?number 20: number of grid cells horizontally and vertically subdivising the graph’s space. This is used as an optimization scheme. Set it to 1 and you will have O(n²) time complexity, which can sometimes perform better with very few nodes.
+  // margin ?number 5: margin to keep between nodes.
+  // expansion ?number 1.1: percentage of current space that nodes could attempt to move outside of.
+  // ratio ?number 1.0: ratio scaling node sizes.
+  // speed ?number 3: dampening factor that will slow down node movements to ease the overall process.
+};
+
+/**
+ * This is a ConcreteProduct
+ */
+export class GraphologyNoverlap extends Graphology {
+  constructor() {
+    super('Graphology_noverlap');
+  }
+
+  public override layout(
+    graph: Graph<Attributes, Attributes, Attributes>
+  ): void {
+    // // // To directly assign the positions to the nodes:
+    noverlap.assign(graph, {
+      maxIterations: 5000,
+      settings: DEFAULT_NOVERLAP_SETTINGS,
+    });
+  }
+}
+
+const DEFAULT_FORCEATLAS2_SETTINGS: ForceAtlas2Settings = {
+  gravity: 10,
+  adjustSizes: true,
+  linLogMode: true,
+
+  // adjustSizes ?boolean false: should the node’s sizes be taken into account?
+  // barnesHutOptimize ?boolean false: whether to use the Barnes-Hut approximation to compute repulsion in O(n*log(n)) rather than default O(n^2), n being the number of nodes.
+  // barnesHutTheta ?number 0.5: Barnes-Hut approximation theta parameter.
+  // edgeWeightInfluence ?number 1: influence of the edge’s weights on the layout. To consider edge weight, don’t forget to pass weighted as true when applying the synchronous layout or when instantiating the worker.
+  // gravity ?number 1: strength of the layout’s gravity.
+  // linLogMode ?boolean false: whether to use Noack’s LinLog model.
+  // outboundAttractionDistribution ?boolean false
+  // scalingRatio ?number 1
+  // slowDown ?number 1
+  // strongGravityMode ?boolean false
+};
+
+/**
+ * This is a ConcreteProduct
+ */
+export class GraphologyForceAtlas2 extends Graphology {
+  constructor() {
+    super('Graphology_forceAtlas2');
+  }
+
+  public override layout(
+    graph: Graph<Attributes, Attributes, Attributes>
+  ): void {
+    // To directly assign the positions to the nodes:
+
+    forceAtlas2.assign(graph, {
+      iterations: 500000,
+      settings: DEFAULT_FORCEATLAS2_SETTINGS,
+    });
+  }
+}
diff --git a/libs/shared/graph-layout/src/factory/layout-creator-usecase.spec.ts b/libs/shared/graph-layout/src/factory/layout-creator-usecase.spec.ts
new file mode 100644
index 000000000..e9a0771d5
--- /dev/null
+++ b/libs/shared/graph-layout/src/factory/layout-creator-usecase.spec.ts
@@ -0,0 +1,142 @@
+import {
+  AllLayoutAlgorithms,
+  LayoutFactory,
+} from '@graphpolaris/shared/graph-layout';
+
+import {
+  movieSchema,
+  northWindSchema,
+  simpleSchema,
+  twitterSchema,
+} from '@graphpolaris/shared/mock-data';
+import Graph, { MultiGraph } from 'graphology';
+
+import ladder from 'graphology-generators/classic/ladder';
+
+/**
+ * @jest-environment jsdom
+ */
+describe('LayoutFactory', () => {
+  /**
+   * @jest-environment jsdom
+   */
+  it('should work with noverlap from graphology ', () => {
+    const graph = new MultiGraph();
+
+    // Adding some nodes
+    graph.addNode('John', { x: 0, y: 0 });
+    graph.addNode('Martha', { x: 0, y: 0 });
+
+    // Adding an edge
+    graph.addEdge('John', 'Martha');
+
+    const layoutFactory = new LayoutFactory();
+
+    const layout = layoutFactory.createLayout('Graphology_noverlap');
+
+    layout?.layout(graph);
+
+    graph.forEachNode((node, attr) => {
+      console.log(node, attr);
+    });
+  });
+
+  test('should work with noverlap from graphology on generated graph', () => {
+    // Creating a ladder graph
+    const graph = ladder(Graph, 10);
+
+    graph.forEachNode((node, attr) => {
+      graph.setNodeAttribute(node, 'x', 0);
+      graph.setNodeAttribute(node, 'y', 0);
+    });
+
+    const layoutFactory = new LayoutFactory();
+
+    const layout = layoutFactory.createLayout('Graphology_noverlap');
+    layout?.layout(graph);
+
+    graph.forEachNode((node, attr) => {
+      console.log(node, attr);
+    });
+  });
+
+  test('should work with random from graphology on generated graph', () => {
+    // Creating a ladder graph
+    const graph = ladder(Graph, 10);
+
+    graph.forEachNode((node, attr) => {
+      graph.setNodeAttribute(node, 'x', 0);
+      graph.setNodeAttribute(node, 'y', 0);
+    });
+
+    const layoutFactory = new LayoutFactory();
+
+    const layout = layoutFactory.createLayout('Graphology_random');
+    layout?.setDimensions(100, 100);
+    layout?.layout(graph);
+
+    graph.forEachNode((node, attr) => {
+      console.log(node, attr);
+    });
+  });
+
+  test('should work with circular from graphology on generated graph', () => {
+    // Creating a ladder graph
+    const graph = ladder(Graph, 100);
+
+    graph.forEachNode((node, attr) => {
+      graph.setNodeAttribute(node, 'x', 0);
+      graph.setNodeAttribute(node, 'y', 0);
+    });
+
+    const layoutFactory = new LayoutFactory();
+
+    const layout = layoutFactory.createLayout('Graphology_circular');
+    layout?.setDimensions(100, 100);
+    layout?.layout(graph);
+
+    graph.forEachNode((node, attr) => {
+      console.log(node, attr);
+    });
+  });
+
+  test('should work with circular from graphology on generated graph', () => {
+    // Creating a ladder graph
+    const graph = ladder(Graph, 100);
+
+    graph.forEachNode((node, attr) => {
+      graph.setNodeAttribute(node, 'x', 0);
+      graph.setNodeAttribute(node, 'y', 0);
+    });
+
+    const layoutFactory = new LayoutFactory();
+    const layout = layoutFactory.createLayout('Graphology_forceAtlas2');
+    layout?.setDimensions(100, 100);
+    layout?.layout(graph);
+
+    graph.forEachNode((node, attr) => {
+      console.log(node, attr);
+    });
+  });
+
+  test('should add x,y for graphology layouts if not existing', () => {
+    // console.log(Object.keys(AllLayoutAlgorithms))
+
+    const graph = ladder(Graph, 100);
+
+    graph.forEachNode((node, attr) => {
+      expect(graph.getNodeAttribute(node, 'x')).toBeUndefined();
+      expect(graph.getNodeAttribute(node, 'y')).toBeUndefined();
+    });
+
+    const layoutFactory = new LayoutFactory();
+    const layout = layoutFactory.createLayout('Graphology_forceAtlas2');
+    layout?.setDimensions(100, 100);
+    layout?.layout(graph);
+
+    graph.forEachNode((node, attr) => {
+      expect(graph.getNodeAttribute(node, 'x')).toBeDefined();
+      expect(graph.getNodeAttribute(node, 'y')).toBeDefined();
+    });
+  });
+});
diff --git a/libs/shared/graph-layout/src/factory/layout-creator-usecase.ts b/libs/shared/graph-layout/src/factory/layout-creator-usecase.ts
new file mode 100644
index 000000000..53a6411db
--- /dev/null
+++ b/libs/shared/graph-layout/src/factory/layout-creator-usecase.ts
@@ -0,0 +1,77 @@
+import {
+  Cytoscape,
+  CytoscapeFactory,
+  CytoscapeLayoutAlgorithms,
+  CytoscapeProvider,
+} from './cytoscape-layouts';
+import {
+  Graphology,
+  GraphologyFactory,
+  GraphologyLayoutAlgorithms,
+  GraphologyProvider,
+} from './graphology-layouts';
+import { Layout } from './Layout';
+
+export type Providers = GraphologyProvider | CytoscapeProvider;
+export type LayoutAlgorithm<Provider extends Providers> =
+  `${Provider}_${string}`;
+
+export type AllLayoutAlgorithms =
+  | GraphologyLayoutAlgorithms
+  | CytoscapeLayoutAlgorithms;
+
+export type AlgorithmToLayoutProvider<Algorithm extends AllLayoutAlgorithms> =
+  Algorithm extends GraphologyLayoutAlgorithms
+    ? Graphology
+    : Algorithm extends CytoscapeLayoutAlgorithms
+    ? Cytoscape
+    : Cytoscape | Graphology;
+
+export interface ILayoutFactory<Algorithm extends AllLayoutAlgorithms> {
+  createLayout: (
+    Algorithm: Algorithm
+  ) => AlgorithmToLayoutProvider<Algorithm> | null;
+}
+
+/**
+ * This is our Creator
+ */
+export class LayoutFactory implements ILayoutFactory<AllLayoutAlgorithms> {
+  private graphologyFactory = new GraphologyFactory();
+  private cytoscapeFactory = new CytoscapeFactory();
+
+  private isSpecificAlgorithm<Algorithm extends AllLayoutAlgorithms>(
+    LayoutAlgorithm: AllLayoutAlgorithms,
+    startsWith: string
+  ): LayoutAlgorithm is Algorithm {
+    return LayoutAlgorithm.startsWith(startsWith);
+  }
+
+  createLayout<Algorithm extends AllLayoutAlgorithms>(
+    layoutAlgorithm: Algorithm
+  ): AlgorithmToLayoutProvider<Algorithm> | null {
+    if (
+      this.isSpecificAlgorithm<GraphologyLayoutAlgorithms>(
+        layoutAlgorithm,
+        'Graphology'
+      )
+    ) {
+      return this.graphologyFactory.createLayout(
+        layoutAlgorithm
+      ) as AlgorithmToLayoutProvider<Algorithm>;
+    }
+
+    if (
+      this.isSpecificAlgorithm<CytoscapeLayoutAlgorithms>(
+        layoutAlgorithm,
+        'Cytoscape'
+      )
+    ) {
+      return this.cytoscapeFactory.createLayout(
+        layoutAlgorithm
+      ) as AlgorithmToLayoutProvider<Algorithm>;
+    }
+
+    return null;
+  }
+}
diff --git a/libs/shared/graph-layout/src/factory/test.ts b/libs/shared/graph-layout/src/factory/test.ts
new file mode 100644
index 000000000..e69de29bb
diff --git a/libs/shared/graph-layout/src/index.ts b/libs/shared/graph-layout/src/index.ts
new file mode 100644
index 000000000..7bdb94a4e
--- /dev/null
+++ b/libs/shared/graph-layout/src/index.ts
@@ -0,0 +1,6 @@
+// export * from './factory/layout-creator-usecase';
+
+export {
+  AllLayoutAlgorithms,
+  LayoutFactory,
+} from './factory/layout-creator-usecase';
diff --git a/libs/shared/graph-layout/tsconfig.json b/libs/shared/graph-layout/tsconfig.json
new file mode 100644
index 000000000..648c1247a
--- /dev/null
+++ b/libs/shared/graph-layout/tsconfig.json
@@ -0,0 +1,22 @@
+{
+  "extends": "../../../tsconfig.base.json",
+  "files": [],
+  "include": [],
+  "references": [
+    {
+      "path": "./tsconfig.lib.json"
+    },
+    {
+      "path": "./tsconfig.spec.json"
+    }
+  ],
+  "compilerOptions": {
+    "forceConsistentCasingInFileNames": true,
+    "strict": true,
+    "noImplicitReturns": true,
+    "noFallthroughCasesInSwitch": true,
+    "lib": ["webworker", "scripthost"],
+    "esModuleInterop": true,
+    "composite": true
+  }
+}
diff --git a/libs/shared/graph-layout/tsconfig.lib.json b/libs/shared/graph-layout/tsconfig.lib.json
new file mode 100644
index 000000000..6eb3eb9ea
--- /dev/null
+++ b/libs/shared/graph-layout/tsconfig.lib.json
@@ -0,0 +1,11 @@
+{
+  "extends": "./tsconfig.json",
+  "compilerOptions": {
+    "outDir": "../../../dist/out-tsc",
+    "declaration": true,
+    "types": [],
+    "composite": true
+  },
+  "include": ["**/*.ts"],
+  "exclude": ["**/*.spec.ts"]
+}
diff --git a/libs/shared/graph-layout/tsconfig.spec.json b/libs/shared/graph-layout/tsconfig.spec.json
new file mode 100644
index 000000000..d8716fecf
--- /dev/null
+++ b/libs/shared/graph-layout/tsconfig.spec.json
@@ -0,0 +1,19 @@
+{
+  "extends": "./tsconfig.json",
+  "compilerOptions": {
+    "outDir": "../../../dist/out-tsc",
+    "module": "commonjs",
+    "types": ["jest", "node"]
+  },
+  "include": [
+    "**/*.test.ts",
+    "**/*.spec.ts",
+    "**/*.test.tsx",
+    "**/*.spec.tsx",
+    "**/*.test.js",
+    "**/*.spec.js",
+    "**/*.test.jsx",
+    "**/*.spec.jsx",
+    "**/*.d.ts"
+  ]
+}
diff --git a/package.json b/package.json
index a400f2140..c2b43c245 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,7 @@
     "core-js": "^3.6.5",
     "cytoscape": "^3.21.0",
     "graphology": "^0.24.0",
+    "graphology-library": "^0.7.1",
     "graphology-types": "^0.24.0",
     "react": "17.0.2",
     "react-cookie": "^4.1.1",
@@ -35,6 +36,8 @@
   },
   "devDependencies": {
     "@babel/core": "7.12.13",
+    "@babel/plugin-syntax-flow": "^7.16.7",
+    "@babel/preset-flow": "^7.16.7",
     "@babel/preset-typescript": "7.12.13",
     "@commitlint/cli": "^16.0.1",
     "@commitlint/config-angular": "^16.0.0",
diff --git a/tsconfig.base.json b/tsconfig.base.json
index 60c712ba8..f20c2ad21 100644
--- a/tsconfig.base.json
+++ b/tsconfig.base.json
@@ -28,6 +28,10 @@
         "libs/shared/data-access/theme/src/index.ts"
       ],
       "@graphpolaris/shared/mock-data": ["libs/shared/mock-data/src/index.ts"],
+      "@graphpolaris/shared/graph-layout": [
+        "libs/shared/graph-layout/src/index.ts"
+      ],
+
       "@mui/styled-engine": ["./node_modules/@mui/styled-engine-sc"]
     }
   },
diff --git a/yarn.lock b/yarn.lock
index 3d6d637e5..898701c93 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1133,7 +1133,7 @@
     core-js-compat "^3.20.2"
     semver "^6.3.0"
 
-"@babel/preset-flow@^7.12.1":
+"@babel/preset-flow@^7.12.1", "@babel/preset-flow@^7.16.7":
   version "7.16.7"
   resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.16.7.tgz#7fd831323ab25eeba6e4b77a589f680e30581cbd"
   integrity sha512-6ceP7IyZdUYQ3wUVqyRSQXztd1YmFHWI4Xv11MIqAlE4WqxBSd/FZ61V9k+TS5Gd4mkHOtQtPp9ymRpxH4y1Ug==
@@ -4929,6 +4929,11 @@
     "@webassemblyjs/wast-parser" "1.9.0"
     "@xtuc/long" "4.2.2"
 
+"@xmldom/xmldom@^0.7.5":
+  version "0.7.5"
+  resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.7.5.tgz#09fa51e356d07d0be200642b0e4f91d8e6dd408d"
+  integrity sha512-V3BIhmY36fXZ1OtVcI9W+FxQqxVLsPKcNjWigIaa81dLC9IolJl5Mt4Cvhmr0flUnjSpTdrbMTSbXqYqV5dT6A==
+
 "@xtuc/ieee754@^1.2.0":
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
@@ -4949,6 +4954,11 @@
     tslib "^2.3.1"
     upath2 "^3.1.12"
 
+"@yomguithereal/helpers@^1.1.1":
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/@yomguithereal/helpers/-/helpers-1.1.1.tgz#185dfb0f88ca2beec53d0adf6eed15c33b1c549d"
+  integrity sha512-UYvAq/XCA7xoh1juWDYsq3W0WywOB+pz8cgVnE1b45ZfdMhBvHDrgmSFG3jXeZSr2tMTYLGHFHON+ekG05Jebg==
+
 JSONStream@^1.0.4:
   version "1.3.5"
   resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0"
@@ -9567,11 +9577,185 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6
   resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96"
   integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==
 
+graphology-assertions@~2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/graphology-assertions/-/graphology-assertions-2.2.1.tgz#2fdc64a26434a2aac2de3d6d4ef889a0005ff379"
+  integrity sha512-X6yvm8eYDepIyywDM/K0ud/NDD6I5aZj5+D459z4wZFEtb8B33A4NNPsMpjMNwjNdEo1q4VL1Gqp/usoItEP4g==
+  dependencies:
+    fast-deep-equal "^3.1.3"
+    graphology-utils "^2.1.2"
+
+graphology-communities-louvain@~2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/graphology-communities-louvain/-/graphology-communities-louvain-2.0.0.tgz#ef93a89e0122078ce77676f5351731ee7eb58df9"
+  integrity sha512-zHqfPBh43XHs5Pp/u2XwdXrPmMLGBEdlgXqciowpa/dsD/VOC7pnD9HquJ3dGuLa2V2cdUAesOehFDb2M7soeA==
+  dependencies:
+    graphology-indices "^0.16.4"
+    graphology-utils "^2.4.4"
+    mnemonist "^0.39.0"
+    pandemonium "^2.3.0"
+
+graphology-components@~1.5.2:
+  version "1.5.2"
+  resolved "https://registry.yarnpkg.com/graphology-components/-/graphology-components-1.5.2.tgz#a2bdf0f3e09eee1e3d5913a95442cadcd74b912f"
+  integrity sha512-EW26mjHWX9sggUhZcW1OHsOnEV7lj0nx50mcEHFRNucC3MBoe4yDYtBY8HQqUcGH4FdEq0ukNzzweJGLiy58Tg==
+  dependencies:
+    graphology-indices "^0.16.2"
+    graphology-utils "^2.1.2"
+
+graphology-generators@~0.11.2:
+  version "0.11.2"
+  resolved "https://registry.yarnpkg.com/graphology-generators/-/graphology-generators-0.11.2.tgz#eff2c97e4f5bf401e86ab045470dded95f2ebe24"
+  integrity sha512-hx+F0OZRkVdoQ0B1tWrpxoakmHZNex0c6RAoR0PrqJ+6fz/gz6CQ88Qlw78C6yD9nlZVRgepIoDYhRTFV+bEHg==
+  dependencies:
+    graphology-metrics "^2.0.0"
+    graphology-utils "^2.3.0"
+
+graphology-gexf@~0.10.1:
+  version "0.10.1"
+  resolved "https://registry.yarnpkg.com/graphology-gexf/-/graphology-gexf-0.10.1.tgz#55165379945bc5e1435ab8c12cb51052792c8d58"
+  integrity sha512-vNBn5eVOWRSiedwAFVBehuA0KxzOzorBMvRW2md01UZcaVVh0BRzB6uFEB6+QHmdRqtpewhCQ6RQUifQ8r7btg==
+  dependencies:
+    "@xmldom/xmldom" "^0.7.5"
+    graphology-operators "^1.5.0"
+    graphology-utils "^2.4.1"
+    xml-writer "^1.7.0"
+
+graphology-graphml@^0.5.0:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/graphology-graphml/-/graphology-graphml-0.5.1.tgz#d6573694b16e8daecb3fd33196daf21a92fafa51"
+  integrity sha512-h2bpxlMtSC5lxQuv53r2i4sGqapAmeGUsfjbPmIH1v+y2BiEq4kLbqZuE1JKTD5oXQJeSsHksXKhN8pMGXOnxQ==
+  dependencies:
+    "@xmldom/xmldom" "^0.7.5"
+    graphology-operators "^1.5.0"
+    graphology-utils "^2.4.1"
+    xml-writer "^1.7.0"
+
+graphology-indices@^0.16.2, graphology-indices@^0.16.3, graphology-indices@^0.16.4:
+  version "0.16.6"
+  resolved "https://registry.yarnpkg.com/graphology-indices/-/graphology-indices-0.16.6.tgz#0de112ef0367e44041490933e34ad2075cb24e80"
+  integrity sha512-tozTirLb7pd37wULJ5qeIZfZqKuVln/V+bWmUWJ7MmoTU8YkW5dehOkRz2by/O+5MdJ52imqL8LH4+GCd0yEVw==
+  dependencies:
+    graphology-utils "^2.4.2"
+    mnemonist "^0.39.0"
+
+graphology-layout-force@~0.2.3:
+  version "0.2.4"
+  resolved "https://registry.yarnpkg.com/graphology-layout-force/-/graphology-layout-force-0.2.4.tgz#a9b5f2aa5c7b56985503d302dbce4c73c76b9eb3"
+  integrity sha512-NYZz0YAnDkn5pkm30cvB0IScFoWGtbzJMrqaiH070dYlYJiag12Oc89dbVfaMaVR/w8DMIKxn/ix9Bqj+Umm9Q==
+  dependencies:
+    graphology-utils "^2.4.2"
+
+graphology-layout-forceatlas2@~0.8.1:
+  version "0.8.1"
+  resolved "https://registry.yarnpkg.com/graphology-layout-forceatlas2/-/graphology-layout-forceatlas2-0.8.1.tgz#bb6f34f5181616bb25ea7a8adec73c79aef2aa8d"
+  integrity sha512-lAm9T0uBxhECZTVyYDMMnPi3l7h5kG2+7yfxqoT9wpgF/omComGc6vR9wmQqClQjSXiM3OU4frO4j2Il5E72Xg==
+  dependencies:
+    graphology-utils "^2.1.0"
+
+graphology-layout-noverlap@^0.4.1:
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/graphology-layout-noverlap/-/graphology-layout-noverlap-0.4.2.tgz#2ffa054ceeebaa31fcffe695d271fc55707cd29c"
+  integrity sha512-13WwZSx96zim6l1dfZONcqLh3oqyRcjIBsqz2c2iJ3ohgs3605IDWjldH41Gnhh462xGB1j6VGmuGhZ2FKISXA==
+  dependencies:
+    graphology-utils "^2.3.0"
+
+graphology-layout@~0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/graphology-layout/-/graphology-layout-0.5.0.tgz#a0a54861cebae5f486c778dbdafc6294859f23b5"
+  integrity sha512-aIeXYPLeGMLvXIkO41TlhBv0ROFWUx1bqR2VQoJ7Mp2IW+TF+rxqMeRUrmyLHoe3HtKo8jhloB2KHp7g6fcDSg==
+  dependencies:
+    graphology-utils "^2.3.0"
+    pandemonium "^1.5.0"
+
+graphology-library@^0.7.1:
+  version "0.7.1"
+  resolved "https://registry.yarnpkg.com/graphology-library/-/graphology-library-0.7.1.tgz#9fdec0f6d00f5207895dc9b7e299e454bb3c52f8"
+  integrity sha512-pKqaMiuKNAaVwYQAL9I3EVADYOh1tcWe1NfxzmoSGWLYdHvalNGAI+c63Wd4DG021He2YUYR6yB5gtccqVUS3Q==
+  dependencies:
+    graphology-assertions "~2.2.1"
+    graphology-communities-louvain "~2.0.0"
+    graphology-components "~1.5.2"
+    graphology-generators "~0.11.2"
+    graphology-gexf "~0.10.1"
+    graphology-graphml "^0.5.0"
+    graphology-layout "~0.5.0"
+    graphology-layout-force "~0.2.3"
+    graphology-layout-forceatlas2 "~0.8.1"
+    graphology-layout-noverlap "^0.4.1"
+    graphology-metrics "~2.0.0"
+    graphology-operators "~1.5.0"
+    graphology-shortest-path "~2.0.0"
+    graphology-simple-path "^0.1.2"
+    graphology-traversal "^0.3.0"
+    graphology-utils "~2.5.0"
+
+graphology-metrics@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/graphology-metrics/-/graphology-metrics-2.1.0.tgz#7d00bae92d8970583afd020e6d40d8a16c378002"
+  integrity sha512-E+y4kgVGxhYl/+bPHEftJeWLS8LgVno4/Wvg+C7IoDIjY6OlIZghgMKDR8LKsxU6GC43mlx08FTZs229cvEkwQ==
+  dependencies:
+    graphology-shortest-path "^2.0.0"
+    graphology-utils "^2.4.4"
+    mnemonist "^0.39.0"
+
+graphology-metrics@~2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/graphology-metrics/-/graphology-metrics-2.0.0.tgz#af2bfcadd1d5842d14c9a6092175e22fbab7024f"
+  integrity sha512-vh2XaAaiB9Of92ac2imaztFjPHmMIotuIN/rNt/X+DqJhxpuyOp+Ir3fQPVJScvk11zMWOimTsMdLYt1gbXWeQ==
+  dependencies:
+    graphology-shortest-path "^2.0.0"
+    graphology-utils "^2.4.4"
+    mnemonist "^0.39.0"
+
+graphology-operators@^1.5.0, graphology-operators@~1.5.0:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/graphology-operators/-/graphology-operators-1.5.1.tgz#67f4447df21baa59b571ab7a4c688a2302f9ce20"
+  integrity sha512-VojhTwtKlGtbopHPzOmAsAgM8MJY1HScgAs3G8FobtI+xsSlnFSKQeuWIibXEg6/wwPHGYT2oxMJbgHcwAEr3Q==
+  dependencies:
+    graphology-utils "^2.0.0"
+
+graphology-shortest-path@^2.0.0, graphology-shortest-path@~2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/graphology-shortest-path/-/graphology-shortest-path-2.0.0.tgz#27a01b3a9980872bd44a197fc77114623dd2b302"
+  integrity sha512-6dJWgbr7w4YQKb7Y0w7vhZn2qAkqP+J0IhE9F3vz/HZcx7VSOqnNfTGtYr44BQ5ohdXj0l9iKjlWCb+3vqEINQ==
+  dependencies:
+    "@yomguithereal/helpers" "^1.1.1"
+    graphology-indices "^0.16.3"
+    graphology-utils "^2.4.3"
+    mnemonist "^0.39.0"
+
+graphology-simple-path@^0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/graphology-simple-path/-/graphology-simple-path-0.1.2.tgz#b8d84852c94a069a8e906faa5274d33df0a53419"
+  integrity sha512-jOut2ihx5XMN97eUtmy4ZMp22btx3oa8GnvzQXHiBZOMyaC/gCpupnKVh0IvtzKd0RmmC5lT0zPBAqvU2O7Ejg==
+  dependencies:
+    graphology-utils "^1.8.0"
+    mnemonist "^0.39.0"
+
+graphology-traversal@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/graphology-traversal/-/graphology-traversal-0.3.0.tgz#1045af9e35a86932bc964caf110b45338769cfcb"
+  integrity sha512-/dexAoGbaRqmBMtv9IBXUuLZg7b5YBpWYXZYirwRaFX0DsQmsqMAJ+Jx0RQndQqLCOJI3LZyheemv3+tLlrjjQ==
+  dependencies:
+    graphology-indices "^0.16.4"
+    graphology-utils "^2.0.0"
+
 graphology-types@^0.24.0:
   version "0.24.0"
   resolved "https://registry.yarnpkg.com/graphology-types/-/graphology-types-0.24.0.tgz#81aaef55226edb692dd63a9ce5eaecc80694cd93"
   integrity sha512-3qSanRtucm6rwBjpwuAc18GQcl68NqIRE4OA3wFUzdB2HRVXYoCAUsUJVS898bW+byEgd+BTcwR26CbltNvSWQ==
 
+graphology-utils@^1.8.0:
+  version "1.8.0"
+  resolved "https://registry.yarnpkg.com/graphology-utils/-/graphology-utils-1.8.0.tgz#41315c468656e2a3e028a76468bbc2fbe42b0145"
+  integrity sha512-Pa7SW30OMm8fVtyH49b3GJ/uxlMHGfXly50wIhlcc7ZoX9ahZa7sPBz+obo4WZClrRV6wh3tIu0GJoI42eao1A==
+
+graphology-utils@^2.0.0, graphology-utils@^2.1.0, graphology-utils@^2.1.2, graphology-utils@^2.3.0, graphology-utils@^2.4.1, graphology-utils@^2.4.2, graphology-utils@^2.4.3, graphology-utils@^2.4.4, graphology-utils@~2.5.0:
+  version "2.5.0"
+  resolved "https://registry.yarnpkg.com/graphology-utils/-/graphology-utils-2.5.0.tgz#ccb0ec8231e4de403ed7a385644c911e40bc4833"
+  integrity sha512-TmuBAoM1rZxWo3Wd7qC2Rhnu3KZwq8pWNgjWCFKubn3pt3a1Vh/k3CJaFw4G7k6Mvb6aSdWVYJnlGNThMl+bAQ==
+
 graphology@^0.24.0:
   version "0.24.0"
   resolved "https://registry.yarnpkg.com/graphology/-/graphology-0.24.0.tgz#c3c78b197f8ff6d8d3422a2d705c16e637b295f6"
@@ -12284,6 +12468,13 @@ mkdirp@^1.0.3, mkdirp@^1.0.4, mkdirp@~1.0.4:
   resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
   integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
 
+mnemonist@^0.39.0:
+  version "0.39.0"
+  resolved "https://registry.yarnpkg.com/mnemonist/-/mnemonist-0.39.0.tgz#4c83dd22e8d9d05dfb721ff66a905fec4c460041"
+  integrity sha512-7v08Ldk1lnlywnIShqfKYN7EW4WKLUnkoWApdmR47N1xA2xmEtWERfEvyRCepbuFCETG5OnfaGQpp/p4Bus6ZQ==
+  dependencies:
+    obliterator "^2.0.1"
+
 modify-values@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022"
@@ -12701,7 +12892,7 @@ objectorarray@^1.0.5:
   resolved "https://registry.yarnpkg.com/objectorarray/-/objectorarray-1.0.5.tgz#2c05248bbefabd8f43ad13b41085951aac5e68a5"
   integrity sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg==
 
-obliterator@^2.0.2:
+obliterator@^2.0.1, obliterator@^2.0.2:
   version "2.0.2"
   resolved "https://registry.yarnpkg.com/obliterator/-/obliterator-2.0.2.tgz#25f50dc92e1181371b9d8209d11890f1a3c2fc21"
   integrity sha512-g0TrA7SbUggROhDPK8cEu/qpItwH2LSKcNl4tlfBNT54XY+nOsqrs0Q68h1V9b3HOSpIWv15jb1lax2hAggdIg==
@@ -12955,6 +13146,18 @@ pako@~1.0.5:
   resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
   integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
 
+pandemonium@^1.5.0:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/pandemonium/-/pandemonium-1.5.0.tgz#93f35af555de1420022b341e730215c51c725be3"
+  integrity sha512-9PU9fy93rJhZHLMjX+4M1RwZPEYl6g7DdWKGmGNhkgBZR5+tOBVExNZc00kzdEGMxbaAvWdQy9MqGAScGwYlcA==
+
+pandemonium@^2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/pandemonium/-/pandemonium-2.3.0.tgz#d9c70686bb33c3ee4f435162601b0755a439bdcb"
+  integrity sha512-/+5rFCn3npqNwAvhKOSRKwAnEWQeXH4xFuur7vWKlj5Z7AM2JNJt1tC2rptfm1M7t7OlXAyeBuRjspqe+gQGHA==
+  dependencies:
+    mnemonist "^0.39.0"
+
 parallel-transform@^1.1.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc"
@@ -17111,6 +17314,11 @@ xml-name-validator@^3.0.0:
   resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a"
   integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==
 
+xml-writer@^1.7.0:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/xml-writer/-/xml-writer-1.7.0.tgz#b76f1d591c16a2634ebdb703c7bdbd0fd6819065"
+  integrity sha1-t28dWRwWomNOvbcDx729D9aBkGU=
+
 xmlchars@^2.2.0:
   version "2.2.0"
   resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb"
-- 
GitLab