diff --git a/package.json b/package.json
index c9f2008830..ce4ad42a73 100644
--- a/package.json
+++ b/package.json
@@ -10,6 +10,7 @@
"@chakra-ui/accordion": "^2.3.0",
"@chakra-ui/system": "^2.6.0",
"@codesandbox/sandpack-react": "^2.13.5",
+ "@dagrejs/dagre": "^1.1.2",
"@docusaurus/core": "^3.1.0",
"@docusaurus/preset-classic": "^3.1.0",
"@emotion/react": "^11.11.1",
@@ -166,6 +167,7 @@
"react-router-dom": "^6.4.4",
"react-textarea-autosize": "^8.4.1",
"react-tooltip": "^5.13.1",
+ "reactflow": "^11.11.3",
"recoil": "^0.7.7",
"rehype-slug": "^6.0.0",
"remark-behead": "^3.1.0",
@@ -240,6 +242,7 @@
"@types/bytes": "^3.1.1",
"@types/chrome": "^0.0.267",
"@types/crypto-js": "^4.2.2",
+ "@types/dagre": "^0.7.52",
"@types/deep-equal": "^1.0.1",
"@types/express": "^4.17.13",
"@types/graphql-fields": "^1.3.6",
diff --git a/packages/twenty-front/src/App.tsx b/packages/twenty-front/src/App.tsx
index ed890f4806..53c879b5fe 100644
--- a/packages/twenty-front/src/App.tsx
+++ b/packages/twenty-front/src/App.tsx
@@ -59,6 +59,7 @@ import { SettingsObjectEdit } from '~/pages/settings/data-model/SettingsObjectEd
import { SettingsObjectFieldEdit } from '~/pages/settings/data-model/SettingsObjectFieldEdit';
import { SettingsObjectNewFieldStep1 } from '~/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep1';
import { SettingsObjectNewFieldStep2 } from '~/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep2';
+import { SettingsObjectOverview } from '~/pages/settings/data-model/SettingsObjectOverview';
import { SettingsObjects } from '~/pages/settings/data-model/SettingsObjects';
import { SettingsDevelopersApiKeyDetail } from '~/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail';
import { SettingsDevelopersApiKeysNew } from '~/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew';
@@ -200,6 +201,10 @@ const createRouter = (isBillingEnabled?: boolean) =>
path={SettingsPath.Objects}
element={}
/>
+ }
+ />
}
diff --git a/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverview.tsx b/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverview.tsx
new file mode 100644
index 0000000000..9f99c9d7eb
--- /dev/null
+++ b/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverview.tsx
@@ -0,0 +1,246 @@
+import { useCallback } from 'react';
+import ReactFlow, {
+ applyEdgeChanges,
+ applyNodeChanges,
+ Background,
+ Controls,
+ EdgeChange,
+ getIncomers,
+ getOutgoers,
+ NodeChange,
+ useEdgesState,
+ useNodesState,
+} from 'reactflow';
+import styled from '@emotion/styled';
+import { IconX } from 'twenty-ui';
+
+import { SettingsDataModelOverviewEffect } from '@/settings/data-model/graph-overview/components/SettingsDataModelOverviewEffect';
+import { SettingsDataModelOverviewObject } from '@/settings/data-model/graph-overview/components/SettingsDataModelOverviewObject';
+import { SettingsDataModelOverviewRelationMarkers } from '@/settings/data-model/graph-overview/components/SettingsDataModelOverviewRelationMarkers';
+import { calculateHandlePosition } from '@/settings/data-model/graph-overview/util/calculateHandlePosition';
+import { Button } from '@/ui/input/button/components/Button';
+import { isDefined } from '~/utils/isDefined';
+
+import 'reactflow/dist/style.css';
+
+const NodeTypes = {
+ object: SettingsDataModelOverviewObject,
+};
+const StyledContainer = styled.div`
+ height: 100%;
+ .has-many-edge {
+ &.selected path.react-flow__edge-path {
+ marker-end: url(#hasManySelected);
+ stroke-width: 1.5;
+ }
+ }
+ .has-many-edge--highlighted {
+ path.react-flow__edge-path,
+ path.react-flow__edge-interaction,
+ path.react-flow__connection-path {
+ stroke: ${({ theme }) => theme.tag.background.blue} !important;
+ stroke-width: 1.5px;
+ }
+ }
+ .has-many-edge-reversed {
+ &.selected path.react-flow__edge-path {
+ marker-end: url(#hasManyReversedSelected);
+ stroke-width: 1.5;
+ }
+ }
+ .has-many-edge-reversed--highlighted {
+ path.react-flow__edge-path,
+ path.react-flow__edge-interaction,
+ path.react-flow__connection-path {
+ stroke: ${({ theme }) => theme.tag.background.blue} !important;
+ stroke-width: 1.5px;
+ }
+ }
+ .react-flow__handle {
+ border: 0 !important;
+ background: transparent !important;
+ width: 6px;
+ height: 6px;
+ min-height: 6px;
+ min-width: 6px;
+ pointer-events: none;
+ }
+ .left-handle {
+ left: 0;
+ top: 50%;
+ transform: translateX(-50%) translateY(-50%);
+ }
+ .right-handle {
+ right: 0;
+ top: 50%;
+ transform: translateX(50%) translateY(-50%);
+ }
+ .top-handle {
+ top: 0;
+ left: 50%;
+ transform: translateX(-50%) translateY(-50%);
+ }
+ .bottom-handle {
+ bottom: 0;
+ left: 50%;
+ transform: translateX(-50%) translateY(50%);
+ }
+ .react-flow__panel {
+ display: flex;
+ border-radius: ${({ theme }) => theme.border.radius.md};
+ box-shadow: unset;
+
+ button {
+ background: ${({ theme }) => theme.background.secondary};
+ border-bottom: none;
+ fill: ${({ theme }) => theme.font.color.secondary};
+ }
+ }
+ .react-flow__node {
+ z-index: -1 !important;
+ }
+`;
+
+const StyledCloseButton = styled.div`
+ position: absolute;
+ top: ${({ theme }) => theme.spacing(3)};
+ left: ${({ theme }) => theme.spacing(3)};
+ z-index: 5;
+`;
+
+export const SettingsDataModelOverview = () => {
+ const [nodes, setNodes] = useNodesState([]);
+ const [edges, setEdges] = useEdgesState([]);
+
+ const onNodesChange = useCallback(
+ (changes: NodeChange[]) =>
+ setNodes((nds) => applyNodeChanges(changes, nds)),
+ [setNodes],
+ );
+ const onEdgesChange = useCallback(
+ (changes: EdgeChange[]) =>
+ setEdges((eds) => applyEdgeChanges(changes, eds)),
+ [setEdges],
+ );
+
+ const handleNodesChange = useCallback(
+ (nodeChanges: any[]) => {
+ nodeChanges.forEach((nodeChange) => {
+ const node = nodes.find((node) => node.id === nodeChange.id);
+ if (!node) {
+ return;
+ }
+
+ const incomingNodes = getIncomers(node, nodes, edges);
+ const newXPos =
+ 'positionAbsolute' in nodeChange
+ ? nodeChange.positionAbsolute?.x
+ : node.position.x || 0;
+
+ incomingNodes.forEach((incomingNode) => {
+ const edge = edges.find((edge) => {
+ return edge.target === node.id && edge.source === incomingNode.id;
+ });
+
+ if (isDefined(newXPos)) {
+ setEdges((eds) =>
+ eds.map((ed) => {
+ if (isDefined(edge) && ed.id === edge.id) {
+ const sourcePosition = calculateHandlePosition(
+ incomingNode.width as number,
+ incomingNode.position.x,
+ node.width as number,
+ newXPos,
+ 'source',
+ );
+ const targetPosition = calculateHandlePosition(
+ incomingNode.width as number,
+ incomingNode.position.x,
+ node.width as number,
+ newXPos,
+ 'target',
+ );
+ const sourceHandle = `${edge.data.sourceField}-${sourcePosition}`;
+ const targetHandle = `${edge.data.targetField}-${targetPosition}`;
+ ed.sourceHandle = sourceHandle;
+ ed.targetHandle = targetHandle;
+ ed.markerEnd = 'marker';
+ ed.markerStart = 'marker';
+ }
+
+ return ed;
+ }),
+ );
+ }
+ });
+
+ const outgoingNodes = getOutgoers(node, nodes, edges);
+ outgoingNodes.forEach((targetNode) => {
+ const edge = edges.find((edge) => {
+ return edge.target === targetNode.id && edge.source === node.id;
+ });
+ if (isDefined(newXPos)) {
+ setEdges((eds) =>
+ eds.map((ed) => {
+ if (isDefined(edge) && ed.id === edge.id) {
+ const sourcePosition = calculateHandlePosition(
+ node.width as number,
+ newXPos,
+ targetNode.width as number,
+ targetNode.position.x,
+ 'source',
+ );
+ const targetPosition = calculateHandlePosition(
+ node.width as number,
+ newXPos,
+ targetNode.width as number,
+ targetNode.position.x,
+ 'target',
+ );
+
+ const sourceHandle = `${edge.data.sourceField}-${sourcePosition}`;
+ const targetHandle = `${edge.data.targetField}-${targetPosition}`;
+
+ ed.sourceHandle = sourceHandle;
+ ed.targetHandle = targetHandle;
+ ed.markerEnd = 'marker';
+ ed.markerStart = 'marker';
+ }
+
+ return ed;
+ }),
+ );
+ }
+ });
+ });
+
+ onNodesChange(nodeChanges);
+ },
+ [onNodesChange, setEdges, nodes, edges],
+ );
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverviewEffect.tsx b/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverviewEffect.tsx
new file mode 100644
index 0000000000..1cb6c6716b
--- /dev/null
+++ b/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverviewEffect.tsx
@@ -0,0 +1,104 @@
+import { useEffect } from 'react';
+import { Edge, Node } from 'reactflow';
+import dagre from '@dagrejs/dagre';
+import { useTheme } from '@emotion/react';
+import { useRecoilValue } from 'recoil';
+
+import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
+import { isDefined } from '~/utils/isDefined';
+import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
+
+type SettingsDataModelOverviewEffectProps = {
+ setEdges: (edges: Edge[]) => void;
+ setNodes: (nodes: Node[]) => void;
+};
+
+export const SettingsDataModelOverviewEffect = ({
+ setEdges,
+ setNodes,
+}: SettingsDataModelOverviewEffectProps) => {
+ const theme = useTheme();
+ const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
+
+ useEffect(() => {
+ const items = objectMetadataItems.filter((x) => !x.isSystem);
+
+ const g = new dagre.graphlib.Graph();
+ g.setGraph({ rankdir: 'LR' });
+ g.setDefaultEdgeLabel(() => ({}));
+
+ const edges: Edge[] = [];
+ const nodes = [];
+ let i = 0;
+ for (const object of items) {
+ nodes.push({
+ id: object.namePlural,
+ width: 220,
+ height: 100,
+ position: { x: i * 300, y: 0 },
+ data: object,
+ type: 'object',
+ });
+ g.setNode(object.namePlural, { width: 220, height: 100 });
+
+ for (const field of object.fields) {
+ if (
+ isDefined(field.toRelationMetadata) &&
+ isDefined(
+ items.find(
+ (x) => x.id === field.toRelationMetadata?.fromObjectMetadata.id,
+ ),
+ )
+ ) {
+ const sourceObj =
+ field.relationDefinition?.sourceObjectMetadata.namePlural;
+ const targetObj =
+ field.relationDefinition?.targetObjectMetadata.namePlural;
+
+ edges.push({
+ id: `${sourceObj}-${targetObj}`,
+ source: object.namePlural,
+ sourceHandle: `${field.id}-right`,
+ target: field.toRelationMetadata.fromObjectMetadata.namePlural,
+ targetHandle: `${field.toRelationMetadata.fromFieldMetadataId}-left`,
+ type: 'smoothstep',
+ style: {
+ strokeWidth: 1,
+ stroke: theme.color.gray,
+ },
+ markerEnd: 'marker',
+ markerStart: 'marker',
+ data: {
+ sourceField: field.id,
+ targetField: field.toRelationMetadata.fromFieldMetadataId,
+ relation: field.toRelationMetadata.relationType,
+ sourceObject: sourceObj,
+ targetObject: targetObj,
+ },
+ });
+ if (!isUndefinedOrNull(sourceObj) && !isUndefinedOrNull(targetObj)) {
+ g.setEdge(sourceObj, targetObj);
+ }
+ }
+ }
+ i++;
+ }
+
+ dagre.layout(g);
+
+ nodes.forEach((node) => {
+ const nodeWithPosition = g.node(node.id);
+ node.position = {
+ // We are shifting the dagre node position (anchor=center center) to the top left
+ // so it matches the React Flow node anchor point (top left).
+ x: nodeWithPosition.x - node.width / 2,
+ y: nodeWithPosition.y - node.height / 2,
+ };
+ });
+
+ setNodes(nodes);
+ setEdges(edges);
+ }, [objectMetadataItems, setEdges, setNodes, theme]);
+
+ return <>>;
+};
diff --git a/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverviewField.tsx b/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverviewField.tsx
new file mode 100644
index 0000000000..960a0abfd9
--- /dev/null
+++ b/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverviewField.tsx
@@ -0,0 +1,63 @@
+import { Handle, Position } from 'reactflow';
+import { useTheme } from '@emotion/react';
+import styled from '@emotion/styled';
+import { useRecoilValue } from 'recoil';
+import { useIcons } from 'twenty-ui';
+
+import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
+import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
+import { capitalize } from '~/utils/string/capitalize';
+
+type ObjectFieldRowProps = {
+ field: FieldMetadataItem;
+};
+
+const StyledRow = styled.div`
+ align-items: center;
+ display: flex;
+ gap: ${({ theme }) => theme.spacing(1)};
+ position: relative;
+ width: 100%;
+ padding: 0 ${({ theme }) => theme.spacing(2)};
+`;
+
+export const ObjectFieldRow = ({ field }: ObjectFieldRowProps) => {
+ const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
+ const { getIcon } = useIcons();
+ const theme = useTheme();
+
+ const relatedObjectId = field.relationDefinition?.targetObjectMetadata.id;
+
+ const relatedObject = objectMetadataItems.find(
+ (x) => x.id === relatedObjectId,
+ );
+
+ const Icon = getIcon(relatedObject?.icon);
+
+ return (
+
+ {Icon && }
+ {capitalize(relatedObject?.namePlural ?? '')}
+
+
+
+ );
+};
diff --git a/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverviewObject.tsx b/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverviewObject.tsx
new file mode 100644
index 0000000000..d03c5caff2
--- /dev/null
+++ b/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverviewObject.tsx
@@ -0,0 +1,142 @@
+import { Link } from 'react-router-dom';
+import { NodeProps } from 'reactflow';
+import { useTheme } from '@emotion/react';
+import styled from '@emotion/styled';
+import { IconTag, useIcons } from 'twenty-ui';
+
+import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
+import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
+import { ObjectFieldRow } from '@/settings/data-model/graph-overview/components/SettingsDataModelOverviewField';
+import { SettingsDataModelObjectTypeTag } from '@/settings/data-model/objects/SettingsDataModelObjectTypeTag';
+import { getObjectTypeLabel } from '@/settings/data-model/utils/getObjectTypeLabel';
+import { FieldMetadataType } from '~/generated/graphql';
+import { capitalize } from '~/utils/string/capitalize';
+
+import '@reactflow/node-resizer/dist/style.css';
+
+type SettingsDataModelOverviewObjectProps = NodeProps;
+
+const StyledNode = styled.div`
+ background-color: ${({ theme }) => theme.background.secondary};
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+ display: flex;
+ flex-direction: column;
+ width: 220px;
+ padding: ${({ theme }) => theme.spacing(2)};
+ gap: ${({ theme }) => theme.spacing(2)};
+ border: 1px solid ${({ theme }) => theme.border.color.medium};
+`;
+
+const StyledHeader = styled.div`
+ align-items: center;
+ display: flex;
+ justify-content: space-between;
+`;
+
+const StyledObjectName = styled.div`
+ border: 0;
+ border-radius: 4px 4px 0 0;
+ display: flex;
+ font-weight: bold;
+ gap: ${({ theme }) => theme.spacing(1)};
+ position: relative;
+ text-align: center;
+`;
+
+const StyledInnerCard = styled.div`
+ border: 1px solid ${({ theme }) => theme.border.color.light};
+ background-color: ${({ theme }) => theme.background.primary};
+ border-radius: ${({ theme }) => theme.border.radius.sm};
+ padding: ${({ theme }) => theme.spacing(2)} 0
+ ${({ theme }) => theme.spacing(2)} 0;
+ display: flex;
+ flex-flow: column nowrap;
+ gap: ${({ theme }) => theme.spacing(0.5)};
+ color: ${({ theme }) => theme.font.color.tertiary};
+`;
+
+const StyledCardRow = styled.div`
+ align-items: center;
+ display: flex;
+ height: 24px;
+ gap: ${({ theme }) => theme.spacing(1)};
+`;
+
+const StyledCardRowOther = styled.div`
+ align-items: center;
+ display: flex;
+ height: 24px;
+ padding: 0 ${({ theme }) => theme.spacing(2)};
+ gap: ${({ theme }) => theme.spacing(1)};
+`;
+
+const StyledCardRowText = styled.div``;
+
+const StyledObjectInstanceCount = styled.div`
+ color: ${({ theme }) => theme.font.color.tertiary};
+`;
+
+const StyledObjectLink = styled(Link)`
+ align-items: center;
+ display: flex;
+ text-decoration: none;
+ color: ${({ theme }) => theme.font.color.primary};
+
+ &:hover {
+ color: ${({ theme }) => theme.font.color.secondary};
+ }
+`;
+
+export const SettingsDataModelOverviewObject = ({
+ data,
+}: SettingsDataModelOverviewObjectProps) => {
+ const theme = useTheme();
+ const { getIcon } = useIcons();
+
+ const { totalCount } = useFindManyRecords({
+ objectNameSingular: data.nameSingular,
+ });
+
+ const fields = data.fields.filter((x) => !x.isSystem);
+
+ const countNonRelation = fields.filter(
+ (x) => x.type !== FieldMetadataType.Relation,
+ ).length;
+
+ const Icon = getIcon(data.icon);
+
+ return (
+
+
+ {}} onMouseLeave={() => {}}>
+
+ {Icon && }
+ {capitalize(data.namePlural)}
+
+ ยท {totalCount}
+
+
+
+
+
+ {fields
+ .filter((x) => x.type === FieldMetadataType.Relation)
+ .map((field) => (
+
+
+
+ ))}
+ {countNonRelation > 0 && (
+
+
+
+ {countNonRelation} other fields
+
+
+ )}
+
+
+ );
+};
diff --git a/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverviewRelationMarkers.tsx b/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverviewRelationMarkers.tsx
new file mode 100644
index 0000000000..bc36c6c937
--- /dev/null
+++ b/packages/twenty-front/src/modules/settings/data-model/graph-overview/components/SettingsDataModelOverviewRelationMarkers.tsx
@@ -0,0 +1,22 @@
+import { useTheme } from '@emotion/react';
+
+export const SettingsDataModelOverviewRelationMarkers = () => {
+ const theme = useTheme();
+ return (
+
+ );
+};
diff --git a/packages/twenty-front/src/modules/settings/data-model/graph-overview/util/__tests__/calculateHandlePosition.test.ts b/packages/twenty-front/src/modules/settings/data-model/graph-overview/util/__tests__/calculateHandlePosition.test.ts
new file mode 100644
index 0000000000..0c278ee95e
--- /dev/null
+++ b/packages/twenty-front/src/modules/settings/data-model/graph-overview/util/__tests__/calculateHandlePosition.test.ts
@@ -0,0 +1,19 @@
+import { calculateHandlePosition } from '../calculateHandlePosition';
+describe('calculatePosition', () => {
+ test('should calculate source handle', () => {
+ // Source node right from start of target node
+ expect(calculateHandlePosition(220, 1000, 220, 540, 'source')).toBe('left');
+ expect(calculateHandlePosition(220, 600, 220, 540, 'source')).toBe('left');
+ // Source node left from start of target node
+ expect(calculateHandlePosition(220, 0, 220, 540, 'source')).toBe('right');
+ });
+
+ test('should calculate target handle', () => {
+ // Source node right from start of target node
+ expect(calculateHandlePosition(220, 1200, 220, 540, 'target')).toBe(
+ 'right',
+ );
+ // Source node left from start of target node
+ expect(calculateHandlePosition(220, 0, 220, 540, 'target')).toBe('left');
+ });
+});
diff --git a/packages/twenty-front/src/modules/settings/data-model/graph-overview/util/calculateHandlePosition.ts b/packages/twenty-front/src/modules/settings/data-model/graph-overview/util/calculateHandlePosition.ts
new file mode 100644
index 0000000000..236069dc24
--- /dev/null
+++ b/packages/twenty-front/src/modules/settings/data-model/graph-overview/util/calculateHandlePosition.ts
@@ -0,0 +1,24 @@
+export const calculateHandlePosition = (
+ sourceNodeWidth: number,
+ sourceNodeX: number,
+ targetNodeWidth: number,
+ targetNodeX: number,
+ type: 'source' | 'target',
+) => {
+ if (type === 'source') {
+ if (
+ sourceNodeX > targetNodeX + targetNodeWidth ||
+ sourceNodeX + sourceNodeWidth > targetNodeX
+ ) {
+ return 'left';
+ }
+ return 'right';
+ }
+
+ if (type === 'target') {
+ if (sourceNodeX > targetNodeX + targetNodeWidth) {
+ return 'right';
+ }
+ return 'left';
+ }
+};
diff --git a/packages/twenty-front/src/modules/settings/data-model/objects/SettingsObjectCoverImage.tsx b/packages/twenty-front/src/modules/settings/data-model/objects/SettingsObjectCoverImage.tsx
index 38f8fe0f7d..25886edaa2 100644
--- a/packages/twenty-front/src/modules/settings/data-model/objects/SettingsObjectCoverImage.tsx
+++ b/packages/twenty-front/src/modules/settings/data-model/objects/SettingsObjectCoverImage.tsx
@@ -1,12 +1,8 @@
-import { useState } from 'react';
-import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
-import { IconX } from 'twenty-ui';
+import { IconEye } from 'twenty-ui';
-import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
+import { Button } from '@/ui/input/button/components/Button';
import { Card } from '@/ui/layout/card/components/Card';
-import { AnimatedFadeOut } from '@/ui/utilities/animation/components/AnimatedFadeOut';
-import { cookieStorage } from '~/utils/cookie-storage';
import DarkCoverImage from '../assets/cover-dark.png';
import LightCoverImage from '../assets/cover-light.png';
@@ -24,45 +20,23 @@ const StyledCoverImageContainer = styled(Card)`
height: 153px;
justify-content: center;
position: relative;
+ margin-bottom: ${({ theme }) => theme.spacing(8)};
`;
-const StyledTitle = styled.span`
- color: ${({ theme }) => theme.font.color.tertiary};
- font-size: ${({ theme }) => theme.font.size.sm};
- font-weight: ${({ theme }) => theme.font.weight.medium};
+const StyledButtonContainer = styled.div`
padding-top: ${({ theme }) => theme.spacing(5)};
`;
-
-const StyledLighIconButton = styled(LightIconButton)`
- position: absolute;
- right: ${({ theme }) => theme.spacing(1)};
- top: ${({ theme }) => theme.spacing(1)};
-`;
-
export const SettingsObjectCoverImage = () => {
- const theme = useTheme();
-
- const [cookieState, setCookieState] = useState(
- cookieStorage.getItem('settings-object-cover-image'),
- );
-
return (
-
-
- Build your business logic
-
+
+
-
+ to="/settings/objects/overview"
+ >
+
+
);
};
diff --git a/packages/twenty-front/src/modules/types/SettingsPath.ts b/packages/twenty-front/src/modules/types/SettingsPath.ts
index b4415d0f6c..c2d744067c 100644
--- a/packages/twenty-front/src/modules/types/SettingsPath.ts
+++ b/packages/twenty-front/src/modules/types/SettingsPath.ts
@@ -9,6 +9,7 @@ export enum SettingsPath {
AccountsEmailsInboxSettings = 'accounts/emails/:accountUuid',
Billing = 'billing',
Objects = 'objects',
+ ObjectOverview = 'objects/overview',
ObjectDetail = 'objects/:objectSlug',
ObjectEdit = 'objects/:objectSlug/edit',
ObjectNewFieldStep1 = 'objects/:objectSlug/new-field/step-1',
diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectOverview.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectOverview.tsx
new file mode 100644
index 0000000000..68d52499c9
--- /dev/null
+++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectOverview.tsx
@@ -0,0 +1,12 @@
+import { IconSettings } from 'twenty-ui';
+
+import { SettingsDataModelOverview } from '@/settings/data-model/graph-overview/components/SettingsDataModelOverview';
+import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
+
+export const SettingsObjectOverview = () => {
+ return (
+
+
+
+ );
+};
diff --git a/yarn.lock b/yarn.lock
index 0c30a1271c..039279ebe4 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4112,6 +4112,22 @@ __metadata:
languageName: node
linkType: hard
+"@dagrejs/dagre@npm:^1.1.2":
+ version: 1.1.2
+ resolution: "@dagrejs/dagre@npm:1.1.2"
+ dependencies:
+ "@dagrejs/graphlib": "npm:2.2.2"
+ checksum: 717b3e6974b67a3839ea828228582fa3bd310fac5aadc4a68d5e4b96c3f7bcb97cb6f78518bdbd4c14e4fa1cc764ac6259fa567734916fa51f078f5747c85877
+ languageName: node
+ linkType: hard
+
+"@dagrejs/graphlib@npm:2.2.2":
+ version: 2.2.2
+ resolution: "@dagrejs/graphlib@npm:2.2.2"
+ checksum: 2e79a4f5c6c402054b7ef42e786459645495934476170999f13867a55a00072636a23914772cce6bc03ce51eef70de589058860b8f034c1d70804fb61e01fcfc
+ languageName: node
+ linkType: hard
+
"@discoveryjs/json-ext@npm:0.5.7, @discoveryjs/json-ext@npm:^0.5.3":
version: 0.5.7
resolution: "@discoveryjs/json-ext@npm:0.5.7"
@@ -11281,6 +11297,102 @@ __metadata:
languageName: node
linkType: hard
+"@reactflow/background@npm:11.3.13":
+ version: 11.3.13
+ resolution: "@reactflow/background@npm:11.3.13"
+ dependencies:
+ "@reactflow/core": "npm:11.11.3"
+ classcat: "npm:^5.0.3"
+ zustand: "npm:^4.4.1"
+ peerDependencies:
+ react: ">=17"
+ react-dom: ">=17"
+ checksum: 54929a506c1b73b6406d511a0a55a89cf88eb2073bc4e72defde63b3da46794ea87638e017180492798d717e9220e833f66c7419270137ace9acaa040f790e6e
+ languageName: node
+ linkType: hard
+
+"@reactflow/controls@npm:11.2.13":
+ version: 11.2.13
+ resolution: "@reactflow/controls@npm:11.2.13"
+ dependencies:
+ "@reactflow/core": "npm:11.11.3"
+ classcat: "npm:^5.0.3"
+ zustand: "npm:^4.4.1"
+ peerDependencies:
+ react: ">=17"
+ react-dom: ">=17"
+ checksum: 219285855f5a76ad77bf858e1eb3ed867d95f96b8c2f6480e6f9f89dce9e68617cd97565960455aa6fa9c190292ebf81f28da3a254abd413c358a0288773203c
+ languageName: node
+ linkType: hard
+
+"@reactflow/core@npm:11.11.3":
+ version: 11.11.3
+ resolution: "@reactflow/core@npm:11.11.3"
+ dependencies:
+ "@types/d3": "npm:^7.4.0"
+ "@types/d3-drag": "npm:^3.0.1"
+ "@types/d3-selection": "npm:^3.0.3"
+ "@types/d3-zoom": "npm:^3.0.1"
+ classcat: "npm:^5.0.3"
+ d3-drag: "npm:^3.0.0"
+ d3-selection: "npm:^3.0.0"
+ d3-zoom: "npm:^3.0.0"
+ zustand: "npm:^4.4.1"
+ peerDependencies:
+ react: ">=17"
+ react-dom: ">=17"
+ checksum: 08c8353316c38ebc398e645f2e1e2d7246ea4e331485d604f8c6a8d54a83cc85e87921427b3fd7d161314258072b44508c9bba79faefa67e9d401e6b3f262b19
+ languageName: node
+ linkType: hard
+
+"@reactflow/minimap@npm:11.7.13":
+ version: 11.7.13
+ resolution: "@reactflow/minimap@npm:11.7.13"
+ dependencies:
+ "@reactflow/core": "npm:11.11.3"
+ "@types/d3-selection": "npm:^3.0.3"
+ "@types/d3-zoom": "npm:^3.0.1"
+ classcat: "npm:^5.0.3"
+ d3-selection: "npm:^3.0.0"
+ d3-zoom: "npm:^3.0.0"
+ zustand: "npm:^4.4.1"
+ peerDependencies:
+ react: ">=17"
+ react-dom: ">=17"
+ checksum: 71f89a7ae36ce6b50237401640043be20264fedfcd055f6a3e16cf84adcac343ad2f3fd74eb48875ab12538d3566aaddc21cce6160d602120e71797c79ee374e
+ languageName: node
+ linkType: hard
+
+"@reactflow/node-resizer@npm:2.2.13":
+ version: 2.2.13
+ resolution: "@reactflow/node-resizer@npm:2.2.13"
+ dependencies:
+ "@reactflow/core": "npm:11.11.3"
+ classcat: "npm:^5.0.4"
+ d3-drag: "npm:^3.0.0"
+ d3-selection: "npm:^3.0.0"
+ zustand: "npm:^4.4.1"
+ peerDependencies:
+ react: ">=17"
+ react-dom: ">=17"
+ checksum: 8fa01dc3c2805af56bfb93a05d7c2aecbf1c40fdd25d768ae0a0d252cec9ac04911493103abfbe3f8fcd840a8ea4a8c8342646eed7dcfcb3147d1de2a0661dff
+ languageName: node
+ linkType: hard
+
+"@reactflow/node-toolbar@npm:1.3.13":
+ version: 1.3.13
+ resolution: "@reactflow/node-toolbar@npm:1.3.13"
+ dependencies:
+ "@reactflow/core": "npm:11.11.3"
+ classcat: "npm:^5.0.3"
+ zustand: "npm:^4.4.1"
+ peerDependencies:
+ react: ">=17"
+ react-dom: ">=17"
+ checksum: bfba042b97bcb11c11f71db3c3eab5f153fb2b666f6135d0658efb0bf2b6f210ecb52fa1da3af59eb995dd91d04fe223ef88af7c6e3bc349650fb93e17ed876c
+ languageName: node
+ linkType: hard
+
"@redis/bloom@npm:1.2.0, @redis/bloom@npm:^1.2.0":
version: 1.2.0
resolution: "@redis/bloom@npm:1.2.0"
@@ -16008,6 +16120,45 @@ __metadata:
languageName: node
linkType: hard
+"@types/d3-array@npm:*":
+ version: 3.2.1
+ resolution: "@types/d3-array@npm:3.2.1"
+ checksum: 38bf2c778451f4b79ec81a2288cb4312fe3d6449ecdf562970cc339b60f280f31c93a024c7ff512607795e79d3beb0cbda123bb07010167bce32927f71364bca
+ languageName: node
+ linkType: hard
+
+"@types/d3-axis@npm:*":
+ version: 3.0.6
+ resolution: "@types/d3-axis@npm:3.0.6"
+ dependencies:
+ "@types/d3-selection": "npm:*"
+ checksum: d756d42360261f44d8eefd0950c5bb0a4f67a46dd92069da3f723ac36a1e8cb2b9ce6347d836ef19d5b8aef725dbcf8fdbbd6cfbff676ca4b0642df2f78b599a
+ languageName: node
+ linkType: hard
+
+"@types/d3-brush@npm:*":
+ version: 3.0.6
+ resolution: "@types/d3-brush@npm:3.0.6"
+ dependencies:
+ "@types/d3-selection": "npm:*"
+ checksum: fd6e2ac7657a354f269f6b9c58451ffae9d01b89ccb1eb6367fd36d635d2f1990967215ab498e0c0679ff269429c57fad6a2958b68f4d45bc9f81d81672edc01
+ languageName: node
+ linkType: hard
+
+"@types/d3-chord@npm:*":
+ version: 3.0.6
+ resolution: "@types/d3-chord@npm:3.0.6"
+ checksum: c5a25eb5389db01e63faec0c5c2ec7cc41c494e9b3201630b494c4e862a60f1aa83fabbc33a829e7e1403941e3c30d206c741559b14406ac2a4239cfdf4b4c17
+ languageName: node
+ linkType: hard
+
+"@types/d3-color@npm:*":
+ version: 3.1.3
+ resolution: "@types/d3-color@npm:3.1.3"
+ checksum: 65eb0487de606eb5ad81735a9a5b3142d30bc5ea801ed9b14b77cb14c9b909f718c059f13af341264ee189acf171508053342142bdf99338667cea26a2d8d6ae
+ languageName: node
+ linkType: hard
+
"@types/d3-color@npm:^2.0.0":
version: 2.0.6
resolution: "@types/d3-color@npm:2.0.6"
@@ -16015,6 +16166,108 @@ __metadata:
languageName: node
linkType: hard
+"@types/d3-contour@npm:*":
+ version: 3.0.6
+ resolution: "@types/d3-contour@npm:3.0.6"
+ dependencies:
+ "@types/d3-array": "npm:*"
+ "@types/geojson": "npm:*"
+ checksum: e7d83e94719af4576ceb5ac7f277c5806f83ba6c3631744ae391cffc3641f09dfa279470b83053cd0b2acd6784e8749c71141d05bdffa63ca58ffb5b31a0f27c
+ languageName: node
+ linkType: hard
+
+"@types/d3-delaunay@npm:*":
+ version: 6.0.4
+ resolution: "@types/d3-delaunay@npm:6.0.4"
+ checksum: d154a8864f08c4ea23ecb9bdabcef1c406a25baa8895f0cb08a0ed2799de0d360e597552532ce7086ff0cdffa8f3563f9109d18f0191459d32bb620a36939123
+ languageName: node
+ linkType: hard
+
+"@types/d3-dispatch@npm:*":
+ version: 3.0.6
+ resolution: "@types/d3-dispatch@npm:3.0.6"
+ checksum: 405eb7d0ec139fbf72fa6a43b0f3ca8a1f913bb2cb38f607827e63fca8d4393f021f32f3b96b33c93ddbd37789453a0b3624f14f504add5308fd9aec8a46dda0
+ languageName: node
+ linkType: hard
+
+"@types/d3-drag@npm:*, @types/d3-drag@npm:^3.0.1":
+ version: 3.0.7
+ resolution: "@types/d3-drag@npm:3.0.7"
+ dependencies:
+ "@types/d3-selection": "npm:*"
+ checksum: 65e29fa32a87c72d26c44b5e2df3bf15af21cd128386bcc05bcacca255927c0397d0cd7e6062aed5f0abd623490544a9d061c195f5ed9f018fe0b698d99c079d
+ languageName: node
+ linkType: hard
+
+"@types/d3-dsv@npm:*":
+ version: 3.0.7
+ resolution: "@types/d3-dsv@npm:3.0.7"
+ checksum: c0f01da862465594c8a28278b51c850af3b4239cc22b14fd1a19d7a98f93d94efa477bf59d8071beb285dca45bf614630811451e18e7c52add3a0abfee0a1871
+ languageName: node
+ linkType: hard
+
+"@types/d3-ease@npm:*":
+ version: 3.0.2
+ resolution: "@types/d3-ease@npm:3.0.2"
+ checksum: aff5a1e572a937ee9bff6465225d7ba27d5e0c976bd9eacdac2e6f10700a7cb0c9ea2597aff6b43a6ed850a3210030870238894a77ec73e309b4a9d0333f099c
+ languageName: node
+ linkType: hard
+
+"@types/d3-fetch@npm:*":
+ version: 3.0.7
+ resolution: "@types/d3-fetch@npm:3.0.7"
+ dependencies:
+ "@types/d3-dsv": "npm:*"
+ checksum: 3d147efa52a26da1a5d40d4d73e6cebaaa964463c378068062999b93ea3731b27cc429104c21ecbba98c6090e58ef13429db6399238c5e3500162fb3015697a0
+ languageName: node
+ linkType: hard
+
+"@types/d3-force@npm:*":
+ version: 3.0.9
+ resolution: "@types/d3-force@npm:3.0.9"
+ checksum: 6d791a48ea570daaada6df93af8c877d58e6b940b3ab4515cde08ed6ed1d4e8e59fd8407efe37a1b3f5fe95867fe83a2974c4314a7924dc19860a5e955c26211
+ languageName: node
+ linkType: hard
+
+"@types/d3-format@npm:*":
+ version: 3.0.4
+ resolution: "@types/d3-format@npm:3.0.4"
+ checksum: 3ac1600bf9061a59a228998f7cd3f29e85cbf522997671ba18d4d84d10a2a1aff4f95aceb143fa9960501c3ec351e113fc75884e6a504ace44dc1744083035ee
+ languageName: node
+ linkType: hard
+
+"@types/d3-geo@npm:*":
+ version: 3.1.0
+ resolution: "@types/d3-geo@npm:3.1.0"
+ dependencies:
+ "@types/geojson": "npm:*"
+ checksum: 3745a93439038bb5b0b38facf435f7079812921d46406f5d38deaee59e90084ff742443c7ea0a8446df81a0d81eaf622fe7068cf4117a544bd4aa3b2dc182f88
+ languageName: node
+ linkType: hard
+
+"@types/d3-hierarchy@npm:*":
+ version: 3.1.7
+ resolution: "@types/d3-hierarchy@npm:3.1.7"
+ checksum: 873711737d6b8e7b6f1dda0bcd21294a48f75024909ae510c5d2c21fad2e72032e0958def4d9f68319d3aaac298ad09c49807f8bfc87a145a82693b5208613c7
+ languageName: node
+ linkType: hard
+
+"@types/d3-interpolate@npm:*":
+ version: 3.0.4
+ resolution: "@types/d3-interpolate@npm:3.0.4"
+ dependencies:
+ "@types/d3-color": "npm:*"
+ checksum: 066ebb8da570b518dd332df6b12ae3b1eaa0a7f4f0c702e3c57f812cf529cc3500ec2aac8dc094f31897790346c6b1ebd8cd7a077176727f4860c2b181a65ca4
+ languageName: node
+ linkType: hard
+
+"@types/d3-path@npm:*":
+ version: 3.1.0
+ resolution: "@types/d3-path@npm:3.1.0"
+ checksum: 85e8b3aa968a60a5b33198ade06ae7ffedcf9a22d86f24859ff58e014b053ccb7141ec163b78d547bc8215bb12bb54171c666057ab6156912814005b686afb31
+ languageName: node
+ linkType: hard
+
"@types/d3-path@npm:^2":
version: 2.0.4
resolution: "@types/d3-path@npm:2.0.4"
@@ -16022,6 +16275,34 @@ __metadata:
languageName: node
linkType: hard
+"@types/d3-polygon@npm:*":
+ version: 3.0.2
+ resolution: "@types/d3-polygon@npm:3.0.2"
+ checksum: f46307bb32b6c2aef8c7624500e0f9b518de8f227ccc10170b869dc43e4c542560f6c8d62e9f087fac45e198d6e4b623e579c0422e34c85baf56717456d3f439
+ languageName: node
+ linkType: hard
+
+"@types/d3-quadtree@npm:*":
+ version: 3.0.6
+ resolution: "@types/d3-quadtree@npm:3.0.6"
+ checksum: 7eaa0a4d404adc856971c9285e1c4ab17e9135ea669d847d6db7e0066126a28ac751864e7ce99c65d526e130f56754a2e437a1617877098b3bdcc3ef23a23616
+ languageName: node
+ linkType: hard
+
+"@types/d3-random@npm:*":
+ version: 3.0.3
+ resolution: "@types/d3-random@npm:3.0.3"
+ checksum: 5f4fea40080cd6d4adfee05183d00374e73a10c530276a6455348983dda341003a251def28565a27c25d9cf5296a33e870e397c9d91ff83fb7495a21c96b6882
+ languageName: node
+ linkType: hard
+
+"@types/d3-scale-chromatic@npm:*":
+ version: 3.0.3
+ resolution: "@types/d3-scale-chromatic@npm:3.0.3"
+ checksum: 2f48c6f370edba485b57b73573884ded71914222a4580140ff87ee96e1d55ccd05b1d457f726e234a31269b803270ac95d5554229ab6c43c7e4a9894e20dd490
+ languageName: node
+ linkType: hard
+
"@types/d3-scale-chromatic@npm:^2.0.0":
version: 2.0.4
resolution: "@types/d3-scale-chromatic@npm:2.0.4"
@@ -16029,6 +16310,15 @@ __metadata:
languageName: node
linkType: hard
+"@types/d3-scale@npm:*":
+ version: 4.0.8
+ resolution: "@types/d3-scale@npm:4.0.8"
+ dependencies:
+ "@types/d3-time": "npm:*"
+ checksum: 57de90e4016f640b83cb960b7e3a0ab3ed02e720898840ddc5105264ffcfea73336161442fdc91895377c2d2f91904d637282f16852b8535b77e15a761c8e99e
+ languageName: node
+ linkType: hard
+
"@types/d3-scale@npm:^3.2.3":
version: 3.3.5
resolution: "@types/d3-scale@npm:3.3.5"
@@ -16038,6 +16328,22 @@ __metadata:
languageName: node
linkType: hard
+"@types/d3-selection@npm:*, @types/d3-selection@npm:^3.0.3":
+ version: 3.0.10
+ resolution: "@types/d3-selection@npm:3.0.10"
+ checksum: de1f99ab186a08999bf394a645fd76911add1b02316270d4c07616c8383903a2b068d7e02b73b6a99a1f26bb49a2e99ef4b55a5d2ddfa165f6f3c53144897920
+ languageName: node
+ linkType: hard
+
+"@types/d3-shape@npm:*":
+ version: 3.1.6
+ resolution: "@types/d3-shape@npm:3.1.6"
+ dependencies:
+ "@types/d3-path": "npm:*"
+ checksum: 0625715925d3c7ed3d44ce998b42c993f063c31605b6e4a8046c4be0fe724e2d214fc83e86d04f429a30a6e1f439053e92b0d9e59e1180c3a5327b4a6e79fa0a
+ languageName: node
+ linkType: hard
+
"@types/d3-shape@npm:^2.0.0":
version: 2.1.7
resolution: "@types/d3-shape@npm:2.1.7"
@@ -16047,6 +16353,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/d3-time-format@npm:*":
+ version: 4.0.3
+ resolution: "@types/d3-time-format@npm:4.0.3"
+ checksum: 9ef5e8e2b96b94799b821eed5d61a3d432c7903247966d8ad951b8ce5797fe46554b425cb7888fa5bf604b4663c369d7628c0328ffe80892156671c58d1a7f90
+ languageName: node
+ linkType: hard
+
"@types/d3-time-format@npm:^3.0.0":
version: 3.0.4
resolution: "@types/d3-time-format@npm:3.0.4"
@@ -16054,6 +16367,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/d3-time@npm:*":
+ version: 3.0.3
+ resolution: "@types/d3-time@npm:3.0.3"
+ checksum: 245a8aadca504df27edf730de502e47a68f16ae795c86b5ca35e7afa91c133aa9ef4d08778f8cf1ed2be732f89a4105ba4b437ce2afbdfd17d3d937b6ba5f568
+ languageName: node
+ linkType: hard
+
"@types/d3-time@npm:^1.0.10":
version: 1.1.4
resolution: "@types/d3-time@npm:1.1.4"
@@ -16068,6 +16388,77 @@ __metadata:
languageName: node
linkType: hard
+"@types/d3-timer@npm:*":
+ version: 3.0.2
+ resolution: "@types/d3-timer@npm:3.0.2"
+ checksum: c644dd9571fcc62b1aa12c03bcad40571553020feeb5811f1d8a937ac1e65b8a04b759b4873aef610e28b8714ac71c9885a4d6c127a048d95118f7e5b506d9e1
+ languageName: node
+ linkType: hard
+
+"@types/d3-transition@npm:*":
+ version: 3.0.8
+ resolution: "@types/d3-transition@npm:3.0.8"
+ dependencies:
+ "@types/d3-selection": "npm:*"
+ checksum: feba7845bd1e1d49e38b0d55562e01e90bfbcf0a56fbe0de4279c12e43a687032d22ed559629c0412145d25d61e4e53ddfef34c89c6bf043d48b6c2cd3a929dc
+ languageName: node
+ linkType: hard
+
+"@types/d3-zoom@npm:*, @types/d3-zoom@npm:^3.0.1":
+ version: 3.0.8
+ resolution: "@types/d3-zoom@npm:3.0.8"
+ dependencies:
+ "@types/d3-interpolate": "npm:*"
+ "@types/d3-selection": "npm:*"
+ checksum: 1dbdbcafddcae12efb5beb6948546963f29599e18bc7f2a91fb69cc617c2299a65354f2d47e282dfb86fec0968406cd4fb7f76ba2d2fb67baa8e8d146eb4a547
+ languageName: node
+ linkType: hard
+
+"@types/d3@npm:^7.4.0":
+ version: 7.4.3
+ resolution: "@types/d3@npm:7.4.3"
+ dependencies:
+ "@types/d3-array": "npm:*"
+ "@types/d3-axis": "npm:*"
+ "@types/d3-brush": "npm:*"
+ "@types/d3-chord": "npm:*"
+ "@types/d3-color": "npm:*"
+ "@types/d3-contour": "npm:*"
+ "@types/d3-delaunay": "npm:*"
+ "@types/d3-dispatch": "npm:*"
+ "@types/d3-drag": "npm:*"
+ "@types/d3-dsv": "npm:*"
+ "@types/d3-ease": "npm:*"
+ "@types/d3-fetch": "npm:*"
+ "@types/d3-force": "npm:*"
+ "@types/d3-format": "npm:*"
+ "@types/d3-geo": "npm:*"
+ "@types/d3-hierarchy": "npm:*"
+ "@types/d3-interpolate": "npm:*"
+ "@types/d3-path": "npm:*"
+ "@types/d3-polygon": "npm:*"
+ "@types/d3-quadtree": "npm:*"
+ "@types/d3-random": "npm:*"
+ "@types/d3-scale": "npm:*"
+ "@types/d3-scale-chromatic": "npm:*"
+ "@types/d3-selection": "npm:*"
+ "@types/d3-shape": "npm:*"
+ "@types/d3-time": "npm:*"
+ "@types/d3-time-format": "npm:*"
+ "@types/d3-timer": "npm:*"
+ "@types/d3-transition": "npm:*"
+ "@types/d3-zoom": "npm:*"
+ checksum: a9c6d65b13ef3b42c87f2a89ea63a6d5640221869f97d0657b0cb2f1dac96a0f164bf5605643c0794e0de3aa2bf05df198519aaf15d24ca135eb0e8bd8a9d879
+ languageName: node
+ linkType: hard
+
+"@types/dagre@npm:^0.7.52":
+ version: 0.7.52
+ resolution: "@types/dagre@npm:0.7.52"
+ checksum: 0e196a8c17a92765d6e28b10d78d5c1cb1ee540598428cbb61ce3b90e0fedaac2b11f6dbeebf0d2f69d5332d492b12091be5f1e575f538194e20d8887979d006
+ languageName: node
+ linkType: hard
+
"@types/debug@npm:^4.0.0":
version: 4.1.12
resolution: "@types/debug@npm:4.1.12"
@@ -16276,6 +16667,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/geojson@npm:*":
+ version: 7946.0.14
+ resolution: "@types/geojson@npm:7946.0.14"
+ checksum: 54f3997708fa2970c03eeb31f7e4540a0eb6387b15e9f8a60513a1409c23cafec8d618525404573468b59c6fecbfd053724b3327f7fca416729c26271d799f55
+ languageName: node
+ linkType: hard
+
"@types/glob@npm:^7.1.3":
version: 7.2.0
resolution: "@types/glob@npm:7.2.0"
@@ -22220,6 +22618,13 @@ __metadata:
languageName: node
linkType: hard
+"classcat@npm:^5.0.3, classcat@npm:^5.0.4":
+ version: 5.0.5
+ resolution: "classcat@npm:5.0.5"
+ checksum: ff8d273055ef9b518529cfe80fd0486f7057a9917373807ff802d75ceb46e8f8e148f41fa094ee7625c8f34642cfaa98395ff182d9519898da7cbf383d4a210d
+ languageName: node
+ linkType: hard
+
"classnames@npm:^2.2.6, classnames@npm:^2.3.0, classnames@npm:^2.3.1":
version: 2.5.1
resolution: "classnames@npm:2.5.1"
@@ -23919,6 +24324,30 @@ __metadata:
languageName: node
linkType: hard
+"d3-dispatch@npm:1 - 3":
+ version: 3.0.1
+ resolution: "d3-dispatch@npm:3.0.1"
+ checksum: 6eca77008ce2dc33380e45d4410c67d150941df7ab45b91d116dbe6d0a3092c0f6ac184dd4602c796dc9e790222bad3ff7142025f5fd22694efe088d1d941753
+ languageName: node
+ linkType: hard
+
+"d3-drag@npm:2 - 3, d3-drag@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "d3-drag@npm:3.0.0"
+ dependencies:
+ d3-dispatch: "npm:1 - 3"
+ d3-selection: "npm:3"
+ checksum: d2556e8dc720741a443b595a30af403dd60642dfd938d44d6e9bfc4c71a962142f9a028c56b61f8b4790b65a34acad177d1263d66f103c3c527767b0926ef5aa
+ languageName: node
+ linkType: hard
+
+"d3-ease@npm:1 - 3":
+ version: 3.0.1
+ resolution: "d3-ease@npm:3.0.1"
+ checksum: fec8ef826c0cc35cda3092c6841e07672868b1839fcaf556e19266a3a37e6bc7977d8298c0fcb9885e7799bfdcef7db1baaba9cd4dcf4bc5e952cf78574a88b0
+ languageName: node
+ linkType: hard
+
"d3-format@npm:1 - 2":
version: 2.0.0
resolution: "d3-format@npm:2.0.0"
@@ -23991,6 +24420,13 @@ __metadata:
languageName: node
linkType: hard
+"d3-selection@npm:2 - 3, d3-selection@npm:3, d3-selection@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "d3-selection@npm:3.0.0"
+ checksum: e59096bbe8f0cb0daa1001d9bdd6dbc93a688019abc97d1d8b37f85cd3c286a6875b22adea0931b0c88410d025563e1643019161a883c516acf50c190a11b56b
+ languageName: node
+ linkType: hard
+
"d3-shape@npm:^1.3.5":
version: 1.3.7
resolution: "d3-shape@npm:1.3.7"
@@ -24025,6 +24461,41 @@ __metadata:
languageName: node
linkType: hard
+"d3-timer@npm:1 - 3":
+ version: 3.0.1
+ resolution: "d3-timer@npm:3.0.1"
+ checksum: d4c63cb4bb5461d7038aac561b097cd1c5673969b27cbdd0e87fa48d9300a538b9e6f39b4a7f0e3592ef4f963d858c8a9f0e92754db73116770856f2fc04561a
+ languageName: node
+ linkType: hard
+
+"d3-transition@npm:2 - 3":
+ version: 3.0.1
+ resolution: "d3-transition@npm:3.0.1"
+ dependencies:
+ d3-color: "npm:1 - 3"
+ d3-dispatch: "npm:1 - 3"
+ d3-ease: "npm:1 - 3"
+ d3-interpolate: "npm:1 - 3"
+ d3-timer: "npm:1 - 3"
+ peerDependencies:
+ d3-selection: 2 - 3
+ checksum: 4e74535dda7024aa43e141635b7522bb70cf9d3dfefed975eb643b36b864762eca67f88fafc2ca798174f83ca7c8a65e892624f824b3f65b8145c6a1a88dbbad
+ languageName: node
+ linkType: hard
+
+"d3-zoom@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "d3-zoom@npm:3.0.0"
+ dependencies:
+ d3-dispatch: "npm:1 - 3"
+ d3-drag: "npm:2 - 3"
+ d3-interpolate: "npm:1 - 3"
+ d3-selection: "npm:2 - 3"
+ d3-transition: "npm:2 - 3"
+ checksum: ee2036479049e70d8c783d594c444fe00e398246048e3f11a59755cd0e21de62ece3126181b0d7a31bf37bcf32fd726f83ae7dea4495ff86ec7736ce5ad36fd3
+ languageName: node
+ linkType: hard
+
"d@npm:1, d@npm:^1.0.1":
version: 1.0.1
resolution: "d@npm:1.0.1"
@@ -41677,6 +42148,23 @@ __metadata:
languageName: node
linkType: hard
+"reactflow@npm:^11.11.3":
+ version: 11.11.3
+ resolution: "reactflow@npm:11.11.3"
+ dependencies:
+ "@reactflow/background": "npm:11.3.13"
+ "@reactflow/controls": "npm:11.2.13"
+ "@reactflow/core": "npm:11.11.3"
+ "@reactflow/minimap": "npm:11.7.13"
+ "@reactflow/node-resizer": "npm:2.2.13"
+ "@reactflow/node-toolbar": "npm:1.3.13"
+ peerDependencies:
+ react: ">=17"
+ react-dom: ">=17"
+ checksum: 1de038357a3b1ec440a06f041540ec4738419366bff13829996407b963f69bec7acfd1dca475c067727146bfd8f6ce1b230ce499abdbd6a8a2a37493cf547a94
+ languageName: node
+ linkType: hard
+
"read-cmd-shim@npm:^2.0.0":
version: 2.0.0
resolution: "read-cmd-shim@npm:2.0.0"
@@ -46341,6 +46829,7 @@ __metadata:
"@chakra-ui/system": "npm:^2.6.0"
"@codesandbox/sandpack-react": "npm:^2.13.5"
"@crxjs/vite-plugin": "npm:^1.0.14"
+ "@dagrejs/dagre": "npm:^1.1.2"
"@docusaurus/core": "npm:^3.1.0"
"@docusaurus/module-type-aliases": "npm:^3.1.0"
"@docusaurus/preset-classic": "npm:^3.1.0"
@@ -46430,6 +46919,7 @@ __metadata:
"@types/bytes": "npm:^3.1.1"
"@types/chrome": "npm:^0.0.267"
"@types/crypto-js": "npm:^4.2.2"
+ "@types/dagre": "npm:^0.7.52"
"@types/deep-equal": "npm:^1.0.1"
"@types/dompurify": "npm:^3.0.5"
"@types/express": "npm:^4.17.13"
@@ -46610,6 +47100,7 @@ __metadata:
react-router-dom: "npm:^6.4.4"
react-textarea-autosize: "npm:^8.4.1"
react-tooltip: "npm:^5.13.1"
+ reactflow: "npm:^11.11.3"
recoil: "npm:^0.7.7"
rehype-slug: "npm:^6.0.0"
remark-behead: "npm:^3.1.0"
@@ -47758,7 +48249,7 @@ __metadata:
languageName: node
linkType: hard
-"use-sync-external-store@npm:^1.0.0":
+"use-sync-external-store@npm:1.2.0, use-sync-external-store@npm:^1.0.0":
version: 1.2.0
resolution: "use-sync-external-store@npm:1.2.0"
peerDependencies:
@@ -49750,6 +50241,26 @@ __metadata:
languageName: node
linkType: hard
+"zustand@npm:^4.4.1":
+ version: 4.5.2
+ resolution: "zustand@npm:4.5.2"
+ dependencies:
+ use-sync-external-store: "npm:1.2.0"
+ peerDependencies:
+ "@types/react": ">=16.8"
+ immer: ">=9.0.6"
+ react: ">=16.8"
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ immer:
+ optional: true
+ react:
+ optional: true
+ checksum: aee26f11facebb39b016e89539f72a72c2c00151208907fc909c3cedd455728240e09e01d98ebd3b63a2a3518a5917eac5de6c853743ca55a1655296d750bb48
+ languageName: node
+ linkType: hard
+
"zwitch@npm:^1.0.0":
version: 1.0.5
resolution: "zwitch@npm:1.0.5"