@powerhousedao/academy 3.2.0-dev.3 → 3.2.0-dev.4

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 (17) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/docs/academy/01-GetStarted/home.mdx +6 -6
  3. package/docs/academy/02-MasteryTrack/01-BuilderEnvironment/02-StandardDocumentModelWorkflow.md +3 -2
  4. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/07-ExampleToDoListRepository.md +4 -4
  5. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/01-BuildingDocumentEditors.md +5 -4
  6. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/02-ConfiguringDrives.md +0 -2
  7. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/03-BuildingADriveExplorer.md +483 -89
  8. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/07-DocumentTools/{00-DocumentToolbar.md → 00-DocumentToolbar.mdx} +7 -2
  9. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/07-DocumentTools/01-OperationHistory.md +3 -3
  10. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/07-DocumentTools/02-RevisionHistoryTimeline.md +14 -3
  11. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/07-DocumentTools/images/DocumentToolbar.png +0 -0
  12. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/07-DocumentTools/images/revision-history-timeline.png +0 -0
  13. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/08-Authorization/01-RenownAuthenticationFlow.md +14 -3
  14. package/docs/academy/02-MasteryTrack/04-WorkWithData/01-ReadingAndWritingThroughTheAPI.mdx +9 -15
  15. package/docs/academy/04-APIReferences/01-ReactHooks.md +209 -0
  16. package/package.json +1 -1
  17. package/docs/academy/04-APIReferences/01-ReactHooks +0 -98
@@ -1,32 +1,30 @@
1
1
  # Build a drive explorer
2
2
 
3
- **Drive Explorers or Drive Apps** enhance how contributors and organizations interact with document models.
4
- An 'app-like' experience is created by providing a **custom interface** for working with or exploring the contents of a drive.
5
- :::tip
6
- A 'Drive Explorer or Drive App' offers a tailored application designed around its document models.
3
+ **Drive Explorers (or Drive Apps)** enhance how contributors and organizations interact with document models.
4
+ They create an 'app-like' experience by providing a **custom interface** for exploring and interacting with the contents of a drive.
5
+ :::tip What is a Drive Explorer or Drive App?
6
+ A Drive Explorer or Drive App offers a tailored application designed around its document models.
7
7
  Think of a Drive Explorer as a specialized lens—it offers **different ways to visualize, organize, and interact with** the data stored within a drive, making it more intuitive and efficient for specific use cases.
8
8
  :::
9
9
 
10
- ### **Designed for specific use cases**
10
+ ### Drive explorers are purpose-built
11
11
 
12
- Most Drive Explorers are built by organizations for specific purposes, aligning closely with a document model package or even being part of one. By integrating Drive Apps with document models, organizations can customize user experiences, streamline workflows, and maximize efficiency for their contributors.
12
+ Organizations typically build Drive Explorers for specific use cases, often packaging them with a corresponding document model. This allows for customized user experiences, streamlined workflows, and maximized efficiency for contributors.
13
13
 
14
14
  Drive Explorers or Drive Apps **bridge the gap between raw data and usability**, unlocking the full potential of document models within the Powerhouse framework.
15
15
 
16
- ### **Key features of drive apps**
16
+ ### Key features of drive apps
17
17
 
18
18
  - **Custom Views & Organization** – Drive Apps can present data in formats like Kanban boards, list views, or other structured layouts to suit different workflows.
19
19
  - **Aggregated Insights** – They can provide high-level summaries of important details across document models, enabling quick decision-making.
20
20
  - **Enhanced Interactivity** – Drive Apps can include widgets, data processors, or read models to process and display document data dynamically.
21
21
 
22
- ### **Building a drive app**
22
+ ## Build a drive app
23
23
 
24
- #### The steps of our tutorial
24
+ Drive Apps provide custom interfaces for interacting with the contents of a drive.
25
+ Let's start with a **quick overview** of the three steps for building a Drive App. We will then apply these steps to create our **To-do List Drive App**.
25
26
 
