@powerhousedao/connect 1.0.21-staging.0 → 1.0.22-dev.1
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/.env +1 -1
- package/dist/assets/{app-B2txMMB6.js → app-B-5qYsgM.js} +8796 -3328
- package/dist/assets/app-B-5qYsgM.js.map +1 -0
- package/dist/assets/{app-CDOWlDp2.css → app-CmlD3Pwe.css} +119 -1
- package/dist/assets/{app-loader-uTr5bb-C.js → app-loader-DXPAMQYN.js} +681 -375
- package/dist/assets/app-loader-DXPAMQYN.js.map +1 -0
- package/dist/assets/{app-loader-DiF8OhX3.css → app-loader-DaCxVT0x.css} +134 -0
- package/dist/assets/browser-DC1g4ocI.js +27235 -0
- package/dist/assets/browser-DC1g4ocI.js.map +1 -0
- package/dist/assets/{ccip-Eu5ix3yZ.js → ccip-B4L3odPP.js} +5 -3
- package/dist/assets/ccip-B4L3odPP.js.map +1 -0
- package/dist/assets/{content-ZNvpO_Bf.js → content-D22zsKwo.js} +1052 -374
- package/dist/assets/content-D22zsKwo.js.map +1 -0
- package/dist/assets/{index-CdCNoFiu.js → index-CCV8LLva.js} +4 -3
- package/dist/assets/index-CCV8LLva.js.map +1 -0
- package/dist/assets/{index-CXtQlZED.js → index-CKPKk_m5.js} +24 -171
- package/dist/assets/index-CKPKk_m5.js.map +1 -0
- package/dist/assets/index-CWah4bZB.js +209 -0
- package/dist/assets/index-CWah4bZB.js.map +1 -0
- package/dist/assets/{index-BQuSynqj.js → index-bTL_WhmE.js} +8 -6
- package/dist/assets/index-bTL_WhmE.js.map +1 -0
- package/dist/assets/{main.D6_W-5oY.js → main.B0yzXDFz.js} +2 -1
- package/dist/assets/main.B0yzXDFz.js.map +1 -0
- package/dist/assets/reactor-analytics-BF1jqSpK.js +45 -0
- package/dist/assets/reactor-analytics-BF1jqSpK.js.map +1 -0
- package/dist/assets/router-C1-W7Dq7.js +1585 -0
- package/dist/assets/router-C1-W7Dq7.js.map +1 -0
- package/dist/assets/{style-Ce3V83BE.css → style-BPUyhu8E.css} +3 -0
- package/dist/external-packages.js +1 -0
- package/dist/external-packages.js.map +1 -0
- package/dist/hmr.js +1 -0
- package/dist/hmr.js.map +1 -0
- package/dist/index.html +1 -1
- package/dist/service-worker.js +1 -0
- package/dist/service-worker.js.map +1 -0
- package/dist/vite-envs.sh +1 -1
- package/package.json +10 -9
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment as Fragment$1 } from "react/jsx-runtime";
|
|
2
|
-
import { t as twMerge, B as Button,
|
|
2
|
+
import { t as twMerge, B as Button, aO as mergeClassNameProps, x as ERROR, aP as MISSING, C as CONFLICT, S as SUCCESS, aQ as SYNCING, aR as INITIAL_SYNC, aS as ConnectDropdownMenu, aT as useOnClickOutside, aU as useEventListener, aV as useCopyToClipboard, aW as Select, aX as Provider, aY as Root3, aZ as Trigger, a_ as Portal, a$ as Content2, b0 as validateInitialState, b1 as validateStateSchemaName, b2 as validateModules, b3 as useDocumentDrives, A as useUiNodesContext, b4 as useDriveContext, b5 as FILE$1, F as useUnwrappedReactor, b6 as useConnectDid, b7 as useConnectCrypto, o as useTranslation, G as useModal, b8 as useAtomValue, b9 as themeAtom, ba as useUser, bb as useUserPermissions$1, p as useUiNodes, bc as exportFile, bd as useGetDocumentModelModule, be as addActionContext$1, bf as signOperation$1, e as useDocumentDriveServer, bg as useHotkeys, bh as DriveLayout, bi as DriveContextProvider, bj as SearchBar, N as useAnalyticsStore, bk as useQueryClient, u as useQuery, a4 as AnalyticsPath, bl as useAnalyticsEngine, a3 as DateTime, bm as AnalyticsGranularity, bn as useGetEditor, bo as isSameDocument, n as useNavigate, s as useAsyncReactor, bp as useFilteredDocumentModels, bq as useDriveEditor, br as useDocumentDriveById, z as useParams, q as useDocumentDrives$1, w as toast } from "./app-B-5qYsgM.js";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import React__default, { useState, useCallback, useMemo, useEffect, Fragment, useRef, useLayoutEffect, memo as memo$1, createElement, useSyncExternalStore, Suspense } from "react";
|
|
5
|
-
import {
|
|
5
|
+
import { $ as Icon, bX as getDimensions, bY as READ, bZ as nodeOptionsMap, b_ as defaultFileOptions, b$ as DELETE, c0 as RENAME, c1 as WRITE, c2 as DUPLICATE, c3 as defaultFolderOptions, c4 as garbageCollect, c5 as sortOperations, c6 as UI_NODE, aQ as DRIVE, aB as FILE, ae as buildSignedOperation, aq as generateId$1, ay as isFolderNode, aD as generateNodesCopy, aE as copyNode, aC as moveNode, aA as updateNode, az as deleteNode, at as generateAddNodeAction, au as isFileNode, ax as addFolder, c7 as undo, c8 as redo, _ as logger, aR as FOLDER, c9 as useDocumentDispatch$1, an as driveDocumentModelModule } from "./app-loader-DXPAMQYN.js";
|
|
6
|
+
import { E as ENSAvatar, a as ErrorBoundary } from "./router-C1-W7Dq7.js";
|
|
6
7
|
import { flushSync } from "react-dom";
|
|
7
|
-
import "./main.
|
|
8
|
+
import "./main.B0yzXDFz.js";
|
|
9
|
+
import "node:fs";
|
|
8
10
|
const PaginationButton = ({ active = false, ...props }) => {
|
|
9
11
|
const className = twMerge("h-8 min-w-8 border border-solid border-gray-300 bg-white px-3 py-1 text-xs text-gray-900 hover:bg-gray-100", !active && "border-0");
|
|
10
12
|
return jsx(Button, { color: "light", size: "small", ...mergeClassNameProps(props, className), children: props.children });
|
|
@@ -151,131 +153,12 @@ function DefaultEditorLoader(props) {
|
|
|
151
153
|
const { message: message2 = "Loading editor", ...divProps } = props;
|
|
152
154
|
return jsx("div", { className: "grid h-full place-items-center", ...divProps, children: jsxs("div", { className: "-mt-20 grid place-items-center", children: [jsx("h3", { className: "mb-4 text-xl", children: message2 }), jsx(AnimatedLoader, {})] }) });
|
|
153
155
|
}
|
|
154
|
-
const DocumentToolbar = (props) => {
|
|
155
|
-
const { undo: undo2, canUndo, redo: redo2, canRedo, title, onClose, onExport, className, onShowRevisionHistory, onSwitchboardLinkClick, onShowTimeline } = props;
|
|
156
|
-
const isUndoDisabled = !canUndo || !undo2;
|
|
157
|
-
const isRedoDisabled = !canRedo || !redo2;
|
|
158
|
-
const isExportDisabled = !onExport;
|
|
159
|
-
const isSwitchboardLinkDisabled = !onSwitchboardLinkClick;
|
|
160
|
-
const isRevisionHistoryDisabled = !onShowRevisionHistory;
|
|
161
|
-
const isTimelineDisabled = !onShowTimeline;
|
|
162
|
-
return jsxs("div", { className: twMerge("flex h-12 w-full items-center justify-between rounded-xl border border-gray-200 bg-slate-50 px-4", className), children: [jsxs("div", { className: "flex items-center gap-x-2", children: [jsx("button", { className: twMerge("grid size-8 place-items-center rounded-lg border border-gray-200 bg-white", isUndoDisabled ? "cursor-not-allowed" : "cursor-pointer active:opacity-70"), onClick: undo2, disabled: isUndoDisabled, children: jsx(Icon, { name: "ArrowCouterclockwise", size: 16, className: isUndoDisabled ? "text-gray-500" : "text-gray-900" }) }), jsx("button", { className: twMerge("grid size-8 place-items-center rounded-lg border border-gray-200 bg-white", isRedoDisabled ? "cursor-not-allowed" : "cursor-pointer active:opacity-70"), onClick: redo2, disabled: isRedoDisabled, children: jsx("div", { className: "-scale-x-100", children: jsx(Icon, { name: "ArrowCouterclockwise", size: 16, className: isRedoDisabled ? "text-gray-500" : "text-gray-900" }) }) }), jsx("button", { className: twMerge("flex h-8 items-center rounded-lg border border-gray-200 bg-white px-3 text-sm", isExportDisabled ? "cursor-not-allowed" : "cursor-pointer active:opacity-70"), onClick: onExport, disabled: isExportDisabled, children: jsx("span", { className: isExportDisabled ? "text-gray-500" : "text-gray-900", children: "Export" }) })] }), jsx("div", { className: "flex items-center", children: jsx("h1", { className: "text-sm font-medium text-gray-500", children: title }) }), jsxs("div", { className: "flex items-center gap-x-2", children: [jsx("button", { className: twMerge("grid size-8 place-items-center rounded-lg border border-gray-200 bg-white", isSwitchboardLinkDisabled ? "cursor-not-allowed" : "cursor-pointer active:opacity-70"), onClick: onSwitchboardLinkClick, disabled: isSwitchboardLinkDisabled, children: jsx(Icon, { name: "Drive", size: 16, className: isSwitchboardLinkDisabled ? "text-gray-500" : "text-gray-900" }) }), jsx("button", { className: twMerge("grid size-8 place-items-center rounded-lg border border-gray-200 bg-white", isRevisionHistoryDisabled ? "cursor-not-allowed" : "cursor-pointer active:opacity-70"), onClick: onShowRevisionHistory, disabled: isRevisionHistoryDisabled, children: jsx(Icon, { name: "History", size: 16, className: isRevisionHistoryDisabled ? "text-gray-500" : "text-gray-900" }) }), jsx("button", { className: twMerge("grid size-8 place-items-center rounded-lg border border-gray-200 bg-white", isTimelineDisabled ? "cursor-not-allowed" : "cursor-pointer active:opacity-70"), onClick: onShowTimeline, disabled: isTimelineDisabled, children: jsx(Icon, { name: "Timeline", size: 16, className: twMerge("text-gray-900", isTimelineDisabled && "opacity-50") }) }), jsx("button", { className: "grid size-8 cursor-pointer place-items-center rounded-lg border border-gray-200 bg-white active:opacity-70", onClick: onClose, children: jsx(Icon, { name: "XmarkLight", size: 16, className: "text-gray-900" }) })] })] });
|
|
163
|
-
};
|
|
164
|
-
const syncIcons = {
|
|
165
|
-
SYNCING: "Syncing",
|
|
166
|
-
SUCCESS: "Synced",
|
|
167
|
-
CONFLICT: "Error",
|
|
168
|
-
MISSING: "Circle",
|
|
169
|
-
ERROR: "Error",
|
|
170
|
-
INITIAL_SYNC: "Syncing"
|
|
171
|
-
};
|
|
172
|
-
function SyncStatusIcon(props) {
|
|
173
|
-
const { syncStatus, className, overrideSyncIcons = {}, ...iconProps } = props;
|
|
174
|
-
const icons = { ...syncIcons, ...overrideSyncIcons };
|
|
175
|
-
const syncStatusIcons = {
|
|
176
|
-
[INITIAL_SYNC]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-blue-900", className), name: icons[INITIAL_SYNC] }),
|
|
177
|
-
[SYNCING]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-blue-900", className), name: icons[SYNCING] }),
|
|
178
|
-
[SUCCESS]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-green-900", className), name: icons[SUCCESS] }),
|
|
179
|
-
[CONFLICT]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-orange-900", className), name: icons[CONFLICT] }),
|
|
180
|
-
[MISSING]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-red-900", className), name: icons[MISSING] }),
|
|
181
|
-
[ERROR]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-red-900", className), name: icons[ERROR] })
|
|
182
|
-
};
|
|
183
|
-
return syncStatusIcons[syncStatus];
|
|
184
|
-
}
|
|
185
|
-
function FileItem(props) {
|
|
186
|
-
const { uiNode, className, customDocumentIconSrc, onSelectNode, onRenameNode, onDuplicateNode, onDeleteNode, isAllowedToCreateDocuments } = props;
|
|
187
|
-
const [mode, setMode] = useState(READ);
|
|
188
|
-
const [isDropdownMenuOpen, setIsDropdownMenuOpen] = useState(false);
|
|
189
|
-
const { dragProps } = useDrag({ uiNode });
|
|
190
|
-
const isReadMode = mode === READ;
|
|
191
|
-
const dropdownMenuHandlers = {
|
|
192
|
-
[DUPLICATE]: () => onDuplicateNode(uiNode),
|
|
193
|
-
[RENAME]: () => setMode(WRITE),
|
|
194
|
-
[DELETE]: () => onDeleteNode(uiNode)
|
|
195
|
-
};
|
|
196
|
-
const dropdownMenuOptions = Object.entries(nodeOptionsMap).map(([id, option]) => ({
|
|
197
|
-
...option,
|
|
198
|
-
id
|
|
199
|
-
})).filter((option) => defaultFileOptions.includes(option.id));
|
|
200
|
-
function onSubmit(name) {
|
|
201
|
-
onRenameNode(name, uiNode);
|
|
202
|
-
setMode(READ);
|
|
203
|
-
}
|
|
204
|
-
function onCancel() {
|
|
205
|
-
setMode(READ);
|
|
206
|
-
}
|
|
207
|
-
function onClick() {
|
|
208
|
-
onSelectNode(uiNode);
|
|
209
|
-
}
|
|
210
|
-
function onDropdownMenuOptionClick(itemId) {
|
|
211
|
-
const handler = dropdownMenuHandlers[itemId];
|
|
212
|
-
if (!handler) {
|
|
213
|
-
console.error(`No handler found for dropdown menu item: ${itemId}`);
|
|
214
|
-
return;
|
|
215
|
-
}
|
|
216
|
-
handler();
|
|
217
|
-
setIsDropdownMenuOpen(false);
|
|
218
|
-
}
|
|
219
|
-
const iconSrc = getDocumentIconSrc(uiNode.documentType, customDocumentIconSrc);
|
|
220
|
-
const iconNode = jsxs("div", { className: "relative", children: [jsx("img", { alt: "file icon", className: "max-w-none", height: 34, src: iconSrc, width: 32 }), isReadMode && uiNode.syncStatus && jsx("div", { className: "absolute bottom-[-2px] right-0 size-3 rounded-full bg-white", children: jsx("div", { className: "absolute left-[-2px] top-[-2px]", children: jsx(SyncStatusIcon, { overrideSyncIcons: { SUCCESS: "CheckCircleFill" }, syncStatus: uiNode.syncStatus }) }) })] });
|
|
221
|
-
const containerStyles = twMerge("group flex h-12 cursor-pointer select-none items-center rounded-lg bg-gray-200 px-2 text-gray-600 hover:text-gray-800", className);
|
|
222
|
-
const content = isReadMode ? jsxs("div", { className: "flex w-52 items-center justify-between", children: [jsxs("div", { className: "mr-2 truncate group-hover:mr-0", children: [jsx("div", { className: "max-h-6 truncate text-sm font-medium group-hover:text-gray-800", children: uiNode.name }), jsx("div", { className: "max-h-6 truncate text-xs font-medium text-gray-600 group-hover:text-gray-800", children: uiNode.documentType })] }), isAllowedToCreateDocuments ? jsx(ConnectDropdownMenu, { items: dropdownMenuOptions, onItemClick: onDropdownMenuOptionClick, onOpenChange: setIsDropdownMenuOpen, open: isDropdownMenuOpen, children: jsx("button", { className: twMerge("hidden group-hover:block", isDropdownMenuOpen && "block"), onClick: (e) => {
|
|
223
|
-
e.stopPropagation();
|
|
224
|
-
setIsDropdownMenuOpen(true);
|
|
225
|
-
}, children: jsx(Icon, { className: "text-gray-600", name: "VerticalDots" }) }) }) : null] }) : jsx(NodeInput, { className: "ml-3 flex-1 font-medium", defaultValue: uiNode.name, onCancel, onSubmit });
|
|
226
|
-
return jsx("div", { className: "relative w-64", onClick, children: jsx("div", { ...dragProps, className: containerStyles, children: jsxs("div", { className: "flex items-center", children: [jsx("div", { className: "mr-1.5", children: iconNode }), content] }) }) });
|
|
227
|
-
}
|
|
228
|
-
function FolderItem(props) {
|
|
229
|
-
const { uiNode, isAllowedToCreateDocuments, className, onRenameNode, onDuplicateNode, onDeleteNode, onSelectNode, onAddFile, onCopyNode, onMoveNode } = props;
|
|
230
|
-
const [mode, setMode] = useState(READ);
|
|
231
|
-
const [isDropdownMenuOpen, setIsDropdownMenuOpen] = useState(false);
|
|
232
|
-
const { dragProps } = useDrag({ ...props, uiNode });
|
|
233
|
-
const { isDropTarget, dropProps } = useDrop({
|
|
234
|
-
uiNode,
|
|
235
|
-
onAddFile,
|
|
236
|
-
onCopyNode,
|
|
237
|
-
onMoveNode
|
|
238
|
-
});
|
|
239
|
-
const isReadMode = mode === READ;
|
|
240
|
-
function onCancel() {
|
|
241
|
-
setMode(READ);
|
|
242
|
-
}
|
|
243
|
-
function onSubmit(name) {
|
|
244
|
-
onRenameNode(name, uiNode);
|
|
245
|
-
setMode(READ);
|
|
246
|
-
}
|
|
247
|
-
function onClick() {
|
|
248
|
-
onSelectNode(uiNode);
|
|
249
|
-
}
|
|
250
|
-
const dropdownMenuHandlers = {
|
|
251
|
-
[DUPLICATE]: () => onDuplicateNode(uiNode),
|
|
252
|
-
[RENAME]: () => setMode(WRITE),
|
|
253
|
-
[DELETE]: () => onDeleteNode(uiNode)
|
|
254
|
-
};
|
|
255
|
-
const dropdownMenuOptions = Object.entries(nodeOptionsMap).map(([id, option]) => ({
|
|
256
|
-
...option,
|
|
257
|
-
id
|
|
258
|
-
})).filter((option) => defaultFolderOptions.includes(option.id));
|
|
259
|
-
function onDropdownMenuOptionClick(itemId) {
|
|
260
|
-
const handler = dropdownMenuHandlers[itemId];
|
|
261
|
-
if (!handler) {
|
|
262
|
-
console.error(`No handler found for dropdown menu item: ${itemId}`);
|
|
263
|
-
return;
|
|
264
|
-
}
|
|
265
|
-
handler();
|
|
266
|
-
setIsDropdownMenuOpen(false);
|
|
267
|
-
}
|
|
268
|
-
const content = isReadMode || !isAllowedToCreateDocuments ? jsx("div", { className: "ml-3 max-h-6 truncate font-medium text-gray-600 group-hover:text-gray-800", children: uiNode.name }) : jsx(NodeInput, { className: "ml-3 font-medium", defaultValue: uiNode.name, onCancel, onSubmit });
|
|
269
|
-
const containerStyles = twMerge("group flex h-12 cursor-pointer select-none items-center rounded-lg bg-gray-200 px-2", className, isDropTarget && "bg-blue-100");
|
|
270
|
-
return jsx("div", { className: "relative w-64", onClick, children: jsxs("div", { ...dragProps, ...dropProps, className: containerStyles, children: [jsxs("div", { className: "flex items-center overflow-hidden", children: [jsx("div", { className: "p-1", children: jsxs("div", { className: "relative", children: [jsx(Icon, { name: "FolderClose", size: 24 }), isReadMode && uiNode.syncStatus ? jsx("div", { className: "absolute bottom-[-3px] right-[-2px] size-3 rounded-full bg-white", children: jsx("div", { className: "absolute left-[-2px] top-[-2px]", children: jsx(SyncStatusIcon, { overrideSyncIcons: {
|
|
271
|
-
SUCCESS: "CheckCircleFill"
|
|
272
|
-
}, syncStatus: uiNode.syncStatus }) }) }) : null] }) }), content] }), isReadMode && isAllowedToCreateDocuments ? jsx(ConnectDropdownMenu, { items: dropdownMenuOptions, onItemClick: onDropdownMenuOptionClick, onOpenChange: setIsDropdownMenuOpen, open: isDropdownMenuOpen, children: jsx("button", { className: twMerge("ml-auto hidden group-hover:block", isDropdownMenuOpen && "block"), onClick: (e) => {
|
|
273
|
-
e.stopPropagation();
|
|
274
|
-
setIsDropdownMenuOpen(true);
|
|
275
|
-
}, children: jsx(Icon, { className: "text-gray-600", name: "VerticalDots" }) }) }) : null] }) });
|
|
276
|
-
}
|
|
277
156
|
const millisecondsInWeek = 6048e5;
|
|
278
157
|
const millisecondsInDay = 864e5;
|
|
158
|
+
const millisecondsInMinute = 6e4;
|
|
159
|
+
const millisecondsInHour = 36e5;
|
|
160
|
+
const minutesInMonth = 43200;
|
|
161
|
+
const minutesInDay = 1440;
|
|
279
162
|
const constructFromSymbol = Symbol.for("constructDateFrom");
|
|
280
163
|
function constructFrom(date, value) {
|
|
281
164
|
if (typeof date === "function") return date(value);
|
|
@@ -343,7 +226,7 @@ function getTimezoneOffsetInMilliseconds(date) {
|
|
|
343
226
|
function normalizeDates(context, ...dates) {
|
|
344
227
|
const normalize = constructFrom.bind(
|
|
345
228
|
null,
|
|
346
|
-
dates.find((date) => typeof date === "object")
|
|
229
|
+
context || dates.find((date) => typeof date === "object")
|
|
347
230
|
);
|
|
348
231
|
return dates.map(normalize);
|
|
349
232
|
}
|
|
@@ -371,12 +254,83 @@ function startOfISOWeekYear(date, options) {
|
|
|
371
254
|
fourthOfJanuary.setHours(0, 0, 0, 0);
|
|
372
255
|
return startOfISOWeek(fourthOfJanuary);
|
|
373
256
|
}
|
|
257
|
+
function compareAsc(dateLeft, dateRight) {
|
|
258
|
+
const diff = +toDate(dateLeft) - +toDate(dateRight);
|
|
259
|
+
if (diff < 0) return -1;
|
|
260
|
+
else if (diff > 0) return 1;
|
|
261
|
+
return diff;
|
|
262
|
+
}
|
|
263
|
+
function constructNow(date) {
|
|
264
|
+
return constructFrom(date, Date.now());
|
|
265
|
+
}
|
|
374
266
|
function isDate(value) {
|
|
375
267
|
return value instanceof Date || typeof value === "object" && Object.prototype.toString.call(value) === "[object Date]";
|
|
376
268
|
}
|
|
377
269
|
function isValid(date) {
|
|
378
270
|
return !(!isDate(date) && typeof date !== "number" || isNaN(+toDate(date)));
|
|
379
271
|
}
|
|
272
|
+
function differenceInCalendarMonths(laterDate, earlierDate, options) {
|
|
273
|
+
const [laterDate_, earlierDate_] = normalizeDates(
|
|
274
|
+
options == null ? void 0 : options.in,
|
|
275
|
+
laterDate,
|
|
276
|
+
earlierDate
|
|
277
|
+
);
|
|
278
|
+
const yearsDiff = laterDate_.getFullYear() - earlierDate_.getFullYear();
|
|
279
|
+
const monthsDiff = laterDate_.getMonth() - earlierDate_.getMonth();
|
|
280
|
+
return yearsDiff * 12 + monthsDiff;
|
|
281
|
+
}
|
|
282
|
+
function getRoundingMethod(method) {
|
|
283
|
+
return (number) => {
|
|
284
|
+
const round = method ? Math[method] : Math.trunc;
|
|
285
|
+
const result = round(number);
|
|
286
|
+
return result === 0 ? 0 : result;
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
function differenceInMilliseconds(laterDate, earlierDate) {
|
|
290
|
+
return +toDate(laterDate) - +toDate(earlierDate);
|
|
291
|
+
}
|
|
292
|
+
function endOfDay(date, options) {
|
|
293
|
+
const _date = toDate(date, options == null ? void 0 : options.in);
|
|
294
|
+
_date.setHours(23, 59, 59, 999);
|
|
295
|
+
return _date;
|
|
296
|
+
}
|
|
297
|
+
function endOfMonth(date, options) {
|
|
298
|
+
const _date = toDate(date, options == null ? void 0 : options.in);
|
|
299
|
+
const month = _date.getMonth();
|
|
300
|
+
_date.setFullYear(_date.getFullYear(), month + 1, 0);
|
|
301
|
+
_date.setHours(23, 59, 59, 999);
|
|
302
|
+
return _date;
|
|
303
|
+
}
|
|
304
|
+
function isLastDayOfMonth(date, options) {
|
|
305
|
+
const _date = toDate(date, options == null ? void 0 : options.in);
|
|
306
|
+
return +endOfDay(_date, options) === +endOfMonth(_date, options);
|
|
307
|
+
}
|
|
308
|
+
function differenceInMonths(laterDate, earlierDate, options) {
|
|
309
|
+
const [laterDate_, workingLaterDate, earlierDate_] = normalizeDates(
|
|
310
|
+
options == null ? void 0 : options.in,
|
|
311
|
+
laterDate,
|
|
312
|
+
laterDate,
|
|
313
|
+
earlierDate
|
|
314
|
+
);
|
|
315
|
+
const sign = compareAsc(workingLaterDate, earlierDate_);
|
|
316
|
+
const difference = Math.abs(
|
|
317
|
+
differenceInCalendarMonths(workingLaterDate, earlierDate_)
|
|
318
|
+
);
|
|
319
|
+
if (difference < 1) return 0;
|
|
320
|
+
if (workingLaterDate.getMonth() === 1 && workingLaterDate.getDate() > 27)
|
|
321
|
+
workingLaterDate.setDate(30);
|
|
322
|
+
workingLaterDate.setMonth(workingLaterDate.getMonth() - sign * difference);
|
|
323
|
+
let isLastMonthNotFull = compareAsc(workingLaterDate, earlierDate_) === -sign;
|
|
324
|
+
if (isLastDayOfMonth(laterDate_) && difference === 1 && compareAsc(laterDate_, earlierDate_) === 1) {
|
|
325
|
+
isLastMonthNotFull = false;
|
|
326
|
+
}
|
|
327
|
+
const result = sign * (difference - +isLastMonthNotFull);
|
|
328
|
+
return result === 0 ? 0 : result;
|
|
329
|
+
}
|
|
330
|
+
function differenceInSeconds(laterDate, earlierDate, options) {
|
|
331
|
+
const diff = differenceInMilliseconds(laterDate, earlierDate) / 1e3;
|
|
332
|
+
return getRoundingMethod(options == null ? void 0 : options.roundingMethod)(diff);
|
|
333
|
+
}
|
|
380
334
|
function startOfYear(date, options) {
|
|
381
335
|
const date_ = toDate(date, options == null ? void 0 : options.in);
|
|
382
336
|
date_.setFullYear(date_.getFullYear(), 0, 1);
|
|
@@ -446,7 +400,7 @@ const formatDistanceLocale = {
|
|
|
446
400
|
other: "almost {{count}} years"
|
|
447
401
|
}
|
|
448
402
|
};
|
|
449
|
-
const formatDistance = (token, count, options) => {
|
|
403
|
+
const formatDistance$1 = (token, count, options) => {
|
|
450
404
|
let result;
|
|
451
405
|
const tokenValue = formatDistanceLocale[token];
|
|
452
406
|
if (typeof tokenValue === "string") {
|
|
@@ -862,7 +816,7 @@ const match = {
|
|
|
862
816
|
};
|
|
863
817
|
const enUS = {
|
|
864
818
|
code: "en-US",
|
|
865
|
-
formatDistance,
|
|
819
|
+
formatDistance: formatDistance$1,
|
|
866
820
|
formatLong,
|
|
867
821
|
formatRelative,
|
|
868
822
|
localize,
|
|
@@ -1764,75 +1718,574 @@ function cleanEscapedString(input) {
|
|
|
1764
1718
|
}
|
|
1765
1719
|
return matched[1].replace(doubleQuoteRegExp, "'");
|
|
1766
1720
|
}
|
|
1767
|
-
function
|
|
1768
|
-
const
|
|
1769
|
-
const
|
|
1770
|
-
const
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1721
|
+
function formatDistance(laterDate, earlierDate, options) {
|
|
1722
|
+
const defaultOptions2 = getDefaultOptions();
|
|
1723
|
+
const locale = (options == null ? void 0 : options.locale) ?? defaultOptions2.locale ?? enUS;
|
|
1724
|
+
const minutesInAlmostTwoDays = 2520;
|
|
1725
|
+
const comparison = compareAsc(laterDate, earlierDate);
|
|
1726
|
+
if (isNaN(comparison)) throw new RangeError("Invalid time value");
|
|
1727
|
+
const localizeOptions = Object.assign({}, options, {
|
|
1728
|
+
addSuffix: options == null ? void 0 : options.addSuffix,
|
|
1729
|
+
comparison
|
|
1730
|
+
});
|
|
1731
|
+
const [laterDate_, earlierDate_] = normalizeDates(
|
|
1732
|
+
options == null ? void 0 : options.in,
|
|
1733
|
+
...comparison > 0 ? [earlierDate, laterDate] : [laterDate, earlierDate]
|
|
1734
|
+
);
|
|
1735
|
+
const seconds = differenceInSeconds(earlierDate_, laterDate_);
|
|
1736
|
+
const offsetInSeconds = (getTimezoneOffsetInMilliseconds(earlierDate_) - getTimezoneOffsetInMilliseconds(laterDate_)) / 1e3;
|
|
1737
|
+
const minutes = Math.round((seconds - offsetInSeconds) / 60);
|
|
1738
|
+
let months;
|
|
1739
|
+
if (minutes < 2) {
|
|
1740
|
+
if (options == null ? void 0 : options.includeSeconds) {
|
|
1741
|
+
if (seconds < 5) {
|
|
1742
|
+
return locale.formatDistance("lessThanXSeconds", 5, localizeOptions);
|
|
1743
|
+
} else if (seconds < 10) {
|
|
1744
|
+
return locale.formatDistance("lessThanXSeconds", 10, localizeOptions);
|
|
1745
|
+
} else if (seconds < 20) {
|
|
1746
|
+
return locale.formatDistance("lessThanXSeconds", 20, localizeOptions);
|
|
1747
|
+
} else if (seconds < 40) {
|
|
1748
|
+
return locale.formatDistance("halfAMinute", 0, localizeOptions);
|
|
1749
|
+
} else if (seconds < 60) {
|
|
1750
|
+
return locale.formatDistance("lessThanXMinutes", 1, localizeOptions);
|
|
1751
|
+
} else {
|
|
1752
|
+
return locale.formatDistance("xMinutes", 1, localizeOptions);
|
|
1753
|
+
}
|
|
1754
|
+
} else {
|
|
1755
|
+
if (minutes === 0) {
|
|
1756
|
+
return locale.formatDistance("lessThanXMinutes", 1, localizeOptions);
|
|
1757
|
+
} else {
|
|
1758
|
+
return locale.formatDistance("xMinutes", minutes, localizeOptions);
|
|
1759
|
+
}
|
|
1775
1760
|
}
|
|
1776
|
-
|
|
1777
|
-
|
|
1761
|
+
} else if (minutes < 45) {
|
|
1762
|
+
return locale.formatDistance("xMinutes", minutes, localizeOptions);
|
|
1763
|
+
} else if (minutes < 90) {
|
|
1764
|
+
return locale.formatDistance("aboutXHours", 1, localizeOptions);
|
|
1765
|
+
} else if (minutes < minutesInDay) {
|
|
1766
|
+
const hours = Math.round(minutes / 60);
|
|
1767
|
+
return locale.formatDistance("aboutXHours", hours, localizeOptions);
|
|
1768
|
+
} else if (minutes < minutesInAlmostTwoDays) {
|
|
1769
|
+
return locale.formatDistance("xDays", 1, localizeOptions);
|
|
1770
|
+
} else if (minutes < minutesInMonth) {
|
|
1771
|
+
const days = Math.round(minutes / minutesInDay);
|
|
1772
|
+
return locale.formatDistance("xDays", days, localizeOptions);
|
|
1773
|
+
} else if (minutes < minutesInMonth * 2) {
|
|
1774
|
+
months = Math.round(minutes / minutesInMonth);
|
|
1775
|
+
return locale.formatDistance("aboutXMonths", months, localizeOptions);
|
|
1776
|
+
}
|
|
1777
|
+
months = differenceInMonths(earlierDate_, laterDate_);
|
|
1778
|
+
if (months < 12) {
|
|
1779
|
+
const nearestMonth = Math.round(minutes / minutesInMonth);
|
|
1780
|
+
return locale.formatDistance("xMonths", nearestMonth, localizeOptions);
|
|
1781
|
+
} else {
|
|
1782
|
+
const monthsSinceStartOfYear = months % 12;
|
|
1783
|
+
const years = Math.trunc(months / 12);
|
|
1784
|
+
if (monthsSinceStartOfYear < 3) {
|
|
1785
|
+
return locale.formatDistance("aboutXYears", years, localizeOptions);
|
|
1786
|
+
} else if (monthsSinceStartOfYear < 9) {
|
|
1787
|
+
return locale.formatDistance("overXYears", years, localizeOptions);
|
|
1788
|
+
} else {
|
|
1789
|
+
return locale.formatDistance("almostXYears", years + 1, localizeOptions);
|
|
1778
1790
|
}
|
|
1779
|
-
}
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
function formatDistanceToNow(date, options) {
|
|
1794
|
+
return formatDistance(date, constructNow(date), options);
|
|
1795
|
+
}
|
|
1796
|
+
function parseISO(argument, options) {
|
|
1797
|
+
const invalidDate = () => constructFrom(options == null ? void 0 : options.in, NaN);
|
|
1798
|
+
const additionalDigits = 2;
|
|
1799
|
+
const dateStrings = splitDateString(argument);
|
|
1800
|
+
let date;
|
|
1801
|
+
if (dateStrings.date) {
|
|
1802
|
+
const parseYearResult = parseYear(dateStrings.date, additionalDigits);
|
|
1803
|
+
date = parseDate(parseYearResult.restDateString, parseYearResult.year);
|
|
1804
|
+
}
|
|
1805
|
+
if (!date || isNaN(+date)) return invalidDate();
|
|
1806
|
+
const timestamp = +date;
|
|
1807
|
+
let time = 0;
|
|
1808
|
+
let offset;
|
|
1809
|
+
if (dateStrings.time) {
|
|
1810
|
+
time = parseTime(dateStrings.time);
|
|
1811
|
+
if (isNaN(time)) return invalidDate();
|
|
1812
|
+
}
|
|
1813
|
+
if (dateStrings.timezone) {
|
|
1814
|
+
offset = parseTimezone(dateStrings.timezone);
|
|
1815
|
+
if (isNaN(offset)) return invalidDate();
|
|
1816
|
+
} else {
|
|
1817
|
+
const tmpDate = new Date(timestamp + time);
|
|
1818
|
+
const result = toDate(0, options == null ? void 0 : options.in);
|
|
1819
|
+
result.setFullYear(
|
|
1820
|
+
tmpDate.getUTCFullYear(),
|
|
1821
|
+
tmpDate.getUTCMonth(),
|
|
1822
|
+
tmpDate.getUTCDate()
|
|
1823
|
+
);
|
|
1824
|
+
result.setHours(
|
|
1825
|
+
tmpDate.getUTCHours(),
|
|
1826
|
+
tmpDate.getUTCMinutes(),
|
|
1827
|
+
tmpDate.getUTCSeconds(),
|
|
1828
|
+
tmpDate.getUTCMilliseconds()
|
|
1829
|
+
);
|
|
1830
|
+
return result;
|
|
1831
|
+
}
|
|
1832
|
+
return toDate(timestamp + time + offset, options == null ? void 0 : options.in);
|
|
1833
|
+
}
|
|
1834
|
+
const patterns = {
|
|
1835
|
+
dateTimeDelimiter: /[T ]/,
|
|
1836
|
+
timeZoneDelimiter: /[Z ]/i,
|
|
1837
|
+
timezone: /([Z+-].*)$/
|
|
1838
|
+
};
|
|
1839
|
+
const dateRegex = /^-?(?:(\d{3})|(\d{2})(?:-?(\d{2}))?|W(\d{2})(?:-?(\d{1}))?|)$/;
|
|
1840
|
+
const timeRegex = /^(\d{2}(?:[.,]\d*)?)(?::?(\d{2}(?:[.,]\d*)?))?(?::?(\d{2}(?:[.,]\d*)?))?$/;
|
|
1841
|
+
const timezoneRegex = /^([+-])(\d{2})(?::?(\d{2}))?$/;
|
|
1842
|
+
function splitDateString(dateString) {
|
|
1843
|
+
const dateStrings = {};
|
|
1844
|
+
const array = dateString.split(patterns.dateTimeDelimiter);
|
|
1845
|
+
let timeString;
|
|
1846
|
+
if (array.length > 2) {
|
|
1847
|
+
return dateStrings;
|
|
1848
|
+
}
|
|
1849
|
+
if (/:/.test(array[0])) {
|
|
1850
|
+
timeString = array[0];
|
|
1851
|
+
} else {
|
|
1852
|
+
dateStrings.date = array[0];
|
|
1853
|
+
timeString = array[1];
|
|
1854
|
+
if (patterns.timeZoneDelimiter.test(dateStrings.date)) {
|
|
1855
|
+
dateStrings.date = dateString.split(patterns.timeZoneDelimiter)[0];
|
|
1856
|
+
timeString = dateString.substr(
|
|
1857
|
+
dateStrings.date.length,
|
|
1858
|
+
dateString.length
|
|
1859
|
+
);
|
|
1791
1860
|
}
|
|
1792
1861
|
}
|
|
1793
|
-
|
|
1862
|
+
if (timeString) {
|
|
1863
|
+
const token = patterns.timezone.exec(timeString);
|
|
1864
|
+
if (token) {
|
|
1865
|
+
dateStrings.time = timeString.replace(token[1], "");
|
|
1866
|
+
dateStrings.timezone = token[1];
|
|
1867
|
+
} else {
|
|
1868
|
+
dateStrings.time = timeString;
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
return dateStrings;
|
|
1794
1872
|
}
|
|
1795
|
-
function
|
|
1796
|
-
const
|
|
1797
|
-
|
|
1873
|
+
function parseYear(dateString, additionalDigits) {
|
|
1874
|
+
const regex = new RegExp(
|
|
1875
|
+
"^(?:(\\d{4}|[+-]\\d{" + (4 + additionalDigits) + "})|(\\d{2}|[+-]\\d{" + (2 + additionalDigits) + "})$)"
|
|
1876
|
+
);
|
|
1877
|
+
const captures = dateString.match(regex);
|
|
1878
|
+
if (!captures) return { year: NaN, restDateString: "" };
|
|
1879
|
+
const year = captures[1] ? parseInt(captures[1]) : null;
|
|
1880
|
+
const century = captures[2] ? parseInt(captures[2]) : null;
|
|
1881
|
+
return {
|
|
1882
|
+
year: century === null ? year : century * 100,
|
|
1883
|
+
restDateString: dateString.slice((captures[1] || captures[2]).length)
|
|
1884
|
+
};
|
|
1798
1885
|
}
|
|
1799
|
-
function
|
|
1800
|
-
|
|
1801
|
-
const
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1886
|
+
function parseDate(dateString, year) {
|
|
1887
|
+
if (year === null) return /* @__PURE__ */ new Date(NaN);
|
|
1888
|
+
const captures = dateString.match(dateRegex);
|
|
1889
|
+
if (!captures) return /* @__PURE__ */ new Date(NaN);
|
|
1890
|
+
const isWeekDate = !!captures[4];
|
|
1891
|
+
const dayOfYear = parseDateUnit(captures[1]);
|
|
1892
|
+
const month = parseDateUnit(captures[2]) - 1;
|
|
1893
|
+
const day = parseDateUnit(captures[3]);
|
|
1894
|
+
const week = parseDateUnit(captures[4]);
|
|
1895
|
+
const dayOfWeek = parseDateUnit(captures[5]) - 1;
|
|
1896
|
+
if (isWeekDate) {
|
|
1897
|
+
if (!validateWeekDate(year, week, dayOfWeek)) {
|
|
1898
|
+
return /* @__PURE__ */ new Date(NaN);
|
|
1899
|
+
}
|
|
1900
|
+
return dayOfISOWeekYear(year, week, dayOfWeek);
|
|
1901
|
+
} else {
|
|
1902
|
+
const date = /* @__PURE__ */ new Date(0);
|
|
1903
|
+
if (!validateDate(year, month, day) || !validateDayOfYearDate(year, dayOfYear)) {
|
|
1904
|
+
return /* @__PURE__ */ new Date(NaN);
|
|
1905
|
+
}
|
|
1906
|
+
date.setUTCFullYear(year, month, Math.max(dayOfYear, day));
|
|
1907
|
+
return date;
|
|
1808
1908
|
}
|
|
1809
|
-
return jsxs("button", { className: "flex h-8 items-center gap-1 rounded-lg bg-slate-50 pl-1 pr-2 text-xs text-slate-100", onClick: handleCopy(docId), children: [jsx(Icon, { name: "Link" }), "DOC ID", jsx("span", { className: "text-gray-900", children: docId })] });
|
|
1810
1909
|
}
|
|
1811
|
-
function
|
|
1812
|
-
|
|
1813
|
-
const items = [
|
|
1814
|
-
{ displayValue: "Global scope", value: "global" },
|
|
1815
|
-
{ displayValue: "Local scope", value: "local" }
|
|
1816
|
-
];
|
|
1817
|
-
return jsx(Select, { absolutePositionMenu: true, containerClassName: "bg-slate-50 text-gray-500 rounded-lg w-fit text-xs z-10", id: "scope select", itemClassName: "py-2 text-gray-500 grid grid-cols-[auto,auto] gap-1", items, menuClassName: "min-w-0 text-gray-500", onChange, value });
|
|
1910
|
+
function parseDateUnit(value) {
|
|
1911
|
+
return value ? parseInt(value) : 1;
|
|
1818
1912
|
}
|
|
1819
|
-
function
|
|
1820
|
-
const
|
|
1821
|
-
|
|
1913
|
+
function parseTime(timeString) {
|
|
1914
|
+
const captures = timeString.match(timeRegex);
|
|
1915
|
+
if (!captures) return NaN;
|
|
1916
|
+
const hours = parseTimeUnit(captures[1]);
|
|
1917
|
+
const minutes = parseTimeUnit(captures[2]);
|
|
1918
|
+
const seconds = parseTimeUnit(captures[3]);
|
|
1919
|
+
if (!validateTime(hours, minutes, seconds)) {
|
|
1920
|
+
return NaN;
|
|
1921
|
+
}
|
|
1922
|
+
return hours * millisecondsInHour + minutes * millisecondsInMinute + seconds * 1e3;
|
|
1822
1923
|
}
|
|
1823
|
-
function
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1924
|
+
function parseTimeUnit(value) {
|
|
1925
|
+
return value && parseFloat(value.replace(",", ".")) || 0;
|
|
1926
|
+
}
|
|
1927
|
+
function parseTimezone(timezoneString) {
|
|
1928
|
+
if (timezoneString === "Z") return 0;
|
|
1929
|
+
const captures = timezoneString.match(timezoneRegex);
|
|
1930
|
+
if (!captures) return 0;
|
|
1931
|
+
const sign = captures[1] === "+" ? -1 : 1;
|
|
1932
|
+
const hours = parseInt(captures[2]);
|
|
1933
|
+
const minutes = captures[3] && parseInt(captures[3]) || 0;
|
|
1934
|
+
if (!validateTimezone(hours, minutes)) {
|
|
1935
|
+
return NaN;
|
|
1936
|
+
}
|
|
1937
|
+
return sign * (hours * millisecondsInHour + minutes * millisecondsInMinute);
|
|
1938
|
+
}
|
|
1939
|
+
function dayOfISOWeekYear(isoWeekYear, week, day) {
|
|
1940
|
+
const date = /* @__PURE__ */ new Date(0);
|
|
1941
|
+
date.setUTCFullYear(isoWeekYear, 0, 4);
|
|
1942
|
+
const fourthOfJanuaryDay = date.getUTCDay() || 7;
|
|
1943
|
+
const diff = (week - 1) * 7 + day + 1 - fourthOfJanuaryDay;
|
|
1944
|
+
date.setUTCDate(date.getUTCDate() + diff);
|
|
1945
|
+
return date;
|
|
1946
|
+
}
|
|
1947
|
+
const daysInMonths = [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
1948
|
+
function isLeapYearIndex(year) {
|
|
1949
|
+
return year % 400 === 0 || year % 4 === 0 && year % 100 !== 0;
|
|
1950
|
+
}
|
|
1951
|
+
function validateDate(year, month, date) {
|
|
1952
|
+
return month >= 0 && month <= 11 && date >= 1 && date <= (daysInMonths[month] || (isLeapYearIndex(year) ? 29 : 28));
|
|
1953
|
+
}
|
|
1954
|
+
function validateDayOfYearDate(year, dayOfYear) {
|
|
1955
|
+
return dayOfYear >= 1 && dayOfYear <= (isLeapYearIndex(year) ? 366 : 365);
|
|
1956
|
+
}
|
|
1957
|
+
function validateWeekDate(_year, week, day) {
|
|
1958
|
+
return week >= 1 && week <= 53 && day >= 0 && day <= 6;
|
|
1959
|
+
}
|
|
1960
|
+
function validateTime(hours, minutes, seconds) {
|
|
1961
|
+
if (hours === 24) {
|
|
1962
|
+
return minutes === 0 && seconds === 0;
|
|
1963
|
+
}
|
|
1964
|
+
return seconds >= 0 && seconds < 60 && minutes >= 0 && minutes < 60 && hours >= 0 && hours < 25;
|
|
1965
|
+
}
|
|
1966
|
+
function validateTimezone(_hours, minutes) {
|
|
1967
|
+
return minutes >= 0 && minutes <= 59;
|
|
1968
|
+
}
|
|
1969
|
+
const HDivider = (props) => {
|
|
1970
|
+
const { className, timestamp, title, subtitle, onClick, isSelected = false } = props;
|
|
1971
|
+
const [open, setOpen] = useState(false);
|
|
1972
|
+
const hasContent = !!title || !!subtitle || !!timestamp;
|
|
1973
|
+
useEffect(() => {
|
|
1974
|
+
if (open) {
|
|
1975
|
+
setOpen(false);
|
|
1976
|
+
setTimeout(() => hasContent && setOpen(true), 50);
|
|
1834
1977
|
}
|
|
1835
|
-
|
|
1978
|
+
}, [title, subtitle, timestamp, hasContent]);
|
|
1979
|
+
const formatTimestamp2 = (isoString) => {
|
|
1980
|
+
if (!isoString)
|
|
1981
|
+
return "";
|
|
1982
|
+
try {
|
|
1983
|
+
return formatDistanceToNow(new Date(isoString), { addSuffix: true });
|
|
1984
|
+
} catch {
|
|
1985
|
+
return isoString;
|
|
1986
|
+
}
|
|
1987
|
+
};
|
|
1988
|
+
const tooltipContent = jsxs("div", { className: "flex flex-col text-xs", children: [!!title && jsx("div", { children: title }), !!subtitle && jsx("div", { className: "text-gray-300", children: subtitle }), !!timestamp && jsx("div", { children: formatTimestamp2(timestamp) })] });
|
|
1989
|
+
const handleMouseEnter = () => {
|
|
1990
|
+
if (hasContent) {
|
|
1991
|
+
setOpen(true);
|
|
1992
|
+
}
|
|
1993
|
+
};
|
|
1994
|
+
const handleMouseLeave = () => {
|
|
1995
|
+
setOpen(false);
|
|
1996
|
+
};
|
|
1997
|
+
return jsxs("div", { className: "relative", onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: [isSelected && jsx(Icon, { name: "TimelineCaret", color: "#4EA9FF", size: 10, className: "absolute top-[-11px] z-40" }), jsx(Tooltip, { className: "rounded-md bg-gray-900 text-white", content: tooltipContent, open: open && hasContent, onOpenChange: setOpen, delayDuration: 0, side: "bottom", sideOffset: 5, children: jsx("div", { className: twMerge("mx-0.5 flex h-[25px] w-1.5 cursor-pointer flex-col items-center justify-center rounded-[2px] hover:bg-blue-300", isSelected && "bg-blue-300", className), onClick, "data-title": title, "data-subtitle": subtitle, "data-timestamp": timestamp, children: jsx("div", { className: "h-0.5 w-1 rounded-full bg-gray-500" }) }) })] });
|
|
1998
|
+
};
|
|
1999
|
+
const getBarHeight = (size = 0) => {
|
|
2000
|
+
switch (true) {
|
|
2001
|
+
case size <= 0:
|
|
2002
|
+
return "h-[1px]";
|
|
2003
|
+
case size === 1:
|
|
2004
|
+
return "h-[3px]";
|
|
2005
|
+
case size === 2:
|
|
2006
|
+
return "h-[6px]";
|
|
2007
|
+
case size === 3:
|
|
2008
|
+
return "h-[9px]";
|
|
2009
|
+
case size >= 4:
|
|
2010
|
+
return "h-[12px]";
|
|
2011
|
+
default:
|
|
2012
|
+
return "h-[1px]";
|
|
2013
|
+
}
|
|
2014
|
+
};
|
|
2015
|
+
const formatTimestamp = (isoString) => {
|
|
2016
|
+
if (!isoString)
|
|
2017
|
+
return "";
|
|
2018
|
+
try {
|
|
2019
|
+
const date = parseISO(isoString);
|
|
2020
|
+
return format(date, "HH:mm, dd, MMMM");
|
|
2021
|
+
} catch {
|
|
2022
|
+
return isoString;
|
|
2023
|
+
}
|
|
2024
|
+
};
|
|
2025
|
+
const TimelineBar = ({ onClick, className, timestamp, additions, deletions, addSize = 0, delSize = 0, isSelected = false }) => {
|
|
2026
|
+
const [open, setOpen] = useState(false);
|
|
2027
|
+
const noChanges = addSize === 0 && delSize === 0;
|
|
2028
|
+
const addBarHeight = getBarHeight(addSize);
|
|
2029
|
+
const delBarHeight = getBarHeight(delSize);
|
|
2030
|
+
const tooltipContent = jsxs("div", { className: "flex flex-col text-xs", children: [jsx("div", { children: formatTimestamp(timestamp) }), jsx("div", { className: "text-green-900", children: `${additions} additions +` }), jsx("div", { className: "text-red-700", children: `${deletions} deletions -` })] });
|
|
2031
|
+
const handleMouseEnter = () => {
|
|
2032
|
+
if (!noChanges) {
|
|
2033
|
+
setOpen(true);
|
|
2034
|
+
}
|
|
2035
|
+
};
|
|
2036
|
+
const handleMouseLeave = () => {
|
|
2037
|
+
setOpen(false);
|
|
2038
|
+
};
|
|
2039
|
+
return jsxs("div", { className: "relative", onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: [isSelected && jsx(Icon, { name: "TimelineCaret", color: "#4EA9FF", size: 10, className: "absolute left-[-2px] top-[-11px] z-40" }), noChanges ? jsx("div", { className: twMerge("flex h-[25px] w-1.5 cursor-pointer flex-col items-center justify-center rounded-[2px] hover:bg-blue-300", className), "data-timestamp": timestamp, onClick, children: jsx("div", { className: "size-[3px] rounded-full bg-gray-500" }) }) : jsx(Tooltip, { className: "rounded-md bg-gray-900 text-white", content: tooltipContent, open, onOpenChange: setOpen, delayDuration: 0, side: "bottom", sideOffset: 5, children: jsxs("div", { className: twMerge("flex h-[25px] w-1.5 cursor-pointer flex-col items-center justify-center rounded-[2px] hover:bg-blue-300", className, isSelected && "bg-blue-300"), "data-timestamp": timestamp, onClick, children: [jsx("div", { className: "flex h-3 w-0.5 items-end", children: jsx("div", { className: twMerge("h-3 w-0.5 rounded-t-full bg-green-600", addBarHeight) }) }), jsx("div", { className: "flex h-3 w-0.5 items-start", children: jsx("div", { className: twMerge("h-3 w-0.5 rounded-b-full bg-red-600", delBarHeight) }) })] }) })] });
|
|
2040
|
+
};
|
|
2041
|
+
const defaultTimeLineItem = {
|
|
2042
|
+
id: "default",
|
|
2043
|
+
type: "bar",
|
|
2044
|
+
addSize: 0,
|
|
2045
|
+
delSize: 0
|
|
2046
|
+
};
|
|
2047
|
+
const DocumentTimeline = (props) => {
|
|
2048
|
+
const { timeline = [], onItemClick } = props;
|
|
2049
|
+
const [selectedItem, setSelectedItem] = useState(null);
|
|
2050
|
+
const scrollContainerRef = useRef(null);
|
|
2051
|
+
const handleClick = (item) => {
|
|
2052
|
+
if (item.id === selectedItem || item.id === defaultTimeLineItem.id) {
|
|
2053
|
+
onItemClick == null ? void 0 : onItemClick(null);
|
|
2054
|
+
setSelectedItem(null);
|
|
2055
|
+
} else {
|
|
2056
|
+
onItemClick == null ? void 0 : onItemClick(item);
|
|
2057
|
+
setSelectedItem(item.id);
|
|
2058
|
+
}
|
|
2059
|
+
};
|
|
2060
|
+
const mergedTimelineItems = [...timeline, defaultTimeLineItem];
|
|
2061
|
+
const [unselectedItems, selectedItems] = useMemo(() => {
|
|
2062
|
+
const indexSelected = mergedTimelineItems.findIndex((item) => item.id === selectedItem);
|
|
2063
|
+
return indexSelected === -1 ? [mergedTimelineItems, []] : [
|
|
2064
|
+
mergedTimelineItems.slice(0, indexSelected),
|
|
2065
|
+
mergedTimelineItems.slice(indexSelected)
|
|
2066
|
+
];
|
|
2067
|
+
}, [mergedTimelineItems, selectedItem]);
|
|
2068
|
+
const renderTimelineItems = useCallback((items) => {
|
|
2069
|
+
return items.map((item) => {
|
|
2070
|
+
if (item.type === "divider") {
|
|
2071
|
+
const { timestamp, title, subtitle } = item;
|
|
2072
|
+
return jsx(HDivider, { timestamp, title, subtitle, onClick: () => handleClick(item), isSelected: item.id === selectedItem }, item.id);
|
|
2073
|
+
}
|
|
2074
|
+
return jsx(TimelineBar, { timestamp: item.timestamp, addSize: item.addSize, delSize: item.delSize, additions: item.additions, deletions: item.deletions, isSelected: item.id === selectedItem, onClick: () => handleClick(item) }, item.id);
|
|
2075
|
+
});
|
|
2076
|
+
}, [handleClick, selectedItem]);
|
|
2077
|
+
const unselectedContent = useMemo(() => renderTimelineItems(unselectedItems), [unselectedItems, renderTimelineItems]);
|
|
2078
|
+
const selectedContent = useMemo(() => renderTimelineItems(selectedItems), [selectedItems, renderTimelineItems]);
|
|
2079
|
+
useEffect(() => {
|
|
2080
|
+
if (scrollContainerRef.current) {
|
|
2081
|
+
scrollContainerRef.current.scrollLeft = scrollContainerRef.current.scrollWidth;
|
|
2082
|
+
}
|
|
2083
|
+
}, []);
|
|
2084
|
+
return jsx(TooltipProvider, { delayDuration: 0, skipDelayDuration: 0, children: jsxs("div", { className: "relative h-[36px] w-full", children: [jsx("div", { className: "absolute left-[0px] z-[20] h-[17px] w-[6px] bg-white", children: jsx("div", { className: "mt-[11px] h-[6px] w-[6px] rounded-tl-md bg-slate-50" }) }), jsx("div", { className: "absolute right-[0px] top-[11px] z-[20] h-[6px] w-[6px] bg-white", children: jsx("div", { className: "h-[6px] w-[6px] rounded-tr-md bg-slate-50" }) }), jsx("div", { className: "absolute inset-x-0 bottom-0 h-[25px] rounded-md bg-slate-50" }), jsx("div", { className: "absolute inset-x-0 bottom-0 h-[36px]", children: jsx("div", { ref: scrollContainerRef, className: "h-full overflow-x-auto rounded-md", children: jsxs("div", { className: "ml-auto flex h-[36px] w-max items-end px-2 pb-0", children: [jsx("div", { className: "flex", children: unselectedContent }), jsx("div", { className: "flex rounded-sm bg-blue-200", children: selectedContent })] }) }) }), jsx("div", { className: "pointer-events-none absolute bottom-0 left-0 z-10 h-[25px] w-2 rounded-l-md bg-slate-50" }), jsx("div", { className: "pointer-events-none absolute bottom-0 right-0 z-10 h-[25px] w-2 rounded-r-md bg-slate-50" })] }) });
|
|
2085
|
+
};
|
|
2086
|
+
const DocumentToolbar = (props) => {
|
|
2087
|
+
const { undo: undo2, canUndo, redo: redo2, canRedo, title, onClose, onExport, className, onShowRevisionHistory, onSwitchboardLinkClick, timelineItems = [], onTimelineItemClick, initialTimelineVisible = false, timelineButtonVisible = false } = props;
|
|
2088
|
+
const [showTimeline, setShowTimeline] = useState(initialTimelineVisible);
|
|
2089
|
+
const isUndoDisabled = !canUndo || !undo2;
|
|
2090
|
+
const isRedoDisabled = !canRedo || !redo2;
|
|
2091
|
+
const isExportDisabled = !onExport;
|
|
2092
|
+
const isSwitchboardLinkDisabled = !onSwitchboardLinkClick;
|
|
2093
|
+
const isRevisionHistoryDisabled = !onShowRevisionHistory;
|
|
2094
|
+
const isTimelineDisabled = timelineItems.length === 0;
|
|
2095
|
+
useEffect(() => {
|
|
2096
|
+
if (initialTimelineVisible) {
|
|
2097
|
+
setShowTimeline(true);
|
|
2098
|
+
}
|
|
2099
|
+
}, [initialTimelineVisible]);
|
|
2100
|
+
const handleTimelineToggle = () => {
|
|
2101
|
+
if (isTimelineDisabled)
|
|
2102
|
+
return;
|
|
2103
|
+
setShowTimeline(!showTimeline);
|
|
2104
|
+
};
|
|
2105
|
+
return jsxs("div", { className: "flex w-full flex-col", children: [jsxs("div", { className: twMerge("flex h-12 w-full items-center justify-between rounded-xl border border-gray-200 bg-slate-50 px-4", className), children: [jsxs("div", { className: "flex items-center gap-x-2", children: [jsx("button", { className: twMerge("grid size-8 place-items-center rounded-lg border border-gray-200 bg-white", isUndoDisabled ? "cursor-not-allowed" : "cursor-pointer active:opacity-70"), onClick: undo2, disabled: isUndoDisabled, children: jsx(Icon, { name: "ArrowCouterclockwise", size: 16, className: isUndoDisabled ? "text-gray-500" : "text-gray-900" }) }), jsx("button", { className: twMerge("grid size-8 place-items-center rounded-lg border border-gray-200 bg-white", isRedoDisabled ? "cursor-not-allowed" : "cursor-pointer active:opacity-70"), onClick: redo2, disabled: isRedoDisabled, children: jsx("div", { className: "-scale-x-100", children: jsx(Icon, { name: "ArrowCouterclockwise", size: 16, className: isRedoDisabled ? "text-gray-500" : "text-gray-900" }) }) }), jsx("button", { className: twMerge("flex h-8 items-center rounded-lg border border-gray-200 bg-white px-3 text-sm", isExportDisabled ? "cursor-not-allowed" : "cursor-pointer active:opacity-70"), onClick: onExport, disabled: isExportDisabled, children: jsx("span", { className: isExportDisabled ? "text-gray-500" : "text-gray-900", children: "Export" }) })] }), jsx("div", { className: "flex items-center", children: jsx("h1", { className: "text-sm font-medium text-gray-500", children: title }) }), jsxs("div", { className: "flex items-center gap-x-2", children: [jsx("button", { className: twMerge("grid size-8 place-items-center rounded-lg border border-gray-200 bg-white", isSwitchboardLinkDisabled ? "cursor-not-allowed" : "cursor-pointer active:opacity-70"), onClick: onSwitchboardLinkClick, disabled: isSwitchboardLinkDisabled, children: jsx(Icon, { name: "Drive", size: 16, className: isSwitchboardLinkDisabled ? "text-gray-500" : "text-gray-900" }) }), jsx("button", { className: twMerge("grid size-8 place-items-center rounded-lg border border-gray-200 bg-white", isRevisionHistoryDisabled ? "cursor-not-allowed" : "cursor-pointer active:opacity-70"), onClick: onShowRevisionHistory, disabled: isRevisionHistoryDisabled, children: jsx(Icon, { name: "History", size: 16, className: isRevisionHistoryDisabled ? "text-gray-500" : "text-gray-900" }) }), timelineButtonVisible && jsx("button", { className: twMerge("grid size-8 place-items-center rounded-lg border border-gray-200 bg-white", isTimelineDisabled ? "cursor-not-allowed" : "cursor-pointer active:opacity-70"), onClick: handleTimelineToggle, disabled: isTimelineDisabled, "aria-pressed": showTimeline, children: jsx(Icon, { name: "Timeline", size: 16, className: twMerge("text-gray-900", isTimelineDisabled && "opacity-50", showTimeline && "text-blue-600") }) }), jsx("button", { className: "grid size-8 cursor-pointer place-items-center rounded-lg border border-gray-200 bg-white active:opacity-70", onClick: onClose, children: jsx(Icon, { name: "XmarkLight", size: 16, className: "text-gray-900" }) })] })] }), showTimeline && jsx("div", { className: "mt-2 w-full", children: jsx(DocumentTimeline, { timeline: timelineItems, onItemClick: onTimelineItemClick }) })] });
|
|
2106
|
+
};
|
|
2107
|
+
const syncIcons = {
|
|
2108
|
+
SYNCING: "Syncing",
|
|
2109
|
+
SUCCESS: "Synced",
|
|
2110
|
+
CONFLICT: "Error",
|
|
2111
|
+
MISSING: "Circle",
|
|
2112
|
+
ERROR: "Error",
|
|
2113
|
+
INITIAL_SYNC: "Syncing"
|
|
2114
|
+
};
|
|
2115
|
+
function SyncStatusIcon(props) {
|
|
2116
|
+
const { syncStatus, className, overrideSyncIcons = {}, ...iconProps } = props;
|
|
2117
|
+
const icons = { ...syncIcons, ...overrideSyncIcons };
|
|
2118
|
+
const syncStatusIcons = {
|
|
2119
|
+
[INITIAL_SYNC]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-blue-900", className), name: icons[INITIAL_SYNC] }),
|
|
2120
|
+
[SYNCING]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-blue-900", className), name: icons[SYNCING] }),
|
|
2121
|
+
[SUCCESS]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-green-900", className), name: icons[SUCCESS] }),
|
|
2122
|
+
[CONFLICT]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-orange-900", className), name: icons[CONFLICT] }),
|
|
2123
|
+
[MISSING]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-red-900", className), name: icons[MISSING] }),
|
|
2124
|
+
[ERROR]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-red-900", className), name: icons[ERROR] })
|
|
2125
|
+
};
|
|
2126
|
+
return syncStatusIcons[syncStatus];
|
|
2127
|
+
}
|
|
2128
|
+
function FileItem(props) {
|
|
2129
|
+
const { uiNode, className, customDocumentIconSrc, onSelectNode, onRenameNode, onDuplicateNode, onDeleteNode, isAllowedToCreateDocuments } = props;
|
|
2130
|
+
const [mode, setMode] = useState(READ);
|
|
2131
|
+
const [isDropdownMenuOpen, setIsDropdownMenuOpen] = useState(false);
|
|
2132
|
+
const { dragProps } = useDrag({ uiNode });
|
|
2133
|
+
const isReadMode = mode === READ;
|
|
2134
|
+
const dropdownMenuHandlers = {
|
|
2135
|
+
[DUPLICATE]: () => onDuplicateNode(uiNode),
|
|
2136
|
+
[RENAME]: () => setMode(WRITE),
|
|
2137
|
+
[DELETE]: () => onDeleteNode(uiNode)
|
|
2138
|
+
};
|
|
2139
|
+
const dropdownMenuOptions = Object.entries(nodeOptionsMap).map(([id, option]) => ({
|
|
2140
|
+
...option,
|
|
2141
|
+
id
|
|
2142
|
+
})).filter((option) => defaultFileOptions.includes(option.id));
|
|
2143
|
+
function onSubmit(name) {
|
|
2144
|
+
onRenameNode(name, uiNode);
|
|
2145
|
+
setMode(READ);
|
|
2146
|
+
}
|
|
2147
|
+
function onCancel() {
|
|
2148
|
+
setMode(READ);
|
|
2149
|
+
}
|
|
2150
|
+
function onClick() {
|
|
2151
|
+
onSelectNode(uiNode);
|
|
2152
|
+
}
|
|
2153
|
+
function onDropdownMenuOptionClick(itemId) {
|
|
2154
|
+
const handler = dropdownMenuHandlers[itemId];
|
|
2155
|
+
if (!handler) {
|
|
2156
|
+
console.error(`No handler found for dropdown menu item: ${itemId}`);
|
|
2157
|
+
return;
|
|
2158
|
+
}
|
|
2159
|
+
handler();
|
|
2160
|
+
setIsDropdownMenuOpen(false);
|
|
2161
|
+
}
|
|
2162
|
+
const iconSrc = getDocumentIconSrc(uiNode.documentType, customDocumentIconSrc);
|
|
2163
|
+
const iconNode = jsxs("div", { className: "relative", children: [jsx("img", { alt: "file icon", className: "max-w-none", height: 34, src: iconSrc, width: 32 }), isReadMode && uiNode.syncStatus && jsx("div", { className: "absolute bottom-[-2px] right-0 size-3 rounded-full bg-white", children: jsx("div", { className: "absolute left-[-2px] top-[-2px]", children: jsx(SyncStatusIcon, { overrideSyncIcons: { SUCCESS: "CheckCircleFill" }, syncStatus: uiNode.syncStatus }) }) })] });
|
|
2164
|
+
const containerStyles = twMerge("group flex h-12 cursor-pointer select-none items-center rounded-lg bg-gray-200 px-2 text-gray-600 hover:text-gray-800", className);
|
|
2165
|
+
const content = isReadMode ? jsxs("div", { className: "flex w-52 items-center justify-between", children: [jsxs("div", { className: "mr-2 truncate group-hover:mr-0", children: [jsx("div", { className: "max-h-6 truncate text-sm font-medium group-hover:text-gray-800", children: uiNode.name }), jsx("div", { className: "max-h-6 truncate text-xs font-medium text-gray-600 group-hover:text-gray-800", children: uiNode.documentType })] }), isAllowedToCreateDocuments ? jsx(ConnectDropdownMenu, { items: dropdownMenuOptions, onItemClick: onDropdownMenuOptionClick, onOpenChange: setIsDropdownMenuOpen, open: isDropdownMenuOpen, children: jsx("button", { className: twMerge("hidden group-hover:block", isDropdownMenuOpen && "block"), onClick: (e) => {
|
|
2166
|
+
e.stopPropagation();
|
|
2167
|
+
setIsDropdownMenuOpen(true);
|
|
2168
|
+
}, children: jsx(Icon, { className: "text-gray-600", name: "VerticalDots" }) }) }) : null] }) : jsx(NodeInput, { className: "ml-3 flex-1 font-medium", defaultValue: uiNode.name, onCancel, onSubmit });
|
|
2169
|
+
return jsx("div", { className: "relative w-64", onClick, children: jsx("div", { ...dragProps, className: containerStyles, children: jsxs("div", { className: "flex items-center", children: [jsx("div", { className: "mr-1.5", children: iconNode }), content] }) }) });
|
|
2170
|
+
}
|
|
2171
|
+
function FolderItem(props) {
|
|
2172
|
+
const { uiNode, isAllowedToCreateDocuments, className, onRenameNode, onDuplicateNode, onDeleteNode, onSelectNode, onAddFile, onCopyNode, onMoveNode } = props;
|
|
2173
|
+
const [mode, setMode] = useState(READ);
|
|
2174
|
+
const [isDropdownMenuOpen, setIsDropdownMenuOpen] = useState(false);
|
|
2175
|
+
const { dragProps } = useDrag({ ...props, uiNode });
|
|
2176
|
+
const { isDropTarget, dropProps } = useDrop({
|
|
2177
|
+
uiNode,
|
|
2178
|
+
onAddFile,
|
|
2179
|
+
onCopyNode,
|
|
2180
|
+
onMoveNode
|
|
2181
|
+
});
|
|
2182
|
+
const isReadMode = mode === READ;
|
|
2183
|
+
function onCancel() {
|
|
2184
|
+
setMode(READ);
|
|
2185
|
+
}
|
|
2186
|
+
function onSubmit(name) {
|
|
2187
|
+
onRenameNode(name, uiNode);
|
|
2188
|
+
setMode(READ);
|
|
2189
|
+
}
|
|
2190
|
+
function onClick() {
|
|
2191
|
+
onSelectNode(uiNode);
|
|
2192
|
+
}
|
|
2193
|
+
const dropdownMenuHandlers = {
|
|
2194
|
+
[DUPLICATE]: () => onDuplicateNode(uiNode),
|
|
2195
|
+
[RENAME]: () => setMode(WRITE),
|
|
2196
|
+
[DELETE]: () => onDeleteNode(uiNode)
|
|
2197
|
+
};
|
|
2198
|
+
const dropdownMenuOptions = Object.entries(nodeOptionsMap).map(([id, option]) => ({
|
|
2199
|
+
...option,
|
|
2200
|
+
id
|
|
2201
|
+
})).filter((option) => defaultFolderOptions.includes(option.id));
|
|
2202
|
+
function onDropdownMenuOptionClick(itemId) {
|
|
2203
|
+
const handler = dropdownMenuHandlers[itemId];
|
|
2204
|
+
if (!handler) {
|
|
2205
|
+
console.error(`No handler found for dropdown menu item: ${itemId}`);
|
|
2206
|
+
return;
|
|
2207
|
+
}
|
|
2208
|
+
handler();
|
|
2209
|
+
setIsDropdownMenuOpen(false);
|
|
2210
|
+
}
|
|
2211
|
+
const content = isReadMode || !isAllowedToCreateDocuments ? jsx("div", { className: "ml-3 max-h-6 truncate font-medium text-gray-600 group-hover:text-gray-800", children: uiNode.name }) : jsx(NodeInput, { className: "ml-3 font-medium", defaultValue: uiNode.name, onCancel, onSubmit });
|
|
2212
|
+
const containerStyles = twMerge("group flex h-12 cursor-pointer select-none items-center rounded-lg bg-gray-200 px-2", className, isDropTarget && "bg-blue-100");
|
|
2213
|
+
return jsx("div", { className: "relative w-64", onClick, children: jsxs("div", { ...dragProps, ...dropProps, className: containerStyles, children: [jsxs("div", { className: "flex items-center overflow-hidden", children: [jsx("div", { className: "p-1", children: jsxs("div", { className: "relative", children: [jsx(Icon, { name: "FolderClose", size: 24 }), isReadMode && uiNode.syncStatus ? jsx("div", { className: "absolute bottom-[-3px] right-[-2px] size-3 rounded-full bg-white", children: jsx("div", { className: "absolute left-[-2px] top-[-2px]", children: jsx(SyncStatusIcon, { overrideSyncIcons: {
|
|
2214
|
+
SUCCESS: "CheckCircleFill"
|
|
2215
|
+
}, syncStatus: uiNode.syncStatus }) }) }) : null] }) }), content] }), isReadMode && isAllowedToCreateDocuments ? jsx(ConnectDropdownMenu, { items: dropdownMenuOptions, onItemClick: onDropdownMenuOptionClick, onOpenChange: setIsDropdownMenuOpen, open: isDropdownMenuOpen, children: jsx("button", { className: twMerge("ml-auto hidden group-hover:block", isDropdownMenuOpen && "block"), onClick: (e) => {
|
|
2216
|
+
e.stopPropagation();
|
|
2217
|
+
setIsDropdownMenuOpen(true);
|
|
2218
|
+
}, children: jsx(Icon, { className: "text-gray-600", name: "VerticalDots" }) }) }) : null] }) });
|
|
2219
|
+
}
|
|
2220
|
+
function NodeInput(props) {
|
|
2221
|
+
const { onSubmit, onCancel, defaultValue, className, minLength = 1, ...inputProps } = props;
|
|
2222
|
+
const [value, setValue] = useState(defaultValue ?? "");
|
|
2223
|
+
const ref = useRef(null);
|
|
2224
|
+
useOnClickOutside(ref, handleSubmit);
|
|
2225
|
+
useEventListener("keyup", (e) => {
|
|
2226
|
+
if (e.key === "Enter") {
|
|
2227
|
+
handleSubmit();
|
|
2228
|
+
}
|
|
2229
|
+
if (e.key === "Escape") {
|
|
2230
|
+
onCancel();
|
|
2231
|
+
}
|
|
2232
|
+
});
|
|
2233
|
+
useLayoutEffect(() => {
|
|
2234
|
+
setTimeout(() => {
|
|
2235
|
+
var _a, _b, _c;
|
|
2236
|
+
(_a = ref.current) == null ? void 0 : _a.focus();
|
|
2237
|
+
(_b = ref.current) == null ? void 0 : _b.select();
|
|
2238
|
+
(_c = ref.current) == null ? void 0 : _c.scroll({ left: 9999 });
|
|
2239
|
+
}, 100);
|
|
2240
|
+
}, []);
|
|
2241
|
+
function handleSubmit() {
|
|
2242
|
+
if (value.length >= minLength) {
|
|
2243
|
+
onSubmit(value);
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
return jsx("input", { ...inputProps, autoFocus: true, className: twMerge("bg-inherit text-inherit outline-none", className), minLength, onChange: (e) => setValue(e.target.value), ref, required: true, type: "text", value });
|
|
2247
|
+
}
|
|
2248
|
+
function Branch(props) {
|
|
2249
|
+
const { branch = "main" } = props;
|
|
2250
|
+
return jsxs("button", { className: "flex h-8 items-center gap-1 rounded-lg bg-slate-50 pl-1 pr-2 text-xs text-slate-100", children: [jsx(Icon, { name: "Branch" }), jsx("span", { children: "BRANCH" }), jsx("span", { className: "text-gray-900", children: branch })] });
|
|
2251
|
+
}
|
|
2252
|
+
function DocId(props) {
|
|
2253
|
+
const { docId } = props;
|
|
2254
|
+
const [, copy] = useCopyToClipboard();
|
|
2255
|
+
function handleCopy(text) {
|
|
2256
|
+
return () => {
|
|
2257
|
+
copy(text).catch((error) => {
|
|
2258
|
+
console.error("Failed to copy!", error);
|
|
2259
|
+
});
|
|
2260
|
+
};
|
|
2261
|
+
}
|
|
2262
|
+
return jsxs("button", { className: "flex h-8 items-center gap-1 rounded-lg bg-slate-50 pl-1 pr-2 text-xs text-slate-100", onClick: handleCopy(docId), children: [jsx(Icon, { name: "Link" }), "DOC ID", jsx("span", { className: "text-gray-900", children: docId })] });
|
|
2263
|
+
}
|
|
2264
|
+
function Scope(props) {
|
|
2265
|
+
const { value, onChange } = props;
|
|
2266
|
+
const items = [
|
|
2267
|
+
{ displayValue: "Global scope", value: "global" },
|
|
2268
|
+
{ displayValue: "Local scope", value: "local" }
|
|
2269
|
+
];
|
|
2270
|
+
return jsx(Select, { absolutePositionMenu: true, containerClassName: "bg-slate-50 text-gray-500 rounded-lg w-fit text-xs z-10", id: "scope select", itemClassName: "py-2 text-gray-500 grid grid-cols-[auto,auto] gap-1", items, menuClassName: "min-w-0 text-gray-500", onChange, value });
|
|
2271
|
+
}
|
|
2272
|
+
function Header(props) {
|
|
2273
|
+
const { title, docId, scope, onChangeScope, onClose, className, ...divProps } = props;
|
|
2274
|
+
return jsxs("header", { className: twMerge("flex items-center justify-between bg-transparent", className), ...divProps, children: [jsxs("div", { className: "flex items-center gap-3", children: [jsx("button", { className: "shadow-button rounded-lg bg-gray-50 p-1 text-slate-100", onClick: onClose, children: jsx(Icon, { name: "VariantArrowLeft" }) }), jsx("h1", { className: "text-xs", children: title })] }), jsxs("div", { className: "flex items-center gap-2", children: [jsx(DocId, { docId }), jsx(Branch, {}), jsx(Scope, { onChange: onChangeScope, value: scope })] })] });
|
|
2275
|
+
}
|
|
2276
|
+
function memo(getDeps, fn, opts) {
|
|
2277
|
+
let deps = opts.initialDeps ?? [];
|
|
2278
|
+
let result;
|
|
2279
|
+
function memoizedFunction() {
|
|
2280
|
+
var _a, _b, _c, _d;
|
|
2281
|
+
let depTime;
|
|
2282
|
+
if (opts.key && ((_a = opts.debug) == null ? void 0 : _a.call(opts))) depTime = Date.now();
|
|
2283
|
+
const newDeps = getDeps();
|
|
2284
|
+
const depsChanged = newDeps.length !== deps.length || newDeps.some((dep, index) => deps[index] !== dep);
|
|
2285
|
+
if (!depsChanged) {
|
|
2286
|
+
return result;
|
|
2287
|
+
}
|
|
2288
|
+
deps = newDeps;
|
|
1836
2289
|
let resultTime;
|
|
1837
2290
|
if (opts.key && ((_b = opts.debug) == null ? void 0 : _b.call(opts))) resultTime = Date.now();
|
|
1838
2291
|
result = fn(...newDeps);
|
|
@@ -2857,8 +3310,8 @@ function RevisionHistory(props) {
|
|
|
2857
3310
|
return jsxs(TooltipProvider, { children: [jsx(Header, { docId: documentId, onChangeScope, onClose, scope, title: documentTitle }), PaginationComponent, jsx("div", { className: "mt-4 flex justify-center rounded-md bg-slate-50 p-4", children: visibleOperations.length > 0 ? jsx("div", { className: "grid grid-cols-[minmax(min-content,1018px)]", children: jsx(Timeline, { globalOperations: scope === "global" ? pageItems : [], localOperations: scope === "local" ? pageItems : [], scope }) }) : jsx("h3", { className: "my-40 text-gray-600", children: "This document has no recorded operations yet." }) }), PaginationComponent] });
|
|
2858
3311
|
}
|
|
2859
3312
|
function Tooltip(props) {
|
|
2860
|
-
const { children, content, open, defaultOpen, onOpenChange, className, ...rest } = props;
|
|
2861
|
-
return jsxs(Root3, { defaultOpen, delayDuration: 0, onOpenChange, open, children: [jsx(Trigger, { asChild: true, children }), jsx(Portal, { children: jsx(Content2, { ...rest, className: twMerge("shadow-tooltip rounded-lg border border-gray-200 bg-white p-2 text-xs", className), children: content }) })] });
|
|
3313
|
+
const { children, content, open, defaultOpen, onOpenChange, className, side = "top", sideOffset = 5, ...rest } = props;
|
|
3314
|
+
return jsxs(Root3, { defaultOpen, delayDuration: 0, onOpenChange, open, children: [jsx(Trigger, { asChild: true, children }), jsx(Portal, { children: jsx(Content2, { ...rest, side, sideOffset, className: twMerge("shadow-tooltip rounded-lg border border-gray-200 bg-white p-2 text-xs", className), children: content }) })] });
|
|
2862
3315
|
}
|
|
2863
3316
|
const TooltipProvider = Provider;
|
|
2864
3317
|
const BUDGET = "powerhouse/budget-statement";
|
|
@@ -3488,6 +3941,17 @@ function useEditorProps(document2, node, documentDispatch, onAddOperation) {
|
|
|
3488
3941
|
isAllowedToEditDocuments: (userPermissions == null ? void 0 : userPermissions.isAllowedToEditDocuments) ?? false
|
|
3489
3942
|
};
|
|
3490
3943
|
}
|
|
3944
|
+
function useGetDocument() {
|
|
3945
|
+
const { openFile } = useDocumentDriveServer();
|
|
3946
|
+
const getDocument = useCallback(
|
|
3947
|
+
async (driveId, documentId, options) => {
|
|
3948
|
+
const document2 = await openFile(driveId, documentId, options);
|
|
3949
|
+
return document2;
|
|
3950
|
+
},
|
|
3951
|
+
[openFile]
|
|
3952
|
+
);
|
|
3953
|
+
return getDocument;
|
|
3954
|
+
}
|
|
3491
3955
|
function useSyncStatus(driveId, documentId) {
|
|
3492
3956
|
const { getSyncStatusSync, onSyncStatus, documentDrives } = useDocumentDriveServer();
|
|
3493
3957
|
const syncStatus = useSyncExternalStore(
|
|
@@ -3558,36 +4022,363 @@ const useUndoRedoShortcuts = (props) => {
|
|
|
3558
4022
|
[canRedo, redo2]
|
|
3559
4023
|
);
|
|
3560
4024
|
};
|
|
3561
|
-
function
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
}, props.loadingTimeout ?? 200);
|
|
3567
|
-
}, [props]);
|
|
3568
|
-
if (!showLoading) return null;
|
|
3569
|
-
const { customEditorLoader, ...defaultProps } = props;
|
|
3570
|
-
if (customEditorLoader) return /* @__PURE__ */ jsx(Fragment$1, { children: customEditorLoader });
|
|
3571
|
-
return /* @__PURE__ */ jsx(DefaultEditorLoader, { ...defaultProps });
|
|
3572
|
-
}
|
|
3573
|
-
function EditorError({ message: message2 }) {
|
|
3574
|
-
return /* @__PURE__ */ jsx("div", { className: "flex size-full items-center justify-center", children: /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold", children: message2 }) });
|
|
4025
|
+
function getDocumentSpec(doc) {
|
|
4026
|
+
if ("documentModelState" in doc) {
|
|
4027
|
+
return doc.documentModelState;
|
|
4028
|
+
}
|
|
4029
|
+
return doc.documentModel;
|
|
3575
4030
|
}
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
4031
|
+
const CreateDocument = ({ documentModels, createDocument }) => {
|
|
4032
|
+
return jsxs("div", { className: "px-6", children: [jsx("h3", { className: "mb-3 mt-4 text-xl font-bold text-gray-600", children: "New document" }), jsx("div", { className: "flex w-full flex-wrap gap-4", children: documentModels == null ? void 0 : documentModels.map((doc) => {
|
|
4033
|
+
const spec = getDocumentSpec(doc);
|
|
4034
|
+
return jsx(Button, { color: "light", "aria-details": spec.description, onClick: () => createDocument(doc), children: jsx("span", { className: "text-sm", children: spec.name }) }, spec.id);
|
|
4035
|
+
}) })] });
|
|
4036
|
+
};
|
|
4037
|
+
function sortUiNodesByName(a, b) {
|
|
4038
|
+
return a.name.localeCompare(b.name);
|
|
3579
4039
|
}
|
|
3580
|
-
const
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
4040
|
+
const GAP = 8;
|
|
4041
|
+
const ITEM_WIDTH = 256;
|
|
4042
|
+
const ITEM_HEIGHT = 48;
|
|
4043
|
+
const USED_SPACE = 420;
|
|
4044
|
+
function FileContentView(props) {
|
|
4045
|
+
const parentRef = useRef(null);
|
|
4046
|
+
const { t } = useTranslation();
|
|
4047
|
+
const windowSize = useWindowSize();
|
|
4048
|
+
const { fileNodes, ...fileProps } = props;
|
|
4049
|
+
const availableWidth = windowSize.innerWidth - USED_SPACE;
|
|
4050
|
+
const columnCount = Math.floor(availableWidth / (ITEM_WIDTH + GAP)) || 1;
|
|
4051
|
+
const rowCount = Math.ceil(fileNodes.length / columnCount);
|
|
4052
|
+
const rowVirtualizer = useVirtualizer({
|
|
4053
|
+
count: rowCount,
|
|
4054
|
+
getScrollElement: () => parentRef.current,
|
|
4055
|
+
estimateSize: (index) => {
|
|
4056
|
+
if (index > 0) {
|
|
4057
|
+
return ITEM_HEIGHT + GAP;
|
|
4058
|
+
}
|
|
4059
|
+
return ITEM_HEIGHT;
|
|
4060
|
+
},
|
|
4061
|
+
overscan: 5
|
|
4062
|
+
});
|
|
4063
|
+
const columnVirtualizer = useVirtualizer({
|
|
4064
|
+
horizontal: true,
|
|
4065
|
+
count: columnCount,
|
|
4066
|
+
getScrollElement: () => parentRef.current,
|
|
4067
|
+
estimateSize: (index) => {
|
|
4068
|
+
if (index > 0) {
|
|
4069
|
+
return ITEM_WIDTH + GAP;
|
|
4070
|
+
}
|
|
4071
|
+
return ITEM_WIDTH;
|
|
4072
|
+
},
|
|
4073
|
+
overscan: 5
|
|
4074
|
+
});
|
|
4075
|
+
const getItemIndex = (rowIndex, columnIndex) => rowIndex * columnCount + columnIndex;
|
|
4076
|
+
const getItem = (rowIndex, columnIndex) => {
|
|
4077
|
+
const index = getItemIndex(rowIndex, columnIndex);
|
|
4078
|
+
return fileNodes[index] || null;
|
|
4079
|
+
};
|
|
4080
|
+
if (fileNodes.length === 0) {
|
|
4081
|
+
return jsx("div", { className: "mb-8 text-sm text-gray-400", children: t("folderView.sections.documents.empty", {
|
|
4082
|
+
defaultValue: "No documents or files 📄"
|
|
4083
|
+
}) });
|
|
4084
|
+
}
|
|
4085
|
+
const renderItem = (rowIndex, columnIndex) => {
|
|
4086
|
+
const fileNode = getItem(rowIndex, columnIndex);
|
|
4087
|
+
if (!fileNode) {
|
|
4088
|
+
return null;
|
|
4089
|
+
}
|
|
4090
|
+
return jsx("div", { style: {
|
|
4091
|
+
marginLeft: columnIndex === 0 ? 0 : GAP
|
|
4092
|
+
}, children: jsx(FileItem, { uiNode: fileNode, ...fileProps }, fileNode.id) });
|
|
4093
|
+
};
|
|
4094
|
+
return jsx("div", { ref: parentRef, style: {
|
|
4095
|
+
height: `400px`,
|
|
4096
|
+
width: `100%`,
|
|
4097
|
+
overflow: "auto"
|
|
4098
|
+
}, children: jsx("div", { style: {
|
|
4099
|
+
height: `${rowVirtualizer.getTotalSize()}px`,
|
|
4100
|
+
width: `${columnVirtualizer.getTotalSize()}px`,
|
|
4101
|
+
position: "relative"
|
|
4102
|
+
}, children: rowVirtualizer.getVirtualItems().map((virtualRow) => jsx(React__default.Fragment, { children: columnVirtualizer.getVirtualItems().map((virtualColumn) => jsx("div", { style: {
|
|
4103
|
+
position: "absolute",
|
|
4104
|
+
top: 0,
|
|
4105
|
+
left: 0,
|
|
4106
|
+
marginTop: virtualRow.index === 0 ? 0 : GAP,
|
|
4107
|
+
width: `${virtualColumn.size}px`,
|
|
4108
|
+
height: `${virtualRow.size}px`,
|
|
4109
|
+
transform: `translateX(${virtualColumn.start}px) translateY(${virtualRow.start}px)`
|
|
4110
|
+
}, children: renderItem(virtualRow.index, virtualColumn.index) }, virtualColumn.key)) }, virtualRow.key)) }) });
|
|
4111
|
+
}
|
|
4112
|
+
function FolderView(props) {
|
|
4113
|
+
const { node, className, isDropTarget, containerProps, ...nodeProps } = props;
|
|
4114
|
+
const { t } = useTranslation();
|
|
4115
|
+
const folderNodes = node.children.filter((node2) => node2.kind === FOLDER).sort(sortUiNodesByName);
|
|
4116
|
+
const fileNodes = node.children.filter((node2) => node2.kind === FILE).sort(sortUiNodesByName);
|
|
4117
|
+
const folderCallbacks = {
|
|
4118
|
+
onSelectNode: (node2) => nodeProps.onSelectNode(node2),
|
|
4119
|
+
onRenameNode: (name, node2) => nodeProps.onRenameNode(name, node2),
|
|
4120
|
+
onDuplicateNode: (node2) => nodeProps.onDuplicateNode(node2),
|
|
4121
|
+
onDeleteNode: (node2) => nodeProps.onDeleteNode(node2)
|
|
4122
|
+
};
|
|
4123
|
+
const fileCallbacks = {
|
|
4124
|
+
onSelectNode: (node2) => nodeProps.onSelectNode(node2),
|
|
4125
|
+
onRenameNode: (name, node2) => nodeProps.onRenameNode(name, node2),
|
|
4126
|
+
onDuplicateNode: (node2) => nodeProps.onDuplicateNode(node2),
|
|
4127
|
+
onDeleteNode: (node2) => nodeProps.onDeleteNode(node2)
|
|
4128
|
+
};
|
|
4129
|
+
const baseNodeCallbacks = {
|
|
4130
|
+
onAddFile: async (file, parentNode) => {
|
|
4131
|
+
await nodeProps.onAddFile(file, parentNode);
|
|
4132
|
+
},
|
|
4133
|
+
onCopyNode: async (uiNode, targetNode) => {
|
|
4134
|
+
await nodeProps.onCopyNode(uiNode, targetNode);
|
|
4135
|
+
},
|
|
4136
|
+
onMoveNode: async (uiNode, targetNode) => {
|
|
4137
|
+
await nodeProps.onMoveNode(uiNode, targetNode);
|
|
4138
|
+
}
|
|
4139
|
+
};
|
|
4140
|
+
return jsxs("div", { className: twMerge("rounded-md border-2 border-transparent p-2", isDropTarget && "border-dashed border-blue-100", className), ...containerProps, children: [jsx(DriveLayout.ContentSection, { title: t("folderView.sections.folders.title", {
|
|
4141
|
+
defaultValue: "Folders"
|
|
4142
|
+
}), className: "mb-4", children: folderNodes.length > 0 ? folderNodes.map((folderNode) => jsx(FolderItem, { uiNode: folderNode, ...baseNodeCallbacks, ...folderCallbacks, isAllowedToCreateDocuments: nodeProps.isAllowedToCreateDocuments }, folderNode.id)) : jsx("div", { className: "mb-8 text-sm text-gray-400", children: t("folderView.sections.folders.empty", {
|
|
4143
|
+
defaultValue: "No documents or files 📄"
|
|
4144
|
+
}) }) }), jsx(DriveLayout.ContentSection, { title: t("folderView.sections.documents.title", {
|
|
4145
|
+
defaultValue: "Documents and files"
|
|
4146
|
+
}), children: jsx("div", { className: twMerge("w-full", fileNodes.length > 0 ? "min-h-[400px]" : "min-h-14"), children: jsx(FileContentView, { fileNodes, ...fileCallbacks, isAllowedToCreateDocuments: nodeProps.isAllowedToCreateDocuments }) }) })] });
|
|
4147
|
+
}
|
|
4148
|
+
function BaseEditor(props) {
|
|
4149
|
+
const { document: document2, dispatch, className, children } = props;
|
|
4150
|
+
const { state: { global: { id: driveId } } } = document2;
|
|
4151
|
+
const { showSearchBar, isAllowedToCreateDocuments, documentModels, showCreateDocumentModal } = useDriveContext();
|
|
4152
|
+
const { driveNodes, selectedNode, selectedNodePath, getNodeById, setSelectedNode } = useUiNodesContext();
|
|
4153
|
+
const driveNode = useMemo(() => driveNodes.find((n) => n.id === driveId), [driveNodes, driveId]);
|
|
4154
|
+
const { addDocument, addFile, addFolder: addFolder2, renameNode, deleteNode: deleteNode2, moveNode: moveNode2, copyNode: copyNode2, duplicateNode } = useDriveActionsWithUiNodes(document2, dispatch);
|
|
4155
|
+
const onCreateDocument = useCallback(async (documentModel) => {
|
|
4156
|
+
const { name } = await showCreateDocumentModal(documentModel);
|
|
4157
|
+
const document3 = documentModel.utils.createDocument();
|
|
4158
|
+
await addDocument(name, documentModel.documentModel.name, document3, selectedNode == null ? void 0 : selectedNode.id);
|
|
4159
|
+
}, [addDocument, showCreateDocumentModal, selectedNode == null ? void 0 : selectedNode.id]);
|
|
4160
|
+
const { isDropTarget, dropProps } = useDrop({
|
|
4161
|
+
uiNode: selectedNode,
|
|
4162
|
+
onAddFile: addFile,
|
|
4163
|
+
onCopyNode: copyNode2,
|
|
4164
|
+
onMoveNode: moveNode2
|
|
4165
|
+
});
|
|
4166
|
+
const { breadcrumbs, onBreadcrumbSelected } = useBreadcrumbs({
|
|
4167
|
+
selectedNodePath,
|
|
4168
|
+
getNodeById,
|
|
4169
|
+
setSelectedNode
|
|
4170
|
+
});
|
|
4171
|
+
if (!driveNode) {
|
|
4172
|
+
return jsx("div", { children: "Drive not found" });
|
|
4173
|
+
} else if ((selectedNode == null ? void 0 : selectedNode.kind) === FILE$1) {
|
|
4174
|
+
return jsx(Fragment$1, {});
|
|
4175
|
+
}
|
|
4176
|
+
return jsxs(DriveLayout, { className, children: [children, jsxs(DriveLayout.Header, { children: [jsx(Breadcrumbs, { breadcrumbs, createEnabled: isAllowedToCreateDocuments, onCreate: addFolder2, onBreadcrumbSelected }), showSearchBar && jsx(SearchBar, {})] }), jsx(DriveLayout.Content, { children: jsx(FolderView, { node: selectedNode || driveNode, onSelectNode: setSelectedNode, onRenameNode: renameNode, onDuplicateNode: duplicateNode, onDeleteNode: deleteNode2, onAddFile: addFile, onCopyNode: copyNode2, onMoveNode: moveNode2, isDropTarget, isAllowedToCreateDocuments }) }), jsx(DriveLayout.Footer, { children: isAllowedToCreateDocuments && jsx(CreateDocument, { documentModels, createDocument: onCreateDocument }) })] });
|
|
4177
|
+
}
|
|
4178
|
+
function Editor(props) {
|
|
4179
|
+
return jsx(DriveContextProvider, { value: props.context, children: jsx(BaseEditor, { ...props }) });
|
|
4180
|
+
}
|
|
4181
|
+
const GenericDriveExplorer = {
|
|
4182
|
+
Component: Editor
|
|
4183
|
+
};
|
|
4184
|
+
function useAnalyticsQueryWrapper(options) {
|
|
4185
|
+
const { queryFn, ...queryOptions } = options;
|
|
4186
|
+
const store = useAnalyticsStore();
|
|
4187
|
+
const engine = useAnalyticsEngine();
|
|
4188
|
+
return useQuery({
|
|
4189
|
+
...queryOptions,
|
|
4190
|
+
queryFn: () => {
|
|
4191
|
+
if (!store || !engine) {
|
|
4192
|
+
throw new Error("No analytics store available. Use within an AnalyticsProvider.");
|
|
4193
|
+
}
|
|
4194
|
+
return queryFn({ store, engine });
|
|
4195
|
+
}
|
|
4196
|
+
});
|
|
4197
|
+
}
|
|
4198
|
+
function useAnalyticsQuery(query, options) {
|
|
4199
|
+
const store = useAnalyticsStore();
|
|
4200
|
+
const { data: querySources } = useQuerySources(query);
|
|
4201
|
+
const queryClient = useQueryClient();
|
|
4202
|
+
const subscriptions = useRef([]);
|
|
4203
|
+
const result = useAnalyticsQueryWrapper({
|
|
4204
|
+
queryKey: ["analytics", "query", query],
|
|
4205
|
+
queryFn: ({ engine }) => engine.execute(query),
|
|
4206
|
+
...options
|
|
4207
|
+
});
|
|
4208
|
+
useEffect(() => {
|
|
4209
|
+
if (!(querySources == null ? void 0 : querySources.length) || !store) {
|
|
4210
|
+
return;
|
|
4211
|
+
}
|
|
4212
|
+
querySources.forEach((source) => {
|
|
4213
|
+
const unsub = store.subscribeToSource(source, () => {
|
|
4214
|
+
return queryClient.invalidateQueries({
|
|
4215
|
+
queryKey: ["analytics", "query", query]
|
|
4216
|
+
});
|
|
4217
|
+
});
|
|
4218
|
+
subscriptions.current.push(unsub);
|
|
4219
|
+
});
|
|
4220
|
+
return () => {
|
|
4221
|
+
subscriptions.current.forEach((unsub) => unsub());
|
|
4222
|
+
subscriptions.current = [];
|
|
4223
|
+
};
|
|
4224
|
+
}, [querySources]);
|
|
4225
|
+
return result;
|
|
4226
|
+
}
|
|
4227
|
+
function useMatchingSeries(query, options) {
|
|
4228
|
+
const result = useAnalyticsQueryWrapper({
|
|
4229
|
+
queryKey: ["analytics", "matchingSeries", query],
|
|
4230
|
+
queryFn: ({ store }) => store.getMatchingSeries(query),
|
|
4231
|
+
...options
|
|
4232
|
+
});
|
|
4233
|
+
return result;
|
|
4234
|
+
}
|
|
4235
|
+
function useQuerySources(query, options) {
|
|
4236
|
+
const { data: matchingSeries } = useMatchingSeries(query);
|
|
4237
|
+
return useQuery({
|
|
4238
|
+
queryKey: ["analytics", "sources", query],
|
|
4239
|
+
queryFn: () => {
|
|
4240
|
+
if (!(matchingSeries == null ? void 0 : matchingSeries.length)) {
|
|
4241
|
+
return [];
|
|
4242
|
+
}
|
|
4243
|
+
const uniqueSources = [
|
|
4244
|
+
...new Set(matchingSeries.map((s) => s.source.toString()))
|
|
4245
|
+
];
|
|
4246
|
+
return uniqueSources.map((source) => AnalyticsPath.fromString(source));
|
|
4247
|
+
},
|
|
4248
|
+
enabled: !!matchingSeries,
|
|
4249
|
+
...options
|
|
4250
|
+
});
|
|
4251
|
+
}
|
|
4252
|
+
const getBarSize = (value) => {
|
|
4253
|
+
if (value <= 0)
|
|
4254
|
+
return 0;
|
|
4255
|
+
if (value > 0 && value <= 50)
|
|
4256
|
+
return 1;
|
|
4257
|
+
if (value > 50 && value <= 100)
|
|
4258
|
+
return 2;
|
|
4259
|
+
if (value > 100 && value <= 250)
|
|
4260
|
+
return 3;
|
|
4261
|
+
return 4;
|
|
4262
|
+
};
|
|
4263
|
+
const useTimelineItems = (documentId, startTimestamp) => {
|
|
4264
|
+
const start = startTimestamp ? DateTime.fromISO(startTimestamp) : DateTime.now().startOf("day");
|
|
4265
|
+
const { data: diffResult, isLoading } = useAnalyticsQuery({
|
|
4266
|
+
start,
|
|
4267
|
+
end: DateTime.now().endOf("day"),
|
|
4268
|
+
granularity: AnalyticsGranularity.Hourly,
|
|
4269
|
+
metrics: ["Count"],
|
|
4270
|
+
select: {
|
|
4271
|
+
changes: [AnalyticsPath.fromString(`changes`)],
|
|
4272
|
+
document: [AnalyticsPath.fromString(`document/${documentId}`)]
|
|
4273
|
+
},
|
|
4274
|
+
lod: {
|
|
4275
|
+
changes: 2
|
|
4276
|
+
},
|
|
4277
|
+
currency: AnalyticsPath.fromString("")
|
|
4278
|
+
});
|
|
4279
|
+
const mappedResult = useMemo(() => {
|
|
4280
|
+
if (!diffResult)
|
|
4281
|
+
return [];
|
|
4282
|
+
return diffResult.sort((a, b) => {
|
|
4283
|
+
const aDate = new Date(a.start);
|
|
4284
|
+
const bDate = new Date(b.start);
|
|
4285
|
+
return aDate.getTime() - bDate.getTime();
|
|
4286
|
+
}).filter((result) => {
|
|
4287
|
+
return result.rows.every((row) => row.value > 0);
|
|
4288
|
+
}).map((result) => {
|
|
4289
|
+
const { additions, deletions } = result.rows.reduce((acc, row) => {
|
|
4290
|
+
if (row.dimensions.changes.path === "changes/add") {
|
|
4291
|
+
acc.additions += row.value;
|
|
4292
|
+
} else if (row.dimensions.changes.path === "changes/remove") {
|
|
4293
|
+
acc.deletions += row.value;
|
|
4294
|
+
}
|
|
4295
|
+
return acc;
|
|
4296
|
+
}, { additions: 0, deletions: 0 });
|
|
4297
|
+
const startDate = new Date(result.start);
|
|
4298
|
+
return {
|
|
4299
|
+
id: startDate.toISOString(),
|
|
4300
|
+
type: "bar",
|
|
4301
|
+
addSize: getBarSize(additions),
|
|
4302
|
+
delSize: getBarSize(deletions),
|
|
4303
|
+
additions,
|
|
4304
|
+
deletions,
|
|
4305
|
+
timestamp: startDate.toISOString(),
|
|
4306
|
+
startDate,
|
|
4307
|
+
endDate: new Date(result.end),
|
|
4308
|
+
revision: 0
|
|
4309
|
+
};
|
|
4310
|
+
});
|
|
4311
|
+
}, [diffResult]);
|
|
4312
|
+
const resultWithDividers = useMemo(() => {
|
|
4313
|
+
if (!mappedResult.length)
|
|
4314
|
+
return [];
|
|
4315
|
+
const result = [];
|
|
4316
|
+
mappedResult.forEach((item, index) => {
|
|
4317
|
+
result.push(item);
|
|
4318
|
+
if (index < mappedResult.length - 1) {
|
|
4319
|
+
const currentDate = new Date(item.startDate);
|
|
4320
|
+
const nextDate = new Date(mappedResult[index + 1].startDate);
|
|
4321
|
+
const currentHour = currentDate.getHours();
|
|
4322
|
+
const nextHour = nextDate.getHours();
|
|
4323
|
+
const currentDay = currentDate.toDateString();
|
|
4324
|
+
const nextDay = nextDate.toDateString();
|
|
4325
|
+
if (currentDay !== nextDay || currentDay === nextDay && Math.abs(nextHour - currentHour) > 1) {
|
|
4326
|
+
result.push({
|
|
4327
|
+
id: `divider-${item.id}-${mappedResult[index + 1].id}`,
|
|
4328
|
+
type: "divider",
|
|
4329
|
+
revision: 0
|
|
4330
|
+
});
|
|
4331
|
+
}
|
|
4332
|
+
}
|
|
4333
|
+
});
|
|
4334
|
+
return result;
|
|
4335
|
+
}, [mappedResult]);
|
|
4336
|
+
return {
|
|
4337
|
+
isLoading,
|
|
4338
|
+
data: resultWithDividers
|
|
4339
|
+
};
|
|
4340
|
+
};
|
|
4341
|
+
const getRevisionFromDate = (startDate, endDate, operations = []) => {
|
|
4342
|
+
if (!startDate || !endDate)
|
|
4343
|
+
return 0;
|
|
4344
|
+
const operation = operations.find((operation2) => {
|
|
4345
|
+
const operationDate = new Date(operation2.timestamp);
|
|
4346
|
+
return operationDate >= startDate && operationDate <= endDate;
|
|
4347
|
+
});
|
|
4348
|
+
return operation ? operation.index : 0;
|
|
4349
|
+
};
|
|
4350
|
+
function EditorLoader(props) {
|
|
4351
|
+
const [showLoading, setShowLoading] = useState(false);
|
|
4352
|
+
useEffect(() => {
|
|
4353
|
+
setTimeout(() => {
|
|
4354
|
+
setShowLoading(true);
|
|
4355
|
+
}, props.loadingTimeout ?? 200);
|
|
4356
|
+
}, [props]);
|
|
4357
|
+
if (!showLoading) return null;
|
|
4358
|
+
const { customEditorLoader, ...defaultProps } = props;
|
|
4359
|
+
if (customEditorLoader) return /* @__PURE__ */ jsx(Fragment$1, { children: customEditorLoader });
|
|
4360
|
+
return /* @__PURE__ */ jsx(DefaultEditorLoader, { ...defaultProps });
|
|
4361
|
+
}
|
|
4362
|
+
function EditorError({ message: message2 }) {
|
|
4363
|
+
return /* @__PURE__ */ jsx("div", { className: "flex size-full items-center justify-center", children: /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold", children: message2 }) });
|
|
4364
|
+
}
|
|
4365
|
+
function FallbackEditorError(props) {
|
|
4366
|
+
const message2 = props.error instanceof Error ? props.error.message : props.error;
|
|
4367
|
+
return /* @__PURE__ */ jsx(EditorError, { message: message2 });
|
|
4368
|
+
}
|
|
4369
|
+
const DocumentEditor = (props) => {
|
|
4370
|
+
const {
|
|
4371
|
+
fileNodeDocument,
|
|
4372
|
+
document: initialDocument,
|
|
3584
4373
|
onClose,
|
|
3585
4374
|
onChange,
|
|
3586
4375
|
onExport,
|
|
3587
4376
|
onAddOperation,
|
|
4377
|
+
onGetDocumentRevision,
|
|
3588
4378
|
onOpenSwitchboardLink
|
|
3589
4379
|
} = props;
|
|
3590
4380
|
const documentId = fileNodeDocument == null ? void 0 : fileNodeDocument.documentId;
|
|
4381
|
+
const [selectedTimelineItem, setSelectedTimelineItem] = useState(null);
|
|
3591
4382
|
const [revisionHistoryVisible, setRevisionHistoryVisible] = useState(false);
|
|
3592
4383
|
const theme = useAtomValue(themeAtom);
|
|
3593
4384
|
const user = useUser() || void 0;
|
|
@@ -3613,6 +4404,10 @@ const DocumentEditor = (props) => {
|
|
|
3613
4404
|
[theme, user]
|
|
3614
4405
|
);
|
|
3615
4406
|
const userPermissions = useUserPermissions$1();
|
|
4407
|
+
const timelineItems = useTimelineItems(
|
|
4408
|
+
documentId,
|
|
4409
|
+
initialDocument == null ? void 0 : initialDocument.created
|
|
4410
|
+
);
|
|
3616
4411
|
const currentDocument = useRef({ ...fileNodeDocument, document: document2 });
|
|
3617
4412
|
useEffect(() => {
|
|
3618
4413
|
var _a;
|
|
@@ -3789,7 +4584,8 @@ const DocumentEditor = (props) => {
|
|
|
3789
4584
|
const {
|
|
3790
4585
|
disableExternalControls,
|
|
3791
4586
|
documentToolbarEnabled,
|
|
3792
|
-
showSwitchboardLink
|
|
4587
|
+
showSwitchboardLink,
|
|
4588
|
+
timelineEnabled
|
|
3793
4589
|
} = editor.config || {};
|
|
3794
4590
|
const handleSwitchboardLinkClick = showSwitchboardLink !== false ? onOpenSwitchboardLink : void 0;
|
|
3795
4591
|
return /* @__PURE__ */ jsxs("div", { className: "relative h-full", id: "document-editor-context", children: [
|
|
@@ -3800,7 +4596,10 @@ const DocumentEditor = (props) => {
|
|
|
3800
4596
|
onExport,
|
|
3801
4597
|
onShowRevisionHistory: showRevisionHistory,
|
|
3802
4598
|
title: fileNodeDocument.name || document2.name,
|
|
3803
|
-
onSwitchboardLinkClick: handleSwitchboardLinkClick
|
|
4599
|
+
onSwitchboardLinkClick: handleSwitchboardLinkClick,
|
|
4600
|
+
timelineButtonVisible: timelineEnabled,
|
|
4601
|
+
timelineItems: timelineItems.data,
|
|
4602
|
+
onTimelineItemClick: setSelectedTimelineItem
|
|
3804
4603
|
}
|
|
3805
4604
|
),
|
|
3806
4605
|
!disableExternalControls && /* @__PURE__ */ jsxs("div", { className: "mb-4 flex justify-end gap-10", children: [
|
|
@@ -3830,7 +4629,16 @@ const DocumentEditor = (props) => {
|
|
|
3830
4629
|
EditorComponent,
|
|
3831
4630
|
{
|
|
3832
4631
|
error,
|
|
3833
|
-
context
|
|
4632
|
+
context: {
|
|
4633
|
+
...context,
|
|
4634
|
+
getDocumentRevision: onGetDocumentRevision,
|
|
4635
|
+
readMode: !!selectedTimelineItem,
|
|
4636
|
+
selectedTimelineRevision: getRevisionFromDate(
|
|
4637
|
+
selectedTimelineItem == null ? void 0 : selectedTimelineItem.startDate,
|
|
4638
|
+
selectedTimelineItem == null ? void 0 : selectedTimelineItem.endDate,
|
|
4639
|
+
document2.operations.global
|
|
4640
|
+
)
|
|
4641
|
+
},
|
|
3834
4642
|
document: document2,
|
|
3835
4643
|
documentNodeName: fileNodeDocument.name,
|
|
3836
4644
|
dispatch,
|
|
@@ -3868,6 +4676,7 @@ function DocumentEditorContainer() {
|
|
|
3868
4676
|
renameNode,
|
|
3869
4677
|
getDocumentModelModule
|
|
3870
4678
|
} = useUiNodes();
|
|
4679
|
+
const getDocument = useGetDocument();
|
|
3871
4680
|
const handleAddOperationToSelectedDocument = useCallback(
|
|
3872
4681
|
async (operation) => {
|
|
3873
4682
|
if (!selectedDocument) {
|
|
@@ -3930,6 +4739,20 @@ function DocumentEditorContainer() {
|
|
|
3930
4739
|
},
|
|
3931
4740
|
[getDocumentModelModule, showModal, t]
|
|
3932
4741
|
);
|
|
4742
|
+
const onGetDocumentRevision = useCallback(
|
|
4743
|
+
(options) => {
|
|
4744
|
+
if (!selectedNode) {
|
|
4745
|
+
console.error("No selected node");
|
|
4746
|
+
return Promise.reject(new Error("No selected node"));
|
|
4747
|
+
}
|
|
4748
|
+
return getDocument(
|
|
4749
|
+
selectedNode.driveId,
|
|
4750
|
+
selectedNode.id,
|
|
4751
|
+
options
|
|
4752
|
+
);
|
|
4753
|
+
},
|
|
4754
|
+
[getDocument, selectedNode]
|
|
4755
|
+
);
|
|
3933
4756
|
const onExport = useCallback(() => {
|
|
3934
4757
|
if (selectedDocument) {
|
|
3935
4758
|
return exportDocument(selectedDocument);
|
|
@@ -3951,6 +4774,7 @@ function DocumentEditorContainer() {
|
|
|
3951
4774
|
onChange: onDocumentChangeHandler,
|
|
3952
4775
|
onClose,
|
|
3953
4776
|
onExport,
|
|
4777
|
+
onGetDocumentRevision,
|
|
3954
4778
|
onAddOperation: handleAddOperationToSelectedDocument,
|
|
3955
4779
|
onOpenSwitchboardLink
|
|
3956
4780
|
}
|
|
@@ -3959,165 +4783,6 @@ function DocumentEditorContainer() {
|
|
|
3959
4783
|
fileNodeDocument.documentId
|
|
3960
4784
|
);
|
|
3961
4785
|
}
|
|
3962
|
-
function getDocumentSpec(doc) {
|
|
3963
|
-
if ("documentModelState" in doc) {
|
|
3964
|
-
return doc.documentModelState;
|
|
3965
|
-
}
|
|
3966
|
-
return doc.documentModel;
|
|
3967
|
-
}
|
|
3968
|
-
const CreateDocument = ({ documentModels, createDocument }) => {
|
|
3969
|
-
return jsxs("div", { className: "px-6", children: [jsx("h3", { className: "mb-3 mt-4 text-xl font-bold text-gray-600", children: "New document" }), jsx("div", { className: "flex w-full flex-wrap gap-4", children: documentModels == null ? void 0 : documentModels.map((doc) => {
|
|
3970
|
-
const spec = getDocumentSpec(doc);
|
|
3971
|
-
return jsx(Button, { color: "light", "aria-details": spec.description, onClick: () => createDocument(doc), children: jsx("span", { className: "text-sm", children: spec.name }) }, spec.id);
|
|
3972
|
-
}) })] });
|
|
3973
|
-
};
|
|
3974
|
-
function sortUiNodesByName(a, b) {
|
|
3975
|
-
return a.name.localeCompare(b.name);
|
|
3976
|
-
}
|
|
3977
|
-
const GAP = 8;
|
|
3978
|
-
const ITEM_WIDTH = 256;
|
|
3979
|
-
const ITEM_HEIGHT = 48;
|
|
3980
|
-
const USED_SPACE = 420;
|
|
3981
|
-
function FileContentView(props) {
|
|
3982
|
-
const parentRef = useRef(null);
|
|
3983
|
-
const { t } = useTranslation();
|
|
3984
|
-
const windowSize = useWindowSize();
|
|
3985
|
-
const { fileNodes, ...fileProps } = props;
|
|
3986
|
-
const availableWidth = windowSize.innerWidth - USED_SPACE;
|
|
3987
|
-
const columnCount = Math.floor(availableWidth / (ITEM_WIDTH + GAP)) || 1;
|
|
3988
|
-
const rowCount = Math.ceil(fileNodes.length / columnCount);
|
|
3989
|
-
const rowVirtualizer = useVirtualizer({
|
|
3990
|
-
count: rowCount,
|
|
3991
|
-
getScrollElement: () => parentRef.current,
|
|
3992
|
-
estimateSize: (index) => {
|
|
3993
|
-
if (index > 0) {
|
|
3994
|
-
return ITEM_HEIGHT + GAP;
|
|
3995
|
-
}
|
|
3996
|
-
return ITEM_HEIGHT;
|
|
3997
|
-
},
|
|
3998
|
-
overscan: 5
|
|
3999
|
-
});
|
|
4000
|
-
const columnVirtualizer = useVirtualizer({
|
|
4001
|
-
horizontal: true,
|
|
4002
|
-
count: columnCount,
|
|
4003
|
-
getScrollElement: () => parentRef.current,
|
|
4004
|
-
estimateSize: (index) => {
|
|
4005
|
-
if (index > 0) {
|
|
4006
|
-
return ITEM_WIDTH + GAP;
|
|
4007
|
-
}
|
|
4008
|
-
return ITEM_WIDTH;
|
|
4009
|
-
},
|
|
4010
|
-
overscan: 5
|
|
4011
|
-
});
|
|
4012
|
-
const getItemIndex = (rowIndex, columnIndex) => rowIndex * columnCount + columnIndex;
|
|
4013
|
-
const getItem = (rowIndex, columnIndex) => {
|
|
4014
|
-
const index = getItemIndex(rowIndex, columnIndex);
|
|
4015
|
-
return fileNodes[index] || null;
|
|
4016
|
-
};
|
|
4017
|
-
if (fileNodes.length === 0) {
|
|
4018
|
-
return jsx("div", { className: "mb-8 text-sm text-gray-400", children: t("folderView.sections.documents.empty", {
|
|
4019
|
-
defaultValue: "No documents or files 📄"
|
|
4020
|
-
}) });
|
|
4021
|
-
}
|
|
4022
|
-
const renderItem = (rowIndex, columnIndex) => {
|
|
4023
|
-
const fileNode = getItem(rowIndex, columnIndex);
|
|
4024
|
-
if (!fileNode) {
|
|
4025
|
-
return null;
|
|
4026
|
-
}
|
|
4027
|
-
return jsx("div", { style: {
|
|
4028
|
-
marginLeft: columnIndex === 0 ? 0 : GAP
|
|
4029
|
-
}, children: jsx(FileItem, { uiNode: fileNode, ...fileProps }, fileNode.id) });
|
|
4030
|
-
};
|
|
4031
|
-
return jsx("div", { ref: parentRef, style: {
|
|
4032
|
-
height: `400px`,
|
|
4033
|
-
width: `100%`,
|
|
4034
|
-
overflow: "auto"
|
|
4035
|
-
}, children: jsx("div", { style: {
|
|
4036
|
-
height: `${rowVirtualizer.getTotalSize()}px`,
|
|
4037
|
-
width: `${columnVirtualizer.getTotalSize()}px`,
|
|
4038
|
-
position: "relative"
|
|
4039
|
-
}, children: rowVirtualizer.getVirtualItems().map((virtualRow) => jsx(React__default.Fragment, { children: columnVirtualizer.getVirtualItems().map((virtualColumn) => jsx("div", { style: {
|
|
4040
|
-
position: "absolute",
|
|
4041
|
-
top: 0,
|
|
4042
|
-
left: 0,
|
|
4043
|
-
marginTop: virtualRow.index === 0 ? 0 : GAP,
|
|
4044
|
-
width: `${virtualColumn.size}px`,
|
|
4045
|
-
height: `${virtualRow.size}px`,
|
|
4046
|
-
transform: `translateX(${virtualColumn.start}px) translateY(${virtualRow.start}px)`
|
|
4047
|
-
}, children: renderItem(virtualRow.index, virtualColumn.index) }, virtualColumn.key)) }, virtualRow.key)) }) });
|
|
4048
|
-
}
|
|
4049
|
-
function FolderView(props) {
|
|
4050
|
-
const { node, className, isDropTarget, containerProps, ...nodeProps } = props;
|
|
4051
|
-
const { t } = useTranslation();
|
|
4052
|
-
const folderNodes = node.children.filter((node2) => node2.kind === FOLDER).sort(sortUiNodesByName);
|
|
4053
|
-
const fileNodes = node.children.filter((node2) => node2.kind === FILE).sort(sortUiNodesByName);
|
|
4054
|
-
const folderCallbacks = {
|
|
4055
|
-
onSelectNode: (node2) => nodeProps.onSelectNode(node2),
|
|
4056
|
-
onRenameNode: (name, node2) => nodeProps.onRenameNode(name, node2),
|
|
4057
|
-
onDuplicateNode: (node2) => nodeProps.onDuplicateNode(node2),
|
|
4058
|
-
onDeleteNode: (node2) => nodeProps.onDeleteNode(node2)
|
|
4059
|
-
};
|
|
4060
|
-
const fileCallbacks = {
|
|
4061
|
-
onSelectNode: (node2) => nodeProps.onSelectNode(node2),
|
|
4062
|
-
onRenameNode: (name, node2) => nodeProps.onRenameNode(name, node2),
|
|
4063
|
-
onDuplicateNode: (node2) => nodeProps.onDuplicateNode(node2),
|
|
4064
|
-
onDeleteNode: (node2) => nodeProps.onDeleteNode(node2)
|
|
4065
|
-
};
|
|
4066
|
-
const baseNodeCallbacks = {
|
|
4067
|
-
onAddFile: async (file, parentNode) => {
|
|
4068
|
-
await nodeProps.onAddFile(file, parentNode);
|
|
4069
|
-
},
|
|
4070
|
-
onCopyNode: async (uiNode, targetNode) => {
|
|
4071
|
-
await nodeProps.onCopyNode(uiNode, targetNode);
|
|
4072
|
-
},
|
|
4073
|
-
onMoveNode: async (uiNode, targetNode) => {
|
|
4074
|
-
await nodeProps.onMoveNode(uiNode, targetNode);
|
|
4075
|
-
}
|
|
4076
|
-
};
|
|
4077
|
-
return jsxs("div", { className: twMerge("rounded-md border-2 border-transparent p-2", isDropTarget && "border-dashed border-blue-100", className), ...containerProps, children: [jsx(DriveLayout.ContentSection, { title: t("folderView.sections.folders.title", {
|
|
4078
|
-
defaultValue: "Folders"
|
|
4079
|
-
}), className: "mb-4", children: folderNodes.length > 0 ? folderNodes.map((folderNode) => jsx(FolderItem, { uiNode: folderNode, ...baseNodeCallbacks, ...folderCallbacks, isAllowedToCreateDocuments: nodeProps.isAllowedToCreateDocuments }, folderNode.id)) : jsx("div", { className: "mb-8 text-sm text-gray-400", children: t("folderView.sections.folders.empty", {
|
|
4080
|
-
defaultValue: "No documents or files 📄"
|
|
4081
|
-
}) }) }), jsx(DriveLayout.ContentSection, { title: t("folderView.sections.documents.title", {
|
|
4082
|
-
defaultValue: "Documents and files"
|
|
4083
|
-
}), children: jsx("div", { className: twMerge("w-full", fileNodes.length > 0 ? "min-h-[400px]" : "min-h-14"), children: jsx(FileContentView, { fileNodes, ...fileCallbacks, isAllowedToCreateDocuments: nodeProps.isAllowedToCreateDocuments }) }) })] });
|
|
4084
|
-
}
|
|
4085
|
-
function BaseEditor(props) {
|
|
4086
|
-
const { document: document2, dispatch, className, children } = props;
|
|
4087
|
-
const { state: { global: { id: driveId } } } = document2;
|
|
4088
|
-
const { showSearchBar, isAllowedToCreateDocuments, documentModels, showCreateDocumentModal } = useDriveContext();
|
|
4089
|
-
const { driveNodes, selectedNode, selectedNodePath, getNodeById, setSelectedNode } = useUiNodesContext();
|
|
4090
|
-
const driveNode = useMemo(() => driveNodes.find((n) => n.id === driveId), [driveNodes, driveId]);
|
|
4091
|
-
const { addDocument, addFile, addFolder: addFolder2, renameNode, deleteNode: deleteNode2, moveNode: moveNode2, copyNode: copyNode2, duplicateNode } = useDriveActionsWithUiNodes(document2, dispatch);
|
|
4092
|
-
const onCreateDocument = useCallback(async (documentModel) => {
|
|
4093
|
-
const { name } = await showCreateDocumentModal(documentModel);
|
|
4094
|
-
const document3 = documentModel.utils.createDocument();
|
|
4095
|
-
await addDocument(name, documentModel.documentModel.name, document3, selectedNode == null ? void 0 : selectedNode.id);
|
|
4096
|
-
}, [addDocument, showCreateDocumentModal, selectedNode == null ? void 0 : selectedNode.id]);
|
|
4097
|
-
const { isDropTarget, dropProps } = useDrop({
|
|
4098
|
-
uiNode: selectedNode,
|
|
4099
|
-
onAddFile: addFile,
|
|
4100
|
-
onCopyNode: copyNode2,
|
|
4101
|
-
onMoveNode: moveNode2
|
|
4102
|
-
});
|
|
4103
|
-
const { breadcrumbs, onBreadcrumbSelected } = useBreadcrumbs({
|
|
4104
|
-
selectedNodePath,
|
|
4105
|
-
getNodeById,
|
|
4106
|
-
setSelectedNode
|
|
4107
|
-
});
|
|
4108
|
-
if (!driveNode) {
|
|
4109
|
-
return jsx("div", { children: "Drive not found" });
|
|
4110
|
-
} else if ((selectedNode == null ? void 0 : selectedNode.kind) === FILE$1) {
|
|
4111
|
-
return jsx(Fragment$1, {});
|
|
4112
|
-
}
|
|
4113
|
-
return jsxs(DriveLayout, { className, children: [children, jsxs(DriveLayout.Header, { children: [jsx(Breadcrumbs, { breadcrumbs, createEnabled: isAllowedToCreateDocuments, onCreate: addFolder2, onBreadcrumbSelected }), showSearchBar && jsx(SearchBar, {})] }), jsx(DriveLayout.Content, { children: jsx(FolderView, { node: selectedNode || driveNode, onSelectNode: setSelectedNode, onRenameNode: renameNode, onDuplicateNode: duplicateNode, onDeleteNode: deleteNode2, onAddFile: addFile, onCopyNode: copyNode2, onMoveNode: moveNode2, isDropTarget, isAllowedToCreateDocuments }) }), jsx(DriveLayout.Footer, { children: isAllowedToCreateDocuments && jsx(CreateDocument, { documentModels, createDocument: onCreateDocument }) })] });
|
|
4114
|
-
}
|
|
4115
|
-
function Editor(props) {
|
|
4116
|
-
return jsx(DriveContextProvider, { value: props.context, children: jsx(BaseEditor, { ...props }) });
|
|
4117
|
-
}
|
|
4118
|
-
const GenericDriveExplorer = {
|
|
4119
|
-
Component: Editor
|
|
4120
|
-
};
|
|
4121
4786
|
function useDocumentsState(args) {
|
|
4122
4787
|
const { reactor, driveId, documentIds, options } = args;
|
|
4123
4788
|
const [statesByDocumentId, setStatesByDocumentId] = useState({});
|
|
@@ -4304,6 +4969,17 @@ function DriveEditorContainer() {
|
|
|
4304
4969
|
const { addFile, addDocument } = useDocumentDriveServer();
|
|
4305
4970
|
const documentModels = useFilteredDocumentModels();
|
|
4306
4971
|
const useDriveDocumentState = makeDriveDocumentStateHook(reactor);
|
|
4972
|
+
const getDocument = useGetDocument();
|
|
4973
|
+
const onGetDocumentRevision = useCallback(
|
|
4974
|
+
(documentId, options) => {
|
|
4975
|
+
if (!selectedNode) {
|
|
4976
|
+
console.error("No selected node");
|
|
4977
|
+
return Promise.reject(new Error("No selected node"));
|
|
4978
|
+
}
|
|
4979
|
+
return getDocument(selectedNode.driveId, documentId, options);
|
|
4980
|
+
},
|
|
4981
|
+
[getDocument, selectedNode]
|
|
4982
|
+
);
|
|
4307
4983
|
const driveContext = useMemo(
|
|
4308
4984
|
() => ({
|
|
4309
4985
|
showSearchBar: false,
|
|
@@ -4346,7 +5022,8 @@ function DriveEditorContainer() {
|
|
|
4346
5022
|
...editorProps,
|
|
4347
5023
|
context: {
|
|
4348
5024
|
...editorProps.context,
|
|
4349
|
-
...driveContext
|
|
5025
|
+
...driveContext,
|
|
5026
|
+
getDocumentRevision: onGetDocumentRevision
|
|
4350
5027
|
},
|
|
4351
5028
|
onSwitchboardLinkClick: void 0,
|
|
4352
5029
|
document: document2,
|
|
@@ -4380,7 +5057,7 @@ function Content() {
|
|
|
4380
5057
|
}, [selectedDriveNode, selectedNode, addFile]);
|
|
4381
5058
|
useEffect(() => {
|
|
4382
5059
|
if ((status === "LOADED" || status === "ERROR") && !documentDrives.find(
|
|
4383
|
-
(d) => d.state.global.id === driveId || d.
|
|
5060
|
+
(d) => d.state.global.id === driveId || d.slug === driveId || d.state.global.name === driveId
|
|
4384
5061
|
)) {
|
|
4385
5062
|
toast(/* @__PURE__ */ jsxs("p", { children: [
|
|
4386
5063
|
"Drive ",
|
|
@@ -4395,3 +5072,4 @@ function Content() {
|
|
|
4395
5072
|
export {
|
|
4396
5073
|
Content as default
|
|
4397
5074
|
};
|
|
5075
|
+
//# sourceMappingURL=content-D22zsKwo.js.map
|