Skip to content

Commit 36f69cd

Browse files
committed
Fix extend/collapse actions
1 parent f1fbf10 commit 36f69cd

13 files changed

Lines changed: 200 additions & 98 deletions

dist/hyperapp-devtools.js

Lines changed: 76 additions & 45 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/hyperapp-devtools.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/src/api.d.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,16 @@ export interface RuntimeEvent {
3535
}
3636
export declare type PaneDisplay = "fullscreen" | "right" | "bottom";
3737
export declare type ValueDisplay = "state" | "result" | "data" | "debugger-state";
38+
export interface SelectedAction {
39+
run: string;
40+
path: number[];
41+
}
3842
export interface State {
3943
runs: Runs;
4044
logs: RuntimeEvent[];
4145
paneShown: boolean;
4246
paneDisplay: PaneDisplay;
43-
selectedAction: AppAction | null;
47+
selectedAction: SelectedAction | null;
4448
collapseRepeatingActions: boolean;
4549
valueDisplay: ValueDisplay;
4650
}
@@ -52,7 +56,7 @@ export interface Actions {
5256
log(event: RuntimeEvent): any;
5357
logInit(event: InitEvent): any;
5458
logAction(event: ActionEvent): any;
55-
select(action: AppAction | null): any;
59+
select(action: SelectedAction | null): any;
5660
showPane(shown: boolean): any;
5761
setPaneDisplay(paneDisplay: PaneDisplay): any;
5862
setValueDisplay(valueDisplay: ValueDisplay): any;

dist/src/components/RunsPaneItem.d.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,5 @@ export interface RunsPaneItemProps {
55
actions: Actions;
66
run: Run;
77
current: boolean;
8-
path: any[];
98
}
109
export declare function RunsPaneItem(props: RunsPaneItemProps): JSX.Element;

dist/src/selectors.d.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
1-
import { State, Run } from "./api";
1+
import { State, Run, AppAction } from "./api";
2+
import { Path } from "./immutable";
23
export declare function getRuns(state: State): Run[];
4+
export declare function getSelectedAction(state: State): AppAction | null;
5+
export declare function getPath(run: string, path: number[]): Path;
6+
export declare function isSelectedAction(state: State, run: string, path: number[]): boolean;

src/actions.ts

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { ActionsType } from "hyperapp"
22
import { get, merge, set } from "./immutable"
3+
import { getPath } from "./selectors"
34

45
import * as api from "./api"
56

@@ -79,23 +80,22 @@ function appendActionEvent(
7980
}
8081

8182
function toggleAction(
82-
runs: api.Runs,
83-
runId: string,
83+
state: api.State,
84+
run: string,
8485
actionPath: number[]
85-
): api.Runs {
86-
const path: any[] = [runId]
87-
actionPath.forEach(index => {
88-
path.push("actions", index)
89-
})
90-
path.push("collapsed")
91-
92-
const collapsed = get(runs, path)
93-
if (typeof collapsed !== "boolean") {
86+
): Partial<api.State> {
87+
const path = getPath(run, actionPath)
88+
89+
const existingAction = get(state.runs, path)
90+
if (typeof existingAction !== "object") {
9491
console.log("WARN: try to collapse invalid action, path: ", actionPath)
95-
return runs
92+
return state
9693
}
9794

98-
return set(runs, path, !collapsed)
95+
const collapsed = !existingAction.collapsed
96+
const action = { ...existingAction, collapsed }
97+
const runs: api.Runs = set(state.runs, path, action)
98+
return { runs }
9999
}
100100

101101
export const INITIAL_ACTION = "%%% INITIAL STATE %%%"
@@ -123,19 +123,18 @@ export const actions: ActionsType<api.State, api.Actions> = {
123123
collapsed: false
124124
}
125125

126-
return { runs, selectedAction: action }
126+
return { runs, selectedAction: { run: event.runId, path: [0] } }
127127
},
128128
logAction: (event: api.ActionEvent) => state => {
129129
const runs = { ...state.runs }
130130
const run = runs[event.runId]
131131
const actions = [...run.actions]
132132
run.actions = actions
133133
const prevAction = actions.pop()
134-
let selectedAction: api.AppAction
135134
if (prevAction.done) {
136135
// previous action done: create new action and append
137136
if (!event.callDone) {
138-
selectedAction = {
137+
const action = {
139138
done: false,
140139
collapsed: false,
141140
actions: [],
@@ -144,15 +143,20 @@ export const actions: ActionsType<api.State, api.Actions> = {
144143
previousState: prevAction.nextState
145144
}
146145

147-
actions.push(prevAction, selectedAction)
146+
actions.push(prevAction, action)
148147
} else {
149148
// error!, should we log it here?
150149
console.log("Previous action is done and event.callDone", state, event)
151150
}
152151
} else {
153152
// previous action not done: find parent action, create and append
154-
selectedAction = appendActionEvent(prevAction, event)
155-
actions.push(selectedAction)
153+
const action = appendActionEvent(prevAction, event)
154+
actions.push(action)
155+
}
156+
157+
const selectedAction = {
158+
run: event.runId,
159+
path: [actions.length - 1]
156160
}
157161

158162
return { runs, selectedAction }
@@ -164,10 +168,9 @@ export const actions: ActionsType<api.State, api.Actions> = {
164168
},
165169
toggleAction: (payload: api.ToggleActionPayload) => state => {
166170
const { run, path } = payload
167-
const runs = toggleAction(state.runs, run, path)
168-
return { runs }
171+
return toggleAction(state, run, path)
169172
},
170-
select: (selectedAction: api.AppAction | null) => {
173+
select: (selectedAction: api.SelectedAction | null) => {
171174
return { selectedAction }
172175
},
173176
showPane: (paneShown: boolean) => {

src/api.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,17 @@ export type PaneDisplay = "fullscreen" | "right" | "bottom"
4444

4545
export type ValueDisplay = "state" | "result" | "data" | "debugger-state"
4646

47+
export interface SelectedAction {
48+
run: string
49+
path: number[]
50+
}
51+
4752
export interface State {
4853
runs: Runs
4954
logs: RuntimeEvent[]
5055
paneShown: boolean
5156
paneDisplay: PaneDisplay
52-
selectedAction: AppAction | null
57+
selectedAction: SelectedAction | null
5358
collapseRepeatingActions: boolean
5459
valueDisplay: ValueDisplay
5560
}
@@ -65,7 +70,7 @@ export interface Actions {
6570
log(event: RuntimeEvent)
6671
logInit(event: InitEvent)
6772
logAction(event: ActionEvent)
68-
select(action: AppAction | null)
73+
select(action: SelectedAction | null)
6974
showPane(shown: boolean)
7075
setPaneDisplay(paneDisplay: PaneDisplay)
7176
setValueDisplay(valueDisplay: ValueDisplay)

src/components/ObjectDetailsPane.tsx

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,51 +2,53 @@ import { h } from "hyperapp"
22

33
import "./ObjectDetailsPane.scss"
44

5-
import { State, Actions, Run } from "../api"
5+
import { State, Actions, Run, AppAction } from "../api"
6+
import { getSelectedAction } from "../selectors";
67

7-
export interface ObjectDetailsPaneProps {
8+
interface PaneProps {
89
state: State
910
actions: Actions
11+
action: AppAction
1012
}
1113

12-
function PaneData(props: ObjectDetailsPaneProps) {
13-
const { state, actions } = props
14+
function PaneData(props: PaneProps) {
15+
const { action } = props
1416

1517
return (
1618
<div class="object-details-pane scrollable">
1719
<pre class="scrollable-content">
18-
{JSON.stringify(state.selectedAction.actionData, null, 2)}
20+
{JSON.stringify(action.actionData, null, 2)}
1921
</pre>
2022
</div>
2123
)
2224
}
2325

24-
function PaneResult(props: ObjectDetailsPaneProps) {
25-
const { state, actions } = props
26+
function PaneResult(props: PaneProps) {
27+
const { action } = props
2628

2729
return (
2830
<div class="object-details-pane scrollable">
2931
<pre class="scrollable-content">
30-
{JSON.stringify(state.selectedAction.actionResult, null, 2)}
32+
{JSON.stringify(action.actionResult, null, 2)}
3133
</pre>
3234
</div>
3335
)
3436
}
3537

36-
function PaneState(props: ObjectDetailsPaneProps) {
37-
const { state, actions } = props
38+
function PaneState(props: PaneProps) {
39+
const { action } = props
3840

3941
return (
4042
<div class="object-details-pane scrollable">
4143
<pre class="scrollable-content">
42-
{JSON.stringify(state.selectedAction.nextState, null, 2)}
44+
{JSON.stringify(action.nextState, null, 2)}
4345
</pre>
4446
</div>
4547
)
4648
}
4749

48-
function PaneDebuggerState(props: ObjectDetailsPaneProps) {
49-
const { state, actions } = props
50+
function PaneDebuggerState(props: PaneProps) {
51+
const { state } = props
5052

5153
return (
5254
<div class="object-details-pane scrollable">
@@ -55,15 +57,22 @@ function PaneDebuggerState(props: ObjectDetailsPaneProps) {
5557
)
5658
}
5759

60+
export interface ObjectDetailsPaneProps {
61+
state: State
62+
actions: Actions
63+
}
64+
5865
export function ObjectDetailsPane(props: ObjectDetailsPaneProps) {
66+
const { state, actions } = props
67+
const action = getSelectedAction(props.state)
5968
switch (props.state.valueDisplay) {
6069
case "data":
61-
return PaneData(props)
70+
return PaneData({ state, actions, action })
6271
case "result":
63-
return PaneResult(props)
72+
return PaneResult({ state, actions, action })
6473
case "state":
65-
return PaneState(props)
74+
return PaneState({ state, actions, action })
6675
case "debugger-state":
67-
return PaneDebuggerState(props)
76+
return PaneDebuggerState({ state, actions, action })
6877
}
6978
}

src/components/RunActionItem.scss

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,22 @@
1414

1515
&:hover {
1616
background-color: $secondary-color;
17+
text-decoration: none;
1718
color: black;
1819
}
1920

21+
&:focus {
22+
text-decoration: none;
23+
}
24+
2025
&.selected {
2126
background-color: $secondary-color-dark;
2227
font-weight: bold;
2328
color: black;
2429
}
2530
}
31+
32+
.icon:hover {
33+
color: $primary-color;
34+
}
2635
}

src/components/RunActionItem.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { State, Actions, AppAction, Run } from "../api"
66
import { INITIAL_ACTION } from "../actions"
77

88
import { RunActionItemList } from "./RunActionItemList"
9+
import { isSelectedAction } from "../selectors";
910

1011
// # Helpers
1112

@@ -57,6 +58,7 @@ function ToggleActionItem(props: ToggleActionItemProps) {
5758
}
5859

5960
const onclick = (e: Event) => {
61+
event.stopPropagation()
6062
event.preventDefault()
6163
actions.toggleAction({ run: run.id, path })
6264
}
@@ -81,14 +83,14 @@ interface ActionItemLinkProps {
8183
}
8284

8385
function ActionItemLink(props: ActionItemLinkProps) {
84-
const { state, actions, actionList, indexInList, action } = props
86+
const { state, actions, run, actionList, indexInList, action, path } = props
8587

86-
const selected = state.selectedAction === action
88+
const selected = isSelectedAction(state, run.id, path)
8789
const className = "item-link" + (selected ? " selected" : "")
8890

8991
const onclick = (e: Event) => {
9092
e.preventDefault()
91-
actions.select(action)
93+
actions.select({ run: run.id, path })
9294
}
9395

9496
const displayName =

0 commit comments

Comments
 (0)