Skip to content

Commit c69e575

Browse files
feat(overmind-devtools): implement state tree and track updates
1 parent 0d9af84 commit c69e575

File tree

10 files changed

+139
-41
lines changed

10 files changed

+139
-41
lines changed

packages/node_modules/overmind-devtools/src/client/BackendConnector.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { ipcRenderer } from 'electron'
2-
import { resolve } from 'url'
32

43
type Message = {
54
type: string
@@ -26,7 +25,6 @@ class Port {
2625
ipcRenderer.on('port:exists', this.onPortExists)
2726
}
2827
connect() {
29-
console.log('connecting', this.port)
3028
return new Promise((resolve, reject) => {
3129
this.connectionResolver = resolve
3230
this.connectionRejecter = reject
@@ -38,7 +36,6 @@ class Port {
3836
}
3937
onPortAdded = (_, addedPort) => {
4038
if (addedPort === this.port) {
41-
console.log('lisetning for messages')
4239
ipcRenderer.on('message', this.onMessage)
4340
this.connector.sendMessage(this.port, 'ping')
4441
}
@@ -51,7 +48,6 @@ class Port {
5148
}
5249
}
5350
onMessage = (_, message) => {
54-
console.log('got message', message)
5551
if (message.port !== this.port) {
5652
return
5753
}
Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,53 @@
11
import { Action } from './'
2-
import { Tab } from './state'
32
import * as mutations from './mutations'
43
import * as helpers from './helpers'
4+
import { Message } from './state'
55

66
export default (action: Action) => {
7-
const onMessage = action<any>().mutation(mutations.addMessageFromClient)
7+
const onMessage = action<Message>()
8+
.mutation(mutations.addMessagesFromClient)
9+
.mutation(mutations.performMutationsByMessageType)
10+
11+
const loadDevtools = action()
12+
// .do((_, { storage }) => storage.clear())
13+
.map(helpers.getAppsFromStorage)
14+
.mutation(mutations.setApps)
15+
.map(helpers.getCurrentPortFromStorage)
16+
.mutation(mutations.setCurrentPort)
17+
.mutation(mutations.setAppLoaded)
18+
.map(helpers.connectCurrentPort(onMessage))
19+
20+
const setError = action<string>().mutation(mutations.setError)
21+
22+
const changeNewPortValue = action<string>()
23+
.map(helpers.toNumber)
24+
.mutation(mutations.setNewPortValue)
25+
26+
const addPort = action()
27+
.map(helpers.getNewPortFromState)
28+
.mutation(mutations.setCurrentPort)
29+
.mutation(mutations.addNewApp)
30+
.mutation(mutations.resetNewPortValue)
31+
.do(helpers.storeApps)
32+
33+
const openState = action().mutation(mutations.openState)
34+
35+
const openConsole = action().mutation(mutations.openConsole)
36+
37+
const openApp = action<string>()
38+
39+
const toggleExpandState = action<string[]>().mutation(
40+
mutations.toggleExpandStatePath
41+
)
842

943
return {
10-
loadDevtools: action()
11-
.map(helpers.getAppsFromStorage)
12-
.mutation(mutations.setApps)
13-
.map(helpers.getCurrentPortFromStorage)
14-
.mutation(mutations.setCurrentPort)
15-
.mutation(mutations.setAppLoaded)
16-
.map(helpers.connectCurrentPort(onMessage)),
17-
setError: action<string>().mutation(mutations.setError),
18-
changeNewPortValue: action<string>()
19-
.map(helpers.toNumber)
20-
.mutation(mutations.setNewPortValue),
21-
addPort: action()
22-
.map(helpers.getNewPortFromState)
23-
.mutation(mutations.setCurrentPort)
24-
.mutation(mutations.addNewApp)
25-
.mutation(mutations.resetNewPortValue)
26-
.do(helpers.storeApps),
27-
changeTab: action<Tab>().mutation(mutations.changeTab),
28-
openApp: action<string>(),
44+
loadDevtools,
45+
setError,
46+
changeNewPortValue,
47+
addPort,
48+
openState,
49+
openConsole,
50+
openApp,
51+
toggleExpandState,
2952
}
3053
}

packages/node_modules/overmind-devtools/src/client/app/mutations.ts

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Apps, State, Message, Tab } from './state'
2+
import { runMutation } from './utils'
23

34
export const setApps = (apps: Apps, state: State) => (state.apps = apps || {})
45

@@ -22,14 +23,48 @@ export const addNewApp = (_, state: State) =>
2223
name: null,
2324
port: state.newPortValue,
2425
messages: [],
26+
state: {},
2527
})
2628

2729
export const resetNewPortValue = (_, state: State) => (state.newPortValue = '')
2830

29-
export const addMessageFromClient = (message: Message, state: State) => {
31+
export const addMessagesFromClient = (message: Message, state: State) => {
3032
state.apps[message.port].messages = state.apps[message.port].messages.concat(
3133
message.message
3234
)
3335
}
3436

35-
export const changeTab = (tab: Tab, state: State) => (state.currentTab = tab)
37+
export const openState = (_, state: State) => (state.currentTab = Tab.State)
38+
39+
export const openConsole = (_, state: State) => (state.currentTab = Tab.Console)
40+
41+
export const toggleExpandStatePath = (path: string[], state: State) => {
42+
const pathString = path.join('.')
43+
44+
if (state.expandedStatePaths.indexOf(pathString) >= 0) {
45+
state.expandedStatePaths.splice(
46+
state.expandedStatePaths.indexOf(pathString),
47+
1
48+
)
49+
} else {
50+
state.expandedStatePaths.push(pathString)
51+
}
52+
}
53+
54+
export const performMutationsByMessageType = (
55+
message: Message,
56+
state: State
57+
) => {
58+
message.message.forEach((clientMessage) => {
59+
switch (clientMessage.type) {
60+
case 'init':
61+
state.apps[message.port].state = clientMessage.data.state
62+
break
63+
case 'flush':
64+
clientMessage.data.mutations.forEach(
65+
runMutation(state.apps[message.port].state)
66+
)
67+
break
68+
}
69+
})
70+
}

packages/node_modules/overmind-devtools/src/client/app/state.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export type App = {
22
name: string
33
port: string
44
messages: AppMessage[]
5+
state: object
56
}
67

78
export type Apps = {
@@ -10,7 +11,7 @@ export type Apps = {
1011

1112
export type AppMessage = {
1213
type: string
13-
data: object
14+
data: any
1415
}
1516

1617
export type Message = {
@@ -31,6 +32,7 @@ export type State = {
3132
apps: Apps
3233
newPortValue: string
3334
currentTab: Tab
35+
expandedStatePaths: string[]
3436
}
3537

3638
const state: State = {
@@ -41,6 +43,7 @@ const state: State = {
4143
apps: {},
4244
newPortValue: '',
4345
currentTab: Tab.State,
46+
expandedStatePaths: [''],
4447
}
4548

4649
export default state
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export const runMutation = (state) => (mutation) => {
2+
const pathArray = mutation.path.split('.')
3+
const key = pathArray.pop()
4+
const target = pathArray.reduce((current, pathKey) => current[pathKey], state)
5+
6+
switch (mutation.method) {
7+
case 'set':
8+
target[key] = mutation.args[0]
9+
break
10+
case 'unset':
11+
delete target[key]
12+
break
13+
default:
14+
target[key][mutation.method](...mutation.args)
15+
}
16+
}

packages/node_modules/overmind-devtools/src/client/components/Inspector/index.tsx

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import * as React from 'react'
22
import { isObject, isArray } from './utils'
3+
import { connect } from '../../app'
4+
35
import {
46
Wrapper,
57
Key,
@@ -21,7 +23,7 @@ type NestedProps = {
2123
onToggleExpand: (path: string[]) => void
2224
}
2325

24-
class Nested extends React.PureComponent<NestedProps> {
26+
class Nested extends React.Component<NestedProps> {
2527
hasMounted: boolean = false
2628
componentDidMount() {
2729
this.hasMounted = true
@@ -68,12 +70,14 @@ class Nested extends React.PureComponent<NestedProps> {
6870
}
6971
}
7072

73+
const ConnectedNested = connect(Nested)
74+
7175
type ValueComponentProps = {
7276
value: string | number | boolean
7377
path: string[]
7478
}
7579

76-
class ValueComponent extends React.PureComponent<ValueComponentProps> {
80+
class ValueComponent extends React.Component<ValueComponentProps> {
7781
render() {
7882
if (typeof this.props.value === 'string') {
7983
return (
@@ -99,11 +103,11 @@ type InspectorProps = {
99103
onToggleExpand: (path: string[]) => void
100104
}
101105

102-
class Inspector extends React.PureComponent<InspectorProps> {
106+
class Inspector extends React.Component<InspectorProps> {
103107
renderValue(path: string[], value: any) {
104108
if (isObject(value)) {
105109
return (
106-
<Nested
110+
<ConnectedNested
107111
key={path.join('.')}
108112
startBracket="{"
109113
endBracket="}"
@@ -118,11 +122,11 @@ class Inspector extends React.PureComponent<InspectorProps> {
118122
this.renderValue(path.concat(key), value[key])
119123
)
120124
}
121-
</Nested>
125+
</ConnectedNested>
122126
)
123127
} else if (isArray(value)) {
124128
return (
125-
<Nested
129+
<ConnectedNested
126130
key={path.join('.')}
127131
startBracket="["
128132
endBracket="]"
@@ -133,11 +137,11 @@ class Inspector extends React.PureComponent<InspectorProps> {
133137
isArray
134138
>
135139
{() =>
136-
value.map((key, index) =>
140+
value.map((_, index) =>
137141
this.renderValue(path.concat(index), value[index])
138142
)
139143
}
140-
</Nested>
144+
</ConnectedNested>
141145
)
142146
}
143147

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import styled from '../../styled-components'
2+
3+
export const Wrapper = styled.div`
4+
padding: ${({ theme }) => theme.padding.normal};
5+
`
Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
import * as React from 'react'
22
import { connect, Connect } from '../../app'
3+
import { Wrapper } from './elements'
4+
import Inspector from '../Inspector'
35

4-
const State: React.SFC<Connect> = () => <h1>state</h1>
6+
const State: React.SFC<Connect> = ({ appState, actions }) => (
7+
<Wrapper>
8+
<Inspector
9+
value={appState.apps[appState.currentPort].state}
10+
expandedPaths={appState.expandedStatePaths}
11+
onToggleExpand={actions.toggleExpandState}
12+
/>
13+
</Wrapper>
14+
)
515

616
export default connect(State)

packages/node_modules/overmind-devtools/src/client/components/Tabs/index.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,18 @@ import { connect, Connect } from '../../app'
44
import Icon from '../common/Icon'
55
import { Tab } from '../../app/state'
66

7-
const Tabs: React.SFC<Connect> = ({ actions }) => (
7+
const Tabs: React.SFC<Connect> = ({ appState, actions }) => (
88
<Wrapper>
9-
<Button active>
9+
<Button
10+
active={appState.currentTab === Tab.State}
11+
onClick={actions.openState}
12+
>
1013
<Icon>database</Icon>
1114
</Button>
12-
<Button active={false}>
15+
<Button
16+
active={appState.currentTab === Tab.Console}
17+
onClick={actions.openConsole}
18+
>
1319
<Icon>terminal</Icon>
1420
</Button>
1521
</Wrapper>

packages/node_modules/overmind-devtools/webpack.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ module.exports = {
3131
],
3232
},
3333
resolve: {
34-
extensions: ['.tsx', '.ts', '.js'],
34+
extensions: ['.js', '.tsx', '.ts'],
3535
},
3636
plugins: [new HtmlWebpackPlugin()],
3737
}

0 commit comments

Comments
 (0)