@powerhousedao/academy 5.0.0-staging.9 → 5.0.1-staging.2

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 (108) hide show
  1. package/.vscode/settings.json +1 -1
  2. package/CHANGELOG.md +400 -0
  3. package/README.md +3 -3
  4. package/babel.config.js +1 -1
  5. package/blog/BeyondCommunication-ABlueprintForDevelopment.md +25 -24
  6. package/blog/TheChallengeOfChange.md +21 -21
  7. package/docs/academy/01-GetStarted/00-ExploreDemoPackage.mdx +67 -30
  8. package/docs/academy/01-GetStarted/01-CreateNewPowerhouseProject.md +38 -21
  9. package/docs/academy/01-GetStarted/02-DefineToDoListDocumentModel.md +24 -19
  10. package/docs/academy/01-GetStarted/03-ImplementOperationReducers.md +44 -41
  11. package/docs/academy/01-GetStarted/04-BuildToDoListEditor.md +10 -10
  12. package/docs/academy/01-GetStarted/05-VetraStudio.md +164 -0
  13. package/docs/academy/01-GetStarted/06-ReactorMCP.md +58 -0
  14. package/docs/academy/01-GetStarted/home.mdx +185 -90
  15. package/docs/academy/01-GetStarted/images/Modules.png +0 -0
  16. package/docs/academy/01-GetStarted/images/VetraStudioDrive.png +0 -0
  17. package/docs/academy/01-GetStarted/styles.module.css +5 -5
  18. package/docs/academy/02-MasteryTrack/01-BuilderEnvironment/01-Prerequisites.md +46 -18
  19. package/docs/academy/02-MasteryTrack/01-BuilderEnvironment/02-StandardDocumentModelWorkflow.md +118 -68
  20. package/docs/academy/02-MasteryTrack/01-BuilderEnvironment/03-BuilderTools.md +75 -33
  21. package/docs/academy/02-MasteryTrack/01-BuilderEnvironment/_category_.json +6 -6
  22. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/01-WhatIsADocumentModel.md +30 -21
  23. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/02-SpecifyTheStateSchema.md +41 -37
  24. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/03-SpecifyDocumentOperations.md +29 -25
  25. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/04-UseTheDocumentModelGenerator.md +36 -37
  26. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/05-ImplementDocumentReducers.md +128 -109
  27. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/06-ImplementDocumentModelTests.md +95 -86
  28. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/07-ExampleToDoListRepository.md +7 -9
  29. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/_category_.json +6 -6
  30. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/01-BuildingDocumentEditors.md +65 -47
  31. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/02-ConfiguringDrives.md +77 -62
  32. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/03-BuildingADriveExplorer.md +360 -349
  33. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/06-DocumentTools/00-DocumentToolbar.mdx +16 -10
  34. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/06-DocumentTools/01-OperationHistory.md +10 -7
  35. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/06-DocumentTools/02-RevisionHistoryTimeline.md +25 -17
  36. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/06-DocumentTools/_category_.json +6 -6
  37. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/07-Authorization/01-RenownAuthenticationFlow.md +14 -7
  38. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/07-Authorization/02-Authorization.md +0 -1
  39. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/07-Authorization/_category_.json +5 -5
  40. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/_category_.json +1 -1
  41. package/docs/academy/02-MasteryTrack/04-WorkWithData/01-GraphQLAtPowerhouse.md +45 -33
  42. package/docs/academy/02-MasteryTrack/04-WorkWithData/02-UsingTheAPI.mdx +61 -18
  43. package/docs/academy/02-MasteryTrack/04-WorkWithData/03-UsingSubgraphs.md +50 -54
  44. package/docs/academy/02-MasteryTrack/04-WorkWithData/04-analytics-processor.md +126 -110
  45. package/docs/academy/02-MasteryTrack/04-WorkWithData/05-RelationalDbProcessor.md +75 -45
  46. package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/GraphQL References/QueryingADocumentWithGraphQL.md +23 -21
  47. package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/best-practices.md +9 -9
  48. package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/graphql/index.md +11 -23
  49. package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/graphql/integration.md +25 -9
  50. package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/intro.md +10 -10
  51. package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/typescript/benchmarks.md +1 -1
  52. package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/typescript/index.md +16 -11
  53. package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/typescript/memory.md +6 -5
  54. package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/typescript/schema.md +2 -2
  55. package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/typescript/utilities.md +7 -5
  56. package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/use-cases/maker.md +32 -58
  57. package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/use-cases/processors.md +1 -1
  58. package/docs/academy/02-MasteryTrack/04-WorkWithData/07-drive-analytics.md +105 -71
  59. package/docs/academy/02-MasteryTrack/04-WorkWithData/_ARCHIVE-AnalyticsProcessorTutorial/_01-SetupBuilderEnvironment.md +22 -0
  60. package/docs/academy/02-MasteryTrack/04-WorkWithData/_ARCHIVE-AnalyticsProcessorTutorial/_02-CreateNewPowerhouseProject.md +9 -8
  61. package/docs/academy/02-MasteryTrack/04-WorkWithData/_ARCHIVE-AnalyticsProcessorTutorial/_03-GenerateAnAnalyticsProcessor.md +28 -32
  62. package/docs/academy/02-MasteryTrack/04-WorkWithData/_ARCHIVE-AnalyticsProcessorTutorial/_04-UpdateAnalyticsProcessor.md +25 -26
  63. package/docs/academy/02-MasteryTrack/04-WorkWithData/_ARCHIVE-AnalyticsProcessorTutorial/_category_.json +1 -1
  64. package/docs/academy/02-MasteryTrack/04-WorkWithData/_category_.json +7 -7
  65. package/docs/academy/02-MasteryTrack/05-Launch/01-IntroductionToPackages.md +3 -4
  66. package/docs/academy/02-MasteryTrack/05-Launch/02-PublishYourProject.md +69 -45
  67. package/docs/academy/02-MasteryTrack/05-Launch/03-SetupEnvironment.md +70 -40
  68. package/docs/academy/02-MasteryTrack/05-Launch/04-ConfigureEnvironment.md +1 -0
  69. package/docs/academy/02-MasteryTrack/05-Launch/_category_.json +7 -7
  70. package/docs/academy/02-MasteryTrack/_category_.json +6 -6
  71. package/docs/academy/03-ExampleUsecases/Chatroom/02-CreateNewPowerhouseProject.md +5 -3
  72. package/docs/academy/03-ExampleUsecases/Chatroom/03-DefineChatroomDocumentModel.md +38 -37
  73. package/docs/academy/03-ExampleUsecases/Chatroom/04-ImplementOperationReducers.md +45 -41
  74. package/docs/academy/03-ExampleUsecases/Chatroom/05-ImplementChatroomEditor.md +14 -14
  75. package/docs/academy/03-ExampleUsecases/Chatroom/06-LaunchALocalReactor.md +6 -6
  76. package/docs/academy/03-ExampleUsecases/Chatroom/_category_.json +1 -1
  77. package/docs/academy/04-APIReferences/00-PowerhouseCLI.md +104 -43
  78. package/docs/academy/04-APIReferences/01-ReactHooks.md +177 -129
  79. package/docs/academy/04-APIReferences/04-RelationalDatabase.md +121 -113
  80. package/docs/academy/04-APIReferences/05-PHDocumentMigrationGuide.md +48 -41
  81. package/docs/academy/04-APIReferences/_category_.json +6 -6
  82. package/docs/academy/05-Architecture/00-PowerhouseArchitecture.md +1 -2
  83. package/docs/academy/05-Architecture/01-WorkingWithTheReactor.md +11 -8
  84. package/docs/academy/05-Architecture/05-DocumentModelTheory/_category_.json +1 -1
  85. package/docs/academy/05-Architecture/_category_.json +6 -6
  86. package/docs/academy/06-ComponentLibrary/00-DocumentEngineering.md +25 -23
  87. package/docs/academy/06-ComponentLibrary/02-CreateCustomScalars.md +105 -93
  88. package/docs/academy/06-ComponentLibrary/03-IntegrateIntoAReactComponent.md +1 -0
  89. package/docs/academy/06-ComponentLibrary/_category_.json +7 -7
  90. package/docs/academy/07-Cookbook.md +268 -35
  91. package/docs/academy/08-Glossary.md +7 -1
  92. package/docs/bookofpowerhouse/01-Overview.md +2 -2
  93. package/docs/bookofpowerhouse/02-GeneralFrameworkAndPhilosophy.md +1 -7
  94. package/docs/bookofpowerhouse/03-PowerhouseSoftwareArchitecture.md +10 -7
  95. package/docs/bookofpowerhouse/04-DevelopmentApproaches.md +10 -4
  96. package/docs/bookofpowerhouse/05-SNOsandANewModelForOSSandPublicGoods.md +23 -30
  97. package/docs/bookofpowerhouse/06-SNOsInActionAndPlatformEconomies.md +0 -7
  98. package/docusaurus.config.ts +64 -66
  99. package/package.json +9 -7
  100. package/scripts/generate-combined-cli-docs.ts +43 -13
  101. package/sidebars.ts +2 -0
  102. package/src/components/HomepageFeatures/index.tsx +171 -78
  103. package/src/components/HomepageFeatures/styles.module.css +1 -2
  104. package/src/css/custom.css +89 -89
  105. package/src/pages/_archive-homepage.tsx +17 -16
  106. package/src/theme/DocCardList/index.tsx +9 -8
  107. package/static.json +6 -6
  108. package/tsconfig.tsbuildinfo +1 -0