26
- Drive Apps provide custom interfaces for interacting with the contents of a drive.
27
- Here is a **quick overview** of the 3 different steps towards building a Drive App **before we dive into the Todo List Drive App**
28
-
29
- #### Step 1. Generate the scaffolding code
27
+ ### Step 1. Generate the scaffolding code
30
28
 
31
29
  Use the `generate drive editor` command to create the basic template structure for your Drive App:
32
30
 
@@ -34,12 +32,12 @@ Use the `generate drive editor` command to create the basic template structure f
34
32
  ph generate --drive-editor <Drive App>
35
33
  ```
36
34
 
37
- #### Step 2. Update the manifest file
35
+ ### Step 2. Update the manifest file
38
36
 
39
- After creating your Drive App, update the `manifest.json` file with relevant information:
40
- The manifest file identifies your project and its components within the Powerhouse ecosystem.
37
+ After creating your Drive App, you need to update its `manifest.json` file.
38
+ This file identifies your project and its components within the Powerhouse ecosystem.
41
39
 
42
- #### Step 3. Customize the drive app
40
+ ### Step 3. Customize the drive app
43
41
 
44
42
  Review the generated template and modify it to better suit your document model:
45
43
 
@@ -54,81 +52,99 @@ The default template provides a solid foundation. It contains:
54
52
  - Basic file/folder operations
55
53
  - Standard layout components
56
54
 
57
- But the real power comes from tailoring the interface to your specific document models.
58
- Now let's implement a specific example for a more complex todo-list then the one we've been working on.
55
+ But the real power comes from tailoring the interface to your specific document models.
56
+ Now, let's implement a specific example for the to-do list we've been working on throughout this guide.
59
57
 
60
- ### Implementation example: Todo drive explorer
58
+ ## Implementation example: To-do drive explorer
61
59
 
62
- This example demonstrates how to create a Todo Drive Explorer application using the Powerhouse platform.
63
- The application allows users to create and manage todo lists with a visual progress indicator.
60
+ This example demonstrates how to create a To-do Drive Explorer application using the Powerhouse platform.
61
+ The application allows users to create and manage to-do lists with a visual progress indicator.
64
62
 
65
- **1. Create a Todo Document Model:**
66
- - Initialize a new project with `ph init` and give it a project name.
63
+ :::warning Heads-up!
64
+ If you've been following the Mastery Track, you can continue with the to-do list document model and Powerhouse project you've created. For more details, you can refer to the [Document Model Creation guide](/academy/MasteryTrack/DocumentModelCreation/SpecifyTheStateSchema).
67
65
 
68
- - Start by running Connect locally with `ph connect`
66
+ If not, you can follow the shortened guide below to prepare your project for this tutorial.
69
67
 
70
- :::warning
71
- Since you've likely already run through the [document modeling process](/academy/GetStarted/DefineToDoListDocumentModel) of a simplified todo list, we'll offer you a **slightly more advanced** todo list below!
72
- :::
68
+ <details>
69
+ <summary>Prepare your Powerhouse Project to create a custom drive</summary>
73
70
 
74
- - Download [todo.phdm.zip](https://github.com/powerhouse-inc/todo-drive-explorer/blob/ee63786fa8ceed71de63cd9c52f1795ad11ac403/todo.phdm.zip) from our GitHub repo.
75
- - Place it in the project root of your project
76
- - Generate the document model:
71
+ ### 1. Create a To-do document model:
72
+ - Initialize a new project with `ph init` and give it a project name.
77
73
 
78
- ```bash
79
- ph generate todo.phdm.zip
80
- ```
74
+ - Start by running Connect locally with `ph connect`
81
75
 
82
- **2. Add the reducers code:**
83
- - Copy the code from [base-operations.ts](https://github.com/powerhouse-inc/todo-drive-explorer/blob/ee63786fa8ceed71de63cd9c52f1795ad11ac403/document-models/to-do/src/reducers/base-operations.ts)
84
- - Paste it into `document-models/to-do/src/reducers/base-operations.ts`
76
+ - Download the `todolist.phdm.zip` file from the [todo-demo-package GitHub repository](https://github.com/powerhouse-inc/todo-demo-package/blob/production/todolist.phdm.zip).
77
+ - Place the downloaded file in the root of your project directory.
78
+ - Generate the document model:
85
79
 
86
- **3. Generate a document editor:**
87
80
  ```bash
