@powerhousedao/network-admin 0.0.18 → 0.0.20

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.
@@ -1,4 +1,4 @@
1
- /**
1
+ /**1
2
2
  * Main drive explorer component with sidebar navigation and content area.
3
3
  * Layout: Left sidebar (folder tree) + Right content area (files/folders + document editor)
4
4
  */
@@ -1 +1 @@
1
- {"version":3,"file":"DriveExplorer.d.ts","sourceRoot":"","sources":["../../../../editors/network-admin/components/DriveExplorer.tsx"],"names":[],"mappings":"AA4BA;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,GAAG,2CAigBvC"}
1
+ {"version":3,"file":"DriveExplorer.d.ts","sourceRoot":"","sources":["../../../../editors/network-admin/components/DriveExplorer.tsx"],"names":[],"mappings":"AAuCA;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,GAAG,2CA8jBvC"}
@@ -1,11 +1,22 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Button, CreateDocumentModal, } from "@powerhousedao/design-system";
2
+ import { Button, CreateDocumentModal } from "@powerhousedao/design-system";
3
3
  import { Sidebar, SidebarProvider, } from "@powerhousedao/document-engineering";
4
- import { addDocument, setSelectedNode, useAllFolderNodes, useFileChildNodes, useSelectedDrive, useSelectedFolder, dispatchActions, useSelectedDocument, useSelectedDriveDocuments, renameNode, showDeleteNodeModal, useSelectedDriveId, } from "@powerhousedao/reactor-browser";
4
+ import { addDocument, setSelectedNode, useAllFolderNodes, useFileChildNodes, useSelectedDrive, useSelectedFolder, dispatchActions, useSelectedDocument, useSelectedDriveDocuments, showDeleteNodeModal, useSelectedDriveId, useNodeActions, } from "@powerhousedao/reactor-browser";
5
5
  import { useCallback, useRef, useState, useMemo, useEffect } from "react";
6
6
  import { EditorContainer } from "./EditorContainer.js";
7
7
  import { editWorkstream } from "../../../document-models/workstream/gen/creators.js";
8
- /**
8
+ const WorkstreamStatusEnums = [
9
+ "RFP_DRAFT",
10
+ "PREWORK_RFC",
11
+ "RFP_CANCELLED",
12
+ "OPEN_FOR_PROPOSALS",
13
+ "PROPOSAL_SUBMITTED",
14
+ "NOT_AWARDED",
15
+ "AWARDED",
16
+ "IN_PROGRESS",
17
+ "FINISHED",
18
+ ];
19
+ /**1
9
20
  * Main drive explorer component with sidebar navigation and content area.
10
21
  * Layout: Left sidebar (folder tree) + Right content area (files/folders + document editor)
11
22
  */
