@powerhousedao/academy 5.1.0-staging.0 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +46 -1148
- package/blog/BeyondCommunication-ABlueprintForDevelopment.md +1 -2
- package/blog/TheChallengeOfChange.md +0 -1
- package/docs/academy/00-EthereumArgentinaHackathon.md +207 -0
- package/docs/academy/01-GetStarted/00-ExploreDemoPackage.mdx +27 -24
- package/docs/academy/01-GetStarted/01-CreateNewPowerhouseProject.md +10 -155
- package/docs/academy/01-GetStarted/02-DefineToDoListDocumentModel.md +35 -122
- package/docs/academy/01-GetStarted/03-ImplementOperationReducers.md +155 -178
- package/docs/academy/01-GetStarted/04-BuildToDoListEditor.md +218 -0
- package/docs/academy/{02-MasteryTrack/01-BuilderEnvironment → 01-GetStarted}/05-VetraStudio.md +22 -62
- package/docs/academy/01-GetStarted/06-ReactorMCP.md +58 -0
- package/docs/academy/01-GetStarted/_04-BuildToDoListEditor +1 -1
- package/docs/academy/02-MasteryTrack/01-BuilderEnvironment/03-BuilderTools.md +2 -2
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/02-SpecifyTheStateSchema.md +44 -75
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/03-SpecifyDocumentOperations.md +22 -28
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/04-UseTheDocumentModelGenerator.md +31 -28
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/05-ImplementDocumentReducers.md +206 -211
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/06-ImplementDocumentModelTests.md +62 -176
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/07-ExampleToDoListRepository.md +0 -21
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/01-BuildingDocumentEditors.md +319 -309
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/06-DocumentTools/00-DocumentToolbar.mdx +0 -4
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/06-DocumentTools/01-OperationHistory.md +0 -4
- package/docs/academy/02-MasteryTrack/05-Launch/04-ConfigureEnvironment.md +1 -1
- package/docs/academy/03-ExampleUsecases/Chatroom/02-CreateNewPowerhouseProject.md +35 -111
- package/docs/academy/03-ExampleUsecases/Chatroom/03-DefineChatroomDocumentModel.md +79 -195
- package/docs/academy/03-ExampleUsecases/Chatroom/04-ImplementOperationReducers.md +241 -435
- package/docs/academy/03-ExampleUsecases/Chatroom/05-ImplementChatroomEditor.md +27 -388
- package/docs/academy/03-ExampleUsecases/Chatroom/06-LaunchALocalReactor.md +7 -95
- package/docs/academy/03-ExampleUsecases/Chatroom/_category_.json +1 -1
- package/docs/academy/04-APIReferences/00-PowerhouseCLI.md +2 -6
- package/docs/academy/04-APIReferences/01-ReactHooks.md +501 -291
- package/docs/academy/05-Architecture/00-PowerhouseArchitecture.md +39 -7
- package/docs/academy/05-Architecture/02-ReferencingMonorepoPackages +65 -0
- package/docs/academy/05-Architecture/04-MovingBeyondCRUD +61 -0
- package/docs/academy/06-ComponentLibrary/00-DocumentEngineering.md +24 -72
- package/docs/academy/08-Glossary.md +0 -7
- package/docusaurus.config.ts +3 -28
- package/package.json +1 -1
- package/sidebars.ts +13 -49
- package/src/css/custom.css +18 -26
- package/docs/academy/01-GetStarted/04-WriteDocumentModelTests.md +0 -425
- package/docs/academy/01-GetStarted/05-BuildToDoListEditor.md +0 -557
- package/docs/academy/02-MasteryTrack/01-BuilderEnvironment/images/Modules.png +0 -0
- package/docs/academy/02-MasteryTrack/01-BuilderEnvironment/images/VetraStudioDrive.png +0 -0
- package/docs/academy/02-MasteryTrack/05-Launch/05-DockerDeployment.md +0 -384
- package/docs/academy/03-ExampleUsecases/TodoList/00-GetTheStarterCode.md +0 -24
- package/docs/academy/03-ExampleUsecases/TodoList/01-GenerateTodoListDocumentModel.md +0 -211
- package/docs/academy/03-ExampleUsecases/TodoList/02-ImplementTodoListDocumentModelReducerOperationHandlers.md +0 -171
- package/docs/academy/03-ExampleUsecases/TodoList/03-AddTestsForTodoListActions.md +0 -462
- package/docs/academy/03-ExampleUsecases/TodoList/04-GenerateTodoListDocumentEditor.md +0 -45
- package/docs/academy/03-ExampleUsecases/TodoList/05-ImplementTodoListDocumentEditorUIComponents.md +0 -422
- package/docs/academy/03-ExampleUsecases/TodoList/06-GenerateTodoDriveExplorer.md +0 -61
- package/docs/academy/03-ExampleUsecases/TodoList/07-AddSharedComponentForShowingTodoListStats.md +0 -384
- package/docs/academy/03-ExampleUsecases/TodoList/_category_.json +0 -8
- package/docs/academy/03-ExampleUsecases/VetraPackageLibrary/VetraPackageLibrary.md +0 -7
- package/docs/academy/03-ExampleUsecases/VetraPackageLibrary/_category_.json +0 -9
- package/docs/academy/04-APIReferences/06-VetraRemoteDrive.md +0 -160
- package/docs/academy/04-APIReferences/renown-sdk/00-Overview.md +0 -316
- package/docs/academy/04-APIReferences/renown-sdk/01-Authentication.md +0 -672
- package/docs/academy/04-APIReferences/renown-sdk/02-APIReference.md +0 -957
- package/docs/academy/04-APIReferences/renown-sdk/_category_.json +0 -8
- package/docs/academy/10-TodoListTutorial/02-ImplementTodoListDocumentModelReducerOperationHandlers.md +0 -171
- package/docs/academy/10-TodoListTutorial/03-AddTestsForTodoListActions.md +0 -462
- package/docs/academy/10-TodoListTutorial/05-ImplementTodoListDocumentEditorUIComponents.md +0 -422
- package/docs/academy/10-TodoListTutorial/07-AddSharedComponentForShowingTodoListStats.md +0 -370
- package/static/img/Vetra-logo-dark.svg +0 -11
- package/static/img/vetra-logo-light.svg +0 -11
- /package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/06-DocumentTools/{02-RevisionHistoryTimeline/360/237/232/247" → 02-RevisionHistoryTimeline} +0 -0
- /package/docs/academy/05-Architecture/05-DocumentModelTheory/{360/237/232/247 /01-WhatIsADocumentModel" → 01-WhatIsADocumentModel} +0 -0
- /package/docs/academy/05-Architecture/05-DocumentModelTheory/{360/237/232/247 /02-DAOandDocumentsModelsQ+A" → 02-DAOandDocumentsModelsQ+A} +0 -0
- /package/docs/academy/05-Architecture/05-DocumentModelTheory/{360/237/232/247 /02-domain-modeling" → 02-domain-modeling} +0 -0
- /package/docs/academy/05-Architecture/05-DocumentModelTheory/{360/237/232/247 /03-BenefitsOfDocumentModels" → 03-BenefitsOfDocumentModels} +0 -0
- /package/docs/academy/05-Architecture/05-DocumentModelTheory/{360/237/232/247 /04-UtilitiesAndTips" → 04-UtilitiesAndTips} +0 -0
- /package/docs/academy/05-Architecture/05-DocumentModelTheory/{360/237/232/247 /05-best-practices" → 05-best-practices} +0 -0
- /package/docs/academy/05-Architecture/05-DocumentModelTheory/{360/237/232/247 /_category_.json" → _category_.json} +0 -0
- /package/docs/academy/05-Architecture/05-DocumentModelTheory/{360/237/232/247 /three-data-layers.png" → three-data-layers.png} +0 -0
|
@@ -1,64 +1,15 @@
|
|
|
1
1
|
# Write the document specification
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
📦 **Reference Code**: [step-2-generate-todo-list-document-model](https://github.com/powerhouse-inc/todo-tutorial/tree/step-2-generate-todo-list-document-model)
|
|
5
|
-
|
|
6
|
-
This tutorial step has a corresponding branch. After completing this step, your project will have a generated document model with:
|
|
7
|
-
- Document model specification files (`todo-list.json`, `schema.graphql`)
|
|
8
|
-
- Auto-generated TypeScript types and action creators
|
|
9
|
-
- Reducer scaffolding ready for implementation
|
|
10
|
-
:::
|
|
11
|
-
|
|
12
|
-
<details>
|
|
13
|
-
<summary>📖 How to use this tutorial</summary>
|
|
14
|
-
|
|
15
|
-
**Prerequisites**: Complete step 1 and set up the tutorial remote (see previous step).
|
|
16
|
-
|
|
17
|
-
### Compare your generated code
|
|
18
|
-
|
|
19
|
-
After running `ph generate TodoList.phdm.zip`, compare with the reference:
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
# Compare all generated files with step-2
|
|
23
|
-
git diff tutorial/step-2-generate-todo-list-document-model
|
|
24
|
-
|
|
25
|
-
# Compare specific directory
|
|
26
|
-
git diff tutorial/step-2-generate-todo-list-document-model -- document-models/todo-list/
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
### See what was generated
|
|
30
|
-
|
|
31
|
-
View the complete step-2 reference code:
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
# List files in the tutorial's step-2
|
|
35
|
-
git ls-tree -r --name-only tutorial/step-2-generate-todo-list-document-model document-models/
|
|
36
|
-
|
|
37
|
-
# View a specific file from step-2
|
|
38
|
-
git show tutorial/step-2-generate-todo-list-document-model:document-models/todo-list/schema.graphql
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### Visual comparison with GitHub Desktop
|
|
42
|
-
|
|
43
|
-
After making a commit, use GitHub Desktop for visual diff:
|
|
44
|
-
1. **Branch** menu → **"Compare to Branch..."**
|
|
45
|
-
2. Select `tutorial/step-2-generate-todo-list-document-model`
|
|
46
|
-
3. Review all file differences in the visual interface
|
|
47
|
-
|
|
48
|
-
See step 1 for detailed GitHub Desktop instructions.
|
|
49
|
-
|
|
50
|
-
</details>
|
|
51
|
-
|
|
52
|
-
In this tutorial, you will learn how to define the specifications for a **To-do List** document model within Vetra Studio using its GraphQL schema, and then export the resulting document model specification document for your Powerhouse project.
|
|
3
|
+
In this tutorial, you will learn how to define the specifications for a **To-do List** document model within the Connect application using its GraphQL schema, and then export the resulting document model specification document for your Powerhouse project.
|
|
53
4
|
If you don't have a document specification file created yet, have a look at the previous step of this tutorial to create a new document specification.
|
|
54
5
|
|
|
55
|
-
Before you start, make sure you have
|
|
6
|
+
Before you start, make sure you have the Connect application running locally with the command:
|
|
56
7
|
|
|
57
8
|
```bash
|
|
58
|
-
ph
|
|
9
|
+
ph connect
|
|
59
10
|
```
|
|
60
11
|
|
|
61
|
-
|
|
12
|
+
The Connect application will start and you will see the following output:
|
|
62
13
|
|
|
63
14
|
```bash
|
|
64
15
|
➜ Local: http://localhost:3000/
|
|
@@ -66,13 +17,14 @@ Vetra Studio will start and you will see the following output:
|
|
|
66
17
|
➜ press h + enter to show help
|
|
67
18
|
```
|
|
68
19
|
|
|
69
|
-
##
|
|
20
|
+
## To-do list document specification
|
|
70
21
|
|
|
71
|
-
|
|
72
|
-
|
|
22
|
+
Likely you have called your project 'ToDoList'.
|
|
23
|
+
If you've used a different name, please create a new document specification named 'ToDoList'.
|
|
24
|
+
**Pay close attention to capitalization, as it influences our code.**
|
|
73
25
|
|
|
74
26
|
We'll continue with this project to teach you how to create a document model specification and later an editor for your document model. We use the **GraphQL Schema Definition Language** (SDL) to define the schema for the document model.
|
|
75
|
-
Below, you can see the SDL for the `
|
|
27
|
+
Below, you can see the SDL for the `To-do List` document model.
|
|
76
28
|
|
|
77
29
|
:::info
|
|
78
30
|
This schema defines the **data structure** of the document model and the types involved in its operations, which are detailed further as input types.
|
|
@@ -80,49 +32,48 @@ Documents in Powerhouse leverage **event sourcing principles**, where every stat
|
|
|
80
32
|
:::
|
|
81
33
|
|
|
82
34
|
<details>
|
|
83
|
-
<summary>State schema of our simplified
|
|
35
|
+
<summary>State schema of our simplified To-do list</summary>
|
|
84
36
|
|
|
85
37
|
```graphql
|
|
86
|
-
# The state of our
|
|
87
|
-
type
|
|
88
|
-
items: [
|
|
38
|
+
# The state of our ToDoList
|
|
39
|
+
type ToDoListState {
|
|
40
|
+
items: [ToDoItem!]!
|
|
89
41
|
}
|
|
90
42
|
|
|
91
|
-
# A single to-do item
|
|
92
|
-
type
|
|
93
|
-
id:
|
|
94
|
-
text: String!
|
|
95
|
-
checked: Boolean!
|
|
43
|
+
# A single to-do item
|
|
44
|
+
type ToDoItem {
|
|
45
|
+
id: ID!
|
|
46
|
+
text: String!
|
|
47
|
+
checked: Boolean!
|
|
96
48
|
}
|
|
97
49
|
```
|
|
98
50
|
|
|
99
51
|
</details>
|
|
100
52
|
|
|
101
53
|
<details>
|
|
102
|
-
<summary>Operations schema of our simplified
|
|
103
|
-
|
|
54
|
+
<summary>Operations schema of our simplified to-do list</summary>
|
|
104
55
|
```graphql
|
|
105
56
|
# Defines a GraphQL input type for adding a new to-do item
|
|
106
|
-
# Only text is required - ID is generated automatically, checked defaults to false
|
|
107
57
|
input AddTodoItemInput {
|
|
108
|
-
|
|
58
|
+
id: ID!
|
|
59
|
+
text: String!
|
|
109
60
|
}
|
|
110
61
|
|
|
111
62
|
# Defines a GraphQL input type for updating a to-do item
|
|
112
|
-
|
|
113
|
-
# text and checked are optional - only provided fields will be updated
|
|
63
|
+
|
|
114
64
|
input UpdateTodoItemInput {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
65
|
+
id: ID!
|
|
66
|
+
text: String
|
|
67
|
+
checked: Boolean
|
|
118
68
|
}
|
|
119
69
|
|
|
120
70
|
# Defines a GraphQL input type for deleting a to-do item
|
|
71
|
+
|
|
121
72
|
input DeleteTodoItemInput {
|
|
122
|
-
|
|
73
|
+
id: ID!
|
|
123
74
|
}
|
|
124
|
-
```
|
|
125
75
|
|
|
76
|
+
````
|
|
126
77
|
</details>
|
|
127
78
|
|
|
128
79
|
## Define the document model specification
|
|
@@ -131,21 +82,22 @@ To be able to define the document model, you need to open the document model edi
|
|
|
131
82
|
|
|
132
83
|
### The steps below show you how to do this:
|
|
133
84
|
|
|
134
|
-
1. In
|
|
135
|
-
2. Name your document model
|
|
85
|
+
1. In the Connect application, click on **'document model'** to open the document model specification editor.
|
|
86
|
+
2. Name your document model '**ToDoList**' in the Connect application, paying close attention to capitalization.
|
|
136
87
|
3. You'll be presented with a form to fill in metadata about the document model. Fill in the details in the respective fields.
|
|
137
88
|
|
|
138
|
-
In the **Document Type** field, type `powerhouse/
|
|
89
|
+
In the **Document Type** field, type `powerhouse/todolist`. This defines the new type of document that will be created with this document model specification.
|
|
139
90
|
|
|
140
|
-

|
|
141
92
|
|
|
142
93
|
4. In the code editor, you can see the SDL for the document model. Replace the existing SDL template with the SDL defined in the [State Schema](#state-schema) section. Only copy and paste the types, leaving the inputs for the next step. You can, however, already press the 'Sync with schema' button to set the initial state of your document model specification based on your Schema Definition Language.
|
|
143
|
-
5. Below the editor, find the input field `Add module`. You'll use this to create and name a module for organizing your input operations. In this case, we will name the module `
|
|
94
|
+
5. Below the editor, find the input field `Add module`. You'll use this to create and name a module for organizing your input operations. In this case, we will name the module `to_do_list`. Press enter.
|
|
144
95
|
6. Now there is a new field, called `Add operation`. Here you will have to add each input operation to the module, one by one.
|
|
145
96
|
7. Inside the `Add operation` field, type `ADD_TODO_ITEM` and press enter. A small editor will appear underneath it, with an empty input type that you have to fill. Copy the first input type from the [Operations Schema](#operations-schema) section and paste it in the editor. The editor should look like this:
|
|
146
97
|
|
|
147
98
|
```graphql
|
|
148
99
|
input AddTodoItemInput {
|
|
100
|
+
id: ID!
|
|
149
101
|
text: String!
|
|
150
102
|
}
|
|
151
103
|
```
|
|
@@ -158,46 +110,7 @@ Check below screenshot for the complete implementation:
|
|
|
158
110
|
|
|
159
111
|

|
|
160
112
|
|
|
161
|
-
## Verify your document model generation
|
|
162
|
-
|
|
163
|
-
If you have been watching the terminal in your IDE you will see that Vetra has been tracking your changes and scaffolding your directory. Your project should have the following structure in `document-models/todo-list/`:
|
|
164
|
-
|
|
165
|
-
```
|
|
166
|
-
document-models/todo-list/
|
|
167
|
-
├── gen/ # Auto-generated code (don't edit)
|
|
168
|
-
│ ├── actions.ts
|
|
169
|
-
│ ├── creators.ts # Action creator functions
|
|
170
|
-
│ ├── types.ts # TypeScript type definitions
|
|
171
|
-
│ ├── reducer.ts
|
|
172
|
-
│ └── todos/
|
|
173
|
-
│ └── operations.ts # Operation type definitions
|
|
174
|
-
├── src/ # Your custom implementation
|
|
175
|
-
│ ├── reducers/
|
|
176
|
-
│ │ └── todos.ts # Reducer functions (to implement next)
|
|
177
|
-
│ └── tests/
|
|
178
|
-
│ └── todos.test.ts # Test file scaffolding
|
|
179
|
-
├── todo-list.json # Document model specification
|
|
180
|
-
└── schema.graphql # GraphQL schema
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
:::tip Check your work
|
|
184
|
-
|
|
185
|
-
To make sure everything works as expected:
|
|
186
|
-
|
|
187
|
-
```bash
|
|
188
|
-
# Check types compile correctly
|
|
189
|
-
pnpm tsc
|
|
190
|
-
|
|
191
|
-
# Check linting passes
|
|
192
|
-
pnpm lint
|
|
193
|
-
|
|
194
|
-
# Compare your generated files with step-2
|
|
195
|
-
git diff tutorial/step-2-generate-todo-list-document-model -- document-models/todo-list/
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
:::
|
|
199
|
-
|
|
200
113
|
### Up next: reducers
|
|
201
114
|
|
|
202
|
-
Up next, you'll learn how to implement the runtime logic and components that will use the `
|
|
115
|
+
Up next, you'll learn how to implement the runtime logic and components that will use the `ToDoList` document model specification you've just created and exported.
|
|
203
116
|
|
|
@@ -1,48 +1,8 @@
|
|
|
1
|
-
# Implement the document model
|
|
1
|
+
# Implement the document model
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
📦 **Reference Code**: [step-3-implement-reducer-operation-handlers](https://github.com/powerhouse-inc/todo-tutorial/tree/step-3-implement-reducer-operation-handlers)
|
|
3
|
+
In this section, we will implement and test the operation reducers for the **To-do List** document model. For this, you have to export the document model specification from the Connect application and import it into your Powerhouse project directory.
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
:::
|
|
8
|
-
|
|
9
|
-
<details>
|
|
10
|
-
<summary>📖 How to use this tutorial</summary>
|
|
11
|
-
|
|
12
|
-
### Compare your reducer implementation
|
|
13
|
-
|
|
14
|
-
After implementing your reducers:
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
# Compare your reducers with the reference
|
|
18
|
-
git diff tutorial/step-3-implement-reducer-operation-handlers -- document-models/todo-list/src/reducers/
|
|
19
|
-
|
|
20
|
-
# View the reference reducer implementation
|
|
21
|
-
git show tutorial/step-3-implement-reducer-operation-handlers:document-models/todo-list/src/reducers/todos.ts
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
### Visual comparison with GitHub Desktop
|
|
25
|
-
|
|
26
|
-
After committing your work, compare visually:
|
|
27
|
-
1. **Branch** menu → **"Compare to Branch..."**
|
|
28
|
-
2. Select `tutorial/step-3-implement-reducer-operation-handlers`
|
|
29
|
-
3. Review differences in the visual interface
|
|
30
|
-
|
|
31
|
-
### If you get stuck
|
|
32
|
-
|
|
33
|
-
View or reset to a specific step:
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
# View the reducer code
|
|
37
|
-
git show tutorial/step-3-implement-reducer-operation-handlers:document-models/todo-list/src/reducers/todos.ts
|
|
38
|
-
|
|
39
|
-
# Reset to this step (WARNING: loses your changes)
|
|
40
|
-
git reset --hard tutorial/step-3-implement-reducer-operation-handlers
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
</details>
|
|
44
|
-
|
|
45
|
-
In this section, we will implement the operation reducers for the **To-do List** document model. In the previous step Vetra imported our document specification and scaffolded our directory through code generation. If not, you can revisit the [Define TodoList Document Model](/academy/GetStarted/DefineToDoListDocumentModel) section.
|
|
5
|
+
To export the document model specification, follow the steps in the [Define ToDoList Document Model](/academy/GetStarted/DefineToDoListDocumentModel) section.
|
|
46
6
|
|
|
47
7
|
## Understanding reducers in document models
|
|
48
8
|
|
|
@@ -53,172 +13,189 @@ Reducers are a core concept in Powerhouse document models. They implement the st
|
|
|
53
13
|
The reducers provide the actual implementation of what happens when those operations are performed.
|
|
54
14
|
:::
|
|
55
15
|
|
|
56
|
-
|
|
16
|
+
To import the document model specification into your Powerhouse project, you can either:
|
|
57
17
|
|
|
58
|
-
|
|
18
|
+
- Copy and paste the file directly into the root of your Powerhouse project.
|
|
19
|
+
- Or drag and drop the file into the Powerhouse project directory in the VSCode editor as seen in the image below:
|
|
59
20
|
|
|
60
|
-
|
|
61
|
-
import type { TodoListTodosOperations } from "todo-tutorial/document-models/todo-list";
|
|
62
|
-
|
|
63
|
-
export const todoListTodosOperations: TodoListTodosOperations = {
|
|
64
|
-
addTodoItemOperation(state, action) {
|
|
65
|
-
// TODO: Implement "addTodoItemOperation" reducer
|
|
66
|
-
throw new Error('Reducer "addTodoItemOperation" not yet implemented');
|
|
67
|
-
},
|
|
68
|
-
updateTodoItemOperation(state, action) {
|
|
69
|
-
// TODO: Implement "updateTodoItemOperation" reducer
|
|
70
|
-
throw new Error('Reducer "updateTodoItemOperation" not yet implemented');
|
|
71
|
-
},
|
|
72
|
-
deleteTodoItemOperation(state, action) {
|
|
73
|
-
// TODO: Implement "deleteTodoItemOperation" reducer
|
|
74
|
-
throw new Error('Reducer "deleteTodoItemOperation" not yet implemented');
|
|
75
|
-
},
|
|
76
|
-
};
|
|
77
|
-
```
|
|
21
|
+
Either step will import the document model specification into your Powerhouse project.
|
|
78
22
|
|
|
79
|
-
|
|
23
|
+

|
|
80
24
|
|
|
81
|
-
|
|
25
|
+
## In your project directory
|
|
82
26
|
|
|
83
|
-
|
|
27
|
+
The next steps will take place in the VSCode editor. Make sure to have it open and the terminal window inside VSCode open as well.
|
|
84
28
|
|
|
85
|
-
|
|
29
|
+
To write the operation reducers of the **To-do List** document model, you need to generate the document model code from the document model specification file you have exported into the Powerhouse project directory.
|
|
86
30
|
|
|
87
|
-
|
|
88
|
-
// added-line
|
|
89
|
-
import { generateId } from "document-model/core";
|
|
90
|
-
import type { TodoListTodosOperations } from "todo-tutorial/document-models/todo-list";
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
### Step 2: Implement addTodoItemOperation
|
|
31
|
+
To do this, run the following command in the terminal:
|
|
94
32
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
```typescript
|
|
98
|
-
export const todoListTodosOperations: TodoListTodosOperations = {
|
|
99
|
-
// removed-start
|
|
100
|
-
addTodoItemOperation(state, action) {
|
|
101
|
-
// TODO: Implement "addTodoItemOperation" reducer
|
|
102
|
-
throw new Error('Reducer "addTodoItemOperation" not yet implemented');
|
|
103
|
-
},
|
|
104
|
-
// removed-end
|
|
105
|
-
// added-start
|
|
106
|
-
addTodoItemOperation(state, action) {
|
|
107
|
-
const id = generateId();
|
|
108
|
-
state.items.push({ ...action.input, id, checked: false });
|
|
109
|
-
},
|
|
110
|
-
// added-end
|
|
111
|
-
updateTodoItemOperation(state, action) {
|
|
112
|
-
// ...
|
|
113
|
-
},
|
|
114
|
-
deleteTodoItemOperation(state, action) {
|
|
115
|
-
// ...
|
|
116
|
-
},
|
|
117
|
-
};
|
|
33
|
+
```bash
|
|
34
|
+
ph generate ToDoList.phdm.zip
|
|
118
35
|
```
|
|
119
36
|
|
|
120
|
-
|
|
121
|
-
- We generate a unique ID using `generateId()` from `document-model/core`
|
|
122
|
-
- We push a new item to the `items` array with the input text, new ID, and `checked: false`
|
|
123
|
-
- Under the hood, Powerhouse uses Immer.js, so this "mutation" is actually immutable
|
|
37
|
+
Now you can navigate to `/document-models/to-do-list/src/reducers/to-do-list.ts` and start writing the operation reducers.
|
|
124
38
|
|
|
125
|
-
|
|
39
|
+
Open the `to-do-list.ts` file and you should see the code that needs to be filled for the three operations you have specified earlier. The image below shows the code that needs to be filled:
|
|
126
40
|
|
|
127
|
-
|
|
41
|
+

|
|
128
42
|
|
|
129
|
-
|
|
130
|
-
// removed-start
|
|
131
|
-
updateTodoItemOperation(state, action) {
|
|
132
|
-
// TODO: Implement "updateTodoItemOperation" reducer
|
|
133
|
-
throw new Error('Reducer "updateTodoItemOperation" not yet implemented');
|
|
134
|
-
},
|
|
135
|
-
// removed-end
|
|
136
|
-
// added-start
|
|
137
|
-
updateTodoItemOperation(state, action) {
|
|
138
|
-
const item = state.items.find((item) => item.id === action.input.id);
|
|
139
|
-
if (!item) return;
|
|
140
|
-
item.text = action.input.text ?? item.text;
|
|
141
|
-
item.checked = action.input.checked ?? item.checked;
|
|
142
|
-
},
|
|
143
|
-
// added-end
|
|
144
|
-
```
|
|
43
|
+
## Write the operation reducers
|
|
145
44
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
- We return early if the item is not found
|
|
149
|
-
- We use nullish coalescing (`??`) to only update fields that are provided
|
|
45
|
+
1. Copy and paste the code below into the `to-do-list.ts` file in the `reducers` folder.
|
|
46
|
+
2. Save the file.
|
|
150
47
|
|
|
151
|
-
|
|
48
|
+
<details>
|
|
49
|
+
<summary>Operation Reducers</summary>
|
|
50
|
+
```typescript
|
|
51
|
+
import { ToDoListToDoListOperations } from '../../gen/to-do-list/operations.js';
|
|
52
|
+
|
|
53
|
+
// REMARKS: This is our main reducer object that implements all operations defined in the schema.
|
|
54
|
+
// The ToDoListToDoListOperations type is auto-generated from our SDL and ensures type safety.
|
|
55
|
+
export const reducer: ToDoListToDoListOperations = {
|
|
56
|
+
// REMARKS: The addTodoItemOperation adds a new item to our todolist.
|
|
57
|
+
// - state: The current document state that we can modify
|
|
58
|
+
// - action: Contains the operation type and input data from the client
|
|
59
|
+
// - dispatch: Function to trigger additional operations (not used here)
|
|
60
|
+
addTodoItemOperation(state, action, dispatch) {
|
|
61
|
+
// REMARKS: While this looks like we're directly mutating state, Powerhouse
|
|
62
|
+
// handles immutability behind the scenes, creating a new state object.
|
|
63
|
+
state.items.push({
|
|
64
|
+
id: action.input.id, // Using the client-provided ID
|
|
65
|
+
text: action.input.text, // Setting the todo text from input
|
|
66
|
+
checked: false, // New items always start unchecked
|
|
67
|
+
});
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
// REMARKS: The updateTodoItemOperation modifies an existing todo item.
|
|
71
|
+
// It handles partial updates, allowing only specific fields to be updated.
|
|
72
|
+
updateTodoItemOperation(state, action, dispatch) {
|
|
73
|
+
// REMARKS: First find the item we want to update by its ID
|
|
74
|
+
const item = state.items.find(item => item.id === action.input.id);
|
|
75
|
+
|
|
76
|
+
// REMARKS: Proper error handling if item doesn't exist
|
|
77
|
+
if (!item) {
|
|
78
|
+
throw new Error(`Item with id ${action.input.id} not found`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// REMARKS: We only update fields that were included in the input
|
|
82
|
+
// This allows for partial updates (only update what was provided)
|
|
83
|
+
if (action.input.text) {
|
|
84
|
+
item.text = action.input.text;
|
|
85
|
+
}
|
|
86
|
+
if (typeof action.input.checked === 'boolean') {
|
|
87
|
+
item.checked = action.input.checked;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
// REMARKS: The deleteTodoItemOperation removes an item from the list.
|
|
93
|
+
// This showcases functional programming with array filters for immutable updates.
|
|
94
|
+
deleteTodoItemOperation(state, action, dispatch) {
|
|
95
|
+
// REMARKS: Create a new array containing only items that don't match the ID
|
|
96
|
+
// This is a common pattern for immutable array updates in JavaScript
|
|
97
|
+
state.items = state.items.filter(item => item.id !== action.input.id);
|
|
98
|
+
},
|
|
99
|
+
};
|
|
152
100
|
|
|
153
|
-
|
|
101
|
+
````
|
|
102
|
+
</details>
|
|
154
103
|
|
|
155
|
-
|
|
156
|
-
// removed-start
|
|
157
|
-
deleteTodoItemOperation(state, action) {
|
|
158
|
-
// TODO: Implement "deleteTodoItemOperation" reducer
|
|
159
|
-
throw new Error('Reducer "deleteTodoItemOperation" not yet implemented');
|
|
160
|
-
},
|
|
161
|
-
// removed-end
|
|
162
|
-
// added-start
|
|
163
|
-
deleteTodoItemOperation(state, action) {
|
|
164
|
-
state.items = state.items.filter((item) => item.id !== action.input.id);
|
|
165
|
-
},
|
|
166
|
-
// added-end
|
|
167
|
-
```
|
|
104
|
+
## Write the operation reducers tests
|
|
168
105
|
|
|
169
|
-
|
|
170
|
-
- We filter out the item with the matching ID
|
|
171
|
-
- This creates a new array without the deleted item
|
|
106
|
+
In order to make sure the operation reducers are working as expected, you need to write tests for them.
|
|
172
107
|
|
|
173
|
-
|
|
108
|
+
Navigate to `/document-models/to-do-list/src/reducers/tests/to-do-list.test.ts` and copy and paste the code below into the file. Save the file.
|
|
174
109
|
|
|
175
|
-
Here
|
|
110
|
+
Here are the tests for the three operations implemented in the reducers file. This test file creates an empty ToDoList document model, then adds a todo item, updates it and deletes it.
|
|
176
111
|
|
|
177
112
|
<details>
|
|
178
|
-
<summary>
|
|
179
|
-
|
|
113
|
+
<summary>Operation Reducers Tests</summary>
|
|
180
114
|
```typescript
|
|
181
|
-
import
|
|
182
|
-
import
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
};
|
|
201
|
-
|
|
115
|
+
import utils from '../../gen/utils.js';
|
|
116
|
+
import { reducer } from '../../gen/reducer.js';
|
|
117
|
+
import * as creators from '../../gen/creators.js';
|
|
118
|
+
import { ToDoListDocument } from '../../gen/types.js';
|
|
119
|
+
|
|
120
|
+
// REMARKS:
|
|
121
|
+
// These tests demonstrate the event sourcing principles of our document model.
|
|
122
|
+
// Each operation is recorded in the document's operations list and affects the state.
|
|
123
|
+
|
|
124
|
+
describe('Todolist Operations', () => {
|
|
125
|
+
let document: ToDoListDocument;
|
|
126
|
+
|
|
127
|
+
beforeEach(() => {
|
|
128
|
+
// REMARKS: We start with a fresh, empty document for each test
|
|
129
|
+
document = utils.createDocument();
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('should handle addTodoItem operation', () => {
|
|
133
|
+
// REMARKS: We create an input object matching our AddTodoItemInput schema
|
|
134
|
+
const input = { id: '1', text: 'Buy milk' };
|
|
135
|
+
|
|
136
|
+
// REMARKS: We apply the operation to get a new document state
|
|
137
|
+
// Note how we use the creators to generate the operation action
|
|
138
|
+
const updatedDocument = reducer(document, creators.addTodoItem(input));
|
|
139
|
+
|
|
140
|
+
// REMARKS: We verify that:
|
|
141
|
+
// 1. The operation was recorded in the document's operation history
|
|
142
|
+
// 2. The state was updated according to our reducer implementation
|
|
143
|
+
expect(updatedDocument.operations.global).toHaveLength(1);
|
|
144
|
+
expect(updatedDocument.operations.global[0].type).toBe('ADD_TODO_ITEM');
|
|
145
|
+
expect(updatedDocument.state.global.items).toHaveLength(1);
|
|
146
|
+
expect(updatedDocument.state.global.items[0].text).toBe('Buy milk');
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('should handle updateTodoItem operation', () => {
|
|
150
|
+
// REMARKS: For update, we first need to add an item, then update it
|
|
151
|
+
// This demonstrates the sequential application of operations
|
|
152
|
+
const addInput = { id: '1', text: 'Buy milk' };
|
|
153
|
+
const updateInput = { id: '1', text: 'Buy bread' };
|
|
154
|
+
|
|
155
|
+
// REMARKS: Operations are applied in sequence, building up document state
|
|
156
|
+
const createdDocument = reducer(document, creators.addTodoItem(addInput));
|
|
157
|
+
const updatedDocument = reducer(createdDocument, creators.updateTodoItem(updateInput));
|
|
158
|
+
|
|
159
|
+
// REMARKS: Now we have 2 operations in history, and the state reflects both
|
|
160
|
+
expect(updatedDocument.operations.global).toHaveLength(2);
|
|
161
|
+
expect(updatedDocument.state.global.items[0].text).toBe('Buy bread');
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('should handle deleteTodoItem operation', () => {
|
|
165
|
+
// REMARKS: Similar pattern - add an item, then delete it
|
|
166
|
+
const addInput = { id: '1', text: 'Buy milk' };
|
|
167
|
+
const deleteInput = { id: '1' };
|
|
168
|
+
|
|
169
|
+
const createdDocument = reducer(document, creators.addTodoItem(addInput));
|
|
170
|
+
const updatedDocument = reducer(createdDocument, creators.deleteTodoItem(deleteInput));
|
|
171
|
+
|
|
172
|
+
// REMARKS: After deletion, we still have 2 operations in history,
|
|
173
|
+
// but the items array is now empty again in the final state
|
|
174
|
+
expect(updatedDocument.operations.global).toHaveLength(2);
|
|
175
|
+
expect(updatedDocument.state.global.items).toHaveLength(0);
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
````
|
|
202
179
|
|
|
203
180
|
</details>
|
|
204
181
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
To make sure everything works as expected:
|
|
182
|
+
Now you can run the tests to make sure the operation reducers are working as expected.
|
|
208
183
|
|
|
209
184
|
```bash
|
|
210
|
-
|
|
211
|
-
|
|
185
|
+
pnpm run test
|
|
186
|
+
```
|
|
212
187
|
|
|
213
|
-
|
|
214
|
-
pnpm lint
|
|
188
|
+
Output should be as follows:
|
|
215
189
|
|
|
216
|
-
|
|
217
|
-
|
|
190
|
+
```bash
|
|
191
|
+
Test Files 2 passed (2)
|
|
192
|
+
Tests 5 passed (5)
|
|
193
|
+
Start at 12:04:57
|
|
194
|
+
Duration 417ms (transform 79ms, setup 0ms, collect 174ms, tests 12ms, environment 0ms, prepare 158ms)
|
|
218
195
|
```
|
|
219
196
|
|
|
220
|
-
|
|
197
|
+
If you got the same output, you have successfully implemented the operation reducers and tests for the **To-do List** document model. Congratulations, you've successfully set up the backbone for a simple **To-do List** document.
|
|
221
198
|
|
|
222
|
-
## Up next:
|
|
199
|
+
## Up next: To-do list editor
|
|
223
200
|
|
|
224
|
-
In the next chapter
|
|
201
|
+
In the next chapter of this introduction track you will learn how to implement an editor for your document model so you can see a simple user interface for the **To-do List** document model in action.
|