88
- ph generate --editor ToDoList --document-types powerhouse/todo
81
+ ph generate todolist.phdm.zip
89
82
  ```
90
83
 
91
- **4. Add the editor code:**
92
- - Copy the code from [editor.tsx](https://github.com/powerhouse-inc/todo-drive-explorer/blob/ee63786fa8ceed71de63cd9c52f1795ad11ac403/editors/to-do-list/editor.tsx)
93
- - Paste it into `editors/to-do-list/editor.tsx`
84
+ ### 2. Add the reducer code:
85
+ - 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
+ - Paste it into `document-models/to-do/src/reducers/base-operations.ts`
94
87
 
95
- **5. Generate a drive explorer app:**
96
- ```bash
97
- ph generate --drive-editor todo-drive-explorer
98
- ```
88
+ ### 3. Generate a document editor:
89
+ ```bash
90
+ ph generate --editor ToDoList --document-types powerhouse/todolist
91
+ ```
92
+
93
+ ### 4. Add the editor code:
94
+ - Copy the code from [`editor.tsx`](https://github.com/powerhouse-inc/todo-demo-package/blob/production/editors/to-do-list/editor.tsx)
95
+ - Paste it into `editors/to-do-list/editor.tsx`
96
+ </details>
97
+ :::
98
+
99
+ ## Generate the drive explorer app
100
+
101
+ ### 1. Generate a drive explorer app:
102
+ ```bash
103
+ ph generate --drive-editor todo-drive-explorer
104
+ ```
99
105
 
100
- **6. Update the `powerhouse.manifest.json` file to register your Drive App with all its modules.**
106
+ ### 2. Update the `powerhouse.manifest.json` file:
101
107
 
102
- - The information of the manifest file is what the user of your package will see when installing the package:
108
+ - The manifest file contains metadata for your package that is displayed when other users install it. Update the manifest to register your new Drive App:
103
109
 
104
- ```json
105
- {
106
- "name": "Todo List Package",
107
- "description": "A simple todo list with a dedicated Drive Explorer App",
108
- "category": "Productivity",
109
- "publisher": {
110
+ ```json
111
+ {
112
+ "name": "To-do List Package",
113
+ "description": "A simple todo list with a dedicated Drive Explorer App",
114
+ "category": "Productivity",
115
+ "publisher": {
110
116
  "name": "Powerhouse",
111
117
  "url": "https://www.powerhouse.inc/"
112
- },
113
- "documentModels": [],
114
- "editors": [],
115
- "apps": [
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": [
116
133
  {
117
- "id": "todo-drive-explorer",
118
- "name": "Todo Drive App",
119
- "driveEditor": "todo-drive-explorer"
134
+ "id": "todo-drive-explorer",
135
+ "name": "To-do Drive App",
136
+ "driveEditor": "todo-drive-explorer"
120
137
  }
121
- ],
122
- "subgraphs": [],
123
- "importScripts": []
124
- }
125
- ```
138
+ ],
139
+ "subgraphs": [],
140
+ "importScripts": []
141
+ }
126
142
 
127
- ### Customize the drive explorer app
143
+ ```
128
144
 
129
- **1. Remove unnecessary default components:**
145
+ ### 3. Remove Unnecessary Default Components:
130
146
 
131
- - Remove default template files that won't be needed for our specific demo. If you'd like to see what the default template Drive App looks like, you can visualize it by running `ph connect`.
147
+ - First, let's remove some default template files that we won't need for this specific demo. If you want to see what the default template looks like before removing files, you can run `ph connect` at any time.
132
148
 
133
149
  ```bash
