@powerhousedao/academy 5.0.0-staging.9 → 5.0.1-staging.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/settings.json +1 -1
- package/CHANGELOG.md +404 -0
- package/README.md +3 -3
- package/babel.config.js +1 -1
- package/blog/BeyondCommunication-ABlueprintForDevelopment.md +25 -24
- package/blog/TheChallengeOfChange.md +21 -21
- package/docs/academy/01-GetStarted/00-ExploreDemoPackage.mdx +67 -30
- package/docs/academy/01-GetStarted/01-CreateNewPowerhouseProject.md +38 -21
- package/docs/academy/01-GetStarted/02-DefineToDoListDocumentModel.md +24 -19
- package/docs/academy/01-GetStarted/03-ImplementOperationReducers.md +44 -41
- package/docs/academy/01-GetStarted/04-BuildToDoListEditor.md +10 -10
- package/docs/academy/01-GetStarted/05-VetraStudio.md +164 -0
- package/docs/academy/01-GetStarted/06-ReactorMCP.md +58 -0
- package/docs/academy/01-GetStarted/home.mdx +185 -90
- package/docs/academy/01-GetStarted/images/Modules.png +0 -0
- package/docs/academy/01-GetStarted/images/VetraStudioDrive.png +0 -0
- package/docs/academy/01-GetStarted/styles.module.css +5 -5
- package/docs/academy/02-MasteryTrack/01-BuilderEnvironment/01-Prerequisites.md +46 -18
- package/docs/academy/02-MasteryTrack/01-BuilderEnvironment/02-StandardDocumentModelWorkflow.md +118 -68
- package/docs/academy/02-MasteryTrack/01-BuilderEnvironment/03-BuilderTools.md +75 -33
- package/docs/academy/02-MasteryTrack/01-BuilderEnvironment/_category_.json +6 -6
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/01-WhatIsADocumentModel.md +30 -21
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/02-SpecifyTheStateSchema.md +41 -37
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/03-SpecifyDocumentOperations.md +29 -25
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/04-UseTheDocumentModelGenerator.md +36 -37
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/05-ImplementDocumentReducers.md +128 -109
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/06-ImplementDocumentModelTests.md +95 -86
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/07-ExampleToDoListRepository.md +7 -9
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/_category_.json +6 -6
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/01-BuildingDocumentEditors.md +65 -47
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/02-ConfiguringDrives.md +77 -62
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/03-BuildingADriveExplorer.md +360 -349
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/06-DocumentTools/00-DocumentToolbar.mdx +16 -10
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/06-DocumentTools/01-OperationHistory.md +10 -7
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/06-DocumentTools/02-RevisionHistoryTimeline.md +25 -17
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/06-DocumentTools/_category_.json +6 -6
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/07-Authorization/01-RenownAuthenticationFlow.md +14 -7
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/07-Authorization/02-Authorization.md +0 -1
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/07-Authorization/_category_.json +5 -5
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/_category_.json +1 -1
- package/docs/academy/02-MasteryTrack/04-WorkWithData/01-GraphQLAtPowerhouse.md +45 -33
- package/docs/academy/02-MasteryTrack/04-WorkWithData/02-UsingTheAPI.mdx +61 -18
- package/docs/academy/02-MasteryTrack/04-WorkWithData/03-UsingSubgraphs.md +50 -54
- package/docs/academy/02-MasteryTrack/04-WorkWithData/04-analytics-processor.md +126 -110
- package/docs/academy/02-MasteryTrack/04-WorkWithData/05-RelationalDbProcessor.md +75 -45
- package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/GraphQL References/QueryingADocumentWithGraphQL.md +23 -21
- package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/best-practices.md +9 -9
- package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/graphql/index.md +11 -23
- package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/graphql/integration.md +25 -9
- package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/intro.md +10 -10
- package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/typescript/benchmarks.md +1 -1
- package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/typescript/index.md +16 -11
- package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/typescript/memory.md +6 -5
- package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/typescript/schema.md +2 -2
- package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/typescript/utilities.md +7 -5
- package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/use-cases/maker.md +32 -58
- package/docs/academy/02-MasteryTrack/04-WorkWithData/06-Analytics Engine/use-cases/processors.md +1 -1
- package/docs/academy/02-MasteryTrack/04-WorkWithData/07-drive-analytics.md +105 -71
- package/docs/academy/02-MasteryTrack/04-WorkWithData/_ARCHIVE-AnalyticsProcessorTutorial/_01-SetupBuilderEnvironment.md +22 -0
- package/docs/academy/02-MasteryTrack/04-WorkWithData/_ARCHIVE-AnalyticsProcessorTutorial/_02-CreateNewPowerhouseProject.md +9 -8
- package/docs/academy/02-MasteryTrack/04-WorkWithData/_ARCHIVE-AnalyticsProcessorTutorial/_03-GenerateAnAnalyticsProcessor.md +28 -32
- package/docs/academy/02-MasteryTrack/04-WorkWithData/_ARCHIVE-AnalyticsProcessorTutorial/_04-UpdateAnalyticsProcessor.md +25 -26
- package/docs/academy/02-MasteryTrack/04-WorkWithData/_ARCHIVE-AnalyticsProcessorTutorial/_category_.json +1 -1
- package/docs/academy/02-MasteryTrack/04-WorkWithData/_category_.json +7 -7
- package/docs/academy/02-MasteryTrack/05-Launch/01-IntroductionToPackages.md +3 -4
- package/docs/academy/02-MasteryTrack/05-Launch/02-PublishYourProject.md +69 -45
- package/docs/academy/02-MasteryTrack/05-Launch/03-SetupEnvironment.md +70 -40
- package/docs/academy/02-MasteryTrack/05-Launch/04-ConfigureEnvironment.md +1 -0
- package/docs/academy/02-MasteryTrack/05-Launch/_category_.json +7 -7
- package/docs/academy/02-MasteryTrack/_category_.json +6 -6
- package/docs/academy/03-ExampleUsecases/Chatroom/02-CreateNewPowerhouseProject.md +5 -3
- package/docs/academy/03-ExampleUsecases/Chatroom/03-DefineChatroomDocumentModel.md +38 -37
- package/docs/academy/03-ExampleUsecases/Chatroom/04-ImplementOperationReducers.md +45 -41
- package/docs/academy/03-ExampleUsecases/Chatroom/05-ImplementChatroomEditor.md +14 -14
- package/docs/academy/03-ExampleUsecases/Chatroom/06-LaunchALocalReactor.md +6 -6
- package/docs/academy/03-ExampleUsecases/Chatroom/_category_.json +1 -1
- package/docs/academy/04-APIReferences/00-PowerhouseCLI.md +104 -43
- package/docs/academy/04-APIReferences/01-ReactHooks.md +177 -129
- package/docs/academy/04-APIReferences/04-RelationalDatabase.md +121 -113
- package/docs/academy/04-APIReferences/05-PHDocumentMigrationGuide.md +48 -41
- package/docs/academy/04-APIReferences/_category_.json +6 -6
- package/docs/academy/05-Architecture/00-PowerhouseArchitecture.md +1 -2
- package/docs/academy/05-Architecture/01-WorkingWithTheReactor.md +11 -8
- package/docs/academy/05-Architecture/05-DocumentModelTheory/_category_.json +1 -1
- package/docs/academy/05-Architecture/_category_.json +6 -6
- package/docs/academy/06-ComponentLibrary/00-DocumentEngineering.md +25 -23
- package/docs/academy/06-ComponentLibrary/02-CreateCustomScalars.md +105 -93
- package/docs/academy/06-ComponentLibrary/03-IntegrateIntoAReactComponent.md +1 -0
- package/docs/academy/06-ComponentLibrary/_category_.json +7 -7
- package/docs/academy/07-Cookbook.md +268 -35
- package/docs/academy/08-Glossary.md +7 -1
- package/docs/bookofpowerhouse/01-Overview.md +2 -2
- package/docs/bookofpowerhouse/02-GeneralFrameworkAndPhilosophy.md +1 -7
- package/docs/bookofpowerhouse/03-PowerhouseSoftwareArchitecture.md +10 -7
- package/docs/bookofpowerhouse/04-DevelopmentApproaches.md +10 -4
- package/docs/bookofpowerhouse/05-SNOsandANewModelForOSSandPublicGoods.md +23 -30
- package/docs/bookofpowerhouse/06-SNOsInActionAndPlatformEconomies.md +0 -7
- package/docusaurus.config.ts +64 -66
- package/package.json +9 -7
- package/scripts/generate-combined-cli-docs.ts +43 -13
- package/sidebars.ts +2 -0
- package/src/components/HomepageFeatures/index.tsx +171 -78
- package/src/components/HomepageFeatures/styles.module.css +1 -2
- package/src/css/custom.css +89 -89
- package/src/pages/_archive-homepage.tsx +17 -16
- package/src/theme/DocCardList/index.tsx +9 -8
- package/static.json +6 -6
- package/tsconfig.tsbuildinfo +1 -0
package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/03-BuildingADriveExplorer.md
CHANGED
|
@@ -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
|
-
|
|
81
|
-
|
|
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
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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
|
-
|
|
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
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
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
|
-
|
|
289
|
-
|
|
290
|
-
|
|
290
|
+
const handleEditorClose = useCallback(() => {
|
|
291
|
+
setActiveDocumentId(undefined);
|
|
292
|
+
}, []);
|
|
291
293
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
+
const onCreateDocument = useCallback(
|
|
295
|
+
async (fileName: string) => {
|
|
296
|
+
setOpenModal(false);
|
|
294
297
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
fileName,
|
|
298
|
-
documentModel.documentModel.id,
|
|
299
|
-
);
|
|
298
|
+
const documentModel = selectedDocumentModel.current;
|
|
299
|
+
if (!documentModel) return;
|
|
300
300
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
301
|
+
const node = await addDocument(
|
|
302
|
+
driveId,
|
|
303
|
+
fileName,
|
|
304
|
+
documentModel.documentModel.id,
|
|
305
|
+
);
|
|
306
306
|
|
|
307
|
-
|
|
308
|
-
(
|
|
309
|
-
|
|
310
|
-
|
|
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
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
413
|
+
{/* Create Document Section */}
|
|
414
|
+
<CreateDocument
|
|
415
|
+
createDocument={onSelectDocumentModel}
|
|
416
|
+
documentModels={filteredDocumentModels}
|
|
417
|
+
/>
|
|
418
|
+
</>
|
|
419
|
+
)}
|
|
420
|
+
</div>
|
|
322
421
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
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
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
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
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
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
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
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
|
-
|
|
561
|
+
```bash
|
|
562
|
+
ph connect
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+

|
|
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
|
-
|