@@ -48,16 +48,17 @@ Review the generated template and modify it to better suit your document model:
48
48
  ### About the drive app template
49
49
 
50
50
  The default template provides a solid foundation. It contains:
51
+
51
52
  - A tree structure navigation panel
52
53
  - Basic file/folder operations
53
- - Standard layout components
54
+ - Standard layout components
54
55
 
55
56
  But the real power comes from tailoring the interface to your specific document models.
56
57
  Now, let's implement a specific example for the to-do list we've been working on throughout this guide.
57
58
 
58
59
  ## Implementation example: To-do drive explorer
59
60
 
60
- This example demonstrates how to create a To-do Drive Explorer application using the Powerhouse platform.
61
+ This example demonstrates how to create a To-do Drive Explorer application using the Powerhouse platform.
61
62
  The application allows users to create and manage to-do lists with a visual progress indicator.
62
63
 
63
64
  :::warning Heads-up!
@@ -69,6 +70,7 @@ If not, you can follow the shortened guide below to prepare your project for thi
69
70
  <summary>Prepare your Powerhouse Project to create a custom drive</summary>
70
71
 
71
72
  ### 1. Create a To-do document model:
73
+
72
74
  - Initialize a new project with `ph init` and give it a project name.
73
75
 
74
76
  - Start by running Connect locally with `ph connect`