134
150
  rm -rf editors/todo-drive-explorer/hooks
@@ -137,37 +153,415 @@ rm -rf editors/todo-drive-explorer/components/FolderItemsGrid.tsx
137
153
  rm -rf editors/todo-drive-explorer/components/FolderTree.tsx
138
154
  ```
139
155
 
140
- **2. Create new custom components for you drive explorer app:**
141
-
142
- - Create and populate the following files to create our types for the todos & our components to customize the Drive Explorer.
143
-
144
- a. Create `editors/todo-drive-explorer/types/todo.ts`:
145
- - Copy the code from [todo.ts](https://github.com/powerhouse-inc/todo-drive-explorer/blob/ee63786fa8ceed71de63cd9c52f1795ad11ac403/editors/todo-drive-explorer/types/todo.ts)
146
-
147
- This type represents the specific data structure or state shape that the todo-drive-explorer component uses to manage or display To-Do items.
148
-
149
- b. Create `editors/todo-drive-explorer/components/ProgressBar.tsx`:
150
- - Copy the code from [ProgressBar.tsx](https://github.com/powerhouse-inc/todo-drive-explorer/blob/ee63786fa8ceed71de63cd9c52f1795ad11ac403/editors/todo-drive-explorer/components/ProgressBar.tsx)
156
+ ### 4. Create custom components for your drive explorer:
157
+
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.
159
+
160
+ <details>
161
+ <summary>Create `editors/todo-drive-explorer/types/todo.ts`</summary>
162
+
163
+ This file defines the TypeScript type `ToDoState`. It specifies the shape of to-do document data within the Drive Explorer, combining the document's revision information with its global state. This ensures that our components work with a predictable and strongly-typed data structure.
164
+
165
+ ```typescript
166
+ import { type ToDoListDocument} from "../../../document-models/to-do-list/index.js"
167
+
168
+ export type ToDoState = {
169
+ documentType: string;
170
+ revision: {
171
+ global: number;
172
+ local: number;
173
+ };
174
+ global: ToDoListDocument["state"]["global"];
175
+ };
176
+ ```
177
+ </details>
178
+
179
+ <details>
180
+ <summary>Create `editors/todo-drive-explorer/components/ProgressBar.tsx`</summary>
181
+
182
+ This is a simple React component that renders a visual progress bar. It takes a `value` and `max` number to calculate the percentage of completed tasks. It also displays the percentage and has a special state for when there are no tasks.
183
+
184
+ ```tsx
185
+ import type { FC } from 'react';
186
+
187
+ interface ProgressBarProps {
188
+ value: number;
189
+ max: number;
190
+ }
191
+
192
+ export const ProgressBar: FC<ProgressBarProps> = ({ value, max }) => {
193
+ if (max === 0) {
194
+ return (
195
+ <div className="w-full bg-gray-200 rounded-full h-4">
196
+ <div className="bg-gray-300 h-4 rounded-full text-xs text-center text-gray-500">
197
+ No tasks
198
+ </div>
199
+ </div>
200
+ );
201
+ }
202
+
203
+ const percentage = Math.min(100, (value / max) * 100);
204
+
205
+ return (
206
+ <div className="w-full bg-gray-200 rounded-full h-4 relative">
207
+ <div
208
+ className="bg-blue-500 h-4 rounded-full transition-all duration-300"
209
+ style={{ width: `${percentage}%` }}
210
+ />
211
+ <div className="absolute inset-0 flex items-center justify-center text-xs font-medium text-black">
212
+ {Math.round(percentage)}%
213
+ </div>
214
+ </div>
215
+ );
216
+ };
217
+ ```
218
+ </details>
219
+
220
+ <details>
221
+ <summary>Update `editors/todo-drive-explorer/components/DriveExplorer.tsx`</summary>
222
+
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
+ }
151
246
 
152
- c. Update `editors/todo-drive-explorer/components/DriveExplorer.tsx`:
153
- - Copy the code from [DriveExplorer.tsx](https://github.com/powerhouse-inc/todo-drive-explorer/blob/ee63786fa8ceed71de63cd9c52f1795ad11ac403/editors/todo-drive-explorer/components/DriveExplorer.tsx)
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]);
282
+
283
+
284
+ const handleEditorClose = useCallback(() => {
285
+ setActiveDocumentId(undefined);
286
+ }, []);
287
+
288
+ const onCreateDocument = useCallback(
289
+ async (fileName: string) => {
290
+ setOpenModal(false);
291
+
292
+ const documentModel = selectedDocumentModel.current;
293
+ if (!documentModel) return;
294
+
295
+ const node = await addDocument(
296
+ driveId,
297
+ fileName,
298
+ documentModel.documentModel.id,
299
+ );
300
+
301
+ selectedDocumentModel.current = null;
302
+ setActiveDocumentId(node.id);
303
+ },
304
+ [addDocument, driveId],
305
+ );
306
+
307
+ const onSelectDocumentModel = useCallback(
308
+ (documentModel: DocumentModelModule) => {
309
+ selectedDocumentModel.current = documentModel;
310
+ setOpenModal(true);
311
+ },
312
+ [],
313
+ );
314
+
315
+ const onGetDocumentRevision = useCallback(
316
+ (options?: GetDocumentOptions) => {
317
+ if (!activeDocumentId) return;
318
+ return getDocumentRevision?.(activeDocumentId, options);
319
+ },
320
+ [getDocumentRevision, activeDocumentId],
321
+ );
322
+
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>
415
+
416
+ {/* Create Document Modal */}
417
+ <CreateDocumentModal
418
+ onContinue={onCreateDocument}
419
+ onOpenChange={(open) => setOpenModal(open)}
420
+ open={openModal}
421
+ />
422
+ </div>
423
+ );
424
+ }
425
+ ```
426
+ </details>
427
+
428
+
429
+ <details>
430
+ <summary>Update `editors/todo-drive-explorer/components/EditorContainer.tsx`</summary>
431
+
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;
470
+ }
154
471
 
