Add Object Alternative view (#5356)

Current state:

<img width="704" alt="Bildschirmfoto 2024-05-11 um 17 57 33"
src="https://github.com/twentyhq/twenty/assets/48770548/c979f6fd-083e-40d3-8dbb-c572229e0da3">



I have some things im not really happy with right now:

* If I have different connections it would be weird to display a one_one
or many_one connection differently
* The edges overlay always at one hand at the source/target (also being
a problem with the 3 dots vs 1 dot)
* I would have to do 4 versions of the 3 dot marker variant as an svg
with exactly the same width as the edges wich is not as easy as it seems
:)
* The initial layout is not really great - I know dagre or elkjs could
solve this but maybe there is a better solution ...


If someone has a good idea for one or more of the problems im happy to
integrate them ;)

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
This commit is contained in:
brendanlaschke 2024-05-25 10:38:27 +02:00 committed by GitHub
parent 9080981990
commit 1c867d49a1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 1166 additions and 40 deletions

View File

@ -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",

View File

@ -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={<SettingsObjects />}
/>
<Route
path={SettingsPath.ObjectOverview}
element={<SettingsObjectOverview />}
/>
<Route
path={SettingsPath.ObjectDetail}
element={<SettingsObjectDetail />}

View File

@ -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 (
<StyledContainer>
<StyledCloseButton>
<Button Icon={IconX} to="/settings/objects"></Button>
</StyledCloseButton>
<SettingsDataModelOverviewEffect
setEdges={setEdges}
setNodes={setNodes}
/>
<SettingsDataModelOverviewRelationMarkers />
<ReactFlow
fitView
nodes={nodes}
edges={edges}
onEdgesChange={onEdgesChange}
nodeTypes={NodeTypes}
onNodesChange={handleNodesChange}
proOptions={{ hideAttribution: true }}
>
<Background />
<Controls />
</ReactFlow>
</StyledContainer>
);
};

View File

@ -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 <></>;
};

View File

@ -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 (
<StyledRow>
{Icon && <Icon size={theme.icon.size.md} />}
{capitalize(relatedObject?.namePlural ?? '')}
<Handle
type={field.toRelationMetadata ? 'source' : 'target'}
position={Position.Right}
id={`${field.id}-right`}
className={
field.fromRelationMetadata
? 'right-handle source-handle'
: 'right-handle target-handle'
}
/>
<Handle
type={field.toRelationMetadata ? 'source' : 'target'}
position={Position.Left}
id={`${field.id}-left`}
className={
field.fromRelationMetadata
? 'left-handle source-handle'
: 'left-handle target-handle'
}
/>
</StyledRow>
);
};

View File

@ -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<ObjectMetadataItem>;
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 (
<StyledNode>
<StyledHeader>
<StyledObjectName onMouseEnter={() => {}} onMouseLeave={() => {}}>
<StyledObjectLink to={'/settings/objects/' + data.namePlural}>
{Icon && <Icon size={theme.icon.size.md} />}
{capitalize(data.namePlural)}
</StyledObjectLink>
<StyledObjectInstanceCount> · {totalCount}</StyledObjectInstanceCount>
</StyledObjectName>
<SettingsDataModelObjectTypeTag
objectTypeLabel={getObjectTypeLabel(data)}
></SettingsDataModelObjectTypeTag>
</StyledHeader>
<StyledInnerCard>
{fields
.filter((x) => x.type === FieldMetadataType.Relation)
.map((field) => (
<StyledCardRow>
<ObjectFieldRow field={field}></ObjectFieldRow>
</StyledCardRow>
))}
{countNonRelation > 0 && (
<StyledCardRowOther>
<IconTag size={theme.icon.size.md} />
<StyledCardRowText>
{countNonRelation} other fields
</StyledCardRowText>
</StyledCardRowOther>
)}
</StyledInnerCard>
</StyledNode>
);
};

View File

@ -0,0 +1,22 @@
import { useTheme } from '@emotion/react';
export const SettingsDataModelOverviewRelationMarkers = () => {
const theme = useTheme();
return (
<svg style={{ position: 'absolute', top: 0, left: 0 }}>
<defs>
<marker
id="marker"
viewBox="0 0 6 6"
markerHeight="6"
markerWidth="6"
refX="3"
refY="3"
fill="none"
>
<circle cx="3" cy="3" r="3" fill={theme.color.gray} />
</marker>
</defs>
</svg>
);
};

View File

@ -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');
});
});

View File

@ -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';
}
};

View File

@ -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 (
<AnimatedFadeOut
isOpen={cookieState !== 'closed'}
marginBottom={theme.spacing(8)}
>
<StyledCoverImageContainer>
<StyledTitle>Build your business logic</StyledTitle>
<StyledLighIconButton
Icon={IconX}
accent="tertiary"
<StyledCoverImageContainer>
<StyledButtonContainer>
<Button
Icon={IconEye}
title="Visualize"
size="small"
onClick={() => {
cookieStorage.setItem('settings-object-cover-image', 'closed');
setCookieState('closed');
}}
/>
</StyledCoverImageContainer>
</AnimatedFadeOut>
to="/settings/objects/overview"
></Button>
</StyledButtonContainer>
</StyledCoverImageContainer>
);
};

View File

@ -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',

View File

@ -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 (
<SubMenuTopBarContainer Icon={IconSettings} title="Settings">
<SettingsDataModelOverview />
</SubMenuTopBarContainer>
);
};

513
yarn.lock
View File

@ -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"