@powerhousedao/academy 5.1.0-dev.9 → 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 +43 -1108
- 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 +9 -118
- package/docs/academy/01-GetStarted/02-DefineToDoListDocumentModel.md +28 -110
- package/docs/academy/01-GetStarted/03-ImplementOperationReducers.md +145 -191
- package/docs/academy/01-GetStarted/04-BuildToDoListEditor.md +218 -0
- package/docs/academy/{02-MasteryTrack/01-BuilderEnvironment → 01-GetStarted}/05-VetraStudio.md +6 -48
- 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 +76 -255
- package/docs/academy/03-ExampleUsecases/Chatroom/04-ImplementOperationReducers.md +160 -281
- package/docs/academy/03-ExampleUsecases/Chatroom/05-ImplementChatroomEditor.md +35 -188
- 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 +12 -49
- package/src/css/custom.css +18 -26
- package/docs/academy/01-GetStarted/04-WriteDocumentModelTests.md +0 -378
- package/docs/academy/01-GetStarted/05-BuildToDoListEditor.md +0 -560
- 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/01-BuilderEnvironment → 01-GetStarted}/images/Modules.png +0 -0
- /package/docs/academy/{02-MasteryTrack/01-BuilderEnvironment → 01-GetStarted}/images/VetraStudioDrive.png +0 -0
- /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,55 +1,6 @@
|
|
|
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 **TodoList** document model within the Connect application 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
6
|
Before you start, make sure you have the Connect application running locally with the command:
|
|
@@ -66,13 +17,14 @@ The Connect application 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,17 +32,17 @@ 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
43
|
# A single to-do item
|
|
92
|
-
type
|
|
93
|
-
id:
|
|
44
|
+
type ToDoItem {
|
|
45
|
+
id: ID!
|
|
94
46
|
text: String!
|
|
95
47
|
checked: Boolean!
|
|
96
48
|
}
|
|
@@ -99,25 +51,29 @@ type TodoItem {
|
|
|
99
51
|
</details>
|
|
100
52
|
|
|
101
53
|
<details>
|
|
102
|
-
<summary>Operations schema of our simplified
|
|
54
|
+
<summary>Operations schema of our simplified to-do list</summary>
|
|
103
55
|
```graphql
|
|
104
56
|
# Defines a GraphQL input type for adding a new to-do item
|
|
105
57
|
input AddTodoItemInput {
|
|
58
|
+
id: ID!
|
|
106
59
|
text: String!
|
|
107
60
|
}
|
|
108
61
|
|
|
109
62
|
# Defines a GraphQL input type for updating a to-do item
|
|
63
|
+
|
|
110
64
|
input UpdateTodoItemInput {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
65
|
+
id: ID!
|
|
66
|
+
text: String
|
|
67
|
+
checked: Boolean
|
|
114
68
|
}
|
|
115
69
|
|
|
116
70
|
# Defines a GraphQL input type for deleting a to-do item
|
|
71
|
+
|
|
117
72
|
input DeleteTodoItemInput {
|
|
118
|
-
|
|
73
|
+
id: ID!
|
|
119
74
|
}
|
|
120
|
-
|
|
75
|
+
|
|
76
|
+
````
|
|
121
77
|
</details>
|
|
122
78
|
|
|
123
79
|
## Define the document model specification
|
|
@@ -127,20 +83,21 @@ To be able to define the document model, you need to open the document model edi
|
|
|
127
83
|
### The steps below show you how to do this:
|
|
128
84
|
|
|
129
85
|
1. In the Connect application, click on **'document model'** to open the document model specification editor.
|
|
130
|
-
2. Name your document model
|
|
86
|
+
2. Name your document model '**ToDoList**' in the Connect application, paying close attention to capitalization.
|
|
131
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.
|
|
132
88
|
|
|
133
|
-
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.
|
|
134
90
|
|
|
135
|
-

|
|
136
92
|
|
|
137
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.
|
|
138
|
-
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.
|
|
139
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.
|
|
140
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:
|
|
141
97
|
|
|
142
98
|
```graphql
|
|
143
99
|
input AddTodoItemInput {
|
|
100
|
+
id: ID!
|
|
144
101
|
text: String!
|
|
145
102
|
}
|
|
146
103
|
```
|
|
@@ -153,46 +110,7 @@ Check below screenshot for the complete implementation:
|
|
|
153
110
|
|
|
154
111
|

|
|
155
112
|
|
|
156
|
-
## Verify your document model generation
|
|
157
|
-
|
|
158
|
-
After running `pnpm generate TodoList.phd`, your project should have the following structure in `document-models/todo-list/`:
|
|
159
|
-
|
|
160
|
-
```
|
|
161
|
-
document-models/todo-list/
|
|
162
|
-
├── gen/ # Auto-generated code (don't edit)
|
|
163
|
-
│ ├── actions.ts
|
|
164
|
-
│ ├── creators.ts # Action creator functions
|
|
165
|
-
│ ├── types.ts # TypeScript type definitions
|
|
166
|
-
│ ├── reducer.ts
|
|
167
|
-
│ └── todos/
|
|
168
|
-
│ └── operations.ts # Operation type definitions
|
|
169
|
-
├── src/ # Your custom implementation
|
|
170
|
-
│ ├── reducers/
|
|
171
|
-
│ │ └── todos.ts # Reducer functions (to implement next)
|
|
172
|
-
│ └── tests/
|
|
173
|
-
│ └── todos.test.ts # Test file scaffolding
|
|
174
|
-
├── todo-list.json # Document model specification
|
|
175
|
-
└── schema.graphql # GraphQL schema
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
:::tip Check your work
|
|
179
|
-
|
|
180
|
-
To make sure everything works as expected:
|
|
181
|
-
|
|
182
|
-
```bash
|
|
183
|
-
# Check types compile correctly
|
|
184
|
-
pnpm tsc
|
|
185
|
-
|
|
186
|
-
# Check linting passes
|
|
187
|
-
pnpm lint
|
|
188
|
-
|
|
189
|
-
# Compare your generated files with step-2
|
|
190
|
-
git diff tutorial/step-2-generate-todo-list-document-model -- document-models/todo-list/
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
:::
|
|
194
|
-
|
|
195
113
|
### Up next: reducers
|
|
196
114
|
|
|
197
|
-
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.
|
|
198
116
|
|
|
@@ -1,48 +1,6 @@
|
|
|
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)
|
|
5
|
-
|
|
6
|
-
This step focuses on implementing the reducer logic for add, update, and delete operations.
|
|
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. For this, you need to export the document model specification from Connect and import it into your Powerhouse project directory.
|
|
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.
|
|
46
4
|
|
|
47
5
|
To export the document model specification, follow the steps in the [Define ToDoList Document Model](/academy/GetStarted/DefineToDoListDocumentModel) section.
|
|
48
6
|
|
|
@@ -64,184 +22,180 @@ Either step will import the document model specification into your Powerhouse pr
|
|
|
64
22
|
|
|
65
23
|

|
|
66
24
|
|
|
67
|
-
##
|
|
25
|
+
## In your project directory
|
|
68
26
|
|
|
69
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.
|
|
70
28
|
|
|
71
|
-
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.
|
|
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.
|
|
72
30
|
|
|
73
|
-
|
|
31
|
+
To do this, run the following command in the terminal:
|
|
74
32
|
|
|
75
33
|
```bash
|
|
76
|
-
ph generate
|
|
34
|
+
ph generate ToDoList.phdm.zip
|
|
77
35
|
```
|
|
78
36
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
Navigate to `/document-models/todo-list/src/reducers/todos.ts` and open it. You should see scaffolding code that needs to be filled for the three operations you specified:
|
|
82
|
-
|
|
83
|
-
```typescript
|
|
84
|
-
import type { TodoListTodosOperations } from "todo-tutorial/document-models/todo-list";
|
|
85
|
-
|
|
86
|
-
export const todoListTodosOperations: TodoListTodosOperations = {
|
|
87
|
-
addTodoItemOperation(state, action) {
|
|
88
|
-
// TODO: Implement "addTodoItemOperation" reducer
|
|
89
|
-
throw new Error('Reducer "addTodoItemOperation" not yet implemented');
|
|
90
|
-
},
|
|
91
|
-
updateTodoItemOperation(state, action) {
|
|
92
|
-
// TODO: Implement "updateTodoItemOperation" reducer
|
|
93
|
-
throw new Error('Reducer "updateTodoItemOperation" not yet implemented');
|
|
94
|
-
},
|
|
95
|
-
deleteTodoItemOperation(state, action) {
|
|
96
|
-
// TODO: Implement "deleteTodoItemOperation" reducer
|
|
97
|
-
throw new Error('Reducer "deleteTodoItemOperation" not yet implemented');
|
|
98
|
-
},
|
|
99
|
-
};
|
|
100
|
-
```
|
|
37
|
+
Now you can navigate to `/document-models/to-do-list/src/reducers/to-do-list.ts` and start writing the operation reducers.
|
|
101
38
|
|
|
102
|
-
|
|
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:
|
|
103
40
|
|
|
104
|
-
|
|
41
|
+

|
|
105
42
|
|
|
106
|
-
|
|
43
|
+
## Write the operation reducers
|
|
107
44
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
```typescript
|
|
111
|
-
// added-line
|
|
112
|
-
import { generateId } from "document-model/core";
|
|
113
|
-
import type { TodoListTodosOperations } from "todo-tutorial/document-models/todo-list";
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
### Step 2: Implement addTodoItemOperation
|
|
117
|
-
|
|
118
|
-
Replace the boilerplate `addTodoItemOperation` with the actual implementation:
|
|
45
|
+
1. Copy and paste the code below into the `to-do-list.ts` file in the `reducers` folder.
|
|
46
|
+
2. Save the file.
|
|
119
47
|
|
|
48
|
+
<details>
|
|
49
|
+
<summary>Operation Reducers</summary>
|
|
120
50
|
```typescript
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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
|
+
},
|
|
140
99
|
};
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
**What's happening here:**
|
|
144
|
-
- We generate a unique ID using `generateId()` from `document-model/core`
|
|
145
|
-
- We push a new item to the `items` array with the input text, new ID, and `checked: false`
|
|
146
|
-
- Under the hood, Powerhouse uses Immer.js, so this "mutation" is actually immutable
|
|
147
|
-
|
|
148
|
-
### Step 3: Implement updateTodoItemOperation
|
|
149
|
-
|
|
150
|
-
Replace the boilerplate `updateTodoItemOperation`:
|
|
151
|
-
|
|
152
|
-
```typescript
|
|
153
|
-
// removed-start
|
|
154
|
-
updateTodoItemOperation(state, action) {
|
|
155
|
-
// TODO: Implement "updateTodoItemOperation" reducer
|
|
156
|
-
throw new Error('Reducer "updateTodoItemOperation" not yet implemented');
|
|
157
|
-
},
|
|
158
|
-
// removed-end
|
|
159
|
-
// added-start
|
|
160
|
-
updateTodoItemOperation(state, action) {
|
|
161
|
-
const item = state.items.find((item) => item.id === action.input.id);
|
|
162
|
-
if (!item) return;
|
|
163
|
-
item.text = action.input.text ?? item.text;
|
|
164
|
-
item.checked = action.input.checked ?? item.checked;
|
|
165
|
-
},
|
|
166
|
-
// added-end
|
|
167
|
-
```
|
|
168
100
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
- We return early if the item is not found
|
|
172
|
-
- We use nullish coalescing (`??`) to only update fields that are provided
|
|
173
|
-
|
|
174
|
-
### Step 4: Implement deleteTodoItemOperation
|
|
175
|
-
|
|
176
|
-
Replace the boilerplate `deleteTodoItemOperation`:
|
|
101
|
+
````
|
|
102
|
+
</details>
|
|
177
103
|
|
|
178
|
-
|
|
179
|
-
// removed-start
|
|
180
|
-
deleteTodoItemOperation(state, action) {
|
|
181
|
-
// TODO: Implement "deleteTodoItemOperation" reducer
|
|
182
|
-
throw new Error('Reducer "deleteTodoItemOperation" not yet implemented');
|
|
183
|
-
},
|
|
184
|
-
// removed-end
|
|
185
|
-
// added-start
|
|
186
|
-
deleteTodoItemOperation(state, action) {
|
|
187
|
-
state.items = state.items.filter((item) => item.id !== action.input.id);
|
|
188
|
-
},
|
|
189
|
-
// added-end
|
|
190
|
-
```
|
|
104
|
+
## Write the operation reducers tests
|
|
191
105
|
|
|
192
|
-
|
|
193
|
-
- We filter out the item with the matching ID
|
|
194
|
-
- 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.
|
|
195
107
|
|
|
196
|
-
|
|
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.
|
|
197
109
|
|
|
198
|
-
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.
|
|
199
111
|
|
|
200
112
|
<details>
|
|
201
|
-
<summary>
|
|
202
|
-
|
|
113
|
+
<summary>Operation Reducers Tests</summary>
|
|
203
114
|
```typescript
|
|
204
|
-
import
|
|
205
|
-
import
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
};
|
|
224
|
-
|
|
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
|
+
````
|
|
225
179
|
|
|
226
180
|
</details>
|
|
227
181
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
To make sure everything works as expected:
|
|
182
|
+
Now you can run the tests to make sure the operation reducers are working as expected.
|
|
231
183
|
|
|
232
184
|
```bash
|
|
233
|
-
|
|
234
|
-
|
|
185
|
+
pnpm run test
|
|
186
|
+
```
|
|
235
187
|
|
|
236
|
-
|
|
237
|
-
pnpm lint
|
|
188
|
+
Output should be as follows:
|
|
238
189
|
|
|
239
|
-
|
|
240
|
-
|
|
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)
|
|
241
195
|
```
|
|
242
196
|
|
|
243
|
-
|
|
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.
|
|
244
198
|
|
|
245
|
-
## Up next:
|
|
199
|
+
## Up next: To-do list editor
|
|
246
200
|
|
|
247
|
-
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.
|