Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/web/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# react-mobx-starter

todo: https://reactflow.dev/docs/guides/state-management/

## dev

```bash
Expand Down
7 changes: 4 additions & 3 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@
"mobx-react-lite": "^3.4.0",
"mobx-router": "1.0.0",
"mobx-state-tree": "5.1.5",
"mobxtypes": "workspace:*",
"mst-middlewares": "5.1.5",
"react": "18.1.0",
"react-dom": "18.1.0",
"react-flow-renderer": "^10.3.8",
"react-i18next": "^11.16.9",
"react-icons": "^4.4.0",
"mobxtypes": "workspace:*",
"shared-types": "workspace:*"
},
"devDependencies": {
Expand All @@ -44,8 +45,8 @@
"sass": "1.52.1",
"tailwindcss": "^3.0.24",
"tsconfig": "workspace:*",
"vite": "2.9.9",
"typescript": "^4.7.2"
"typescript": "^4.7.2",
"vite": "2.9.9"
},
"description": "",
"main": "vite.config.js",
Expand Down
2 changes: 2 additions & 0 deletions apps/web/src/models/root.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import { Instance, types } from 'mobx-state-tree'
import { createContext, useContext } from 'react'
import { NotFoundPage } from '../pages/404/model'
import { CatsPage } from '../pages/cats/model'
import { FlowPage } from '../pages/flow/model'
import ApiStore, { APIType } from './api'

const PagesStore = types.model('Pages', {
notFound: types.optional(NotFoundPage, () => NotFoundPage.create()),
cats: types.optional(CatsPage, () => CatsPage.create()),
flow: types.optional(FlowPage, () => FlowPage.create()),
})

export const RealRootModel = types.model('Root', {
Expand Down
138 changes: 138 additions & 0 deletions apps/web/src/pages/flow/model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import { types, cast } from 'mobx-state-tree'
import { getRootStore } from '../../models/helpers'
import ReactFlow, {
MiniMap,
Controls,
useNodesState,
useEdgesState,
applyEdgeChanges,
applyNodeChanges,
NodeChange,
EdgeChange,
Node,
Connection,
} from 'react-flow-renderer'

export const FlowPage = types
.model('CatsPage', {
data: types.optional(
types.model({
test: types.optional(types.string, ''),
}),
{},
),
nnodes: types.frozen<Node[]>(),
nodes: types.array(
types.model({
id: types.string,
data: types.model({
label: types.string,
}),
position: types.model({
x: types.number,
y: types.number,
}),
}),
),
edges: types.array(
types.model({
id: types.string,
source: types.string,
target: types.string,
}),
),
})
.actions((self) => ({
// INITIALIZATION
initialisePage() {
self.data.test = 'test'
self.nodes = cast([
{ id: '1', data: { label: 'Node yay' }, position: { x: 100, y: 100 } },
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 200 } },
])
self.edges = cast([{ id: 'e1-2', source: '1', target: '2' }])
},

updateFirstNode() {
self.nodes[0].position.x += 50
},

onNodesChange: (changes: NodeChange[]) => {
const updatedNodes = applyNodeChanges(changes, self.nodes)
for (const updatedNode of updatedNodes) {
for (const node of self.nodes) {
if (updatedNode.id === node.id) {
// console.log(`changing node ${node.id}`)
node.position.x = updatedNode.position.x
node.position.y = updatedNode.position.y
}
}
}
// self.nodes.push(...updatedNodes)
},

onEdgeChange: (changes: any[]) => {
for (const edge of self.edges) {
if (edge.id === changes[0].id) {
self.edges.remove(edge)
return
}
}
},

onConnect: (connection: Connection) => {
// applyEdgeChanges()
self.edges.push({
id: `${connection.source}-${connection.target}`,
source: String(connection.source),
target: String(connection.target),
})
},

addNode: () => {
const ids: number[] = self.nodes.map((node) => Number(node.id))
const maxId = Math.max(...ids)
const newId = String(maxId + 1)
self.nodes.push({
id: newId,
data: {
label: `Node ${newId}`,
},
position: {
x: 50,
y: 50,
},
})
},

removeEdge: (id: string) => {
for (const edge of self.edges) {
if (edge.id === id) {
self.edges.remove(edge)
return
}
}
},
}))
.views((self) => ({
pageModelFetching() {
return true
},

getNodes() {
// console.log(JSON.stringify(self.nodes))
// return self.nodes
return JSON.parse(JSON.stringify(self.nodes))
},

getEdges() {
// return JSON.parse(JSON.stringify(self.edges))
return self.edges.map((edge) => {
return {
id: edge.id,
source: edge.source,
target: edge.target,
}
})
},
}))
51 changes: 51 additions & 0 deletions apps/web/src/pages/flow/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { observer } from 'mobx-react-lite'
import { useMst } from '../../models/root'
import ReactFlow, {
MiniMap,
Controls,
useNodesState,
useEdgesState,
applyEdgeChanges,
applyNodeChanges,
} from 'react-flow-renderer'
import { Button } from '@chakra-ui/react'

const flowKey = 'example-flow'

const getNodeId = () => `randomnode_${+new Date()}`

const initialNodes = [
{ id: '1', data: { label: 'Node 1' }, position: { x: 100, y: 100 } },
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 200 } },
]

const initialEdges = [{ id: 'e1-2', source: '1', target: '2' }]

export default observer(() => {
const {
root: {
pages: { flow: page },
},
} = useMst()

return (
<>
<Button onClick={() => page.addNode()}>Add Node</Button>
<ReactFlow
nodes={page.getNodes()}
edges={page.getEdges()}
style={{ width: '500px', height: '500px' }}
onNodesChange={(event) => {
page.onNodesChange(event)
// applyNodeChanges(event, page.nodes)
}}
onEdgesChange={(event: any) => page.onEdgeChange(event)}
// onConnect={onConnect}
onConnect={(event) => page.onConnect(event)}
>
<MiniMap />
<Controls />
</ReactFlow>
</>
)
})
13 changes: 11 additions & 2 deletions apps/web/src/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import { Route } from 'mobx-router'
import { RootStore } from './models/root'
import NotFoundPage from './pages/404/page'
import CatsPage from './pages/cats/page'
import FlowPage from './pages/flow/page'

export default {
home: new Route<RootStore>({
path: '/',
component: <CatsPage />,
component: <FlowPage />,
onEnter(_route, _parameters, { root: { pages } }) {
pages.cats.initialisePage()
pages.flow.initialisePage()
},
}),

Expand All @@ -20,6 +21,14 @@ export default {
},
}),

flow: new Route<RootStore>({
path: '/flow',
component: <FlowPage />,
onEnter(_route, _parameters, { root: { pages } }) {
pages.flow.initialisePage()
},
}),

notFound: new Route<RootStore>({
path: '/404',
component: <NotFoundPage />,
Expand Down
Loading