@@ -13,6 +24,7 @@ export function DriveExplorer(props) {
13
24
  // === DOCUMENT EDITOR STATE ===
14
25
  // Customize document opening/closing behavior here
15
26
  const [activeDocumentId, setActiveDocumentId] = useState();
27
+ const [activeSidebarNodeId, setActiveSidebarNodeId] = useState("workstreams");
16
28
  const [openModal, setOpenModal] = useState(false);
17
29
  const [selectedRootNode, setSelectedRootNode] = useState("workstreams");
18
30
  const [modalDocumentType, setModalDocumentType] = useState("powerhouse/workstream");
@@ -23,6 +35,7 @@ export function DriveExplorer(props) {
23
35
  const selectedFolder = useSelectedFolder(); // Currently selected folder
24
36
  const allDocuments = useSelectedDriveDocuments();
25
37
  const selectedDriveId = useSelectedDriveId();
38
+ const { onRenameNode } = useNodeActions();
26
39
  // Listen to global selected document state (for external editors like Scope of Work)
27
40
  const [globalSelectedDocument] = useSelectedDocument();
28
41
  // All folders for the sidebar tree view
@@ -38,18 +51,13 @@ export function DriveExplorer(props) {
38
51
  useEffect(() => {
39
52
  if (globalSelectedDocument?.header?.id) {
40
53
  setActiveDocumentId(globalSelectedDocument.header.id);
54
+ // Also update the sidebar node ID to match
55
+ setActiveSidebarNodeId(`editor-${globalSelectedDocument.header.id}`);
41
56
  }
42
57
  }, [globalSelectedDocument]);
43
58
  // Check if current active document is a Scope of Work (should show in full view)
44
59
  const activeDoc = allDocuments?.find((doc) => doc.header.id === activeDocumentId);
45
60
  const isScopeOfWorkFullView = activeDoc?.header.documentType === "powerhouse/scopeofwork";
46
- // rename node
47
- const onRenameNode = async (nodeId, newName) => {
48
- const renamedNode = await renameNode(selectedDriveId || "", nodeId, newName);
49
- if (renamedNode) {
50
- console.log("Renamed node", renamedNode);
51
- }
52
- };
53
61
  // check if workstream doc is created, set isWorkstreamCreated to true
54
62
  const isWorkstreamCreated = networkAdminDocuments?.some((doc) => doc.header.documentType === "powerhouse/workstream") || false;
55
63
  //check if network profile doc is created, set isNetworkProfileCreated to true
@@ -66,26 +74,70 @@ export function DriveExplorer(props) {
66
74
  id: "workstreams",
67
75
  title: "Workstreams",
68
76
  children: [
69
- // Add workstream documents
70
- ...workstreamDocs.map((doc) => ({
71
- id: `editor-${doc.header.id}`,
72
- title: `${doc.state?.global?.code || ""} - ${doc.state?.global?.title || doc.header.name}`,
73
- })),
74
- // Add scope of work documents
75
- ...scopeOfWorkDocs.map((doc) => ({
76
- id: `editor-${doc.header.id}`,
77
- title: `${doc.state?.global?.title || doc.header.name}`,
78
- })),
79
- // Add RFP documents
80
- ...rfpDocs.map((doc) => ({
81
- id: `editor-${doc.header.id}`,
82
- title: `${doc.state?.global?.code || ""} - ${doc.state?.global?.title || doc.header.name}`,
83
- })),
84
- // Add payment terms documents
85
- ...paymentTermsDocs.map((doc) => ({
86
- id: `editor-${doc.header.id}`,
87
- title: `${doc.state?.global?.code || ""} - ${doc.state?.global?.title || doc.header.name}`,
88
- })),
77
+ ...WorkstreamStatusEnums.map((status) => {
78
+ const statusTitle = status
79
+ .toLowerCase()
80
+ .split("_")
81
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
82
+ .join(" ");
83
+ return {
84
+ id: `workstream-status-${status}`,
85
+ title: statusTitle +
86
+ (workstreamDocs.filter((doc) => doc.state?.global?.status === status).length > 0
87
+ ? ` (${workstreamDocs.filter((doc) => doc.state?.global?.status === status).length})`
88
+ : ""),
89
+ children: [
90
+ ...workstreamDocs
91
+ .filter((doc) => doc.state?.global?.status === status)
92
+ .map((doc) => {
93
+ let sow = null;
94
+ let paymentTerms = null;
95
+ let rfp = null;
96
+ if (doc.state?.global?.initialProposal) {
97
+ sow = doc.state?.global?.initialProposal.sow;
98
+ paymentTerms = doc.state?.global?.initialProposal
99
+ .paymentTerms;
100
+ }
101
+ if (doc.state?.global?.rfp) {
102
+ rfp = doc.state?.global?.rfp?.id;
103
+ }
104
+ const sowDoc = allDocuments?.find((doc) => doc.header.id === sow);
105
+ const rfpDoc = allDocuments?.find((doc) => doc.header.id === rfp);
106
+ const pmtDoc = allDocuments?.find((doc) => doc.header.id === paymentTerms);
107
+ // Only include documents that actually exist
108
+ const wstrChildDocs = [sowDoc, rfpDoc, pmtDoc].filter((doc) => doc !== undefined && doc !== null);
109
+ return {
110
+ id: `editor-${doc.header.id}`,
111
+ title: `${doc.state?.global?.code ? doc.state?.global?.code + " - " : ""}${doc.state?.global?.title || doc.header.name}`,
112
+ children: wstrChildDocs.map((childDoc) => ({
113
+ id: `editor-${childDoc.header.id}`,
114
+ title: `${childDoc.state?.global?.code ? childDoc.state?.global?.code + " - " : ""}${childDoc.state?.global?.title || childDoc.header.name}`,
115
+ })),
116
+ };
117
+ }),
118
+ ],
119
+ };
120
+ }),
121
+ // // Add workstream documents
122
+ // ...workstreamDocs.map((doc) => ({
123
+ // id: `editor-${doc.header.id}`,
124
+ // title: `${(doc.state as any)?.global?.code || ""} - ${(doc.state as any)?.global?.title || doc.header.name}`,
125
+ // })),
126
+ // // Add scope of work documents
127
+ // ...scopeOfWorkDocs.map((doc) => ({
128
+ // id: `editor-${doc.header.id}`,
129
+ // title: `${(doc.state as any)?.global?.title || doc.header.name}`,
130
+ // })),
131
+ // // Add RFP documents
132
+ // ...rfpDocs.map((doc) => ({
133
+ // id: `editor-${doc.header.id}`,
134
+ // title: `${(doc.state as any)?.global?.code || ""} - ${(doc.state as any)?.global?.title || doc.header.name}`,
135
+ // })),
136
+ // // Add payment terms documents
137
+ // ...paymentTermsDocs.map((doc) => ({
138
+ // id: `editor-${doc.header.id}`,
139
+ // title: `${(doc.state as any)?.global?.code || ""} - ${(doc.state as any)?.global?.title || doc.header.name}`,
140
+ // })),
89
141
  ],
90
142
  };
91
143
  const networkInfoNode = {
@@ -121,6 +173,8 @@ export function DriveExplorer(props) {
121
173
  const newNode = findNodeById(sidebarNodes, nodeId);
122
174
  if (!newNode)
123
175
  return;
176
+ // Always update the active sidebar node ID
177
+ setActiveSidebarNodeId(newNode.id);
124
178
  if (newNode.id === "workstreams") {
125
179
  setActiveDocumentId(undefined);
126
180
  setSelectedRootNode("workstreams");
@@ -179,34 +233,35 @@ export function DriveExplorer(props) {
179
233
  , size: "medium", className: "cursor-pointer hover:bg-gray-600 hover:text-white", title: "Create Workstream Document", "aria-description": "Create Workstream Document", onClick: () => {
180
234
  setModalDocumentType("powerhouse/workstream");
181
235
  setOpenModal(true);
182
- }, disabled: isWorkstreamCreated, children: _jsx("span", { children: "Create Workstream Document" }) }), _jsx(Button, { color: "dark" // Customize button appearance
236
+ }, children: _jsx("span", { children: "Create Workstream Document" }) }), _jsx(Button, { color: "dark" // Customize button appearance
183
237
  , size: "medium", className: "cursor-pointer hover:bg-gray-600 hover:text-white", title: "Create Network Profile Document", "aria-description": "Create Network Profile Document", onClick: () => {
184
238
  setModalDocumentType("powerhouse/network-profile");
185
239
  setOpenModal(true);
186
240
  }, disabled: isNetworkProfileCreated, children: _jsx("span", { children: "Create Network Profile Document" }) })] })] }), networkAdminDocuments && networkAdminDocuments.length > 0 && (_jsxs("div", { className: "w-full", children: [_jsx("h3", { className: "mb-4 text-lg font-medium text-gray-700", children: "\uD83D\uDCC4 Documents" }), _jsx("div", { className: "overflow-x-auto rounded-lg border border-gray-200 shadow-sm", children: _jsxs("table", { className: "w-full bg-white", children: [_jsx("thead", { className: "bg-gray-50", children: _jsxs("tr", { children: [_jsx("th", { className: "px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider w-1/4", children: "Name" }), _jsx("th", { className: "px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider w-1/4", children: "Type" }), _jsx("th", { className: "px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider w-1/4", children: "Actions" })] }) }), _jsx("tbody", { className: "bg-white divide-y divide-gray-200", children: networkAdminDocuments.map((document) => {
187
241
  // Find the corresponding file node for actions
188
242
  const fileNode = fileChildren?.find((file) => file.id === document.header.id);
189
- return (_jsxs("tr", { className: "hover:bg-gray-50 transition-colors", children: [_jsx("td", { className: "px-2 py-2", children: _jsx("div", { className: "text-sm font-medium text-gray-900 truncate max-w-xs", title: document.header.name, children: document.header.name }) }), _jsx("td", { className: "px-2 py-2", children: _jsx("div", { className: "text-sm text-gray-500 truncate max-w-xs", title: document.header.documentType, children: document.header.documentType }) }), _jsx("td", { className: "px-2 py-2", children: _jsxs("div", { className: "flex gap-2 flex-wrap", children: [_jsx("button", { onClick: () => {
243
+ return (_jsxs("tr", { className: "hover:bg-gray-50 transition-colors", children: [_jsx("td", { className: "px-2 py-2", children: _jsx("div", { className: "text-sm font-medium text-gray-900 truncate max-w-xs", title: fileNode?.name || document.header.name, children: fileNode?.name || document.header.name }) }), _jsx("td", { className: "px-2 py-2", children: _jsx("div", { className: "text-sm text-gray-500 truncate max-w-xs", title: document.header.documentType, children: document.header.documentType }) }), _jsx("td", { className: "px-2 py-2", children: _jsxs("div", { className: "flex gap-2 flex-wrap", children: [_jsx("button", { onClick: () => {
190
244
  if (fileNode) {
191
245
  setSelectedNode(fileNode);
192
246
  }
193
247
  }, className: "px-3 py-1.5 bg-blue-500 text-white rounded text-xs font-medium hover:bg-blue-600 transition-colors whitespace-nowrap", children: "Open" }), _jsx("button", { onClick: async () => {
194
248
  if (!fileNode || !fileNode.id)
195
249
  return;
196
- const newName = prompt("Enter new name:", document.header.name || "");
250
+ const currentName = fileNode.name || document.header.name;
251
+ const newName = prompt("Enter new name:", currentName);
197
252
  if (newName &&
198
253
  newName.trim() &&
199
- newName !== document.header.name) {
254
+ newName !== currentName) {
200
255
  try {
201
- await onRenameNode(fileNode.id || "", newName.trim());
256
+ await onRenameNode(newName.trim(), fileNode);
202
257
  }
203
258
  catch (error) {
204
259
  console.error("Failed to rename document", error);
205
260
  }
206
261
  }
207
262
  }, className: "px-3 py-1.5 bg-yellow-500 text-white rounded text-xs font-medium hover:bg-yellow-600 transition-colors whitespace-nowrap", children: "Edit" }), _jsx("button", { onClick: () => {
208
- if (fileNode) {
209
- showDeleteNodeModal(fileNode.id || "");
263
+ if (fileNode && fileNode.id) {
264
+ showDeleteNodeModal(fileNode.id);
210
265
  }
211
266
  }, className: "px-3 py-1.5 bg-red-500 text-white rounded text-xs font-medium hover:bg-red-600 transition-colors whitespace-nowrap", children: "Delete" })] }) })] }, document.header.id));
212
267
  }) })] }) })] }))] }) }));
@@ -260,12 +315,11 @@ export function DriveExplorer(props) {
260
315
  return (_jsx(SidebarProvider, { nodes: sidebarNodes, children: isScopeOfWorkFullView && activeDocumentId ? (_jsx("div", { className: "h-full w-full", children: _jsx(EditorContainer, { handleClose: () => {
261
316
  setActiveDocumentId(undefined);
262
317
  setSelectedNode(undefined); // Clear global selection
263
- }, hideToolbar: false, activeDocumentId: activeDocumentId, setActiveDocumentId: setActiveDocumentId }) })) : (
318
+ }, hideToolbar: false, activeDocumentId: activeDocumentId, setActiveDocumentId: setActiveDocumentId, setActiveSidebarNodeId: setActiveSidebarNodeId }) })) : (
264
319
  /* === NORMAL VIEW WITH SIDEBAR === */
265
- _jsxs("div", { className: "flex h-full", children: [_jsx(Sidebar, { className: String.raw `
266
- [&_.sidebar\\_\\_item--active]:bg-yellow-500
267
- `, nodes: sidebarNodes, activeNodeId: selectedFolder?.id || activeDocumentId, onActiveNodeChange: (node) => handleActiveNodeChange(node.id), sidebarTitle: "Network Admin", showSearchBar: true, allowPinning: true, resizable: true, initialWidth: 300, maxWidth: 500, enableMacros: 2, handleOnTitleClick: () => {
320
+ _jsxs("div", { className: "flex h-full", children: [_jsx(Sidebar, { nodes: sidebarNodes, activeNodeId: activeSidebarNodeId, onActiveNodeChange: (node) => handleActiveNodeChange(node.id), sidebarTitle: "Network Admin", showSearchBar: true, allowPinning: true, resizable: true, initialWidth: 300, maxWidth: 500, enableMacros: 4, handleOnTitleClick: () => {
268
321
  setActiveDocumentId(undefined);
322
+ setActiveSidebarNodeId("workstreams");
269
323
  setSelectedRootNode("workstreams");
270
- } }), _jsx("div", { className: "flex-1 overflow-y-auto", children: _jsx("div", { className: "h-full", children: activeDocumentId ? (_jsx(EditorContainer, { handleClose: () => setActiveDocumentId(undefined), hideToolbar: false, activeDocumentId: activeDocumentId, setActiveDocumentId: setActiveDocumentId })) : (displayActiveNode(selectedFolder?.id || selectedRootNode)) }) }), _jsx(CreateDocumentModal, { onContinue: onCreateDocument, onOpenChange: (open) => setOpenModal(open), open: openModal })] })) }));
324
+ } }), _jsx("div", { className: "flex-1 overflow-y-auto", children: _jsx("div", { className: "h-full", children: activeDocumentId ? (_jsx(EditorContainer, { handleClose: () => setActiveDocumentId(undefined), hideToolbar: false, activeDocumentId: activeDocumentId, setActiveDocumentId: setActiveDocumentId, setActiveSidebarNodeId: setActiveSidebarNodeId })) : (displayActiveNode(selectedFolder?.id || selectedRootNode)) }) }), _jsx(CreateDocumentModal, { onContinue: onCreateDocument, onOpenChange: (open) => setOpenModal(open), open: openModal })] })) }));
271
325
  }
