@powerhousedao/connect 1.0.23-staging.1 → 1.0.24-dev.0
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-L-nqsJL1.js → app-B5yYl0zv.js} +19842 -18216
- package/dist/assets/app-B5yYl0zv.js.map +1 -0
- package/dist/assets/{app-Dtx0nq4m.css → app-DWlDE8AF.css} +240 -181
- package/dist/assets/{app-loader-B9WMnDgs.js → app-loader-CmEZOj3m.js} +735 -420
- package/dist/assets/app-loader-CmEZOj3m.js.map +1 -0
- package/dist/assets/{app-loader-3ipafc56.css → app-loader-NDVZu4bS.css} +238 -228
- package/dist/assets/browser-D5LEpLBa.js +27224 -0
- package/dist/assets/browser-D5LEpLBa.js.map +1 -0
- package/dist/assets/{ccip-XbQMrTCQ.js → ccip-KtRjx9vh.js} +6 -8
- package/dist/assets/ccip-KtRjx9vh.js.map +1 -0
- package/dist/assets/{content-B39UDenT.js → content-2lJzkjLx.js} +1100 -462
- package/dist/assets/content-2lJzkjLx.js.map +1 -0
- package/dist/assets/{index-CCHuBMLB.js → index-BVVRVlZN.js} +4 -3
- package/dist/assets/index-BVVRVlZN.js.map +1 -0
- package/dist/assets/{index-DZDjpeBO.js → index-BhHOiwFw.js} +2476 -2660
- package/dist/assets/index-BhHOiwFw.js.map +1 -0
- package/dist/assets/index-DZiF5od7.js +208 -0
- package/dist/assets/index-DZiF5od7.js.map +1 -0
- package/dist/assets/{index-C3q-1asu.js → index-dSMCpjcQ.js} +23 -171
- package/dist/assets/index-dSMCpjcQ.js.map +1 -0
- package/dist/assets/{main.B_-fy86f.js → main.DA6nl4Ov.js} +3 -12
- package/dist/assets/main.DA6nl4Ov.js.map +1 -0
- package/dist/assets/reactor-analytics-CF_JKt8H.js +42 -0
- package/dist/assets/reactor-analytics-CF_JKt8H.js.map +1 -0
- package/dist/assets/router-Ch1WZD-6.js +1585 -0
- package/dist/assets/router-Ch1WZD-6.js.map +1 -0
- package/dist/assets/{style-0ej1afQi.css → style-CdxGKc2g.css} +39 -95
- 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 +21 -20
|
@@ -1,10 +1,11 @@
|
|
|
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, aP as INITIAL_SYNC, aQ as SYNCING, S as SUCCESS, C as CONFLICT, aR as MISSING, x as ERROR, 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, a3 as AnalyticsPath, bl as useAnalyticsEngine, a4 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-B5yYl0zv.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 DUPLICATE, c0 as RENAME, c1 as WRITE, c2 as DELETE, c3 as defaultFolderOptions, c4 as garbageCollect, c5 as sortOperations, c6 as UI_NODE, aQ as DRIVE, aB as FILE, ae as buildSignedOperation, ax as addFolder, at as generateAddNodeAction, ay as isFolderNode, au as isFileNode, az as deleteNode, aA as updateNode, aC as moveNode, aD as generateNodesCopy, aE as copyNode, aq as generateId$1, c7 as undo, c8 as redo, _ as logger, aR as FOLDER, c9 as useDocumentDispatch$1, an as driveDocumentModelModule, ah as connectConfig } from "./app-loader-CmEZOj3m.js";
|
|
6
|
+
import { E as ENSAvatar, a as ErrorBoundary } from "./router-Ch1WZD-6.js";
|
|
6
7
|
import { flushSync } from "react-dom";
|
|
7
|
-
import "./main.
|
|
8
|
+
import "./main.DA6nl4Ov.js";
|
|
8
9
|
const PaginationButton = ({ active = false, ...props }) => {
|
|
9
10
|
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
11
|
return jsx(Button, { color: "light", size: "small", ...mergeClassNameProps(props, className), children: props.children });
|
|
@@ -14,7 +15,7 @@ const Pagination = (props) => {
|
|
|
14
15
|
return jsxs("div", { className: "flex gap-x-1", children: [firstPageLabel ? jsx(PaginationButton, { disabled: !isPreviousPageAvailable, onClick: () => goToFirstPage(), children: firstPageLabel }) : null, previousPageLabel ? jsxs(PaginationButton, { disabled: !isPreviousPageAvailable, onClick: () => goToPreviousPage(), children: [jsx(Icon, { className: "rotate-90", name: "ChevronDown", size: 16 }), previousPageLabel] }) : null, pages.map((page) => jsx(PaginationButton, { active: page.active, onClick: () => goToPage(page.index), children: page.number }, page.index)), hiddenNextPages ? jsx("span", { className: "flex items-center justify-center px-2", children: "..." }) : null, nextPageLabel ? jsxs(PaginationButton, { disabled: !isNextPageAvailable, onClick: () => goToNextPage(), children: [nextPageLabel, jsx(Icon, { className: "-rotate-90", name: "ChevronDown", size: 16 })] }) : null, lastPageLabel ? jsx(PaginationButton, { disabled: !isNextPageAvailable, onClick: () => goToLastPage(), children: lastPageLabel }) : null] });
|
|
15
16
|
};
|
|
16
17
|
function usePagination(items, options) {
|
|
17
|
-
const { itemsPerPage = 20, initialPage = 0, pageRange = 3 } = options
|
|
18
|
+
const { itemsPerPage = 20, initialPage = 0, pageRange = 3 } = options;
|
|
18
19
|
const [currentPage, setCurrentPage] = useState(initialPage);
|
|
19
20
|
const pageCount = Math.ceil(items.length / itemsPerPage);
|
|
20
21
|
const isNextPageAvailable = currentPage < pageCount - 1;
|
|
@@ -151,131 +152,12 @@ function DefaultEditorLoader(props) {
|
|
|
151
152
|
const { message: message2 = "Loading editor", ...divProps } = props;
|
|
152
153
|
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
154
|
}
|
|
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
155
|
const millisecondsInWeek = 6048e5;
|
|
278
156
|
const millisecondsInDay = 864e5;
|
|
157
|
+
const millisecondsInMinute = 6e4;
|
|
158
|
+
const millisecondsInHour = 36e5;
|
|
159
|
+
const minutesInMonth = 43200;
|
|
160
|
+
const minutesInDay = 1440;
|
|
279
161
|
const constructFromSymbol = Symbol.for("constructDateFrom");
|
|
280
162
|
function constructFrom(date, value) {
|
|
281
163
|
if (typeof date === "function") return date(value);
|
|
@@ -343,7 +225,7 @@ function getTimezoneOffsetInMilliseconds(date) {
|
|
|
343
225
|
function normalizeDates(context, ...dates) {
|
|
344
226
|
const normalize = constructFrom.bind(
|
|
345
227
|
null,
|
|
346
|
-
dates.find((date) => typeof date === "object")
|
|
228
|
+
context || dates.find((date) => typeof date === "object")
|
|
347
229
|
);
|
|
348
230
|
return dates.map(normalize);
|
|
349
231
|
}
|
|
@@ -371,12 +253,83 @@ function startOfISOWeekYear(date, options) {
|
|
|
371
253
|
fourthOfJanuary.setHours(0, 0, 0, 0);
|
|
372
254
|
return startOfISOWeek(fourthOfJanuary);
|
|
373
255
|
}
|
|
256
|
+
function compareAsc(dateLeft, dateRight) {
|
|
257
|
+
const diff = +toDate(dateLeft) - +toDate(dateRight);
|
|
258
|
+
if (diff < 0) return -1;
|
|
259
|
+
else if (diff > 0) return 1;
|
|
260
|
+
return diff;
|
|
261
|
+
}
|
|
262
|
+
function constructNow(date) {
|
|
263
|
+
return constructFrom(date, Date.now());
|
|
264
|
+
}
|
|
374
265
|
function isDate(value) {
|
|
375
266
|
return value instanceof Date || typeof value === "object" && Object.prototype.toString.call(value) === "[object Date]";
|
|
376
267
|
}
|
|
377
268
|
function isValid(date) {
|
|
378
269
|
return !(!isDate(date) && typeof date !== "number" || isNaN(+toDate(date)));
|
|
379
270
|
}
|
|
271
|
+
function differenceInCalendarMonths(laterDate, earlierDate, options) {
|
|
272
|
+
const [laterDate_, earlierDate_] = normalizeDates(
|
|
273
|
+
options == null ? void 0 : options.in,
|
|
274
|
+
laterDate,
|
|
275
|
+
earlierDate
|
|
276
|
+
);
|
|
277
|
+
const yearsDiff = laterDate_.getFullYear() - earlierDate_.getFullYear();
|
|
278
|
+
const monthsDiff = laterDate_.getMonth() - earlierDate_.getMonth();
|
|
279
|
+
return yearsDiff * 12 + monthsDiff;
|
|
280
|
+
}
|
|
281
|
+
function getRoundingMethod(method) {
|
|
282
|
+
return (number) => {
|
|
283
|
+
const round = method ? Math[method] : Math.trunc;
|
|
284
|
+
const result = round(number);
|
|
285
|
+
return result === 0 ? 0 : result;
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
function differenceInMilliseconds(laterDate, earlierDate) {
|
|
289
|
+
return +toDate(laterDate) - +toDate(earlierDate);
|
|
290
|
+
}
|
|
291
|
+
function endOfDay(date, options) {
|
|
292
|
+
const _date = toDate(date, options == null ? void 0 : options.in);
|
|
293
|
+
_date.setHours(23, 59, 59, 999);
|
|
294
|
+
return _date;
|
|
295
|
+
}
|
|
296
|
+
function endOfMonth(date, options) {
|
|
297
|
+
const _date = toDate(date, options == null ? void 0 : options.in);
|
|
298
|
+
const month = _date.getMonth();
|
|
299
|
+
_date.setFullYear(_date.getFullYear(), month + 1, 0);
|
|
300
|
+
_date.setHours(23, 59, 59, 999);
|
|
301
|
+
return _date;
|
|
302
|
+
}
|
|
303
|
+
function isLastDayOfMonth(date, options) {
|
|
304
|
+
const _date = toDate(date, options == null ? void 0 : options.in);
|
|
305
|
+
return +endOfDay(_date, options) === +endOfMonth(_date, options);
|
|
306
|
+
}
|
|
307
|
+
function differenceInMonths(laterDate, earlierDate, options) {
|
|
308
|
+
const [laterDate_, workingLaterDate, earlierDate_] = normalizeDates(
|
|
309
|
+
options == null ? void 0 : options.in,
|
|
310
|
+
laterDate,
|
|
311
|
+
laterDate,
|
|
312
|
+
earlierDate
|
|
313
|
+
);
|
|
314
|
+
const sign = compareAsc(workingLaterDate, earlierDate_);
|
|
315
|
+
const difference = Math.abs(
|
|
316
|
+
differenceInCalendarMonths(workingLaterDate, earlierDate_)
|
|
317
|
+
);
|
|
318
|
+
if (difference < 1) return 0;
|
|
319
|
+
if (workingLaterDate.getMonth() === 1 && workingLaterDate.getDate() > 27)
|
|
320
|
+
workingLaterDate.setDate(30);
|
|
321
|
+
workingLaterDate.setMonth(workingLaterDate.getMonth() - sign * difference);
|
|
322
|
+
let isLastMonthNotFull = compareAsc(workingLaterDate, earlierDate_) === -sign;
|
|
323
|
+
if (isLastDayOfMonth(laterDate_) && difference === 1 && compareAsc(laterDate_, earlierDate_) === 1) {
|
|
324
|
+
isLastMonthNotFull = false;
|
|
325
|
+
}
|
|
326
|
+
const result = sign * (difference - +isLastMonthNotFull);
|
|
327
|
+
return result === 0 ? 0 : result;
|
|
328
|
+
}
|
|
329
|
+
function differenceInSeconds(laterDate, earlierDate, options) {
|
|
330
|
+
const diff = differenceInMilliseconds(laterDate, earlierDate) / 1e3;
|
|
331
|
+
return getRoundingMethod(options == null ? void 0 : options.roundingMethod)(diff);
|
|
332
|
+
}
|
|
380
333
|
function startOfYear(date, options) {
|
|
381
334
|
const date_ = toDate(date, options == null ? void 0 : options.in);
|
|
382
335
|
date_.setFullYear(date_.getFullYear(), 0, 1);
|
|
@@ -446,7 +399,7 @@ const formatDistanceLocale = {
|
|
|
446
399
|
other: "almost {{count}} years"
|
|
447
400
|
}
|
|
448
401
|
};
|
|
449
|
-
const formatDistance = (token, count, options) => {
|
|
402
|
+
const formatDistance$1 = (token, count, options) => {
|
|
450
403
|
let result;
|
|
451
404
|
const tokenValue = formatDistanceLocale[token];
|
|
452
405
|
if (typeof tokenValue === "string") {
|
|
@@ -862,7 +815,7 @@ const match = {
|
|
|
862
815
|
};
|
|
863
816
|
const enUS = {
|
|
864
817
|
code: "en-US",
|
|
865
|
-
formatDistance,
|
|
818
|
+
formatDistance: formatDistance$1,
|
|
866
819
|
formatLong,
|
|
867
820
|
formatRelative,
|
|
868
821
|
localize,
|
|
@@ -985,6 +938,8 @@ const lightFormatters = {
|
|
|
985
938
|
}
|
|
986
939
|
};
|
|
987
940
|
const dayPeriodEnum = {
|
|
941
|
+
am: "am",
|
|
942
|
+
pm: "pm",
|
|
988
943
|
midnight: "midnight",
|
|
989
944
|
noon: "noon",
|
|
990
945
|
morning: "morning",
|
|
@@ -1764,76 +1719,575 @@ function cleanEscapedString(input) {
|
|
|
1764
1719
|
}
|
|
1765
1720
|
return matched[1].replace(doubleQuoteRegExp, "'");
|
|
1766
1721
|
}
|
|
1767
|
-
function
|
|
1768
|
-
const
|
|
1769
|
-
const
|
|
1770
|
-
const
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1722
|
+
function formatDistance(laterDate, earlierDate, options) {
|
|
1723
|
+
const defaultOptions2 = getDefaultOptions();
|
|
1724
|
+
const locale = (options == null ? void 0 : options.locale) ?? defaultOptions2.locale ?? enUS;
|
|
1725
|
+
const minutesInAlmostTwoDays = 2520;
|
|
1726
|
+
const comparison = compareAsc(laterDate, earlierDate);
|
|
1727
|
+
if (isNaN(comparison)) throw new RangeError("Invalid time value");
|
|
1728
|
+
const localizeOptions = Object.assign({}, options, {
|
|
1729
|
+
addSuffix: options == null ? void 0 : options.addSuffix,
|
|
1730
|
+
comparison
|
|
1731
|
+
});
|
|
1732
|
+
const [laterDate_, earlierDate_] = normalizeDates(
|
|
1733
|
+
options == null ? void 0 : options.in,
|
|
1734
|
+
...comparison > 0 ? [earlierDate, laterDate] : [laterDate, earlierDate]
|
|
1735
|
+
);
|
|
1736
|
+
const seconds = differenceInSeconds(earlierDate_, laterDate_);
|
|
1737
|
+
const offsetInSeconds = (getTimezoneOffsetInMilliseconds(earlierDate_) - getTimezoneOffsetInMilliseconds(laterDate_)) / 1e3;
|
|
1738
|
+
const minutes = Math.round((seconds - offsetInSeconds) / 60);
|
|
1739
|
+
let months;
|
|
1740
|
+
if (minutes < 2) {
|
|
1741
|
+
if (options == null ? void 0 : options.includeSeconds) {
|
|
1742
|
+
if (seconds < 5) {
|
|
1743
|
+
return locale.formatDistance("lessThanXSeconds", 5, localizeOptions);
|
|
1744
|
+
} else if (seconds < 10) {
|
|
1745
|
+
return locale.formatDistance("lessThanXSeconds", 10, localizeOptions);
|
|
1746
|
+
} else if (seconds < 20) {
|
|
1747
|
+
return locale.formatDistance("lessThanXSeconds", 20, localizeOptions);
|
|
1748
|
+
} else if (seconds < 40) {
|
|
1749
|
+
return locale.formatDistance("halfAMinute", 0, localizeOptions);
|
|
1750
|
+
} else if (seconds < 60) {
|
|
1751
|
+
return locale.formatDistance("lessThanXMinutes", 1, localizeOptions);
|
|
1752
|
+
} else {
|
|
1753
|
+
return locale.formatDistance("xMinutes", 1, localizeOptions);
|
|
1754
|
+
}
|
|
1755
|
+
} else {
|
|
1756
|
+
if (minutes === 0) {
|
|
1757
|
+
return locale.formatDistance("lessThanXMinutes", 1, localizeOptions);
|
|
1758
|
+
} else {
|
|
1759
|
+
return locale.formatDistance("xMinutes", minutes, localizeOptions);
|
|
1760
|
+
}
|
|
1775
1761
|
}
|
|
1776
|
-
|
|
1777
|
-
|
|
1762
|
+
} else if (minutes < 45) {
|
|
1763
|
+
return locale.formatDistance("xMinutes", minutes, localizeOptions);
|
|
1764
|
+
} else if (minutes < 90) {
|
|
1765
|
+
return locale.formatDistance("aboutXHours", 1, localizeOptions);
|
|
1766
|
+
} else if (minutes < minutesInDay) {
|
|
1767
|
+
const hours = Math.round(minutes / 60);
|
|
1768
|
+
return locale.formatDistance("aboutXHours", hours, localizeOptions);
|
|
1769
|
+
} else if (minutes < minutesInAlmostTwoDays) {
|
|
1770
|
+
return locale.formatDistance("xDays", 1, localizeOptions);
|
|
1771
|
+
} else if (minutes < minutesInMonth) {
|
|
1772
|
+
const days = Math.round(minutes / minutesInDay);
|
|
1773
|
+
return locale.formatDistance("xDays", days, localizeOptions);
|
|
1774
|
+
} else if (minutes < minutesInMonth * 2) {
|
|
1775
|
+
months = Math.round(minutes / minutesInMonth);
|
|
1776
|
+
return locale.formatDistance("aboutXMonths", months, localizeOptions);
|
|
1777
|
+
}
|
|
1778
|
+
months = differenceInMonths(earlierDate_, laterDate_);
|
|
1779
|
+
if (months < 12) {
|
|
1780
|
+
const nearestMonth = Math.round(minutes / minutesInMonth);
|
|
1781
|
+
return locale.formatDistance("xMonths", nearestMonth, localizeOptions);
|
|
1782
|
+
} else {
|
|
1783
|
+
const monthsSinceStartOfYear = months % 12;
|
|
1784
|
+
const years = Math.trunc(months / 12);
|
|
1785
|
+
if (monthsSinceStartOfYear < 3) {
|
|
1786
|
+
return locale.formatDistance("aboutXYears", years, localizeOptions);
|
|
1787
|
+
} else if (monthsSinceStartOfYear < 9) {
|
|
1788
|
+
return locale.formatDistance("overXYears", years, localizeOptions);
|
|
1789
|
+
} else {
|
|
1790
|
+
return locale.formatDistance("almostXYears", years + 1, localizeOptions);
|
|
1778
1791
|
}
|
|
1779
|
-
}
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
function formatDistanceToNow(date, options) {
|
|
1795
|
+
return formatDistance(date, constructNow(date), options);
|
|
1796
|
+
}
|
|
1797
|
+
function parseISO(argument, options) {
|
|
1798
|
+
const invalidDate = () => constructFrom(options == null ? void 0 : options.in, NaN);
|
|
1799
|
+
const additionalDigits = 2;
|
|
1800
|
+
const dateStrings = splitDateString(argument);
|
|
1801
|
+
let date;
|
|
1802
|
+
if (dateStrings.date) {
|
|
1803
|
+
const parseYearResult = parseYear(dateStrings.date, additionalDigits);
|
|
1804
|
+
date = parseDate(parseYearResult.restDateString, parseYearResult.year);
|
|
1805
|
+
}
|
|
1806
|
+
if (!date || isNaN(+date)) return invalidDate();
|
|
1807
|
+
const timestamp = +date;
|
|
1808
|
+
let time = 0;
|
|
1809
|
+
let offset;
|
|
1810
|
+
if (dateStrings.time) {
|
|
1811
|
+
time = parseTime(dateStrings.time);
|
|
1812
|
+
if (isNaN(time)) return invalidDate();
|
|
1813
|
+
}
|
|
1814
|
+
if (dateStrings.timezone) {
|
|
1815
|
+
offset = parseTimezone(dateStrings.timezone);
|
|
1816
|
+
if (isNaN(offset)) return invalidDate();
|
|
1817
|
+
} else {
|
|
1818
|
+
const tmpDate = new Date(timestamp + time);
|
|
1819
|
+
const result = toDate(0, options == null ? void 0 : options.in);
|
|
1820
|
+
result.setFullYear(
|
|
1821
|
+
tmpDate.getUTCFullYear(),
|
|
1822
|
+
tmpDate.getUTCMonth(),
|
|
1823
|
+
tmpDate.getUTCDate()
|
|
1824
|
+
);
|
|
1825
|
+
result.setHours(
|
|
1826
|
+
tmpDate.getUTCHours(),
|
|
1827
|
+
tmpDate.getUTCMinutes(),
|
|
1828
|
+
tmpDate.getUTCSeconds(),
|
|
1829
|
+
tmpDate.getUTCMilliseconds()
|
|
1830
|
+
);
|
|
1831
|
+
return result;
|
|
1832
|
+
}
|
|
1833
|
+
return toDate(timestamp + time + offset, options == null ? void 0 : options.in);
|
|
1834
|
+
}
|
|
1835
|
+
const patterns = {
|
|
1836
|
+
dateTimeDelimiter: /[T ]/,
|
|
1837
|
+
timeZoneDelimiter: /[Z ]/i,
|
|
1838
|
+
timezone: /([Z+-].*)$/
|
|
1839
|
+
};
|
|
1840
|
+
const dateRegex = /^-?(?:(\d{3})|(\d{2})(?:-?(\d{2}))?|W(\d{2})(?:-?(\d{1}))?|)$/;
|
|
1841
|
+
const timeRegex = /^(\d{2}(?:[.,]\d*)?)(?::?(\d{2}(?:[.,]\d*)?))?(?::?(\d{2}(?:[.,]\d*)?))?$/;
|
|
1842
|
+
const timezoneRegex = /^([+-])(\d{2})(?::?(\d{2}))?$/;
|
|
1843
|
+
function splitDateString(dateString) {
|
|
1844
|
+
const dateStrings = {};
|
|
1845
|
+
const array = dateString.split(patterns.dateTimeDelimiter);
|
|
1846
|
+
let timeString;
|
|
1847
|
+
if (array.length > 2) {
|
|
1848
|
+
return dateStrings;
|
|
1849
|
+
}
|
|
1850
|
+
if (/:/.test(array[0])) {
|
|
1851
|
+
timeString = array[0];
|
|
1852
|
+
} else {
|
|
1853
|
+
dateStrings.date = array[0];
|
|
1854
|
+
timeString = array[1];
|
|
1855
|
+
if (patterns.timeZoneDelimiter.test(dateStrings.date)) {
|
|
1856
|
+
dateStrings.date = dateString.split(patterns.timeZoneDelimiter)[0];
|
|
1857
|
+
timeString = dateString.substr(
|
|
1858
|
+
dateStrings.date.length,
|
|
1859
|
+
dateString.length
|
|
1860
|
+
);
|
|
1791
1861
|
}
|
|
1792
1862
|
}
|
|
1793
|
-
|
|
1863
|
+
if (timeString) {
|
|
1864
|
+
const token = patterns.timezone.exec(timeString);
|
|
1865
|
+
if (token) {
|
|
1866
|
+
dateStrings.time = timeString.replace(token[1], "");
|
|
1867
|
+
dateStrings.timezone = token[1];
|
|
1868
|
+
} else {
|
|
1869
|
+
dateStrings.time = timeString;
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
return dateStrings;
|
|
1794
1873
|
}
|
|
1795
|
-
function
|
|
1796
|
-
const
|
|
1797
|
-
|
|
1874
|
+
function parseYear(dateString, additionalDigits) {
|
|
1875
|
+
const regex = new RegExp(
|
|
1876
|
+
"^(?:(\\d{4}|[+-]\\d{" + (4 + additionalDigits) + "})|(\\d{2}|[+-]\\d{" + (2 + additionalDigits) + "})$)"
|
|
1877
|
+
);
|
|
1878
|
+
const captures = dateString.match(regex);
|
|
1879
|
+
if (!captures) return { year: NaN, restDateString: "" };
|
|
1880
|
+
const year = captures[1] ? parseInt(captures[1]) : null;
|
|
1881
|
+
const century = captures[2] ? parseInt(captures[2]) : null;
|
|
1882
|
+
return {
|
|
1883
|
+
year: century === null ? year : century * 100,
|
|
1884
|
+
restDateString: dateString.slice((captures[1] || captures[2]).length)
|
|
1885
|
+
};
|
|
1798
1886
|
}
|
|
1799
|
-
function
|
|
1800
|
-
|
|
1801
|
-
const
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1887
|
+
function parseDate(dateString, year) {
|
|
1888
|
+
if (year === null) return /* @__PURE__ */ new Date(NaN);
|
|
1889
|
+
const captures = dateString.match(dateRegex);
|
|
1890
|
+
if (!captures) return /* @__PURE__ */ new Date(NaN);
|
|
1891
|
+
const isWeekDate = !!captures[4];
|
|
1892
|
+
const dayOfYear = parseDateUnit(captures[1]);
|
|
1893
|
+
const month = parseDateUnit(captures[2]) - 1;
|
|
1894
|
+
const day = parseDateUnit(captures[3]);
|
|
1895
|
+
const week = parseDateUnit(captures[4]);
|
|
1896
|
+
const dayOfWeek = parseDateUnit(captures[5]) - 1;
|
|
1897
|
+
if (isWeekDate) {
|
|
1898
|
+
if (!validateWeekDate(year, week, dayOfWeek)) {
|
|
1899
|
+
return /* @__PURE__ */ new Date(NaN);
|
|
1900
|
+
}
|
|
1901
|
+
return dayOfISOWeekYear(year, week, dayOfWeek);
|
|
1902
|
+
} else {
|
|
1903
|
+
const date = /* @__PURE__ */ new Date(0);
|
|
1904
|
+
if (!validateDate(year, month, day) || !validateDayOfYearDate(year, dayOfYear)) {
|
|
1905
|
+
return /* @__PURE__ */ new Date(NaN);
|
|
1906
|
+
}
|
|
1907
|
+
date.setUTCFullYear(year, month, Math.max(dayOfYear, day));
|
|
1908
|
+
return date;
|
|
1808
1909
|
}
|
|
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
1910
|
}
|
|
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 });
|
|
1911
|
+
function parseDateUnit(value) {
|
|
1912
|
+
return value ? parseInt(value) : 1;
|
|
1818
1913
|
}
|
|
1819
|
-
function
|
|
1820
|
-
const
|
|
1821
|
-
|
|
1914
|
+
function parseTime(timeString) {
|
|
1915
|
+
const captures = timeString.match(timeRegex);
|
|
1916
|
+
if (!captures) return NaN;
|
|
1917
|
+
const hours = parseTimeUnit(captures[1]);
|
|
1918
|
+
const minutes = parseTimeUnit(captures[2]);
|
|
1919
|
+
const seconds = parseTimeUnit(captures[3]);
|
|
1920
|
+
if (!validateTime(hours, minutes, seconds)) {
|
|
1921
|
+
return NaN;
|
|
1922
|
+
}
|
|
1923
|
+
return hours * millisecondsInHour + minutes * millisecondsInMinute + seconds * 1e3;
|
|
1822
1924
|
}
|
|
1823
|
-
function
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1925
|
+
function parseTimeUnit(value) {
|
|
1926
|
+
return value && parseFloat(value.replace(",", ".")) || 0;
|
|
1927
|
+
}
|
|
1928
|
+
function parseTimezone(timezoneString) {
|
|
1929
|
+
if (timezoneString === "Z") return 0;
|
|
1930
|
+
const captures = timezoneString.match(timezoneRegex);
|
|
1931
|
+
if (!captures) return 0;
|
|
1932
|
+
const sign = captures[1] === "+" ? -1 : 1;
|
|
1933
|
+
const hours = parseInt(captures[2]);
|
|
1934
|
+
const minutes = captures[3] && parseInt(captures[3]) || 0;
|
|
1935
|
+
if (!validateTimezone(hours, minutes)) {
|
|
1936
|
+
return NaN;
|
|
1937
|
+
}
|
|
1938
|
+
return sign * (hours * millisecondsInHour + minutes * millisecondsInMinute);
|
|
1939
|
+
}
|
|
1940
|
+
function dayOfISOWeekYear(isoWeekYear, week, day) {
|
|
1941
|
+
const date = /* @__PURE__ */ new Date(0);
|
|
1942
|
+
date.setUTCFullYear(isoWeekYear, 0, 4);
|
|
1943
|
+
const fourthOfJanuaryDay = date.getUTCDay() || 7;
|
|
1944
|
+
const diff = (week - 1) * 7 + day + 1 - fourthOfJanuaryDay;
|
|
1945
|
+
date.setUTCDate(date.getUTCDate() + diff);
|
|
1946
|
+
return date;
|
|
1947
|
+
}
|
|
1948
|
+
const daysInMonths = [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
1949
|
+
function isLeapYearIndex(year) {
|
|
1950
|
+
return year % 400 === 0 || year % 4 === 0 && year % 100 !== 0;
|
|
1951
|
+
}
|
|
1952
|
+
function validateDate(year, month, date) {
|
|
1953
|
+
return month >= 0 && month <= 11 && date >= 1 && date <= (daysInMonths[month] || (isLeapYearIndex(year) ? 29 : 28));
|
|
1954
|
+
}
|
|
1955
|
+
function validateDayOfYearDate(year, dayOfYear) {
|
|
1956
|
+
return dayOfYear >= 1 && dayOfYear <= (isLeapYearIndex(year) ? 366 : 365);
|
|
1957
|
+
}
|
|
1958
|
+
function validateWeekDate(_year, week, day) {
|
|
1959
|
+
return week >= 1 && week <= 53 && day >= 0 && day <= 6;
|
|
1960
|
+
}
|
|
1961
|
+
function validateTime(hours, minutes, seconds) {
|
|
1962
|
+
if (hours === 24) {
|
|
1963
|
+
return minutes === 0 && seconds === 0;
|
|
1964
|
+
}
|
|
1965
|
+
return seconds >= 0 && seconds < 60 && minutes >= 0 && minutes < 60 && hours >= 0 && hours < 25;
|
|
1966
|
+
}
|
|
1967
|
+
function validateTimezone(_hours, minutes) {
|
|
1968
|
+
return minutes >= 0 && minutes <= 59;
|
|
1969
|
+
}
|
|
1970
|
+
const HDivider = (props) => {
|
|
1971
|
+
const { className, timestamp, title, subtitle, onClick, isSelected = false } = props;
|
|
1972
|
+
const [open, setOpen] = useState(false);
|
|
1973
|
+
const hasContent = !!title || !!subtitle || !!timestamp;
|
|
1974
|
+
useEffect(() => {
|
|
1975
|
+
if (open) {
|
|
1976
|
+
setOpen(false);
|
|
1977
|
+
setTimeout(() => hasContent && setOpen(true), 50);
|
|
1834
1978
|
}
|
|
1835
|
-
|
|
1836
|
-
|
|
1979
|
+
}, [title, subtitle, timestamp, hasContent]);
|
|
1980
|
+
const formatTimestamp2 = (isoString) => {
|
|
1981
|
+
if (!isoString)
|
|
1982
|
+
return "";
|
|
1983
|
+
try {
|
|
1984
|
+
return formatDistanceToNow(new Date(isoString), { addSuffix: true });
|
|
1985
|
+
} catch {
|
|
1986
|
+
return isoString;
|
|
1987
|
+
}
|
|
1988
|
+
};
|
|
1989
|
+
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) })] });
|
|
1990
|
+
const handleMouseEnter = () => {
|
|
1991
|
+
if (hasContent) {
|
|
1992
|
+
setOpen(true);
|
|
1993
|
+
}
|
|
1994
|
+
};
|
|
1995
|
+
const handleMouseLeave = () => {
|
|
1996
|
+
setOpen(false);
|
|
1997
|
+
};
|
|
1998
|
+
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" }) }) })] });
|
|
1999
|
+
};
|
|
2000
|
+
const getBarHeight = (size = 0) => {
|
|
2001
|
+
switch (true) {
|
|
2002
|
+
case size <= 0:
|
|
2003
|
+
return "h-[1px]";
|
|
2004
|
+
case size === 1:
|
|
2005
|
+
return "h-[3px]";
|
|
2006
|
+
case size === 2:
|
|
2007
|
+
return "h-[6px]";
|
|
2008
|
+
case size === 3:
|
|
2009
|
+
return "h-[9px]";
|
|
2010
|
+
case size >= 4:
|
|
2011
|
+
return "h-[12px]";
|
|
2012
|
+
default:
|
|
2013
|
+
return "h-[1px]";
|
|
2014
|
+
}
|
|
2015
|
+
};
|
|
2016
|
+
const formatTimestamp = (isoString) => {
|
|
2017
|
+
if (!isoString)
|
|
2018
|
+
return "";
|
|
2019
|
+
try {
|
|
2020
|
+
const date = parseISO(isoString);
|
|
2021
|
+
return format(date, "HH:mm, dd, MMMM");
|
|
2022
|
+
} catch {
|
|
2023
|
+
return isoString;
|
|
2024
|
+
}
|
|
2025
|
+
};
|
|
2026
|
+
const TimelineBar = ({ onClick, className, timestamp, additions, deletions, addSize = 0, delSize = 0, isSelected = false }) => {
|
|
2027
|
+
const [open, setOpen] = useState(false);
|
|
2028
|
+
const noChanges = addSize === 0 && delSize === 0;
|
|
2029
|
+
const addBarHeight = getBarHeight(addSize);
|
|
2030
|
+
const delBarHeight = getBarHeight(delSize);
|
|
2031
|
+
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 -` })] });
|
|
2032
|
+
const handleMouseEnter = () => {
|
|
2033
|
+
if (!noChanges) {
|
|
2034
|
+
setOpen(true);
|
|
2035
|
+
}
|
|
2036
|
+
};
|
|
2037
|
+
const handleMouseLeave = () => {
|
|
2038
|
+
setOpen(false);
|
|
2039
|
+
};
|
|
2040
|
+
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) }) })] }) })] });
|
|
2041
|
+
};
|
|
2042
|
+
const defaultTimeLineItem = {
|
|
2043
|
+
id: "default",
|
|
2044
|
+
type: "bar",
|
|
2045
|
+
addSize: 0,
|
|
2046
|
+
delSize: 0
|
|
2047
|
+
};
|
|
2048
|
+
const DocumentTimeline = (props) => {
|
|
2049
|
+
const { timeline = [], onItemClick } = props;
|
|
2050
|
+
const [selectedItem, setSelectedItem] = useState(null);
|
|
2051
|
+
const scrollContainerRef = useRef(null);
|
|
2052
|
+
const handleClick = (item) => {
|
|
2053
|
+
if (item.id === selectedItem || item.id === defaultTimeLineItem.id) {
|
|
2054
|
+
onItemClick == null ? void 0 : onItemClick(null);
|
|
2055
|
+
setSelectedItem(null);
|
|
2056
|
+
} else {
|
|
2057
|
+
onItemClick == null ? void 0 : onItemClick(item);
|
|
2058
|
+
setSelectedItem(item.id);
|
|
2059
|
+
}
|
|
2060
|
+
};
|
|
2061
|
+
const mergedTimelineItems = [...timeline, defaultTimeLineItem];
|
|
2062
|
+
const [unselectedItems, selectedItems] = useMemo(() => {
|
|
2063
|
+
const indexSelected = mergedTimelineItems.findIndex((item) => item.id === selectedItem);
|
|
2064
|
+
return indexSelected === -1 ? [mergedTimelineItems, []] : [
|
|
2065
|
+
mergedTimelineItems.slice(0, indexSelected),
|
|
2066
|
+
mergedTimelineItems.slice(indexSelected)
|
|
2067
|
+
];
|
|
2068
|
+
}, [mergedTimelineItems, selectedItem]);
|
|
2069
|
+
const renderTimelineItems = useCallback((items) => {
|
|
2070
|
+
return items.map((item) => {
|
|
2071
|
+
if (item.type === "divider") {
|
|
2072
|
+
const { timestamp, title, subtitle } = item;
|
|
2073
|
+
return jsx(HDivider, { timestamp, title, subtitle, onClick: () => handleClick(item), isSelected: item.id === selectedItem }, item.id);
|
|
2074
|
+
}
|
|
2075
|
+
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);
|
|
2076
|
+
});
|
|
2077
|
+
}, [handleClick, selectedItem]);
|
|
2078
|
+
const unselectedContent = useMemo(() => renderTimelineItems(unselectedItems), [unselectedItems, renderTimelineItems]);
|
|
2079
|
+
const selectedContent = useMemo(() => renderTimelineItems(selectedItems), [selectedItems, renderTimelineItems]);
|
|
2080
|
+
useEffect(() => {
|
|
2081
|
+
if (scrollContainerRef.current) {
|
|
2082
|
+
scrollContainerRef.current.scrollLeft = scrollContainerRef.current.scrollWidth;
|
|
2083
|
+
}
|
|
2084
|
+
}, []);
|
|
2085
|
+
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" })] }) });
|
|
2086
|
+
};
|
|
2087
|
+
const DocumentToolbar = (props) => {
|
|
2088
|
+
const { undo: undo2, canUndo, redo: redo2, canRedo, title, onClose, onExport, className, onShowRevisionHistory, onSwitchboardLinkClick, timelineItems = [], onTimelineItemClick, initialTimelineVisible = false, timelineButtonVisible = false } = props;
|
|
2089
|
+
const [showTimeline, setShowTimeline] = useState(initialTimelineVisible);
|
|
2090
|
+
const isUndoDisabled = !canUndo || !undo2;
|
|
2091
|
+
const isRedoDisabled = !canRedo || !redo2;
|
|
2092
|
+
const isExportDisabled = !onExport;
|
|
2093
|
+
const isSwitchboardLinkDisabled = !onSwitchboardLinkClick;
|
|
2094
|
+
const isRevisionHistoryDisabled = !onShowRevisionHistory;
|
|
2095
|
+
const isTimelineDisabled = timelineItems.length === 0;
|
|
2096
|
+
useEffect(() => {
|
|
2097
|
+
if (initialTimelineVisible) {
|
|
2098
|
+
setShowTimeline(true);
|
|
2099
|
+
}
|
|
2100
|
+
}, [initialTimelineVisible]);
|
|
2101
|
+
const handleTimelineToggle = () => {
|
|
2102
|
+
if (isTimelineDisabled)
|
|
2103
|
+
return;
|
|
2104
|
+
setShowTimeline(!showTimeline);
|
|
2105
|
+
};
|
|
2106
|
+
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 }) })] });
|
|
2107
|
+
};
|
|
2108
|
+
const syncIcons = {
|
|
2109
|
+
SYNCING: "Syncing",
|
|
2110
|
+
SUCCESS: "Synced",
|
|
2111
|
+
CONFLICT: "Error",
|
|
2112
|
+
MISSING: "Circle",
|
|
2113
|
+
ERROR: "Error",
|
|
2114
|
+
INITIAL_SYNC: "Syncing"
|
|
2115
|
+
};
|
|
2116
|
+
function SyncStatusIcon(props) {
|
|
2117
|
+
const { syncStatus, className, overrideSyncIcons = {}, ...iconProps } = props;
|
|
2118
|
+
const icons = { ...syncIcons, ...overrideSyncIcons };
|
|
2119
|
+
const syncStatusIcons = {
|
|
2120
|
+
[INITIAL_SYNC]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-blue-900", className), name: icons[INITIAL_SYNC] }),
|
|
2121
|
+
[SYNCING]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-blue-900", className), name: icons[SYNCING] }),
|
|
2122
|
+
[SUCCESS]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-green-900", className), name: icons[SUCCESS] }),
|
|
2123
|
+
[CONFLICT]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-orange-900", className), name: icons[CONFLICT] }),
|
|
2124
|
+
[MISSING]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-red-900", className), name: icons[MISSING] }),
|
|
2125
|
+
[ERROR]: jsx(Icon, { size: 16, ...iconProps, className: twMerge("text-red-900", className), name: icons[ERROR] })
|
|
2126
|
+
};
|
|
2127
|
+
return syncStatusIcons[syncStatus];
|
|
2128
|
+
}
|
|
2129
|
+
function FileItem(props) {
|
|
2130
|
+
const { uiNode, className, customDocumentIconSrc, onSelectNode, onRenameNode, onDuplicateNode, onDeleteNode, isAllowedToCreateDocuments } = props;
|
|
2131
|
+
const [mode, setMode] = useState(READ);
|
|
2132
|
+
const [isDropdownMenuOpen, setIsDropdownMenuOpen] = useState(false);
|
|
2133
|
+
const { dragProps } = useDrag({ uiNode });
|
|
2134
|
+
const isReadMode = mode === READ;
|
|
2135
|
+
const dropdownMenuHandlers = {
|
|
2136
|
+
[DUPLICATE]: () => onDuplicateNode(uiNode),
|
|
2137
|
+
[RENAME]: () => setMode(WRITE),
|
|
2138
|
+
[DELETE]: () => onDeleteNode(uiNode)
|
|
2139
|
+
};
|
|
2140
|
+
const dropdownMenuOptions = Object.entries(nodeOptionsMap).map(([id, option]) => ({
|
|
2141
|
+
...option,
|
|
2142
|
+
id
|
|
2143
|
+
})).filter((option) => defaultFileOptions.includes(option.id));
|
|
2144
|
+
function onSubmit(name) {
|
|
2145
|
+
onRenameNode(name, uiNode);
|
|
2146
|
+
setMode(READ);
|
|
2147
|
+
}
|
|
2148
|
+
function onCancel() {
|
|
2149
|
+
setMode(READ);
|
|
2150
|
+
}
|
|
2151
|
+
function onClick() {
|
|
2152
|
+
onSelectNode(uiNode);
|
|
2153
|
+
}
|
|
2154
|
+
function onDropdownMenuOptionClick(itemId) {
|
|
2155
|
+
const handler = dropdownMenuHandlers[itemId];
|
|
2156
|
+
if (!handler) {
|
|
2157
|
+
console.error(`No handler found for dropdown menu item: ${itemId}`);
|
|
2158
|
+
return;
|
|
2159
|
+
}
|
|
2160
|
+
handler();
|
|
2161
|
+
setIsDropdownMenuOpen(false);
|
|
2162
|
+
}
|
|
2163
|
+
const iconSrc = getDocumentIconSrc(uiNode.documentType, customDocumentIconSrc);
|
|
2164
|
+
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 }) }) })] });
|
|
2165
|
+
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);
|
|
2166
|
+
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) => {
|
|
2167
|
+
e.stopPropagation();
|
|
2168
|
+
setIsDropdownMenuOpen(true);
|
|
2169
|
+
}, children: jsx(Icon, { className: "text-gray-600", name: "VerticalDots" }) }) }) : null] }) : jsx(NodeInput, { className: "ml-3 flex-1 font-medium", defaultValue: uiNode.name, onCancel, onSubmit });
|
|
2170
|
+
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] }) }) });
|
|
2171
|
+
}
|
|
2172
|
+
function FolderItem(props) {
|
|
2173
|
+
const { uiNode, isAllowedToCreateDocuments, className, onRenameNode, onDuplicateNode, onDeleteNode, onSelectNode, onAddFile, onCopyNode, onMoveNode } = props;
|
|
2174
|
+
const [mode, setMode] = useState(READ);
|
|
2175
|
+
const [isDropdownMenuOpen, setIsDropdownMenuOpen] = useState(false);
|
|
2176
|
+
const { dragProps } = useDrag({ ...props, uiNode });
|
|
2177
|
+
const { isDropTarget, dropProps } = useDrop({
|
|
2178
|
+
uiNode,
|
|
2179
|
+
onAddFile,
|
|
2180
|
+
onCopyNode,
|
|
2181
|
+
onMoveNode
|
|
2182
|
+
});
|
|
2183
|
+
const isReadMode = mode === READ;
|
|
2184
|
+
function onCancel() {
|
|
2185
|
+
setMode(READ);
|
|
2186
|
+
}
|
|
2187
|
+
function onSubmit(name) {
|
|
2188
|
+
onRenameNode(name, uiNode);
|
|
2189
|
+
setMode(READ);
|
|
2190
|
+
}
|
|
2191
|
+
function onClick() {
|
|
2192
|
+
onSelectNode(uiNode);
|
|
2193
|
+
}
|
|
2194
|
+
const dropdownMenuHandlers = {
|
|
2195
|
+
[DUPLICATE]: () => onDuplicateNode(uiNode),
|
|
2196
|
+
[RENAME]: () => setMode(WRITE),
|
|
2197
|
+
[DELETE]: () => onDeleteNode(uiNode)
|
|
2198
|
+
};
|
|
2199
|
+
const dropdownMenuOptions = Object.entries(nodeOptionsMap).map(([id, option]) => ({
|
|
2200
|
+
...option,
|
|
2201
|
+
id
|
|
2202
|
+
})).filter((option) => defaultFolderOptions.includes(option.id));
|
|
2203
|
+
function onDropdownMenuOptionClick(itemId) {
|
|
2204
|
+
const handler = dropdownMenuHandlers[itemId];
|
|
2205
|
+
if (!handler) {
|
|
2206
|
+
console.error(`No handler found for dropdown menu item: ${itemId}`);
|
|
2207
|
+
return;
|
|
2208
|
+
}
|
|
2209
|
+
handler();
|
|
2210
|
+
setIsDropdownMenuOpen(false);
|
|
2211
|
+
}
|
|
2212
|
+
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 });
|
|
2213
|
+
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");
|
|
2214
|
+
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: {
|
|
2215
|
+
SUCCESS: "CheckCircleFill"
|
|
2216
|
+
}, 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) => {
|
|
2217
|
+
e.stopPropagation();
|
|
2218
|
+
setIsDropdownMenuOpen(true);
|
|
2219
|
+
}, children: jsx(Icon, { className: "text-gray-600", name: "VerticalDots" }) }) }) : null] }) });
|
|
2220
|
+
}
|
|
2221
|
+
function NodeInput(props) {
|
|
2222
|
+
const { onSubmit, onCancel, defaultValue, className, minLength = 1, ...inputProps } = props;
|
|
2223
|
+
const [value, setValue] = useState(defaultValue ?? "");
|
|
2224
|
+
const ref = useRef(null);
|
|
2225
|
+
useOnClickOutside(ref, handleSubmit);
|
|
2226
|
+
useEventListener("keyup", (e) => {
|
|
2227
|
+
if (e.key === "Enter") {
|
|
2228
|
+
handleSubmit();
|
|
2229
|
+
}
|
|
2230
|
+
if (e.key === "Escape") {
|
|
2231
|
+
onCancel();
|
|
2232
|
+
}
|
|
2233
|
+
});
|
|
2234
|
+
useLayoutEffect(() => {
|
|
2235
|
+
setTimeout(() => {
|
|
2236
|
+
var _a, _b, _c;
|
|
2237
|
+
(_a = ref.current) == null ? void 0 : _a.focus();
|
|
2238
|
+
(_b = ref.current) == null ? void 0 : _b.select();
|
|
2239
|
+
(_c = ref.current) == null ? void 0 : _c.scroll({ left: 9999 });
|
|
2240
|
+
}, 100);
|
|
2241
|
+
}, []);
|
|
2242
|
+
function handleSubmit() {
|
|
2243
|
+
if (value.length >= minLength) {
|
|
2244
|
+
onSubmit(value);
|
|
2245
|
+
}
|
|
2246
|
+
}
|
|
2247
|
+
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 });
|
|
2248
|
+
}
|
|
2249
|
+
function Branch(props) {
|
|
2250
|
+
const { branch = "main" } = props;
|
|
2251
|
+
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 })] });
|
|
2252
|
+
}
|
|
2253
|
+
function DocId(props) {
|
|
2254
|
+
const { docId } = props;
|
|
2255
|
+
const [, copy] = useCopyToClipboard();
|
|
2256
|
+
function handleCopy(text) {
|
|
2257
|
+
return () => {
|
|
2258
|
+
copy(text).catch((error) => {
|
|
2259
|
+
console.error("Failed to copy!", error);
|
|
2260
|
+
});
|
|
2261
|
+
};
|
|
2262
|
+
}
|
|
2263
|
+
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 })] });
|
|
2264
|
+
}
|
|
2265
|
+
function Scope(props) {
|
|
2266
|
+
const { value, onChange } = props;
|
|
2267
|
+
const items = [
|
|
2268
|
+
{ displayValue: "Global scope", value: "global" },
|
|
2269
|
+
{ displayValue: "Local scope", value: "local" }
|
|
2270
|
+
];
|
|
2271
|
+
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 });
|
|
2272
|
+
}
|
|
2273
|
+
function Header(props) {
|
|
2274
|
+
const { title, docId, scope, onChangeScope, onClose, className, ...divProps } = props;
|
|
2275
|
+
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 })] })] });
|
|
2276
|
+
}
|
|
2277
|
+
function memo(getDeps, fn, opts) {
|
|
2278
|
+
let deps = opts.initialDeps ?? [];
|
|
2279
|
+
let result;
|
|
2280
|
+
return () => {
|
|
2281
|
+
var _a, _b, _c, _d;
|
|
2282
|
+
let depTime;
|
|
2283
|
+
if (opts.key && ((_a = opts.debug) == null ? void 0 : _a.call(opts))) depTime = Date.now();
|
|
2284
|
+
const newDeps = getDeps();
|
|
2285
|
+
const depsChanged = newDeps.length !== deps.length || newDeps.some((dep, index) => deps[index] !== dep);
|
|
2286
|
+
if (!depsChanged) {
|
|
2287
|
+
return result;
|
|
2288
|
+
}
|
|
2289
|
+
deps = newDeps;
|
|
2290
|
+
let resultTime;
|
|
1837
2291
|
if (opts.key && ((_b = opts.debug) == null ? void 0 : _b.call(opts))) resultTime = Date.now();
|
|
1838
2292
|
result = fn(...newDeps);
|
|
1839
2293
|
if (opts.key && ((_c = opts.debug) == null ? void 0 : _c.call(opts))) {
|
|
@@ -1861,11 +2315,7 @@ function memo(getDeps, fn, opts) {
|
|
|
1861
2315
|
}
|
|
1862
2316
|
(_d = opts == null ? void 0 : opts.onChange) == null ? void 0 : _d.call(opts, result);
|
|
1863
2317
|
return result;
|
|
1864
|
-
}
|
|
1865
|
-
memoizedFunction.updateDeps = (newDeps) => {
|
|
1866
|
-
deps = newDeps;
|
|
1867
2318
|
};
|
|
1868
|
-
return memoizedFunction;
|
|
1869
2319
|
}
|
|
1870
2320
|
function notUndefined(value, msg) {
|
|
1871
2321
|
if (value === void 0) {
|
|
@@ -1911,18 +2361,15 @@ const observeElementRect = (instance, cb) => {
|
|
|
1911
2361
|
};
|
|
1912
2362
|
}
|
|
1913
2363
|
const observer = new targetWindow.ResizeObserver((entries) => {
|
|
1914
|
-
const
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
return;
|
|
1921
|
-
}
|
|
2364
|
+
const entry = entries[0];
|
|
2365
|
+
if (entry == null ? void 0 : entry.borderBoxSize) {
|
|
2366
|
+
const box = entry.borderBoxSize[0];
|
|
2367
|
+
if (box) {
|
|
2368
|
+
handler({ width: box.inlineSize, height: box.blockSize });
|
|
2369
|
+
return;
|
|
1922
2370
|
}
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
instance.options.useAnimationFrameWithResizeObserver ? requestAnimationFrame(run) : run();
|
|
2371
|
+
}
|
|
2372
|
+
handler(element.getBoundingClientRect());
|
|
1926
2373
|
});
|
|
1927
2374
|
observer.observe(element, { box: "border-box" });
|
|
1928
2375
|
return () => {
|
|
@@ -1960,15 +2407,10 @@ const observeElementOffset = (instance, cb) => {
|
|
|
1960
2407
|
const endHandler = createHandler(false);
|
|
1961
2408
|
endHandler();
|
|
1962
2409
|
element.addEventListener("scroll", handler, addEventListenerOptions);
|
|
1963
|
-
|
|
1964
|
-
if (registerScrollendEvent) {
|
|
1965
|
-
element.addEventListener("scrollend", endHandler, addEventListenerOptions);
|
|
1966
|
-
}
|
|
2410
|
+
element.addEventListener("scrollend", endHandler, addEventListenerOptions);
|
|
1967
2411
|
return () => {
|
|
1968
2412
|
element.removeEventListener("scroll", handler);
|
|
1969
|
-
|
|
1970
|
-
element.removeEventListener("scrollend", endHandler);
|
|
1971
|
-
}
|
|
2413
|
+
element.removeEventListener("scrollend", endHandler);
|
|
1972
2414
|
};
|
|
1973
2415
|
};
|
|
1974
2416
|
const measureElement = (element, entry, instance) => {
|
|
@@ -2022,10 +2464,7 @@ class Virtualizer {
|
|
|
2022
2464
|
}
|
|
2023
2465
|
return _ro = new this.targetWindow.ResizeObserver((entries) => {
|
|
2024
2466
|
entries.forEach((entry) => {
|
|
2025
|
-
|
|
2026
|
-
this._measureElement(entry.target, entry);
|
|
2027
|
-
};
|
|
2028
|
-
this.options.useAnimationFrameWithResizeObserver ? requestAnimationFrame(run) : run();
|
|
2467
|
+
this._measureElement(entry.target, entry);
|
|
2029
2468
|
});
|
|
2030
2469
|
});
|
|
2031
2470
|
};
|
|
@@ -2073,8 +2512,7 @@ class Virtualizer {
|
|
|
2073
2512
|
isScrollingResetDelay: 150,
|
|
2074
2513
|
enabled: true,
|
|
2075
2514
|
isRtl: false,
|
|
2076
|
-
useScrollendEvent:
|
|
2077
|
-
useAnimationFrameWithResizeObserver: false,
|
|
2515
|
+
useScrollendEvent: true,
|
|
2078
2516
|
...opts2
|
|
2079
2517
|
};
|
|
2080
2518
|
};
|
|
@@ -2263,18 +2701,12 @@ class Virtualizer {
|
|
|
2263
2701
|
}
|
|
2264
2702
|
);
|
|
2265
2703
|
this.calculateRange = memo(
|
|
2266
|
-
() => [
|
|
2267
|
-
|
|
2268
|
-
this.getSize(),
|
|
2269
|
-
this.getScrollOffset(),
|
|
2270
|
-
this.options.lanes
|
|
2271
|
-
],
|
|
2272
|
-
(measurements, outerSize, scrollOffset, lanes) => {
|
|
2704
|
+
() => [this.getMeasurements(), this.getSize(), this.getScrollOffset()],
|
|
2705
|
+
(measurements, outerSize, scrollOffset) => {
|
|
2273
2706
|
return this.range = measurements.length > 0 && outerSize > 0 ? calculateRange({
|
|
2274
2707
|
measurements,
|
|
2275
2708
|
outerSize,
|
|
2276
|
-
scrollOffset
|
|
2277
|
-
lanes
|
|
2709
|
+
scrollOffset
|
|
2278
2710
|
}) : null;
|
|
2279
2711
|
},
|
|
2280
2712
|
{
|
|
@@ -2282,7 +2714,7 @@ class Virtualizer {
|
|
|
2282
2714
|
debug: () => this.options.debug
|
|
2283
2715
|
}
|
|
2284
2716
|
);
|
|
2285
|
-
this.
|
|
2717
|
+
this.getIndexes = memo(
|
|
2286
2718
|
() => {
|
|
2287
2719
|
let startIndex = null;
|
|
2288
2720
|
let endIndex = null;
|
|
@@ -2291,7 +2723,6 @@ class Virtualizer {
|
|
|
2291
2723
|
startIndex = range.startIndex;
|
|
2292
2724
|
endIndex = range.endIndex;
|
|
2293
2725
|
}
|
|
2294
|
-
this.maybeNotify.updateDeps([this.isScrolling, startIndex, endIndex]);
|
|
2295
2726
|
return [
|
|
2296
2727
|
this.options.rangeExtractor,
|
|
2297
2728
|
this.options.overscan,
|
|
@@ -2375,7 +2806,7 @@ class Virtualizer {
|
|
|
2375
2806
|
this._measureElement(node, void 0);
|
|
2376
2807
|
};
|
|
2377
2808
|
this.getVirtualItems = memo(
|
|
2378
|
-
() => [this.
|
|
2809
|
+
() => [this.getIndexes(), this.getMeasurements()],
|
|
2379
2810
|
(indexes, measurements) => {
|
|
2380
2811
|
const virtualItems = [];
|
|
2381
2812
|
for (let k = 0, len = indexes.length; k < len; k++) {
|
|
@@ -2404,15 +2835,15 @@ class Virtualizer {
|
|
|
2404
2835
|
)]
|
|
2405
2836
|
);
|
|
2406
2837
|
};
|
|
2407
|
-
this.getOffsetForAlignment = (toOffset, align
|
|
2838
|
+
this.getOffsetForAlignment = (toOffset, align) => {
|
|
2408
2839
|
const size = this.getSize();
|
|
2409
2840
|
const scrollOffset = this.getScrollOffset();
|
|
2410
2841
|
if (align === "auto") {
|
|
2411
|
-
|
|
2842
|
+
if (toOffset >= scrollOffset + size) {
|
|
2843
|
+
align = "end";
|
|
2844
|
+
}
|
|
2412
2845
|
}
|
|
2413
|
-
if (align === "
|
|
2414
|
-
toOffset += (itemSize - size) / 2;
|
|
2415
|
-
} else if (align === "end") {
|
|
2846
|
+
if (align === "end") {
|
|
2416
2847
|
toOffset -= size;
|
|
2417
2848
|
}
|
|
2418
2849
|
const scrollSizeProp = this.options.horizontal ? "scrollWidth" : "scrollHeight";
|
|
@@ -2437,11 +2868,27 @@ class Virtualizer {
|
|
|
2437
2868
|
return [scrollOffset, align];
|
|
2438
2869
|
}
|
|
2439
2870
|
}
|
|
2440
|
-
const
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2871
|
+
const centerOffset = item.start - this.options.scrollPaddingStart + (item.size - size) / 2;
|
|
2872
|
+
switch (align) {
|
|
2873
|
+
case "center":
|
|
2874
|
+
return [this.getOffsetForAlignment(centerOffset, align), align];
|
|
2875
|
+
case "end":
|
|
2876
|
+
return [
|
|
2877
|
+
this.getOffsetForAlignment(
|
|
2878
|
+
item.end + this.options.scrollPaddingEnd,
|
|
2879
|
+
align
|
|
2880
|
+
),
|
|
2881
|
+
align
|
|
2882
|
+
];
|
|
2883
|
+
default:
|
|
2884
|
+
return [
|
|
2885
|
+
this.getOffsetForAlignment(
|
|
2886
|
+
item.start - this.options.scrollPaddingStart,
|
|
2887
|
+
align
|
|
2888
|
+
),
|
|
2889
|
+
align
|
|
2890
|
+
];
|
|
2891
|
+
}
|
|
2445
2892
|
};
|
|
2446
2893
|
this.isDynamicMode = () => this.elementsCache.size > 0;
|
|
2447
2894
|
this.cancelScrollToIndex = () => {
|
|
@@ -2511,19 +2958,10 @@ class Virtualizer {
|
|
|
2511
2958
|
let end;
|
|
2512
2959
|
if (measurements.length === 0) {
|
|
2513
2960
|
end = this.options.paddingStart;
|
|
2514
|
-
} else if (this.options.lanes === 1) {
|
|
2515
|
-
end = ((_a = measurements[measurements.length - 1]) == null ? void 0 : _a.end) ?? 0;
|
|
2516
2961
|
} else {
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
const item = measurements[endIndex];
|
|
2521
|
-
if (endByLane[item.lane] === null) {
|
|
2522
|
-
endByLane[item.lane] = item.end;
|
|
2523
|
-
}
|
|
2524
|
-
endIndex--;
|
|
2525
|
-
}
|
|
2526
|
-
end = Math.max(...endByLane.filter((val) => val !== null));
|
|
2962
|
+
end = this.options.lanes === 1 ? ((_a = measurements[measurements.length - 1]) == null ? void 0 : _a.end) ?? 0 : Math.max(
|
|
2963
|
+
...measurements.slice(-this.options.lanes).map((m) => m.end)
|
|
2964
|
+
);
|
|
2527
2965
|
}
|
|
2528
2966
|
return Math.max(
|
|
2529
2967
|
end - this.options.scrollMargin + this.options.paddingEnd,
|
|
@@ -2564,43 +3002,14 @@ const findNearestBinarySearch = (low, high, getCurrentValue, value) => {
|
|
|
2564
3002
|
function calculateRange({
|
|
2565
3003
|
measurements,
|
|
2566
3004
|
outerSize,
|
|
2567
|
-
scrollOffset
|
|
2568
|
-
lanes
|
|
3005
|
+
scrollOffset
|
|
2569
3006
|
}) {
|
|
2570
|
-
const
|
|
3007
|
+
const count = measurements.length - 1;
|
|
2571
3008
|
const getOffset = (index) => measurements[index].start;
|
|
2572
|
-
|
|
2573
|
-
return {
|
|
2574
|
-
startIndex: 0,
|
|
2575
|
-
endIndex: lastIndex
|
|
2576
|
-
};
|
|
2577
|
-
}
|
|
2578
|
-
let startIndex = findNearestBinarySearch(
|
|
2579
|
-
0,
|
|
2580
|
-
lastIndex,
|
|
2581
|
-
getOffset,
|
|
2582
|
-
scrollOffset
|
|
2583
|
-
);
|
|
3009
|
+
const startIndex = findNearestBinarySearch(0, count, getOffset, scrollOffset);
|
|
2584
3010
|
let endIndex = startIndex;
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
endIndex++;
|
|
2588
|
-
}
|
|
2589
|
-
} else if (lanes > 1) {
|
|
2590
|
-
const endPerLane = Array(lanes).fill(0);
|
|
2591
|
-
while (endIndex < lastIndex && endPerLane.some((pos) => pos < scrollOffset + outerSize)) {
|
|
2592
|
-
const item = measurements[endIndex];
|
|
2593
|
-
endPerLane[item.lane] = item.end;
|
|
2594
|
-
endIndex++;
|
|
2595
|
-
}
|
|
2596
|
-
const startPerLane = Array(lanes).fill(scrollOffset + outerSize);
|
|
2597
|
-
while (startIndex >= 0 && startPerLane.some((pos) => pos >= scrollOffset)) {
|
|
2598
|
-
const item = measurements[startIndex];
|
|
2599
|
-
startPerLane[item.lane] = item.start;
|
|
2600
|
-
startIndex--;
|
|
2601
|
-
}
|
|
2602
|
-
startIndex = Math.max(0, startIndex - startIndex % lanes);
|
|
2603
|
-
endIndex = Math.min(lastIndex, endIndex + (lanes - 1 - endIndex % lanes));
|
|
3011
|
+
while (endIndex < count && measurements[endIndex].end < scrollOffset + outerSize) {
|
|
3012
|
+
endIndex++;
|
|
2604
3013
|
}
|
|
2605
3014
|
return { startIndex, endIndex };
|
|
2606
3015
|
}
|
|
@@ -2857,8 +3266,8 @@ function RevisionHistory(props) {
|
|
|
2857
3266
|
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
3267
|
}
|
|
2859
3268
|
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 }) })] });
|
|
3269
|
+
const { children, content, open, defaultOpen, onOpenChange, className, side = "top", sideOffset = 5, ...rest } = props;
|
|
3270
|
+
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
3271
|
}
|
|
2863
3272
|
const TooltipProvider = Provider;
|
|
2864
3273
|
const BUDGET = "powerhouse/budget-statement";
|
|
@@ -3106,9 +3515,7 @@ function useAddDebouncedOperations(reactor, props) {
|
|
|
3106
3515
|
const { driveId, documentId } = props;
|
|
3107
3516
|
const [documentDrives] = useDocumentDrives(reactor);
|
|
3108
3517
|
const documentDrivesRef = useRef(documentDrives);
|
|
3109
|
-
const { isAllowedToEditDocuments } = useUserPermissions()
|
|
3110
|
-
isAllowedToEditDocuments: false
|
|
3111
|
-
};
|
|
3518
|
+
const { isAllowedToEditDocuments } = useUserPermissions();
|
|
3112
3519
|
useEffect(() => {
|
|
3113
3520
|
documentDrivesRef.current = documentDrives;
|
|
3114
3521
|
}, [documentDrives]);
|
|
@@ -3119,7 +3526,7 @@ function useAddDebouncedOperations(reactor, props) {
|
|
|
3119
3526
|
if (!reactor) {
|
|
3120
3527
|
throw new Error("Reactor is not loaded");
|
|
3121
3528
|
}
|
|
3122
|
-
const drive = documentDrivesRef.current.find((drive2) => drive2.
|
|
3529
|
+
const drive = documentDrivesRef.current.find((drive2) => drive2.id === driveId2);
|
|
3123
3530
|
if (!drive) {
|
|
3124
3531
|
throw new Error(`Drive with id ${driveId2} not found`);
|
|
3125
3532
|
}
|
|
@@ -3198,7 +3605,7 @@ function getNode(id, drive) {
|
|
|
3198
3605
|
}
|
|
3199
3606
|
function createDriveActions(document2, dispatch, context) {
|
|
3200
3607
|
const drive = document2;
|
|
3201
|
-
const
|
|
3608
|
+
const driveId = drive.id;
|
|
3202
3609
|
const { selectedNode } = context;
|
|
3203
3610
|
const handleAddFolder = async (name, parentFolder, id = generateId()) => {
|
|
3204
3611
|
dispatch(addFolder({
|
|
@@ -3488,6 +3895,17 @@ function useEditorProps(document2, node, documentDispatch, onAddOperation) {
|
|
|
3488
3895
|
isAllowedToEditDocuments: (userPermissions == null ? void 0 : userPermissions.isAllowedToEditDocuments) ?? false
|
|
3489
3896
|
};
|
|
3490
3897
|
}
|
|
3898
|
+
function useGetDocument() {
|
|
3899
|
+
const { openFile } = useDocumentDriveServer();
|
|
3900
|
+
const getDocument = useCallback(
|
|
3901
|
+
async (driveId, documentId, options) => {
|
|
3902
|
+
const document2 = await openFile(driveId, documentId, options);
|
|
3903
|
+
return document2;
|
|
3904
|
+
},
|
|
3905
|
+
[openFile]
|
|
3906
|
+
);
|
|
3907
|
+
return getDocument;
|
|
3908
|
+
}
|
|
3491
3909
|
function useSyncStatus(driveId, documentId) {
|
|
3492
3910
|
const { getSyncStatusSync, onSyncStatus, documentDrives } = useDocumentDriveServer();
|
|
3493
3911
|
const syncStatus = useSyncExternalStore(
|
|
@@ -3497,9 +3915,7 @@ function useSyncStatus(driveId, documentId) {
|
|
|
3497
3915
|
},
|
|
3498
3916
|
() => {
|
|
3499
3917
|
var _a;
|
|
3500
|
-
const drive = documentDrives.find(
|
|
3501
|
-
(_drive) => _drive.state.global.id === driveId
|
|
3502
|
-
);
|
|
3918
|
+
const drive = documentDrives.find((_drive) => _drive.id === driveId);
|
|
3503
3919
|
if (!drive) return;
|
|
3504
3920
|
const isReadDrive = "readContext" in drive;
|
|
3505
3921
|
const _sharingType = !isReadDrive ? (_a = drive.state.local.sharingType) == null ? void 0 : _a.toUpperCase() : "PUBLIC";
|
|
@@ -3558,10 +3974,342 @@ const useUndoRedoShortcuts = (props) => {
|
|
|
3558
3974
|
[canRedo, redo2]
|
|
3559
3975
|
);
|
|
3560
3976
|
};
|
|
3561
|
-
function
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3977
|
+
function getDocumentSpec(doc) {
|
|
3978
|
+
if ("documentModelState" in doc) {
|
|
3979
|
+
return doc.documentModelState;
|
|
3980
|
+
}
|
|
3981
|
+
return doc.documentModel;
|
|
3982
|
+
}
|
|
3983
|
+
const CreateDocument = ({ documentModels, createDocument }) => {
|
|
3984
|
+
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) => {
|
|
3985
|
+
const spec = getDocumentSpec(doc);
|
|
3986
|
+
return jsx(Button, { color: "light", "aria-details": spec.description, onClick: () => createDocument(doc), children: jsx("span", { className: "text-sm", children: spec.name }) }, spec.id);
|
|
3987
|
+
}) })] });
|
|
3988
|
+
};
|
|
3989
|
+
function sortUiNodesByName(a, b) {
|
|
3990
|
+
return a.name.localeCompare(b.name);
|
|
3991
|
+
}
|
|
3992
|
+
const GAP = 8;
|
|
3993
|
+
const ITEM_WIDTH = 256;
|
|
3994
|
+
const ITEM_HEIGHT = 48;
|
|
3995
|
+
const USED_SPACE = 420;
|
|
3996
|
+
function FileContentView(props) {
|
|
3997
|
+
const parentRef = useRef(null);
|
|
3998
|
+
const { t } = useTranslation();
|
|
3999
|
+
const windowSize = useWindowSize();
|
|
4000
|
+
const { fileNodes, ...fileProps } = props;
|
|
4001
|
+
const availableWidth = windowSize.innerWidth - USED_SPACE;
|
|
4002
|
+
const columnCount = Math.floor(availableWidth / (ITEM_WIDTH + GAP)) || 1;
|
|
4003
|
+
const rowCount = Math.ceil(fileNodes.length / columnCount);
|
|
4004
|
+
const rowVirtualizer = useVirtualizer({
|
|
4005
|
+
count: rowCount,
|
|
4006
|
+
getScrollElement: () => parentRef.current,
|
|
4007
|
+
estimateSize: (index) => {
|
|
4008
|
+
if (index > 0) {
|
|
4009
|
+
return ITEM_HEIGHT + GAP;
|
|
4010
|
+
}
|
|
4011
|
+
return ITEM_HEIGHT;
|
|
4012
|
+
},
|
|
4013
|
+
overscan: 5
|
|
4014
|
+
});
|
|
4015
|
+
const columnVirtualizer = useVirtualizer({
|
|
4016
|
+
horizontal: true,
|
|
4017
|
+
count: columnCount,
|
|
4018
|
+
getScrollElement: () => parentRef.current,
|
|
4019
|
+
estimateSize: (index) => {
|
|
4020
|
+
if (index > 0) {
|
|
4021
|
+
return ITEM_WIDTH + GAP;
|
|
4022
|
+
}
|
|
4023
|
+
return ITEM_WIDTH;
|
|
4024
|
+
},
|
|
4025
|
+
overscan: 5
|
|
4026
|
+
});
|
|
4027
|
+
const getItemIndex = (rowIndex, columnIndex) => rowIndex * columnCount + columnIndex;
|
|
4028
|
+
const getItem = (rowIndex, columnIndex) => {
|
|
4029
|
+
const index = getItemIndex(rowIndex, columnIndex);
|
|
4030
|
+
return fileNodes[index] || null;
|
|
4031
|
+
};
|
|
4032
|
+
if (fileNodes.length === 0) {
|
|
4033
|
+
return jsx("div", { className: "mb-8 text-sm text-gray-400", children: t("folderView.sections.documents.empty", {
|
|
4034
|
+
defaultValue: "No documents or files 📄"
|
|
4035
|
+
}) });
|
|
4036
|
+
}
|
|
4037
|
+
const renderItem = (rowIndex, columnIndex) => {
|
|
4038
|
+
const fileNode = getItem(rowIndex, columnIndex);
|
|
4039
|
+
if (!fileNode) {
|
|
4040
|
+
return null;
|
|
4041
|
+
}
|
|
4042
|
+
return jsx("div", { style: {
|
|
4043
|
+
marginLeft: columnIndex === 0 ? 0 : GAP
|
|
4044
|
+
}, children: jsx(FileItem, { uiNode: fileNode, ...fileProps }, fileNode.id) });
|
|
4045
|
+
};
|
|
4046
|
+
return jsx("div", { ref: parentRef, style: {
|
|
4047
|
+
height: `400px`,
|
|
4048
|
+
width: `100%`,
|
|
4049
|
+
overflow: "auto"
|
|
4050
|
+
}, children: jsx("div", { style: {
|
|
4051
|
+
height: `${rowVirtualizer.getTotalSize()}px`,
|
|
4052
|
+
width: `${columnVirtualizer.getTotalSize()}px`,
|
|
4053
|
+
position: "relative"
|
|
4054
|
+
}, children: rowVirtualizer.getVirtualItems().map((virtualRow) => jsx(React__default.Fragment, { children: columnVirtualizer.getVirtualItems().map((virtualColumn) => jsx("div", { style: {
|
|
4055
|
+
position: "absolute",
|
|
4056
|
+
top: 0,
|
|
4057
|
+
left: 0,
|
|
4058
|
+
marginTop: virtualRow.index === 0 ? 0 : GAP,
|
|
4059
|
+
width: `${virtualColumn.size}px`,
|
|
4060
|
+
height: `${virtualRow.size}px`,
|
|
4061
|
+
transform: `translateX(${virtualColumn.start}px) translateY(${virtualRow.start}px)`
|
|
4062
|
+
}, children: renderItem(virtualRow.index, virtualColumn.index) }, virtualColumn.key)) }, virtualRow.key)) }) });
|
|
4063
|
+
}
|
|
4064
|
+
function FolderView(props) {
|
|
4065
|
+
const { node, className, isDropTarget, containerProps, ...nodeProps } = props;
|
|
4066
|
+
const { t } = useTranslation();
|
|
4067
|
+
const folderNodes = node.children.filter((node2) => node2.kind === FOLDER).sort(sortUiNodesByName);
|
|
4068
|
+
const fileNodes = node.children.filter((node2) => node2.kind === FILE).sort(sortUiNodesByName);
|
|
4069
|
+
const folderCallbacks = {
|
|
4070
|
+
onSelectNode: (node2) => nodeProps.onSelectNode(node2),
|
|
4071
|
+
onRenameNode: (name, node2) => nodeProps.onRenameNode(name, node2),
|
|
4072
|
+
onDuplicateNode: (node2) => nodeProps.onDuplicateNode(node2),
|
|
4073
|
+
onDeleteNode: (node2) => nodeProps.onDeleteNode(node2)
|
|
4074
|
+
};
|
|
4075
|
+
const fileCallbacks = {
|
|
4076
|
+
onSelectNode: (node2) => nodeProps.onSelectNode(node2),
|
|
4077
|
+
onRenameNode: (name, node2) => nodeProps.onRenameNode(name, node2),
|
|
4078
|
+
onDuplicateNode: (node2) => nodeProps.onDuplicateNode(node2),
|
|
4079
|
+
onDeleteNode: (node2) => nodeProps.onDeleteNode(node2)
|
|
4080
|
+
};
|
|
4081
|
+
const baseNodeCallbacks = {
|
|
4082
|
+
onAddFile: async (file, parentNode) => {
|
|
4083
|
+
await nodeProps.onAddFile(file, parentNode);
|
|
4084
|
+
},
|
|
4085
|
+
onCopyNode: async (uiNode, targetNode) => {
|
|
4086
|
+
await nodeProps.onCopyNode(uiNode, targetNode);
|
|
4087
|
+
},
|
|
4088
|
+
onMoveNode: async (uiNode, targetNode) => {
|
|
4089
|
+
await nodeProps.onMoveNode(uiNode, targetNode);
|
|
4090
|
+
}
|
|
4091
|
+
};
|
|
4092
|
+
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", {
|
|
4093
|
+
defaultValue: "Folders"
|
|
4094
|
+
}), 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", {
|
|
4095
|
+
defaultValue: "No documents or files 📄"
|
|
4096
|
+
}) }) }), jsx(DriveLayout.ContentSection, { title: t("folderView.sections.documents.title", {
|
|
4097
|
+
defaultValue: "Documents and files"
|
|
4098
|
+
}), children: jsx("div", { className: twMerge("w-full", fileNodes.length > 0 ? "min-h-[400px]" : "min-h-14"), children: jsx(FileContentView, { fileNodes, ...fileCallbacks, isAllowedToCreateDocuments: nodeProps.isAllowedToCreateDocuments }) }) })] });
|
|
4099
|
+
}
|
|
4100
|
+
function BaseEditor(props) {
|
|
4101
|
+
const { document: document2, dispatch, className, children } = props;
|
|
4102
|
+
const { id: driveId } = document2;
|
|
4103
|
+
const { showSearchBar, isAllowedToCreateDocuments, documentModels, showCreateDocumentModal } = useDriveContext();
|
|
4104
|
+
const { driveNodes, selectedNode, selectedNodePath, getNodeById, setSelectedNode } = useUiNodesContext();
|
|
4105
|
+
const driveNode = useMemo(() => driveNodes.find((n) => n.id === driveId), [driveNodes, driveId]);
|
|
4106
|
+
const { addDocument, addFile, addFolder: addFolder2, renameNode, deleteNode: deleteNode2, moveNode: moveNode2, copyNode: copyNode2, duplicateNode } = useDriveActionsWithUiNodes(document2, dispatch);
|
|
4107
|
+
const onCreateDocument = useCallback(async (documentModel) => {
|
|
4108
|
+
const { name } = await showCreateDocumentModal(documentModel);
|
|
4109
|
+
const document3 = documentModel.utils.createDocument();
|
|
4110
|
+
await addDocument(name, documentModel.documentModel.name, document3, selectedNode == null ? void 0 : selectedNode.id);
|
|
4111
|
+
}, [addDocument, showCreateDocumentModal, selectedNode == null ? void 0 : selectedNode.id]);
|
|
4112
|
+
const { isDropTarget, dropProps } = useDrop({
|
|
4113
|
+
uiNode: selectedNode,
|
|
4114
|
+
onAddFile: addFile,
|
|
4115
|
+
onCopyNode: copyNode2,
|
|
4116
|
+
onMoveNode: moveNode2
|
|
4117
|
+
});
|
|
4118
|
+
const { breadcrumbs, onBreadcrumbSelected } = useBreadcrumbs({
|
|
4119
|
+
selectedNodePath,
|
|
4120
|
+
getNodeById,
|
|
4121
|
+
setSelectedNode
|
|
4122
|
+
});
|
|
4123
|
+
if (!driveNode) {
|
|
4124
|
+
return jsx("div", { children: "Drive not found" });
|
|
4125
|
+
} else if ((selectedNode == null ? void 0 : selectedNode.kind) === FILE$1) {
|
|
4126
|
+
return jsx(Fragment$1, {});
|
|
4127
|
+
}
|
|
4128
|
+
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 }) })] });
|
|
4129
|
+
}
|
|
4130
|
+
function Editor(props) {
|
|
4131
|
+
return jsx(DriveContextProvider, { value: props.context, children: jsx(BaseEditor, { ...props }) });
|
|
4132
|
+
}
|
|
4133
|
+
const GenericDriveExplorer = {
|
|
4134
|
+
Component: Editor,
|
|
4135
|
+
documentTypes: ["powerhouse/document-drive"],
|
|
4136
|
+
config: {
|
|
4137
|
+
id: "GenericDriveExplorer",
|
|
4138
|
+
disableExternalControls: true,
|
|
4139
|
+
documentToolbarEnabled: true,
|
|
4140
|
+
showSwitchboardLink: true
|
|
4141
|
+
}
|
|
4142
|
+
};
|
|
4143
|
+
function useAnalyticsQueryWrapper(options) {
|
|
4144
|
+
const { queryFn, ...queryOptions } = options;
|
|
4145
|
+
const store = useAnalyticsStore();
|
|
4146
|
+
const engine = useAnalyticsEngine();
|
|
4147
|
+
return useQuery({
|
|
4148
|
+
...queryOptions,
|
|
4149
|
+
queryFn: () => {
|
|
4150
|
+
if (!store || !engine) {
|
|
4151
|
+
throw new Error("No analytics store available. Use within an AnalyticsProvider.");
|
|
4152
|
+
}
|
|
4153
|
+
return queryFn({ store, engine });
|
|
4154
|
+
}
|
|
4155
|
+
});
|
|
4156
|
+
}
|
|
4157
|
+
function useAnalyticsQuery(query, options) {
|
|
4158
|
+
const store = useAnalyticsStore();
|
|
4159
|
+
const { data: querySources } = useQuerySources(query);
|
|
4160
|
+
const queryClient = useQueryClient();
|
|
4161
|
+
const subscriptions = useRef([]);
|
|
4162
|
+
const result = useAnalyticsQueryWrapper({
|
|
4163
|
+
queryKey: ["analytics", "query", query],
|
|
4164
|
+
queryFn: ({ engine }) => engine.execute(query),
|
|
4165
|
+
...options
|
|
4166
|
+
});
|
|
4167
|
+
useEffect(() => {
|
|
4168
|
+
if (!(querySources == null ? void 0 : querySources.length) || !store) {
|
|
4169
|
+
return;
|
|
4170
|
+
}
|
|
4171
|
+
querySources.forEach((source) => {
|
|
4172
|
+
const unsub = store.subscribeToSource(source, () => {
|
|
4173
|
+
return queryClient.invalidateQueries({
|
|
4174
|
+
queryKey: ["analytics", "query", query]
|
|
4175
|
+
});
|
|
4176
|
+
});
|
|
4177
|
+
subscriptions.current.push(unsub);
|
|
4178
|
+
});
|
|
4179
|
+
return () => {
|
|
4180
|
+
subscriptions.current.forEach((unsub) => unsub());
|
|
4181
|
+
subscriptions.current = [];
|
|
4182
|
+
};
|
|
4183
|
+
}, [querySources]);
|
|
4184
|
+
return result;
|
|
4185
|
+
}
|
|
4186
|
+
function useMatchingSeries(query, options) {
|
|
4187
|
+
const result = useAnalyticsQueryWrapper({
|
|
4188
|
+
queryKey: ["analytics", "matchingSeries", query],
|
|
4189
|
+
queryFn: ({ store }) => store.getMatchingSeries(query),
|
|
4190
|
+
...options
|
|
4191
|
+
});
|
|
4192
|
+
return result;
|
|
4193
|
+
}
|
|
4194
|
+
function useQuerySources(query, options) {
|
|
4195
|
+
const { data: matchingSeries } = useMatchingSeries(query);
|
|
4196
|
+
return useQuery({
|
|
4197
|
+
queryKey: ["analytics", "sources", query],
|
|
4198
|
+
queryFn: () => {
|
|
4199
|
+
if (!(matchingSeries == null ? void 0 : matchingSeries.length)) {
|
|
4200
|
+
return [];
|
|
4201
|
+
}
|
|
4202
|
+
const uniqueSources = [
|
|
4203
|
+
...new Set(matchingSeries.map((s) => s.source.toString()))
|
|
4204
|
+
];
|
|
4205
|
+
return uniqueSources.map((source) => AnalyticsPath.fromString(source));
|
|
4206
|
+
},
|
|
4207
|
+
enabled: !!matchingSeries,
|
|
4208
|
+
...options
|
|
4209
|
+
});
|
|
4210
|
+
}
|
|
4211
|
+
const getBarSize = (value) => {
|
|
4212
|
+
if (value <= 0)
|
|
4213
|
+
return 0;
|
|
4214
|
+
if (value > 0 && value <= 50)
|
|
4215
|
+
return 1;
|
|
4216
|
+
if (value > 50 && value <= 100)
|
|
4217
|
+
return 2;
|
|
4218
|
+
if (value > 100 && value <= 250)
|
|
4219
|
+
return 3;
|
|
4220
|
+
return 4;
|
|
4221
|
+
};
|
|
4222
|
+
const useTimelineItems = (documentId, startTimestamp) => {
|
|
4223
|
+
const start = startTimestamp ? DateTime.fromISO(startTimestamp) : DateTime.now().startOf("day");
|
|
4224
|
+
const { data: diffResult, isLoading } = useAnalyticsQuery({
|
|
4225
|
+
start,
|
|
4226
|
+
end: DateTime.now().endOf("day"),
|
|
4227
|
+
granularity: AnalyticsGranularity.Hourly,
|
|
4228
|
+
metrics: ["Count"],
|
|
4229
|
+
select: {
|
|
4230
|
+
changes: [AnalyticsPath.fromString(`changes`)],
|
|
4231
|
+
document: [AnalyticsPath.fromString(`document/${documentId}`)]
|
|
4232
|
+
},
|
|
4233
|
+
lod: {
|
|
4234
|
+
changes: 2
|
|
4235
|
+
},
|
|
4236
|
+
currency: AnalyticsPath.fromString("")
|
|
4237
|
+
});
|
|
4238
|
+
const mappedResult = useMemo(() => {
|
|
4239
|
+
if (!diffResult)
|
|
4240
|
+
return [];
|
|
4241
|
+
return diffResult.sort((a, b) => {
|
|
4242
|
+
const aDate = new Date(a.start);
|
|
4243
|
+
const bDate = new Date(b.start);
|
|
4244
|
+
return aDate.getTime() - bDate.getTime();
|
|
4245
|
+
}).filter((result) => {
|
|
4246
|
+
return result.rows.every((row) => row.value > 0);
|
|
4247
|
+
}).map((result) => {
|
|
4248
|
+
const { additions, deletions } = result.rows.reduce((acc, row) => {
|
|
4249
|
+
if (row.dimensions.changes.path === "changes/add") {
|
|
4250
|
+
acc.additions += row.value;
|
|
4251
|
+
} else if (row.dimensions.changes.path === "changes/remove") {
|
|
4252
|
+
acc.deletions += row.value;
|
|
4253
|
+
}
|
|
4254
|
+
return acc;
|
|
4255
|
+
}, { additions: 0, deletions: 0 });
|
|
4256
|
+
const startDate = new Date(result.start);
|
|
4257
|
+
return {
|
|
4258
|
+
id: startDate.toISOString(),
|
|
4259
|
+
type: "bar",
|
|
4260
|
+
addSize: getBarSize(additions),
|
|
4261
|
+
delSize: getBarSize(deletions),
|
|
4262
|
+
additions,
|
|
4263
|
+
deletions,
|
|
4264
|
+
timestamp: startDate.toISOString(),
|
|
4265
|
+
startDate,
|
|
4266
|
+
endDate: new Date(result.end),
|
|
4267
|
+
revision: 0
|
|
4268
|
+
};
|
|
4269
|
+
});
|
|
4270
|
+
}, [diffResult]);
|
|
4271
|
+
const resultWithDividers = useMemo(() => {
|
|
4272
|
+
if (!mappedResult.length)
|
|
4273
|
+
return [];
|
|
4274
|
+
const result = [];
|
|
4275
|
+
mappedResult.forEach((item, index) => {
|
|
4276
|
+
result.push(item);
|
|
4277
|
+
if (index < mappedResult.length - 1) {
|
|
4278
|
+
const currentDate = new Date(item.startDate);
|
|
4279
|
+
const nextDate = new Date(mappedResult[index + 1].startDate);
|
|
4280
|
+
const currentHour = currentDate.getHours();
|
|
4281
|
+
const nextHour = nextDate.getHours();
|
|
4282
|
+
const currentDay = currentDate.toDateString();
|
|
4283
|
+
const nextDay = nextDate.toDateString();
|
|
4284
|
+
if (currentDay !== nextDay || currentDay === nextDay && Math.abs(nextHour - currentHour) > 1) {
|
|
4285
|
+
result.push({
|
|
4286
|
+
id: `divider-${item.id}-${mappedResult[index + 1].id}`,
|
|
4287
|
+
type: "divider",
|
|
4288
|
+
revision: 0
|
|
4289
|
+
});
|
|
4290
|
+
}
|
|
4291
|
+
}
|
|
4292
|
+
});
|
|
4293
|
+
return result;
|
|
4294
|
+
}, [mappedResult]);
|
|
4295
|
+
return {
|
|
4296
|
+
isLoading,
|
|
4297
|
+
data: resultWithDividers
|
|
4298
|
+
};
|
|
4299
|
+
};
|
|
4300
|
+
const getRevisionFromDate = (startDate, endDate, operations = []) => {
|
|
4301
|
+
if (!startDate || !endDate)
|
|
4302
|
+
return 0;
|
|
4303
|
+
const operation = operations.find((operation2) => {
|
|
4304
|
+
const operationDate = new Date(operation2.timestamp);
|
|
4305
|
+
return operationDate >= startDate && operationDate <= endDate;
|
|
4306
|
+
});
|
|
4307
|
+
return operation ? operation.index : 0;
|
|
4308
|
+
};
|
|
4309
|
+
function EditorLoader(props) {
|
|
4310
|
+
const [showLoading, setShowLoading] = useState(false);
|
|
4311
|
+
useEffect(() => {
|
|
4312
|
+
setTimeout(() => {
|
|
3565
4313
|
setShowLoading(true);
|
|
3566
4314
|
}, props.loadingTimeout ?? 200);
|
|
3567
4315
|
}, [props]);
|
|
@@ -3585,9 +4333,11 @@ const DocumentEditor = (props) => {
|
|
|
3585
4333
|
onChange,
|
|
3586
4334
|
onExport,
|
|
3587
4335
|
onAddOperation,
|
|
4336
|
+
onGetDocumentRevision,
|
|
3588
4337
|
onOpenSwitchboardLink
|
|
3589
4338
|
} = props;
|
|
3590
4339
|
const documentId = fileNodeDocument == null ? void 0 : fileNodeDocument.documentId;
|
|
4340
|
+
const [selectedTimelineItem, setSelectedTimelineItem] = useState(null);
|
|
3591
4341
|
const [revisionHistoryVisible, setRevisionHistoryVisible] = useState(false);
|
|
3592
4342
|
const theme = useAtomValue(themeAtom);
|
|
3593
4343
|
const user = useUser() || void 0;
|
|
@@ -3613,6 +4363,10 @@ const DocumentEditor = (props) => {
|
|
|
3613
4363
|
[theme, user]
|
|
3614
4364
|
);
|
|
3615
4365
|
const userPermissions = useUserPermissions$1();
|
|
4366
|
+
const timelineItems = useTimelineItems(
|
|
4367
|
+
documentId,
|
|
4368
|
+
initialDocument == null ? void 0 : initialDocument.created
|
|
4369
|
+
);
|
|
3616
4370
|
const currentDocument = useRef({ ...fileNodeDocument, document: document2 });
|
|
3617
4371
|
useEffect(() => {
|
|
3618
4372
|
var _a;
|
|
@@ -3789,7 +4543,8 @@ const DocumentEditor = (props) => {
|
|
|
3789
4543
|
const {
|
|
3790
4544
|
disableExternalControls,
|
|
3791
4545
|
documentToolbarEnabled,
|
|
3792
|
-
showSwitchboardLink
|
|
4546
|
+
showSwitchboardLink,
|
|
4547
|
+
timelineEnabled
|
|
3793
4548
|
} = editor.config || {};
|
|
3794
4549
|
const handleSwitchboardLinkClick = showSwitchboardLink !== false ? onOpenSwitchboardLink : void 0;
|
|
3795
4550
|
return /* @__PURE__ */ jsxs("div", { className: "relative h-full", id: "document-editor-context", children: [
|
|
@@ -3800,7 +4555,10 @@ const DocumentEditor = (props) => {
|
|
|
3800
4555
|
onExport,
|
|
3801
4556
|
onShowRevisionHistory: showRevisionHistory,
|
|
3802
4557
|
title: fileNodeDocument.name || document2.name,
|
|
3803
|
-
onSwitchboardLinkClick: handleSwitchboardLinkClick
|
|
4558
|
+
onSwitchboardLinkClick: handleSwitchboardLinkClick,
|
|
4559
|
+
timelineButtonVisible: timelineEnabled,
|
|
4560
|
+
timelineItems: timelineItems.data,
|
|
4561
|
+
onTimelineItemClick: setSelectedTimelineItem
|
|
3804
4562
|
}
|
|
3805
4563
|
),
|
|
3806
4564
|
!disableExternalControls && /* @__PURE__ */ jsxs("div", { className: "mb-4 flex justify-end gap-10", children: [
|
|
@@ -3830,7 +4588,16 @@ const DocumentEditor = (props) => {
|
|
|
3830
4588
|
EditorComponent,
|
|
3831
4589
|
{
|
|
3832
4590
|
error,
|
|
3833
|
-
context
|
|
4591
|
+
context: {
|
|
4592
|
+
...context,
|
|
4593
|
+
getDocumentRevision: onGetDocumentRevision,
|
|
4594
|
+
readMode: !!selectedTimelineItem,
|
|
4595
|
+
selectedTimelineRevision: getRevisionFromDate(
|
|
4596
|
+
selectedTimelineItem == null ? void 0 : selectedTimelineItem.startDate,
|
|
4597
|
+
selectedTimelineItem == null ? void 0 : selectedTimelineItem.endDate,
|
|
4598
|
+
document2.operations.global
|
|
4599
|
+
)
|
|
4600
|
+
},
|
|
3834
4601
|
document: document2,
|
|
3835
4602
|
documentNodeName: fileNodeDocument.name,
|
|
3836
4603
|
dispatch,
|
|
@@ -3868,6 +4635,7 @@ function DocumentEditorContainer() {
|
|
|
3868
4635
|
renameNode,
|
|
3869
4636
|
getDocumentModelModule
|
|
3870
4637
|
} = useUiNodes();
|
|
4638
|
+
const getDocument = useGetDocument();
|
|
3871
4639
|
const handleAddOperationToSelectedDocument = useCallback(
|
|
3872
4640
|
async (operation) => {
|
|
3873
4641
|
if (!selectedDocument) {
|
|
@@ -3930,6 +4698,20 @@ function DocumentEditorContainer() {
|
|
|
3930
4698
|
},
|
|
3931
4699
|
[getDocumentModelModule, showModal, t]
|
|
3932
4700
|
);
|
|
4701
|
+
const onGetDocumentRevision = useCallback(
|
|
4702
|
+
(options) => {
|
|
4703
|
+
if (!selectedNode) {
|
|
4704
|
+
console.error("No selected node");
|
|
4705
|
+
return Promise.reject(new Error("No selected node"));
|
|
4706
|
+
}
|
|
4707
|
+
return getDocument(
|
|
4708
|
+
selectedNode.driveId,
|
|
4709
|
+
selectedNode.id,
|
|
4710
|
+
options
|
|
4711
|
+
);
|
|
4712
|
+
},
|
|
4713
|
+
[getDocument, selectedNode]
|
|
4714
|
+
);
|
|
3933
4715
|
const onExport = useCallback(() => {
|
|
3934
4716
|
if (selectedDocument) {
|
|
3935
4717
|
return exportDocument(selectedDocument);
|
|
@@ -3951,6 +4733,7 @@ function DocumentEditorContainer() {
|
|
|
3951
4733
|
onChange: onDocumentChangeHandler,
|
|
3952
4734
|
onClose,
|
|
3953
4735
|
onExport,
|
|
4736
|
+
onGetDocumentRevision,
|
|
3954
4737
|
onAddOperation: handleAddOperationToSelectedDocument,
|
|
3955
4738
|
onOpenSwitchboardLink
|
|
3956
4739
|
}
|
|
@@ -3959,165 +4742,6 @@ function DocumentEditorContainer() {
|
|
|
3959
4742
|
fileNodeDocument.documentId
|
|
3960
4743
|
);
|
|
3961
4744
|
}
|
|
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
4745
|
function useDocumentsState(args) {
|
|
4122
4746
|
const { reactor, driveId, documentIds, options } = args;
|
|
4123
4747
|
const [statesByDocumentId, setStatesByDocumentId] = useState({});
|
|
@@ -4304,8 +4928,19 @@ function DriveEditorContainer() {
|
|
|
4304
4928
|
const { addFile, addDocument } = useDocumentDriveServer();
|
|
4305
4929
|
const documentModels = useFilteredDocumentModels();
|
|
4306
4930
|
const useDriveDocumentState = makeDriveDocumentStateHook(reactor);
|
|
4931
|
+
const getDocument = useGetDocument();
|
|
4307
4932
|
const getDocumentModelModule = useGetDocumentModelModule();
|
|
4308
4933
|
const getEditor = useGetEditor();
|
|
4934
|
+
const onGetDocumentRevision = useCallback(
|
|
4935
|
+
(documentId, options) => {
|
|
4936
|
+
if (!selectedNode) {
|
|
4937
|
+
console.error("No selected node");
|
|
4938
|
+
return Promise.reject(new Error("No selected node"));
|
|
4939
|
+
}
|
|
4940
|
+
return getDocument(selectedNode.driveId, documentId, options);
|
|
4941
|
+
},
|
|
4942
|
+
[getDocument, selectedNode]
|
|
4943
|
+
);
|
|
4309
4944
|
const driveContext = useMemo(
|
|
4310
4945
|
() => ({
|
|
4311
4946
|
showSearchBar: false,
|
|
@@ -4349,6 +4984,8 @@ function DriveEditorContainer() {
|
|
|
4349
4984
|
context: {
|
|
4350
4985
|
...editorProps.context,
|
|
4351
4986
|
...driveContext,
|
|
4987
|
+
analyticsDatabaseName: connectConfig.analyticsDatabaseName,
|
|
4988
|
+
getDocumentRevision: onGetDocumentRevision,
|
|
4352
4989
|
getDocumentModelModule,
|
|
4353
4990
|
getEditor
|
|
4354
4991
|
},
|
|
@@ -4384,7 +5021,7 @@ function Content() {
|
|
|
4384
5021
|
}, [selectedDriveNode, selectedNode, addFile]);
|
|
4385
5022
|
useEffect(() => {
|
|
4386
5023
|
if ((status === "LOADED" || status === "ERROR") && !documentDrives.find(
|
|
4387
|
-
(d) => d.
|
|
5024
|
+
(d) => d.id === driveId || d.slug === driveId || d.state.global.name === driveId
|
|
4388
5025
|
)) {
|
|
4389
5026
|
toast(/* @__PURE__ */ jsxs("p", { children: [
|
|
4390
5027
|
"Drive ",
|
|
@@ -4399,3 +5036,4 @@ function Content() {
|
|
|
4399
5036
|
export {
|
|
4400
5037
|
Content as default
|
|
4401
5038
|
};
|
|
5039
|
+
//# sourceMappingURL=content-2lJzkjLx.js.map
|