@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.
- package/dist/editors/network-admin/components/DriveExplorer.d.ts +1 -1
- package/dist/editors/network-admin/components/DriveExplorer.d.ts.map +1 -1
- package/dist/editors/network-admin/components/DriveExplorer.js +96 -42
- package/dist/editors/network-admin/components/EditorContainer.d.ts +1 -0
- package/dist/editors/network-admin/components/EditorContainer.d.ts.map +1 -1
- package/dist/editors/network-admin/components/EditorContainer.js +2 -2
- package/dist/editors/network-admin/index.d.ts.map +1 -1
- package/dist/editors/network-admin/index.js +0 -3
- package/dist/editors/workstream/editor.d.ts.map +1 -1
- package/dist/editors/workstream/editor.js +78 -50
- package/dist/editors/workstream/index.d.ts.map +1 -1
- package/dist/style.css +1 -6
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DriveExplorer.d.ts","sourceRoot":"","sources":["../../../../editors/network-admin/components/DriveExplorer.tsx"],"names":[],"mappings":"
|
|
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
|
|
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,
|
|
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
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
-
},
|
|
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
|
|
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 !==
|
|
254
|
+
newName !== currentName) {
|
|
200
255
|
try {
|
|
201
|
-
await onRenameNode(
|
|
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, {
|
|
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;
|
|
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,
|
|
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,
|
|
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,
|
|
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 {
|
|
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
|
-
|
|
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
|
|
27
|
-
const
|
|
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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
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
|
|
131
|
+
}, [rfpDocumentNode, rfpDocumentDataState]);
|
|
104
132
|
const searchRfpDocuments = (userInput) => {
|
|
105
|
-
const results =
|
|
106
|
-
node.
|
|
107
|
-
node.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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;
|
|
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.
|
|
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");
|