@@ -8,5 +8,6 @@ export declare const EditorContainer: (props: {
8
8
  hideToolbar?: boolean;
9
9
  activeDocumentId: string;
10
10
  setActiveDocumentId: (id: string) => void;
11
+ setActiveSidebarNodeId: (id: string) => void;
11
12
  }) => import("react/jsx-runtime").JSX.Element;
12
13
  //# sourceMappingURL=EditorContainer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"EditorContainer.d.ts","sourceRoot":"","sources":["../../../../editors/network-admin/components/EditorContainer.tsx"],"names":[],"mappings":"AAqBA;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO;IACrC,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3C,4CAgMA,CAAC"}
1
+ {"version":3,"file":"EditorContainer.d.ts","sourceRoot":"","sources":["../../../../editors/network-admin/components/EditorContainer.tsx"],"names":[],"mappings":"AAqBA;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO;IACrC,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,sBAAsB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9C,4CAkMA,CAAC"}
@@ -11,7 +11,7 @@ import { ScopeOfWork } from "@powerhousedao/project-management/document-models";
11
11
  * Customize toolbar actions and editor context here.
12
12
  */
13
13
  export const EditorContainer = (props) => {
14
- const { handleClose, hideToolbar = false, activeDocumentId, setActiveDocumentId, } = props;
14
+ const { handleClose, hideToolbar = false, activeDocumentId, setActiveDocumentId, setActiveSidebarNodeId, } = props;
15
15
  // UI state for revision history and timeline
16
16
  const [selectedTimelineItem, setSelectedTimelineItem] = useState(null);
17
17
  const [showRevisionHistory, setShowRevisionHistory] = useState(false);
@@ -95,5 +95,5 @@ export const EditorContainer = (props) => {
95
95
  _jsxs(Suspense, { fallback: loadingContent, children: [!hideToolbar && (_jsx(DocumentToolbar, { onClose: handleClose, onExport: onExport, onShowRevisionHistory: () => setShowRevisionHistory(true), onSwitchboardLinkClick: () => { }, title: selectedDocument.header.name, timelineButtonVisible: editorModule.config.timelineEnabled, timelineItems: timelineItems.data, onTimelineItemClick: setSelectedTimelineItem })), _jsx(EditorComponent, { context: {
96
96
  readMode: !!selectedTimelineItem,
97
97
  selectedTimelineRevision: getRevisionFromDate(selectedTimelineItem?.startDate, selectedTimelineItem?.endDate, selectedDocument.operations.global),
98
- }, dispatch: dispatch, document: selectedDocument, error: console.error, createRfp: createRfpDocument, setActiveDocumentId: setActiveDocumentId, createSow: createSowDocument, createPaymentTerms: createPaymentTermsDocument, documentId: selectedDocument.header.id })] })) }));
98
+ }, dispatch: dispatch, document: selectedDocument, error: console.error, setActiveSidebarNodeId: setActiveSidebarNodeId, setActiveDocumentId: setActiveDocumentId, createSow: createSowDocument, createPaymentTerms: createPaymentTermsDocument, documentId: selectedDocument.header.id }, selectedDocument.header.id)] })) }));
99
99
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../editors/network-admin/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAGxE,eAAO,MAAM,MAAM,EAAE,iBAoBpB,CAAC;AAEF,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../editors/network-admin/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAGxE,eAAO,MAAM,MAAM,EAAE,iBAiBpB,CAAC;AAEF,eAAe,MAAM,CAAC"}
@@ -11,9 +11,6 @@ export const module = {
11
11
  // List all document types that can be dropped
12
12
  "powerhouse/network-profile",
13
13
  "powerhouse/workstream",
14
- "powerhouse/scopeofwork",
15
- "powerhouse/rfp",
16
- "payment-terms",
17
14
  ],
