@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.
Files changed (75) hide show
  1. package/CHANGELOG.md +43 -1108
  2. package/blog/BeyondCommunication-ABlueprintForDevelopment.md +1 -2
  3. package/blog/TheChallengeOfChange.md +0 -1
  4. package/docs/academy/00-EthereumArgentinaHackathon.md +207 -0
  5. package/docs/academy/01-GetStarted/00-ExploreDemoPackage.mdx +27 -24
  6. package/docs/academy/01-GetStarted/01-CreateNewPowerhouseProject.md +9 -118
  7. package/docs/academy/01-GetStarted/02-DefineToDoListDocumentModel.md +28 -110
  8. package/docs/academy/01-GetStarted/03-ImplementOperationReducers.md +145 -191
  9. package/docs/academy/01-GetStarted/04-BuildToDoListEditor.md +218 -0
  10. package/docs/academy/{02-MasteryTrack/01-BuilderEnvironment → 01-GetStarted}/05-VetraStudio.md +6 -48
  11. package/docs/academy/01-GetStarted/06-ReactorMCP.md +58 -0
  12. package/docs/academy/01-GetStarted/_04-BuildToDoListEditor +1 -1
  13. package/docs/academy/02-MasteryTrack/01-BuilderEnvironment/03-BuilderTools.md +2 -2
  14. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/02-SpecifyTheStateSchema.md +44 -75
  15. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/03-SpecifyDocumentOperations.md +22 -28
  16. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/04-UseTheDocumentModelGenerator.md +31 -28
  17. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/05-ImplementDocumentReducers.md +206 -211
  18. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/06-ImplementDocumentModelTests.md +62 -176
  19. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/07-ExampleToDoListRepository.md +0 -21
  20. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/01-BuildingDocumentEditors.md +319 -309
  21. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/06-DocumentTools/00-DocumentToolbar.mdx +0 -4
  22. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/06-DocumentTools/01-OperationHistory.md +0 -4
  23. package/docs/academy/02-MasteryTrack/05-Launch/04-ConfigureEnvironment.md +1 -1
  24. package/docs/academy/03-ExampleUsecases/Chatroom/02-CreateNewPowerhouseProject.md +35 -111
  25. package/docs/academy/03-ExampleUsecases/Chatroom/03-DefineChatroomDocumentModel.md +76 -255
  26. package/docs/academy/03-ExampleUsecases/Chatroom/04-ImplementOperationReducers.md +160 -281
  27. package/docs/academy/03-ExampleUsecases/Chatroom/05-ImplementChatroomEditor.md +35 -188
  28. package/docs/academy/03-ExampleUsecases/Chatroom/06-LaunchALocalReactor.md +7 -95
  29. package/docs/academy/03-ExampleUsecases/Chatroom/_category_.json +1 -1
  30. package/docs/academy/04-APIReferences/00-PowerhouseCLI.md +2 -6
  31. package/docs/academy/04-APIReferences/01-ReactHooks.md +501 -291
  32. package/docs/academy/05-Architecture/00-PowerhouseArchitecture.md +39 -7
  33. package/docs/academy/05-Architecture/02-ReferencingMonorepoPackages +65 -0
  34. package/docs/academy/05-Architecture/04-MovingBeyondCRUD +61 -0
  35. package/docs/academy/06-ComponentLibrary/00-DocumentEngineering.md +24 -72
  36. package/docs/academy/08-Glossary.md +0 -7
  37. package/docusaurus.config.ts +3 -28
  38. package/package.json +1 -1
  39. package/sidebars.ts +12 -49
  40. package/src/css/custom.css +18 -26
  41. package/docs/academy/01-GetStarted/04-WriteDocumentModelTests.md +0 -378
  42. package/docs/academy/01-GetStarted/05-BuildToDoListEditor.md +0 -560
  43. package/docs/academy/03-ExampleUsecases/TodoList/00-GetTheStarterCode.md +0 -24
  44. package/docs/academy/03-ExampleUsecases/TodoList/01-GenerateTodoListDocumentModel.md +0 -211
  45. package/docs/academy/03-ExampleUsecases/TodoList/02-ImplementTodoListDocumentModelReducerOperationHandlers.md +0 -171
  46. package/docs/academy/03-ExampleUsecases/TodoList/03-AddTestsForTodoListActions.md +0 -462
  47. package/docs/academy/03-ExampleUsecases/TodoList/04-GenerateTodoListDocumentEditor.md +0 -45
  48. package/docs/academy/03-ExampleUsecases/TodoList/05-ImplementTodoListDocumentEditorUIComponents.md +0 -422
  49. package/docs/academy/03-ExampleUsecases/TodoList/06-GenerateTodoDriveExplorer.md +0 -61
  50. package/docs/academy/03-ExampleUsecases/TodoList/07-AddSharedComponentForShowingTodoListStats.md +0 -384
  51. package/docs/academy/03-ExampleUsecases/TodoList/_category_.json +0 -8
  52. package/docs/academy/03-ExampleUsecases/VetraPackageLibrary/VetraPackageLibrary.md +0 -7
  53. package/docs/academy/03-ExampleUsecases/VetraPackageLibrary/_category_.json +0 -9
  54. package/docs/academy/04-APIReferences/06-VetraRemoteDrive.md +0 -160
  55. package/docs/academy/04-APIReferences/renown-sdk/00-Overview.md +0 -316
  56. package/docs/academy/04-APIReferences/renown-sdk/01-Authentication.md +0 -672
  57. package/docs/academy/04-APIReferences/renown-sdk/02-APIReference.md +0 -957
  58. package/docs/academy/04-APIReferences/renown-sdk/_category_.json +0 -8
  59. package/docs/academy/10-TodoListTutorial/02-ImplementTodoListDocumentModelReducerOperationHandlers.md +0 -171
  60. package/docs/academy/10-TodoListTutorial/03-AddTestsForTodoListActions.md +0 -462
  61. package/docs/academy/10-TodoListTutorial/05-ImplementTodoListDocumentEditorUIComponents.md +0 -422
  62. package/docs/academy/10-TodoListTutorial/07-AddSharedComponentForShowingTodoListStats.md +0 -370
  63. package/static/img/Vetra-logo-dark.svg +0 -11
  64. package/static/img/vetra-logo-light.svg +0 -11
  65. /package/docs/academy/{02-MasteryTrack/01-BuilderEnvironment → 01-GetStarted}/images/Modules.png +0 -0
  66. /package/docs/academy/{02-MasteryTrack/01-BuilderEnvironment → 01-GetStarted}/images/VetraStudioDrive.png +0 -0
  67. /package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/06-DocumentTools/{02-RevisionHistoryTimeline/360/237/232/247" → 02-RevisionHistoryTimeline} +0 -0
  68. /package/docs/academy/05-Architecture/05-DocumentModelTheory/{360/237/232/247 /01-WhatIsADocumentModel" → 01-WhatIsADocumentModel} +0 -0
  69. /package/docs/academy/05-Architecture/05-DocumentModelTheory/{360/237/232/247 /02-DAOandDocumentsModelsQ+A" → 02-DAOandDocumentsModelsQ+A} +0 -0
  70. /package/docs/academy/05-Architecture/05-DocumentModelTheory/{360/237/232/247 /02-domain-modeling" → 02-domain-modeling} +0 -0
  71. /package/docs/academy/05-Architecture/05-DocumentModelTheory/{360/237/232/247 /03-BenefitsOfDocumentModels" → 03-BenefitsOfDocumentModels} +0 -0
  72. /package/docs/academy/05-Architecture/05-DocumentModelTheory/{360/237/232/247 /04-UtilitiesAndTips" → 04-UtilitiesAndTips} +0 -0
  73. /package/docs/academy/05-Architecture/05-DocumentModelTheory/{360/237/232/247 /05-best-practices" → 05-best-practices} +0 -0
  74. /package/docs/academy/05-Architecture/05-DocumentModelTheory/{360/237/232/247 /_category_.json" → _category_.json} +0 -0
  75. /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
- :::tip Tutorial Repository
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
- ## TodoList document specification
20
+ ## To-do list document specification
70
21
 
71
- Make sure you have named your document model `TodoList` (PascalCase, no spaces or hyphens).
72
- **Pay close attention to capitalization, as it influences our code generation.**
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 `TodoList` document model.
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 TodoList</summary>
35
+ <summary>State schema of our simplified To-do list</summary>
84
36
 
85
37
  ```graphql
86
- # The state of our TodoList
87
- type TodoListState {
88
- items: [TodoItem!]!
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 TodoItem {
93
- id: OID!
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 TodoList</summary>
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
- id: OID!
112
- text: String
113
- checked: Boolean
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
- id: OID!
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 `TodoList` (PascalCase, no spaces or hyphens) in the Connect application. **Pay close attention to capitalization, as it influences code generation.**
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/todo-list` (lowercase with hyphen). This defines the new type of document that will be created with this document model specification.
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
- ![TodoList Document Model Form Metadata](./images/DocumentModelHeader.png)
91
+ ![ToDoList Document Model Form Metadata](./images/DocumentModelHeader.png)
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 `todos`. Press enter.
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
  ![ToDoList Document Model](./images/DocumentModelOperations.png)
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 `TodoList` document model specification you've just created and exported.
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 reducers
1
+ # Implement the document model
2
2
 
3
- :::tip Tutorial Repository
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
  ![vscode image](./images/vscode.png)
66
24
 
67
- ## Generate the document model code
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
- Run the following command in the terminal:
31
+ To do this, run the following command in the terminal:
74
32
 
75
33
  ```bash
76
- ph generate TodoList.phd
34
+ ph generate ToDoList.phdm.zip
77
35
  ```
78
36
 
79
- ## Explore the generated reducer file
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
- ## Implement the operation reducers
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
- Let's implement each reducer one by one.
41
+ ![to-do-list ts file](./images/reducers.png)
105
42
 
106
- ### Step 1: Add the import
43
+ ## Write the operation reducers
107
44
 
108
- First, add the `generateId` import at the top of the file:
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
- export const todoListTodosOperations: TodoListTodosOperations = {
122
- // removed-start
123
- addTodoItemOperation(state, action) {
124
- // TODO: Implement "addTodoItemOperation" reducer
125
- throw new Error('Reducer "addTodoItemOperation" not yet implemented');
126
- },
127
- // removed-end
128
- // added-start
129
- addTodoItemOperation(state, action) {
130
- const id = generateId();
131
- state.items.push({ ...action.input, id, checked: false });
132
- },
133
- // added-end
134
- updateTodoItemOperation(state, action) {
135
- // ...
136
- },
137
- deleteTodoItemOperation(state, action) {
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
- **What's happening here:**
170
- - We find the item by its ID
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
- ```typescript
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
- **What's happening here:**
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
- ## Complete reducer file
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's the complete implementation:
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>Complete todos.ts</summary>
202
-
113
+ <summary>Operation Reducers Tests</summary>
203
114
  ```typescript
204
- import { generateId } from "document-model/core";
205
- import type { TodoListTodosOperations } from "todo-tutorial/document-models/todo-list";
206
-
207
- export const todoListTodosOperations: TodoListTodosOperations = {
208
- addTodoItemOperation(state, action) {
209
- const id = generateId();
210
- state.items.push({ ...action.input, id, checked: false });
211
- },
212
-
213
- updateTodoItemOperation(state, action) {
214
- const item = state.items.find((item) => item.id === action.input.id);
215
- if (!item) return;
216
- item.text = action.input.text ?? item.text;
217
- item.checked = action.input.checked ?? item.checked;
218
- },
219
-
220
- deleteTodoItemOperation(state, action) {
221
- state.items = state.items.filter((item) => item.id !== action.input.id);
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
- :::tip Check your work
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
- # Check types compile correctly
234
- pnpm tsc
185
+ pnpm run test
186
+ ```
235
187
 
236
- # Check linting passes
237
- pnpm lint
188
+ Output should be as follows:
238
189
 
239
- # Compare with reference implementation
240
- git diff tutorial/step-3-implement-reducer-operation-handlers -- document-models/todo-list/src/reducers/
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: Writing tests
199
+ ## Up next: To-do list editor
246
200
 
247
- In the next chapter, you'll write comprehensive tests to verify your reducer implementations work correctly.
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.