155
- d. Update `editors/todo-drive-explorer/components/EditorContainer.tsx`:
156
- - Copy the code from [EditorContainer.tsx](https://github.com/powerhouse-inc/todo-drive-explorer/blob/ee63786fa8ceed71de63cd9c52f1795ad11ac403/editors/todo-drive-explorer/components/EditorContainer.tsx)
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)}
515
+ />
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
+ ```
546
+ </details>
157
547
 
158
- **3. Now that we've written the functional code for our Drive App it's time to run the application:**
548
+ - 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)
549
+ ### 3. Run the application:
550
+ - With the code for our Drive App in place, it's time to see it in action. Run Connect in Studio mode:
159
551
  ```bash
160
552
  ph connect
161
553
  ```
162
554
 
163
555
  ![Todo Drive Explorer Demo](https://raw.githubusercontent.com/powerhouse-inc/todo-drive-explorer/9a87871e61460e73ddf8635fd756a0cd991306d6/demo.gif)
164
556
 
165
- ### **Start building your own drive apps, explorers or experiences**
166
- Congratulations on completing this tutorial! You've successfully built a custom Drive Explorer, enhancing the way users interact with document models.
557
+ ### Now it's your turn!
558
+ Start building your own drive apps, explorers or experiences.
559
+ Congratulations on completing this tutorial!
560
+ You've successfully built a custom Drive Explorer, enhancing the way users interact with document models.
167
561
 
168
562
  Now, take a moment to think about the possibilities!
169
- - What **unique Drive Experiences** could you create for your own projects?
170
- - How can you tailor interfaces and streamline workflows to unlock the full potential of your document models?
563
+ - What **unique Drive Experiences** could you create for your own projects?
564
+ - How can you tailor interfaces and streamline workflows to unlock the full potential of your document models?
171
565
 
172
566
  The Powerhouse platform provides the tools. It's time to start building!
173
567