18
15
  dragAndDrop: {
19
16
  enabled: true, // Enable drag-and-drop functionality
@@ -1 +1 @@
1
- {"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../../editors/workstream/editor.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAU,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAiC1D,MAAM,MAAM,MAAM,GAAG,WAAW,CAAC;AAejC,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,KAAK,EAAE,GAAG,2CAq0BxC"}
1
+ {"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../../editors/workstream/editor.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAU,WAAW,EAAc,MAAM,gBAAgB,CAAC;AAgCtE,MAAM,MAAM,MAAM,GAAG,WAAW,CAAC;AAejC,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,KAAK,EAAE,GAAG,2CA23BxC"}
@@ -2,8 +2,10 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Button, toast, ToastContainer } from "@powerhousedao/design-system";
3
3
  import { TextInput, Select, PHIDInput, Icon, ObjectSetTable, } from "@powerhousedao/document-engineering";
4
4
  import { actions, } from "../../document-models/workstream/index.js";
5
+ import { actions as rfpActions, } from "../../document-models/request-for-proposals/index.js";
6
+ import { ScopeOfWork } from "@powerhousedao/project-management/document-models";
5
7
  import { generateId } from "document-model";
6
- import { useNodes, useDocumentById, } from "@powerhousedao/reactor-browser";
8
+ import { useDocumentById, useSelectedDrive, addDocument, useSelectedDriveDocuments, dispatchActions, } from "@powerhousedao/reactor-browser";
7
9
  import { useEffect, useMemo, useState } from "react";