@@ -77,20 +79,23 @@ If not, you can follow the shortened guide below to prepare your project for thi
77
79
  - Place the downloaded file in the root of your project directory.
78
80
  - Generate the document model:
79
81
 
80
- ```bash
81
- ph generate todolist.phdm.zip
82
- ```
82
+ ```bash
83
+ ph generate todolist.phdm.zip
84
+ ```
85
+
86
+ ### 2. Add the reducer code:
83
87
 
84
- ### 2. Add the reducer code:
85
88
  - Copy the code from [`base-operations.ts`](https://github.com/powerhouse-inc/todo-demo-package/blob/production/document-models/to-do-list/src/reducers/base-operations.ts)
86
89
  - Paste it into `document-models/to-do/src/reducers/base-operations.ts`
87
90
 
88
91
  ### 3. Generate a document editor:
92
+
89
93
  ```bash
90
94
  ph generate --editor ToDoList --document-types powerhouse/todolist
91
95
  ```
92
96
 
93
97
  ### 4. Add the editor code:
98
+
94
99
  - Copy the code from [`editor.tsx`](https://github.com/powerhouse-inc/todo-demo-package/blob/production/editors/to-do-list/editor.tsx)
95
100
  - Paste it into `editors/to-do-list/editor.tsx`
96
101
  </details>
@@ -99,6 +104,7 @@ ph generate --editor ToDoList --document-types powerhouse/todolist
99
104
  ## Generate the drive explorer app
100
105
 
101
106
  ### 1. Generate a drive explorer app:
107
+
102
108
  ```bash
103
109
  ph generate --drive-editor todo-drive-explorer
104
110
  ```
@@ -109,37 +115,36 @@ ph generate --drive-editor todo-drive-explorer
109
115
 
110
116
  ```json
111
117
  {
112
- "name": "To-do List Package",
113
- "description": "A simple todo list with a dedicated Drive Explorer App",
114
- "category": "Productivity",
115
- "publisher": {
116
- "name": "Powerhouse",
117
- "url": "https://www.powerhouse.inc/"
118
- },
119
- "documentModels": [
120
- {
121
- "id": "to-do-list",
122
- "name": "To-do List"
123
- }
124
- ],
125
- "editors": [
126
- {
127
- "id": "to-do-list-editor",
128
- "name": "To-do List Editor",
129
- "documentTypes": ["todo-list"]
130
- }
131
- ],
132
- "apps": [
133
- {
134
- "id": "todo-drive-explorer",
135
- "name": "To-do Drive App",
136
- "driveEditor": "todo-drive-explorer"
137
- }
138
- ],
139
- "subgraphs": [],
140
- "importScripts": []
118
+ "name": "To-do List Package",
119
+ "description": "A simple todo list with a dedicated Drive Explorer App",
120
+ "category": "Productivity",
121
+ "publisher": {
122
+ "name": "Powerhouse",
123
+ "url": "https://www.powerhouse.inc/"
124
+ },
125
+ "documentModels": [
126
+ {
127
+ "id": "to-do-list",
128
+ "name": "To-do List"
141
129
  }
142
-
130
+ ],
131
+ "editors": [
132
+ {
133
+ "id": "to-do-list-editor",
134
+ "name": "To-do List Editor",
135
+ "documentTypes": ["todo-list"]
136
+ }
137
+ ],
138
+ "apps": [
139
+ {
140
+ "id": "todo-drive-explorer",
141
+ "name": "To-do Drive App",
142
+ "driveEditor": "todo-drive-explorer"
143
+ }
144
+ ],
145
+ "subgraphs": [],
146
+ "importScripts": []
147
+ }
143
148
  ```
144
149
 
145
150
  ### 3. Remove Unnecessary Default Components:
@@ -155,7 +160,7 @@ rm -rf editors/todo-drive-explorer/components/FolderTree.tsx
155
160
 
156
161
  ### 4. Create custom components for your drive explorer:
157
162
 
158
- - Next, create the following files. These will define the data types for our to-do items and provide the custom React components for our Drive Explorer.
163
+ - Next, create the following files. These will define the data types for our to-do items and provide the custom React components for our Drive Explorer.
159
164
 
160
165
  <details>
161
166
  <summary>Create `editors/todo-drive-explorer/types/todo.ts`</summary>
@@ -174,6 +179,7 @@ rm -rf editors/todo-drive-explorer/components/FolderTree.tsx
174
179
  global: ToDoListDocument["state"]["global"];
175
180
  };
176
181
  ```
182
+
177
183
  </details>
178
184
 
179
185
  <details>
@@ -213,355 +219,360 @@ rm -rf editors/todo-drive-explorer/components/FolderTree.tsx
213
219
  </div>
214
220
  </div>
215
221
  );
216
- };
222
+ };
217
223
  ```
218
224
  </details>
219
225
 
220
226
  <details>
221
227
  <summary>Update `editors/todo-drive-explorer/components/DriveExplorer.tsx`</summary>
222
228
 
223
- This is the main component of our Drive Explorer. It fetches all `powerhouse/todo` documents from the drive, displays them in a table with their progress, and allows a user to click on a document to open it in the `EditorContainer`. It also includes a button to create new documents.
224
-
225
- ```typescript
226
- import { useCallback, useState, useRef, useEffect, useMemo } from "react";
227
- import type { FileNode, GetDocumentOptions, Node } from "document-drive";
228
- import { EditorContainer, EditorContainerProps } from "./EditorContainer.js";
229
- import type { DocumentModelModule } from "document-model";
230
- import { CreateDocumentModal } from "@powerhousedao/design-system";
231
- import { CreateDocument } from "./CreateDocument.js";
232
- import { type DriveEditorContext, useDriveContext } from "@powerhousedao/reactor-browser";
233
- import { ProgressBar } from "./ProgressBar.js";
234
-
235
- import { type ToDoState } from "../types/todo.js"
236
-
237
- interface DriveExplorerProps {
238
- driveId: string;
239
- nodes: Node[];
240
- onAddFolder: (name: string, parentFolder?: string) => void;
241
- onDeleteNode: (nodeId: string) => void;
242
- renameNode: (nodeId: string, name: string) => void;
243
- onCopyNode: (nodeId: string, targetName: string, parentId?: string) => void;
244
- context: DriveEditorContext;
245
- }
246
-
247
- export function DriveExplorer({
248
- driveId,
249
- nodes,
250
- context,
251
- }: DriveExplorerProps) {
252
- const { getDocumentRevision } = context;
253
-
254
- const [activeDocumentId, setActiveDocumentId] = useState<
255
- string | undefined
256
- >();
257
- const [openModal, setOpenModal] = useState(false);
258
- const selectedDocumentModel = useRef<DocumentModelModule | null>(null);
259
- const { addDocument, documentModels, useDriveDocumentStates } = useDriveContext();
260
-
261
- const [state, fetchDocuments] = useDriveDocumentStates({ driveId });
262
-
263
- useEffect(() => {
264
- fetchDocuments(driveId).catch(console.error);
265
- }, [activeDocumentId]);
266
-
267
- const { todoNodes } = useMemo(() => {
268
- return Object.keys(state).reduce(
269
- (acc, curr) => {
270
- const document = state[curr];
271
- if (document.documentType.startsWith("powerhouse/todo")) {
272
- acc.todoNodes[curr] = document as ToDoState;
273
- }
274
-
275
- return acc;
276
- },
277
- {
278
- todoNodes: {} as Record<string, ToDoState>,
279
- },
280
- );
281
- }, [state]);
229
+ This is the main component of our Drive Explorer. It fetches all `powerhouse/todo` documents from the drive, displays them in a table with their progress, and allows a user to click on a document to open it in the `EditorContainer`. It also includes a button to create new documents.
230
+
231
+ ```typescript
232
+ import { useCallback, useState, useRef, useEffect, useMemo } from "react";
233
+ import type { FileNode, GetDocumentOptions, Node } from "document-drive";
234
+ import { EditorContainer, EditorContainerProps } from "./EditorContainer.js";
235
+ import type { DocumentModelModule } from "document-model";
236
+ import { CreateDocumentModal } from "@powerhousedao/design-system";
237
+ import { CreateDocument } from "./CreateDocument.js";
238
+ import { type DriveEditorContext, useDriveContext } from "@powerhousedao/reactor-browser";
239
+ import { ProgressBar } from "./ProgressBar.js";
240
+
241
+ import { type ToDoState } from "../types/todo.js"
242
+
243
+ interface DriveExplorerProps {
244
+ driveId: string;
245
+ nodes: Node[];
246
+ onAddFolder: (name: string, parentFolder?: string) => void;
247
+ onDeleteNode: (nodeId: string) => void;
248
+ renameNode: (nodeId: string, name: string) => void;
249
+ onCopyNode: (nodeId: string, targetName: string, parentId?: string) => void;
250
+ context: DriveEditorContext;
251
+ }
252
+
253
+ export function DriveExplorer({
254
+ driveId,
255
+ nodes,
256
+ context,
257
+ }: DriveExplorerProps) {
258
+ const { getDocumentRevision } = context;
259
+
260
+ const [activeDocumentId, setActiveDocumentId] = useState<
261
+ string | undefined
262
+ >();
263
+ const [openModal, setOpenModal] = useState(false);
264
+ const selectedDocumentModel = useRef<DocumentModelModule | null>(null);
265
+ const { addDocument, documentModels, useDriveDocumentStates } = useDriveContext();
266
+
267
+ const [state, fetchDocuments] = useDriveDocumentStates({ driveId });
268
+
269
+ useEffect(() => {
270
+ fetchDocuments(driveId).catch(console.error);
271
+ }, [activeDocumentId]);
272
+
273
+ const { todoNodes } = useMemo(() => {
274
+ return Object.keys(state).reduce(
275
+ (acc, curr) => {
276
+ const document = state[curr];
277
+ if (document.documentType.startsWith("powerhouse/todo")) {
278
+ acc.todoNodes[curr] = document as ToDoState;
279
+ }
282
280
 
281
+ return acc;
282
+ },
283
+ {
284
+ todoNodes: {} as Record<string, ToDoState>,
285
+ },
286
+ );
287
+ }, [state]);
283
288
 
284
- const handleEditorClose = useCallback(() => {
285
- setActiveDocumentId(undefined);
286
- }, []);
287
289
 
288
- const onCreateDocument = useCallback(
289
- async (fileName: string) => {
290
- setOpenModal(false);
290
+ const handleEditorClose = useCallback(() => {
291
+ setActiveDocumentId(undefined);
292
+ }, []);
291
293
 
292
- const documentModel = selectedDocumentModel.current;
293
- if (!documentModel) return;
294
+ const onCreateDocument = useCallback(
295
+ async (fileName: string) => {
296
+ setOpenModal(false);
294
297
 
295
- const node = await addDocument(
296
- driveId,
297
- fileName,
298
- documentModel.documentModel.id,
299
- );
298
+ const documentModel = selectedDocumentModel.current;
299
+ if (!documentModel) return;
300
300
 
301
- selectedDocumentModel.current = null;
302
- setActiveDocumentId(node.id);
303
- },
304
- [addDocument, driveId],
305
- );
301
+ const node = await addDocument(
302
+ driveId,
303
+ fileName,
304
+ documentModel.documentModel.id,
305
+ );
306
306
 
307
- const onSelectDocumentModel = useCallback(
308
- (documentModel: DocumentModelModule) => {
309
- selectedDocumentModel.current = documentModel;
310
- setOpenModal(true);
311
- },
312
- [],
313
- );
307
+ selectedDocumentModel.current = null;
308
+ setActiveDocumentId(node.id);
309
+ },
310
+ [addDocument, driveId],
311
+ );
312
+
313
+ const onSelectDocumentModel = useCallback(
314
+ (documentModel: DocumentModelModule) => {
315
+ selectedDocumentModel.current = documentModel;
316
+ setOpenModal(true);
317
+ },
318
+ [],
319
+ );
320
+
321
+ const onGetDocumentRevision = useCallback(
322
+ (options?: GetDocumentOptions) => {
323
+ if (!activeDocumentId) return;
324
+ return getDocumentRevision?.(activeDocumentId, options);
325
+ },
326
+ [getDocumentRevision, activeDocumentId],
327
+ );
328
+
329
+ const filteredDocumentModels = documentModels;
330
+
331
+
332
+ const fileNodes = nodes.filter((node) => node.kind === "file") as FileNode[];
333
+ // Get the active document info from nodes
334
+ const activeDocument = activeDocumentId
335
+ ? fileNodes.find((file) => file.id === activeDocumentId)
336
+ : undefined;
337
+
338
+ const documentModelModule = activeDocument
339
+ ? context.getDocumentModelModule(activeDocument.documentType)
340
+ : null;
341
+
342
+ const editorModule = activeDocument
343
+ ? context.getEditor(activeDocument.documentType)
344
+ : null;
345
+
346
+
347
+ return (
348
+ <div className="flex h-full">
349
+ {/* Main Content */}
350
+ <div className="flex-1 p-4 overflow-y-auto">
351
+ {activeDocument && documentModelModule && editorModule ? (
352
+ <EditorContainer
353
+ context={{
354
+ ...context,
355
+ getDocumentRevision: onGetDocumentRevision,
356
+ }}
357
+ documentId={activeDocumentId!}
358
+ documentType={activeDocument.documentType}
359
+ driveId={driveId}
360
+ onClose={handleEditorClose}
361
+ title={activeDocument.name}
362
+ documentModelModule={documentModelModule}
363
+ editorModule={editorModule}
364
+ />
365
+ ) : (
366
+ <>
367
+ <h2 className="text-lg font-semibold mb-4">ToDos:</h2>
368
+ <div className="overflow-x-auto">
369
+ <table className="min-w-full divide-y divide-gray-200">
370
+ <thead className="bg-gray-50">
371
+ <tr>
372
+ <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Document ID</th>
373
+ <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Document Type</th>
374
+ <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Tasks</th>
375
+ <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Completed</th>
376
+ <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Progress</th>
377
+ </tr>
378
+ </thead>
379
+ <tbody className="bg-white divide-y divide-gray-200">
380
+ {Object.entries(todoNodes).map(([documentId, todoNode]) => (
381
+ <tr key={documentId} className="hover:bg-gray-50">
382
+ <td className="px-6 py-4 whitespace-nowrap">
383
+ <div
384
+ onClick={() => setActiveDocumentId(documentId)}
385
+ className="text-blue-600 hover:text-blue-800 cursor-pointer"
386
+ >
387
+ {documentId}
388
+ </div>
389
+ </td>
390
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
391
+ {todoNode.documentType}
392
+ </td>
393
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
394
+ {todoNode.global.stats.total}
395
+ </td>
396
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
397
+ {todoNode.global.stats.checked}
398
+ </td>
399
+ <td className="px-6 py-4 whitespace-nowrap">
400
+ <div className="w-32">
401
+ <ProgressBar
402
+ value={todoNode.global.stats.checked}
403
+ max={todoNode.global.stats.total}
404
+ />
405
+ </div>
406
+ </td>
407
+ </tr>
408
+ ))}
409
+ </tbody>
410
+ </table>
411
+ </div>
314
412
 
315
- const onGetDocumentRevision = useCallback(
316
- (options?: GetDocumentOptions) => {
317
- if (!activeDocumentId) return;
318
- return getDocumentRevision?.(activeDocumentId, options);
319
- },
320
- [getDocumentRevision, activeDocumentId],
321
- );
413
+ {/* Create Document Section */}
414
+ <CreateDocument
415
+ createDocument={onSelectDocumentModel}
416
+ documentModels={filteredDocumentModels}
417
+ />
418
+ </>
419
+ )}
420
+ </div>
322
421
 
323
- const filteredDocumentModels = documentModels;
324
-
325
-
326
- const fileNodes = nodes.filter((node) => node.kind === "file") as FileNode[];
327
- // Get the active document info from nodes
328
- const activeDocument = activeDocumentId
329
- ? fileNodes.find((file) => file.id === activeDocumentId)
330
- : undefined;
331
-
332
- const documentModelModule = activeDocument
333
- ? context.getDocumentModelModule(activeDocument.documentType)
334
- : null;
335
-
336
- const editorModule = activeDocument
337
- ? context.getEditor(activeDocument.documentType)
338
- : null;
339
-
340
-
341
- return (
342
- <div className="flex h-full">
343
- {/* Main Content */}
344
- <div className="flex-1 p-4 overflow-y-auto">
345
- {activeDocument && documentModelModule && editorModule ? (
346
- <EditorContainer
347
- context={{
348
- ...context,
349
- getDocumentRevision: onGetDocumentRevision,
350
- }}
351
- documentId={activeDocumentId!}
352
- documentType={activeDocument.documentType}
353
- driveId={driveId}
354
- onClose={handleEditorClose}
355
- title={activeDocument.name}
356
- documentModelModule={documentModelModule}
357
- editorModule={editorModule}
358
- />
359
- ) : (
360
- <>
361
- <h2 className="text-lg font-semibold mb-4">ToDos:</h2>
362
- <div className="overflow-x-auto">
363
- <table className="min-w-full divide-y divide-gray-200">
364
- <thead className="bg-gray-50">
365
- <tr>
366
- <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Document ID</th>
367
- <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Document Type</th>
368
- <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Tasks</th>
369
- <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Completed</th>
370
- <th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Progress</th>
371
- </tr>
372
- </thead>
373
- <tbody className="bg-white divide-y divide-gray-200">
374
- {Object.entries(todoNodes).map(([documentId, todoNode]) => (
375
- <tr key={documentId} className="hover:bg-gray-50">
376
- <td className="px-6 py-4 whitespace-nowrap">
377
- <div
378
- onClick={() => setActiveDocumentId(documentId)}
379
- className="text-blue-600 hover:text-blue-800 cursor-pointer"
380
- >
381
- {documentId}
382
- </div>
383
- </td>
384
- <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
385
- {todoNode.documentType}
386
- </td>
387
- <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
388
- {todoNode.global.stats.total}
389
- </td>
390
- <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
391
- {todoNode.global.stats.checked}
392
- </td>
393
- <td className="px-6 py-4 whitespace-nowrap">
394
- <div className="w-32">
395
- <ProgressBar
396
- value={todoNode.global.stats.checked}
397
- max={todoNode.global.stats.total}
398
- />
399
- </div>
400
- </td>
401
- </tr>
402
- ))}
403
- </tbody>
404
- </table>
405
- </div>
406
-
407
- {/* Create Document Section */}
408
- <CreateDocument
409
- createDocument={onSelectDocumentModel}
410
- documentModels={filteredDocumentModels}
411
- />
412
- </>
413
- )}
414
- </div>
422
+ {/* Create Document Modal */}
423
+ <CreateDocumentModal
424
+ onContinue={onCreateDocument}
425
+ onOpenChange={(open) => setOpenModal(open)}
426
+ open={openModal}
427
+ />
428
+ </div>
429
+ );
430
+ }
431
+ ```
415
432
 
416
- {/* Create Document Modal */}
417
- <CreateDocumentModal
418
- onContinue={onCreateDocument}
419
- onOpenChange={(open) => setOpenModal(open)}
420
- open={openModal}
421
- />
422
- </div>
423
- );
424
- }
425
- ```
426
433
  </details>
427
434
 
428
-
429
435
  <details>
430
436
  <summary>Update `editors/todo-drive-explorer/components/EditorContainer.tsx`</summary>
431
437
 
432
- This component acts as a wrapper for the document editor. When a user selects a document in `DriveExplorer.tsx`, this component mounts the appropriate editor (`to-do-list` editor in this case) and provides it with the necessary context and properties to function. It also renders the `DocumentToolbar` which provides actions like closing, exporting, and viewing revision history.
433
-
434
- ```typescript
435
- import {
436
- useDriveContext,
437
- exportDocument,
438
- type User,
439
- type DriveEditorContext,
440
- } from "@powerhousedao/reactor-browser";
441
- import {
442
- documentModelDocumentModelModule,
443
- type DocumentModelModule,
444
- type EditorContext,
445
- type EditorProps,
446
- type PHDocument,
447
- type EditorModule,
448
- type Operation,
449
- } from "document-model";
450
- import { useTimelineItems, getRevisionFromDate } from "@powerhousedao/common";
451
- import {
452
- DocumentToolbar,
453
- RevisionHistory,
454
- DefaultEditorLoader,
455
- generateLargeTimeline,
456
- type TimelineItem,
457
- } from "@powerhousedao/design-system";
458
- import { useState, Suspense, type FC, useCallback } from "react";
459
-
460
- export interface EditorContainerProps {
461
- driveId: string;
462
- documentId: string;
463
- documentType: string;
464
- onClose: () => void;
465
- title: string;
466
- context: Omit<DriveEditorContext, "getDocumentRevision"> &
467
- Pick<EditorContext, "getDocumentRevision">;
468
- documentModelModule: DocumentModelModule<PHDocument>;
469
- editorModule: EditorModule;
438
+ This component acts as a wrapper for the document editor. When a user selects a document in `DriveExplorer.tsx`, this component mounts the appropriate editor (`to-do-list` editor in this case) and provides it with the necessary context and properties to function. It also renders the `DocumentToolbar` which provides actions like closing, exporting, and viewing revision history.
439
+
440
+ ```typescript
441
+ import {
442
+ useDriveContext,
443
+ exportDocument,
444
+ type User,
445
+ type DriveEditorContext,
446
+ } from "@powerhousedao/reactor-browser";
447
+ import {
448
+ documentModelDocumentModelModule,
449
+ type DocumentModelModule,
450
+ type EditorContext,
451
+ type EditorProps,
452
+ type PHDocument,
453
+ type EditorModule,
454
+ type Operation,
455
+ } from "document-model";
456
+ import { useTimelineItems, getRevisionFromDate } from "@powerhousedao/common";
457
+ import {
458
+ DocumentToolbar,
459
+ RevisionHistory,
460
+ DefaultEditorLoader,
461
+ generateLargeTimeline,
462
+ type TimelineItem,
463
+ } from "@powerhousedao/design-system";
464
+ import { useState, Suspense, type FC, useCallback } from "react";
465
+
466
+ export interface EditorContainerProps {
467
+ driveId: string;
468
+ documentId: string;
469
+ documentType: string;
470
+ onClose: () => void;
471
+ title: string;
472
+ context: Omit<DriveEditorContext, "getDocumentRevision"> &
473
+ Pick<EditorContext, "getDocumentRevision">;
474
+ documentModelModule: DocumentModelModule<PHDocument>;
475
+ editorModule: EditorModule;
476
+ }
477
+
478
+ export const EditorContainer: React.FC<EditorContainerProps> = (props) => {
479
+ const { driveId, documentId, documentType, onClose, title, context, documentModelModule, editorModule } = props;
480
+
481
+ const [selectedTimelineItem, setSelectedTimelineItem] = useState<TimelineItem | null>(null);
482
+ const [showRevisionHistory, setShowRevisionHistory] = useState(false);
483
+ const { useDocumentEditorProps } = useDriveContext();
484
+ const user = context.user as User | undefined;
485
+ const timelineItems = useTimelineItems(documentId);
486
+
487
+ const { dispatch, error, document } = useDocumentEditorProps({
488
+ documentId,
489
+ documentType,
490
+ driveId,
491
+ documentModelModule,
492
+ user,
493
+ });
494
+
495
+ const onExport = useCallback(async () => {
496
+ if (document) {
497
+ const ext = documentModelModule.documentModel.extension;
498
+ await exportDocument(document, title, ext);
470
499
  }
471
-
472
- export const EditorContainer: React.FC<EditorContainerProps> = (props) => {
473
- const { driveId, documentId, documentType, onClose, title, context, documentModelModule, editorModule } = props;
474
-
475
- const [selectedTimelineItem, setSelectedTimelineItem] = useState<TimelineItem | null>(null);
476
- const [showRevisionHistory, setShowRevisionHistory] = useState(false);
477
- const { useDocumentEditorProps } = useDriveContext();
478
- const user = context.user as User | undefined;
479
- const timelineItems = useTimelineItems(documentId);
480
-
481
- const { dispatch, error, document } = useDocumentEditorProps({
482
- documentId,
483
- documentType,
484
- driveId,
485
- documentModelModule,
486
- user,
487
- });
488
-
489
- const onExport = useCallback(async () => {
490
- if (document) {
491
- const ext = documentModelModule.documentModel.extension;
492
- await exportDocument(document, title, ext);
493
- }
494
- }, [document?.revision.global, document?.revision.local]);
495
-
496
- const loadingContent = (
497
- <div className="flex-1 flex justify-center items-center h-full">
498
- <DefaultEditorLoader />
499
- </div>
500
- );
501
-
502
- if (!document) return loadingContent;
503
-
504
- const moduleWithComponent = editorModule as EditorModule<PHDocument>;
505
- const EditorComponent = moduleWithComponent.Component;
506
-
507
- return showRevisionHistory ? (
508
- <RevisionHistory
509
- documentId={documentId}
510
- documentTitle={title}
511
- globalOperations={document.operations.global}
512
- key={documentId}
513
- localOperations={document.operations.local}
514
- onClose={() => setShowRevisionHistory(false)}
500
+ }, [document?.revision.global, document?.revision.local]);
501
+
502
+ const loadingContent = (
503
+ <div className="flex-1 flex justify-center items-center h-full">
504
+ <DefaultEditorLoader />
505
+ </div>
506
+ );
507
+
508
+ if (!document) return loadingContent;
509
+
510
+ const moduleWithComponent = editorModule as EditorModule<PHDocument>;
511
+ const EditorComponent = moduleWithComponent.Component;
512
+
513
+ return showRevisionHistory ? (
514
+ <RevisionHistory
515
+ documentId={documentId}
516
+ documentTitle={title}
517
+ globalOperations={document.operations.global}
518
+ key={documentId}
519
+ localOperations={document.operations.local}
520
+ onClose={() => setShowRevisionHistory(false)}
521
+ />
522
+ ) : (
523
+ <Suspense fallback={loadingContent}>
524
+ <DocumentToolbar
525
+ onClose={onClose}
526
+ onExport={onExport}
527
+ onShowRevisionHistory={() => setShowRevisionHistory(true)}
528
+ onSwitchboardLinkClick={() => {}}
529
+ title={title}
530
+ timelineButtonVisible
531
+ timelineItems={timelineItems.data}
532
+ onTimelineItemClick={setSelectedTimelineItem}
515
533
  />
516
- ) : (
517
- <Suspense fallback={loadingContent}>
518
- <DocumentToolbar
519
- onClose={onClose}
520
- onExport={onExport}
521
- onShowRevisionHistory={() => setShowRevisionHistory(true)}
522
- onSwitchboardLinkClick={() => {}}
523
- title={title}
524
- timelineButtonVisible
525
- timelineItems={timelineItems.data}
526
- onTimelineItemClick={setSelectedTimelineItem}
527
- />
528
- <EditorComponent
529
- context={{
530
- ...context,
531
- readMode: !!selectedTimelineItem,
532
- selectedTimelineRevision: getRevisionFromDate(
533
- selectedTimelineItem?.startDate,
534
- selectedTimelineItem?.endDate,
535
- document.operations.global,
536
- ),
537
- }}
538
- dispatch={dispatch}
539
- document={document}
540
- error={error}
541
- />
542
- </Suspense>
543
- );
544
- };
545
- ```
534
+ <EditorComponent
535
+ context={{
536
+ ...context,
537
+ readMode: !!selectedTimelineItem,
538
+ selectedTimelineRevision: getRevisionFromDate(
539
+ selectedTimelineItem?.startDate,
540
+ selectedTimelineItem?.endDate,
541
+ document.operations.global,
542
+ ),
543
+ }}
544
+ dispatch={dispatch}
545
+ document={document}
546
+ error={error}
547
+ />
548
+ </Suspense>
549
+ );
550
+ };
551
+ ```
552
+
546
553
  </details>
547
554
 
548
555
  - In case you are getting stuck and want to verify your progress with the reference repository you can find the example repository of the [Todo-demo-package here](/academy/MasteryTrack/DocumentModelCreation/ExampleToDoListRepository)
556
+
549
557
  ### 3. Run the application:
558
+
550
559
  - With the code for our Drive App in place, it's time to see it in action. Run Connect in Studio mode:
551
- ```bash
552
- ph connect
553
- ```
554
560
 
555
- ![Todo Drive Explorer Demo](https://raw.githubusercontent.com/powerhouse-inc/todo-drive-explorer/9a87871e61460e73ddf8635fd756a0cd991306d6/demo.gif)
561
+ ```bash
562
+ ph connect
563
+ ```
564
+
565
+ ![Todo Drive Explorer Demo](https://raw.githubusercontent.com/powerhouse-inc/todo-drive-explorer/9a87871e61460e73ddf8635fd756a0cd991306d6/demo.gif)
556
566
 
557
567
  ### Now it's your turn!
568
+
558
569
  Start building your own drive apps, explorers or experiences.
559
570
  Congratulations on completing this tutorial!
560
571
  You've successfully built a custom Drive Explorer, enhancing the way users interact with document models.
561
572
 
562
573
  Now, take a moment to think about the possibilities!
574
+
563
575
  - What **unique Drive Experiences** could you create for your own projects?
564
576
  - How can you tailor interfaces and streamline workflows to unlock the full potential of your document models?
565
577
 
566
578
  The Powerhouse platform provides the tools. It's time to start building!
567
-