Skip to content

Commit f08f3e1

Browse files
committed
Update devtool support
1 parent 957eff8 commit f08f3e1

File tree

4 files changed

+65
-46
lines changed

4 files changed

+65
-46
lines changed

.vscode/settings.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"editor.defaultFormatter": "esbenp.prettier-vscode",
33
"editor.codeActionsOnSave": {
4-
"source.fixAll.eslint": true,
5-
"source.organizeImports": true
4+
"source.fixAll.eslint": "explicit",
5+
"source.organizeImports": "explicit"
66
},
77
"eslint.validate": ["typescript"],
88
"editor.formatOnSave": true

lib/src/dev-tools/state-dev-tools.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,15 +86,15 @@ export class StateDevTools {
8686
map(state => JSON.parse(state)),
8787
mergeMap(state => from(Object.entries(state))),
8888
map(([storeName, state]) => ({
89-
storeName,
89+
storeName: storeName.match(/^\[(.*)\]/)?.[1] ?? storeName,
9090
state,
9191
})),
9292
withLatestFrom(this.storeRegistry.stores$),
9393
tap(([{ state, storeName }, store]) => {
9494
if (state) {
9595
// Temporarily save reference in history
9696
this.stateHistory.push(state);
97-
store[storeName]?.update(() => state);
97+
store[storeName]?.update(() => state, storeName);
9898
}
9999
})
100100
);
@@ -111,8 +111,9 @@ export class StateDevTools {
111111
mergeMap(key =>
112112
stores[key].state$.pipe(
113113
filter(this.isStateUnprocessed.bind(this)),
114-
map(state => {
115-
return { name: key, state: state };
114+
withLatestFrom(stores[key].actions$),
115+
map(([state, action]) => {
116+
return { name: `[${key}] ${action.title}`, state: state };
116117
})
117118
)
118119
)

lib/src/store/store.ts

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,30 @@ import {
1111
import { distinctUntilObjectChanged } from '../utils/distinctUntilObjectChanged';
1212
import { StoreRegistry } from './store-registry';
1313

14-
type Action<State extends object> = (state: State) => State;
14+
type Action<State extends object> = {
15+
reducer: (state: State) => State;
16+
title: string;
17+
};
1518

1619
export abstract class Store<State extends object> {
17-
private readonly actionSource: Subject<Action<State>>;
1820
private readonly stateSource: BehaviorSubject<State>;
1921
private readonly registryService = inject(StoreRegistry);
2022

2123
readonly state$: Observable<State>;
24+
readonly actions$: Subject<Action<State>>;
2225

2326
constructor(
2427
private name: string,
2528
initialState: State
2629
) {
2730
this.stateSource = new BehaviorSubject<State>(initialState);
2831
this.state$ = this.stateSource.asObservable();
29-
this.actionSource = new Subject<Action<State>>();
32+
this.actions$ = new Subject<Action<State>>();
3033
this.registryService.addStore(name, this as unknown as Store<object>);
3134

32-
this.actionSource.pipe(observeOn(queueScheduler)).subscribe(action => {
35+
this.actions$.pipe(observeOn(queueScheduler)).subscribe(action => {
3336
const currentState = this.stateSource.getValue();
34-
const nextState = action(currentState);
37+
const nextState = action.reducer(currentState);
3538
this.stateSource.next(nextState);
3639
});
3740
}
@@ -58,19 +61,22 @@ export abstract class Store<State extends object> {
5861
return this.stateSource.getValue();
5962
}
6063

61-
updateProperty(prop: keyof State, value: State[typeof prop]) {
62-
this.update(state => ({
63-
...state,
64-
[prop]: value,
65-
}));
64+
updateProperty(prop: keyof State, value: State[typeof prop], title: string) {
65+
this.update(
66+
state => ({
67+
...state,
68+
[prop]: value,
69+
}),
70+
title
71+
);
6672
}
6773

68-
update(stateChanger: (state: State) => State) {
69-
this.actionSource.next(stateChanger);
74+
update(stateChanger: (state: State) => State, title: string) {
75+
this.actions$.next({ reducer: stateChanger, title });
7076
}
7177

7278
destroy() {
73-
this.actionSource.complete();
79+
this.actions$.complete();
7480
this.stateSource.complete();
7581
this.registryService.deleteStore(this.name);
7682
}

playground/app/todo-store.service.ts

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,43 +15,55 @@ export class TodoStoreService extends Store<TodoStoreState> {
1515
}
1616

1717
addTodo(description: string) {
18-
this.update(state => ({
19-
...state,
20-
todos: [
21-
...state.todos,
22-
{ description, completed: false, id: String(state.todos.length) },
23-
],
24-
}));
18+
this.update(
19+
state => ({
20+
...state,
21+
todos: [
22+
...state.todos,
23+
{ description, completed: false, id: String(state.todos.length) },
24+
],
25+
}),
26+
'add todo'
27+
);
2528
}
2629

2730
removeTodo(todo: Todo) {
28-
this.update(state => ({
29-
...state,
30-
todos: state.todos.filter(t => t.id !== todo.id),
31-
}));
31+
this.update(
32+
state => ({
33+
...state,
34+
todos: state.todos.filter(t => t.id !== todo.id),
35+
}),
36+
'remove todo'
37+
);
3238
}
3339

3440
completeTodo(todo: Todo) {
35-
this.update(state => ({
36-
...state,
37-
todos: state.todos.map(t => {
38-
if (t.id === todo.id) {
39-
t.completed = true;
40-
}
41-
return t;
41+
this.update(
42+
state => ({
43+
...state,
44+
todos: state.todos.map(t => {
45+
if (t.id === todo.id) {
46+
t.completed = true;
47+
}
48+
return t;
49+
}),
4250
}),
43-
}));
51+
'complete todo'
52+
);
4453
}
4554

4655
uncompleteTodo(todo: Todo) {
47-
this.update(state => ({
48-
...state,
49-
todos: state.todos.map(t => {
50-
if (t.id === todo.id) {
51-
t.completed = false;
52-
}
53-
return t;
56+
this.update(
57+
state => ({
58+
...state,
59+
todos: state.todos.map(t => {
60+
if (t.id === todo.id) {
61+
t.completed = false;
62+
}
63+
return t;
64+
}),
5465
}),
55-
}));
66+
'uncomplete todo'
67+
);
5668
}
5769
}

0 commit comments

Comments
 (0)