8
10
  // Status options for the dropdown
9
11
  const statusOptions = [
@@ -20,11 +22,39 @@ const statusOptions = [
20
22
  export default function Editor(props) {
21
23
  const [doc, dispatch] = useDocumentById(props.documentId);
22
24
  // Try to get dispatch from context or props
23
- const state = doc.state.global;
24
- const createRfpDocument = props.createRfp;
25
+ const [state, setState] = useState(doc.state.global);
26
+ useEffect(() => {
27
+ setState(doc.state.global);
28
+ }, [doc.state.global]);
25
29
  const setActiveDocumentId = props.setActiveDocumentId;
26
- const createSowDocument = props.createSow;
27
- const createPaymentTermsDocument = props.createPaymentTerms;
30
+ const setActiveSidebarNodeId = props.setActiveSidebarNodeId;
31
+ const [selectedDrive] = useSelectedDrive();
32
+ const createRfpDocument = async () => {
33
+ const createdNode = await addDocument(selectedDrive?.header.id || "", `RFP-${state.title || ""}`, "powerhouse/rfp", undefined, undefined, undefined, "request-for-proposals-editor");
34
+ console.log("Created RFP document", createdNode);
35
+ if (createdNode) {
36
+ await dispatchActions(rfpActions.editRfp({
37
+ title: `RFP-${state.title || ""}`,
38
+ }), createdNode.id);
39
+ }
40
+ return createdNode;
41
+ };
42
+ const createSowDocument = async () => {
43
+ const createdNode = await addDocument(selectedDrive?.header.id || "", `SOW-${state.title || ""}`, "powerhouse/scopeofwork", undefined, undefined, undefined, "scope-of-work-editor");
44
+ console.log("Created SOW document", createdNode);
45
+ if (createdNode) {
46
+ await dispatchActions(ScopeOfWork.actions.editScopeOfWork({
47
+ title: `SOW-${state.title || ""}`,
48
+ }), createdNode.id);
49
+ }
50
+ return createdNode;
51
+ };
52
+ const createPaymentTermsDocument = async () => {
53
+ const createdNode = await addDocument(selectedDrive?.header.id || "", `Payment Terms-${state.title || ""}`, "payment-terms", undefined, undefined, undefined, "payment-terms-editor");
54
+ console.log("Created Payment Terms document", createdNode);
55
+ // Note: Payment Terms might not have actions to initialize, so we just create it
56
+ return createdNode;
57
+ };
28
58
  // Local state to track newly created SOW document ID
29
59
  const [newlyCreatedSowId, setNewlyCreatedSowId] = useState(null);
30
60
  // Local state to track newly created Payment Terms document ID
@@ -55,30 +85,16 @@ export default function Editor(props) {
55
85
  setNewlyCreatedRfpId(null);
56
86
  }
57
87
  }, [state.rfp?.id, newlyCreatedRfpId]);
58
- // Checking if there is an RFP document for this workstream
59
- const nodes = useNodes() || [];
60
- const workstreamDocument = nodes.find((node) => node.id === doc.header.id);
61
- const fileNodes = nodes.filter((node) => node.kind === "file");
62
- const rfpDocumentNode = fileNodes.find((node) => {
63
- if (!workstreamDocument && !node.parentFolder)
64
- return false;
65
- return (node.parentFolder === workstreamDocument?.parentFolder &&
66
- node.documentType === "powerhouse/rfp");
67
- });
68
- const sowDocumentNode = fileNodes.find((node) => {
69
- if (!workstreamDocument && !node.parentFolder)
70
- return false;
71
- return (node.parentFolder === workstreamDocument?.parentFolder &&
72
- node.documentType === "powerhouse/scopeofwork");
73
- });
74
- const paymentTermsDocumentNode = fileNodes.find((node) => {
75
- if (!workstreamDocument && !node.parentFolder)
76
- return false;
77
- return (node.parentFolder === workstreamDocument?.parentFolder &&
78
- node.documentType === "payment-terms");
79
- });
88
+ const allDocuments = useSelectedDriveDocuments();
89
+ let rfpDocumentNode = undefined;
90
+ if (state.rfp?.id) {
91
+ rfpDocumentNode = allDocuments?.find((doc) => {
92
+ return (doc.header.documentType === "powerhouse/rfp" &&
93
+ doc.header.id === state.rfp?.id);
94
+ });
95
+ }
80
96
  // Get RFP document data using useDocumentById hook - always call with stable ID
81
- const rfpDocumentId = rfpDocumentNode?.id || "";
97
+ const rfpDocumentId = rfpDocumentNode?.header.id || "";
82
98
  const rfpDocumentData = useDocumentById(rfpDocumentId);
83
99
  const [rfpDocumentDataState] = rfpDocumentData || [];
84
100
  // State to track RFP document
@@ -86,30 +102,41 @@ export default function Editor(props) {
86
102
  // Effect to update RFP document when nodes or document data changes
87
103
  useEffect(() => {
88
104
  if (rfpDocumentNode &&
89
- rfpDocumentNode.id &&
90
- rfpDocumentNode.id !== "" &&
105
+ rfpDocumentNode.header.id &&
106
+ rfpDocumentNode.header.id !== "" &&
91
107
  rfpDocumentDataState?.state?.global) {
92
- setRfpDocument({
108
+ const newRfpDocument = {
93
109
  ...rfpDocumentNode,
94
110
  document: (rfpDocumentDataState?.state)
95
111
  .global,
112
+ };
113
+ // Only update if the ID changed or if we don't have a document yet
114
+ setRfpDocument((prev) => {
115
+ if (!prev || prev.header.id !== newRfpDocument.header.id) {
116
+ return newRfpDocument;
117
+ }
118
+ // Update if the document content changed
119
+ if (JSON.stringify(prev.document) !==
120
+ JSON.stringify(newRfpDocument.document)) {
121
+ return newRfpDocument;
122
+ }
123
+ return prev;
96
124
  });
97
125
  }
98
126
  else if (!rfpDocumentNode ||
99
- !rfpDocumentNode.id ||
100
- rfpDocumentNode.id === "") {
101
- setRfpDocument(undefined);
127
+ !rfpDocumentNode.header.id ||
128
+ rfpDocumentNode.header.id === "") {
129
+ setRfpDocument((prev) => (prev === undefined ? prev : undefined));
102
130
  }
103
- }, [rfpDocumentNode, rfpDocumentDataState, fileNodes]);
131
+ }, [rfpDocumentNode, rfpDocumentDataState]);
104
132
  const searchRfpDocuments = (userInput) => {
105
- const results = fileNodes.filter((node) => (node.kind === "file" &&
106
- node.documentType === "powerhouse/rfp" &&
107
- node.name.toLowerCase().includes(userInput.toLowerCase())) ||
108
- node.id.toLowerCase().includes(userInput.toLowerCase()));
109
- return results.map((doc) => ({
110
- value: doc.id,
111
- title: doc.name,
112
- path: nodes.find((node) => node.id === doc.parentFolder)?.name || "",
133
+ const results = allDocuments?.filter((node) => (node.header.documentType === "powerhouse/rfp" &&
134
+ node.header.name.toLowerCase().includes(userInput.toLowerCase())) ||
135
+ node.header.id.toLowerCase().includes(userInput.toLowerCase()));
136
+ return results?.map((doc) => ({
137
+ value: doc.header.id,
138
+ title: doc.header.name,
139
+ path: "",
113
140
  }));
114
141
  };
115
142
  // Handle workstream field changes
@@ -293,11 +320,11 @@ export default function Editor(props) {
293
320
  },
294
321
  // search options as the user types
295
322
  fetchOptionsCallback: async (userInput) => {
296
- const results = searchRfpDocuments(userInput);
297
- if (results.length === 0) {
323
+ const results = searchRfpDocuments(userInput) || [];
324
+ if (results?.length === 0) {
298
325
  return Promise.reject(new Error("No RFP documents found"));
299
326
  }
300
- return results.map((doc) => ({
327
+ return results?.map((doc) => ({
301
328
  value: doc.value, // unique document ID
302
329
  title: doc.title, // document title or name
303
330
  path: {
@@ -311,7 +338,7 @@ export default function Editor(props) {
311
338
  // get details of a specific option by its ID/value
312
339
  fetchSelectedOptionCallback: async (documentId) => {
313
340
  console.log("fetching selected option", documentId);
314
- const [doc] = searchRfpDocuments(documentId);
341
+ const doc = searchRfpDocuments(documentId)?.[0];
315
342
  if (!doc) {
316
343
  return Promise.reject(new Error("RFP document not found"));
317
344
  }
@@ -327,17 +354,18 @@ export default function Editor(props) {
327
354
  };
328
355
  }, initialOptions: [
329
356
  {
330
- value: rfpDocument.id,
357
+ value: rfpDocument.header.id,
331
358
  title: rfpDocument.document.title,
332
359
  path: {
333
360
  text: rfpDocument.document.title,
334
- url: rfpDocument.id,
361
+ url: rfpDocument.header.id,
335
362
  },
336
363
  description: "",
337
364
  icon: "File",
338
365
  },
339
366
  ] }) }), _jsx("div", { className: "flex items-center", children: _jsxs("span", { className: "inline-flex items-center gap-2", children: [_jsx(Icon, { className: "hover:cursor-pointer hover:bg-gray-500", name: "Moved", size: 18, onClick: () => {
340
- setActiveDocumentId(rfpDocumentNode?.id || "");
367
+ setActiveDocumentId(rfpDocument?.header.id);
368
+ setActiveSidebarNodeId(`editor-${rfpDocument?.header.id}`);
341
369
  } }), _jsx("span", { children: "RFP Editor" })] }) })] })] })) : (_jsxs("div", { className: "bg-white rounded-lg p-6 mt-6 mb-6 shadow-sm", children: [_jsx("h1", { className: "text-2xl text-gray-900 mb-4", children: "Request for Proposal" }), _jsx("div", { className: "mt-4", children: _jsx(Button, { color: "light", size: "small", className: "cursor-pointer hover:bg-gray-600 hover:text-white", title: "Save Workstream", "aria-description": "Save Workstream", onClick: async () => {
342
370
  const createdNode = await createRfpDocument();
343
371
  if (createdNode) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../editors/workstream/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAInD,eAAO,MAAM,MAAM,EAAE,YASpB,CAAC;AAEF,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../editors/workstream/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGnD,eAAO,MAAM,MAAM,EAAE,YASpB,CAAC;AAEF,eAAe,MAAM,CAAC"}
package/dist/style.css CHANGED
@@ -1,4 +1,4 @@
1
- /*! tailwindcss v4.1.13 | MIT License | https://tailwindcss.com */
1
+ /*! tailwindcss v4.1.14 | MIT License | https://tailwindcss.com */
2
2
  @layer properties;
3
3
  @layer theme, base, components, utilities;
4
4
  @layer theme {
@@ -1182,11 +1182,6 @@
1182
1182
  }
1183
1183
  }
1184
1184
  }
1185
- .\[\&_\.sidebar\\\\_\\\\_item--active\]\:bg-yellow-500 {
1186
- & .sidebar\_\_item--active {
1187
- background-color: var(--color-yellow-500);
1188
- }
1189
- }
1190
1185
  }
1191
1186
  /*! tailwindcss v4.1.5 | MIT License | https://tailwindcss.com */
1192
1187
  @import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap");
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@powerhousedao/network-admin",
3
3
  "description": "Network Admin package for Powerhouse",
4
- "version": "0.0.18",
4
+ "version": "0.0.20",
5
5
  "license": "AGPL-3.0-only",
6
6
  "type": "module",
7
7
  "files": [