@powerhousedao/connect 6.2.3-dev.4 → 6.2.3-dev.41
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/{AddDriveModal-xAw48kdl.js → AddDriveModal-DhNfP94R.js} +5 -5
- package/dist/{AddDriveModal-xAw48kdl.js.map → AddDriveModal-DhNfP94R.js.map} +1 -1
- package/dist/{ClearStorageModal-DLchAUxQ.js → ClearStorageModal-DaNmZ8f2.js} +5 -5
- package/dist/{ClearStorageModal-DLchAUxQ.js.map → ClearStorageModal-DaNmZ8f2.js.map} +1 -1
- package/dist/{ConfirmDocumentUpgradeModal-FUOhZsk7.js → ConfirmDocumentUpgradeModal-DcOZy20m.js} +8 -7
- package/dist/{ConfirmDocumentUpgradeModal-FUOhZsk7.js.map → ConfirmDocumentUpgradeModal-DcOZy20m.js.map} +1 -1
- package/dist/{CookiesPolicyModal-BpyPPyxS.js → CookiesPolicyModal-BLw4pnhn.js} +4 -4
- package/dist/{CookiesPolicyModal-BpyPPyxS.js.map → CookiesPolicyModal-BLw4pnhn.js.map} +1 -1
- package/dist/{CreateDocumentModal-C45W8J0V.js → CreateDocumentModal-Bmv0V-kY.js} +6 -5
- package/dist/{CreateDocumentModal-C45W8J0V.js.map → CreateDocumentModal-Bmv0V-kY.js.map} +1 -1
- package/dist/{DebugSettingsModal-Bg0wn3oX.js → DebugSettingsModal-EYgccEiI.js} +7 -7
- package/dist/{DebugSettingsModal-Bg0wn3oX.js.map → DebugSettingsModal-EYgccEiI.js.map} +1 -1
- package/dist/{DeleteDriveModal-Dug84t1j.js → DeleteDriveModal-CjGnG0ht.js} +5 -5
- package/dist/{DeleteDriveModal-Dug84t1j.js.map → DeleteDriveModal-CjGnG0ht.js.map} +1 -1
- package/dist/{DeleteItemModal-mMzy3V8o.js → DeleteItemModal-BbY_4_xT.js} +5 -5
- package/dist/{DeleteItemModal-mMzy3V8o.js.map → DeleteItemModal-BbY_4_xT.js.map} +1 -1
- package/dist/{DisclaimerModal-DvpD5dPM.js → DisclaimerModal-DuglmEwL.js} +4 -4
- package/dist/{DisclaimerModal-DvpD5dPM.js.map → DisclaimerModal-DuglmEwL.js.map} +1 -1
- package/dist/{DocumentVersionUnsupportedModal-C3Q0V75l.js → DocumentVersionUnsupportedModal-C4fy7fZ6.js} +4 -4
- package/dist/{DocumentVersionUnsupportedModal-C3Q0V75l.js.map → DocumentVersionUnsupportedModal-C4fy7fZ6.js.map} +1 -1
- package/dist/{DownloadDocumentWithErrorsModal-IKl0ljQb.js → DownloadDocumentWithErrorsModal-BsPQ5qgy.js} +6 -5
- package/dist/{DownloadDocumentWithErrorsModal-IKl0ljQb.js.map → DownloadDocumentWithErrorsModal-BsPQ5qgy.js.map} +1 -1
- package/dist/{DriveAuthRequiredModal-DVK7ZQzO.js → DriveAuthRequiredModal-CtsB0kwH.js} +5 -5
- package/dist/{DriveAuthRequiredModal-DVK7ZQzO.js.map → DriveAuthRequiredModal-CtsB0kwH.js.map} +1 -1
- package/dist/{DriveSettingsModal-C6-mRQiv.js → DriveSettingsModal-d1L0eYof.js} +4 -4
- package/dist/{DriveSettingsModal-C6-mRQiv.js.map → DriveSettingsModal-d1L0eYof.js.map} +1 -1
- package/dist/{InspectorModal-DoEQVQYq.js → InspectorModal-Bkry1jv9.js} +61 -21
- package/dist/InspectorModal-Bkry1jv9.js.map +1 -0
- package/dist/{LoginModal-CybbOm3N.js → LoginModal-CI0ogC2-.js} +5 -5
- package/dist/{LoginModal-CybbOm3N.js.map → LoginModal-CI0ogC2-.js.map} +1 -1
- package/dist/{MissingPackageModal-nBnExqO0.js → MissingPackageModal-CjkK_4A7.js} +5 -5
- package/dist/{MissingPackageModal-nBnExqO0.js.map → MissingPackageModal-CjkK_4A7.js.map} +1 -1
- package/dist/{OpenFileDocumentsModal-D50ZOp6U.js → OpenFileDocumentsModal-CEFijapC.js} +8 -7
- package/dist/{OpenFileDocumentsModal-D50ZOp6U.js.map → OpenFileDocumentsModal-CEFijapC.js.map} +1 -1
- package/dist/{SettingsModal-Dj6IQcRU.js → SettingsModal-iBBWf4UN.js} +17 -15
- package/dist/{SettingsModal-Dj6IQcRU.js.map → SettingsModal-iBBWf4UN.js.map} +1 -1
- package/dist/{UpgradeDriveModal-_8t9slxQ.js → UpgradeDriveModal-CXX6D5Au.js} +4 -4
- package/dist/{UpgradeDriveModal-_8t9slxQ.js.map → UpgradeDriveModal-CXX6D5Au.js.map} +1 -1
- package/dist/{app-loader-CKTEeFBT.js → app-loader-BXd5hsez.js} +1160 -1121
- package/dist/app-loader-BXd5hsez.js.map +1 -0
- package/dist/app-loader-D_p85Yp8.js +4 -0
- package/dist/app-skeleton--Me5zlSz.js +112 -0
- package/dist/app-skeleton--Me5zlSz.js.map +1 -0
- package/dist/app-skeleton-CBN4tenZ.js +4 -0
- package/dist/boot-DPNEOI2A.js +210 -0
- package/dist/boot-DPNEOI2A.js.map +1 -0
- package/dist/buffer-DNTcuap_.js +66 -0
- package/dist/buffer-DNTcuap_.js.map +1 -0
- package/dist/{build-info-N9NcY_pl.js → build-info-C7dDerrM.js} +5 -5
- package/dist/{build-info-N9NcY_pl.js.map → build-info-C7dDerrM.js.map} +1 -1
- package/dist/components-CRXekmxS.js +5 -0
- package/dist/{connect.config-DaHDEUrw.js → connect.config-CaXMoB42.js} +24 -12
- package/dist/connect.config-CaXMoB42.js.map +1 -0
- package/dist/{connection-state-3w4liC1X.js → connection-state-Eqc2izmt.js} +6 -6
- package/dist/{connection-state-3w4liC1X.js.map → connection-state-Eqc2izmt.js.map} +1 -1
- package/dist/{cookie-banner-BH6bIq24.js → cookie-banner-BxXvPdIY.js} +6 -6
- package/dist/{cookie-banner-BH6bIq24.js.map → cookie-banner-BxXvPdIY.js.map} +1 -1
- package/dist/{i18n-CWO0vYVd.js → i18n-CTgT1HG-.js} +3 -3
- package/dist/{i18n-CWO0vYVd.js.map → i18n-CTgT1HG-.js.map} +1 -1
- package/dist/{load-BcbPl8PK.js → load--VQTmlAi.js} +13 -11
- package/dist/{load-BcbPl8PK.js.map → load--VQTmlAi.js.map} +1 -1
- package/dist/main.d.ts +2 -1
- package/dist/main.js +8 -8
- package/dist/main.js.map +1 -1
- package/dist/package-manager-BbzIV9aN.js +485 -0
- package/dist/package-manager-BbzIV9aN.js.map +1 -0
- package/dist/{pglite-major-B39aOEiE.js → pglite-major-p4_YefAE.js} +23 -5
- package/dist/pglite-major-p4_YefAE.js.map +1 -0
- package/dist/{pglite-migrate-core-Boxqqx-c.js → pglite-migrate-core-BcXcImng.js} +8 -6
- package/dist/{pglite-migrate-core-Boxqqx-c.js.map → pglite-migrate-core-BcXcImng.js.map} +1 -1
- package/dist/{pglite-seed-BqAUvNFw.js → pglite-seed-Cl2d-iyl.js} +4 -4
- package/dist/{pglite-seed-BqAUvNFw.js.map → pglite-seed-Cl2d-iyl.js.map} +1 -1
- package/dist/pglite.worker.d.ts +2 -1
- package/dist/pglite.worker.js +4 -3
- package/dist/pglite.worker.js.map +1 -1
- package/dist/pglite.worker.legacy.d.ts +2 -1
- package/dist/pglite.worker.legacy.js +4 -3
- package/dist/pglite.worker.legacy.js.map +1 -1
- package/dist/{preferences-store-_5Cw4_YV.js → preferences-store-DZUIAkHE.js} +6 -25
- package/dist/preferences-store-DZUIAkHE.js.map +1 -0
- package/dist/{pwa-manifest-link-DIgOSo2Q.js → pwa-manifest-link-DQRJpF0r.js} +3 -3
- package/dist/{pwa-manifest-link-DIgOSo2Q.js.map → pwa-manifest-link-DQRJpF0r.js.map} +1 -1
- package/dist/{reactor-C8xEzPA1.js → reactor-DnUFDbsP.js} +93 -451
- package/dist/reactor-DnUFDbsP.js.map +1 -0
- package/dist/reactor.worker.d.ts +2 -1
- package/dist/reactor.worker.js +76 -21
- package/dist/reactor.worker.js.map +1 -1
- package/dist/{registerServiceWorker-BSzbNfvz.js → registerServiceWorker-smkROQhm.js} +5 -5
- package/dist/{registerServiceWorker-BSzbNfvz.js.map → registerServiceWorker-smkROQhm.js.map} +1 -1
- package/dist/renown-trust-DRgHpxlZ.js +34 -0
- package/dist/renown-trust-DRgHpxlZ.js.map +1 -0
- package/dist/{runtime-config-DL3QjcfM.js → runtime-config-DtJIUgYw.js} +3 -3
- package/dist/{runtime-config-DL3QjcfM.js.map → runtime-config-DtJIUgYw.js.map} +1 -1
- package/dist/{sentry-QXKgQmr2.js → sentry-jfDyrxdX.js} +3 -3
- package/dist/{sentry-QXKgQmr2.js.map → sentry-jfDyrxdX.js.map} +1 -1
- package/dist/start-connect.d.ts +4 -5
- package/dist/start-connect.d.ts.map +1 -1
- package/dist/start-connect.js +6 -8
- package/dist/start-connect.js.map +1 -1
- package/dist/style.css +2907 -1
- package/dist/{toast-BXIGd4Eb.js → toast-C6WW-_O-.js} +3 -3
- package/dist/{toast-BXIGd4Eb.js.map → toast-C6WW-_O-.js.map} +1 -1
- package/dist/{use-renown-login-Cf3va6u_.js → use-renown-login-BzOSQETV.js} +3 -3
- package/dist/{use-renown-login-Cf3va6u_.js.map → use-renown-login-BzOSQETV.js.map} +1 -1
- package/dist/useIsEmbedded-BWJ0qb7w.js +26 -0
- package/dist/useIsEmbedded-BWJ0qb7w.js.map +1 -0
- package/dist/{useRegistryPackages-BnUcL_nZ.js → useRegistryPackages-Bruz_77X.js} +75 -13
- package/dist/useRegistryPackages-Bruz_77X.js.map +1 -0
- package/package.json +19 -19
- package/style.css +7 -5
- package/dist/InspectorModal-DoEQVQYq.js.map +0 -1
- package/dist/app-loader-B2GI39lp.js +0 -4
- package/dist/app-loader-CKTEeFBT.js.map +0 -1
- package/dist/components-CkldoWSk.js +0 -4
- package/dist/connect.config-DaHDEUrw.js.map +0 -1
- package/dist/pglite-major-B39aOEiE.js.map +0 -1
- package/dist/preferences-store-_5Cw4_YV.js.map +0 -1
- package/dist/reactor-C8xEzPA1.js.map +0 -1
- package/dist/useRegistryPackages-BnUcL_nZ.js.map +0 -1
|
@@ -1,27 +1,32 @@
|
|
|
1
1
|
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
3
|
-
import { n as getRuntimeConfig } from "./runtime-config-
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import { n as
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { n as
|
|
12
|
-
import { t as
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="dfdd60eb-74cd-51f4-aecf-a38aed5d8193")}catch(e){}}();
|
|
3
|
+
import { n as getRuntimeConfig } from "./runtime-config-DtJIUgYw.js";
|
|
4
|
+
import { n as drainOpenPanelBuffer, t as clearOpenPanelBuffer } from "./buffer-DNTcuap_.js";
|
|
5
|
+
import { c as idbError, d as isStoredDocumentsRefused } from "./pglite-major-p4_YefAE.js";
|
|
6
|
+
import { n as cloneFileData, r as migrateIdb } from "./pglite-migrate-core-BcXcImng.js";
|
|
7
|
+
import "./i18n-CTgT1HG-.js";
|
|
8
|
+
import { n as setMigrationStatus, t as AppSkeleton } from "./app-skeleton--Me5zlSz.js";
|
|
9
|
+
import { n as useIsEmbedded } from "./useIsEmbedded-BWJ0qb7w.js";
|
|
10
|
+
import { a as defaultPHDocumentEditorConfig, i as defaultPHAppConfig, r as connectConfig } from "./connect.config-CaXMoB42.js";
|
|
11
|
+
import { n as useAcceptedCookies, t as setBannerShown } from "./preferences-store-DZUIAkHE.js";
|
|
12
|
+
import { t as setSentryModule } from "./sentry-jfDyrxdX.js";
|
|
13
|
+
import { n as dismissToast, r as toast, t as ToastContainer } from "./toast-C6WW-_O-.js";
|
|
14
|
+
import { f as PRIMARY_IDB_NAMES, r as subscribeWorkerConnection, s as getCachedMigrationMajor, t as getWorkerConnectionStatus, u as subscribeMigrationMajor } from "./connection-state-Eqc2izmt.js";
|
|
15
|
+
import { n as serviceWorkerManager, r as subscribeServiceWorkerUpdate, t as getServiceWorkerUpdateAvailable } from "./registerServiceWorker-smkROQhm.js";
|
|
16
|
+
import { t as useOpenRenownLogin } from "./use-renown-login-BzOSQETV.js";
|
|
13
17
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
14
|
-
import { useTranslation } from "react-i18next";
|
|
18
|
+
import { Trans, useTranslation } from "react-i18next";
|
|
15
19
|
import React, { StrictMode, Suspense, createElement, lazy, useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import { ConnectSidebar, ConnectTooltipProvider, DefaultEditorLoader, DriveAuthGate, DropZoneWrapper, HomeScreen, HomeScreenAddDriveItem, HomeScreenItem, LogoAnimation, PackageInstallModal, RevisionHistory, SidebarAddDriveItem, SidebarItem, UploadFileListContainer, formatFileSize, mapProgressStageToStatus, useEns } from "@powerhousedao/design-system/connect";
|
|
19
|
-
import { Outlet, RouterProvider, createBrowserRouter, createRoutesFromChildren, matchRoutes, useLocation, useNavigationType } from "react-router-dom";
|
|
20
|
-
import { useHotkeys } from "react-hotkeys-hook";
|
|
20
|
+
import { ConnectSearchBar, ConnectSidebar, ConnectTooltipProvider, DefaultEditorLoader, DriveAuthGate, DropZoneWrapper, Footer, FooterLink, HomeScreen, HomeScreenAddDriveItem, HomeScreenItem, PackageInstallModal, RevisionHistory, SidebarAddDriveItem, SidebarItem, UploadFileListContainer, formatFileSize, mapProgressStageToStatus, useEns } from "@powerhousedao/design-system/connect";
|
|
21
|
+
import { DriveCollectionId, RenownWalletProvider, addFileWithProgress, getRevisionFromDate, logout, setPHAppConfig, setPHDocumentEditorConfig, setRevisionHistoryVisible, setSelectedDrive, setSelectedNode, showPHModal, useAppModuleById, useConnectionStates, useDefaultAppModule, useDocumentById, useDocumentModelModuleById, useDocumentOperations, useDocumentVersionStatus, useDrives, useEditorModuleById, useEditorPreloader, useFallbackEditorModule, useIsAddDriveEnabled, useNodeParentFolderById, usePHModal, usePackageDiscoveryService, useReactorClientModule, useRevisionHistoryVisible, useSelectedDocument, useSelectedDocumentId, useSelectedDriveId, useSelectedDriveSafe, useSelectedFolder, useSelectedTimelineItem, useSync, useSyncList, useTheme, useUser, useVetraPackageManager, useVetraPackages } from "@powerhousedao/reactor-browser";
|
|
21
22
|
import { Icon, Modal, PowerhouseButton } from "@powerhousedao/design-system";
|
|
23
|
+
import { childLogger } from "document-model";
|
|
22
24
|
import { ErrorBoundary } from "react-error-boundary";
|
|
23
25
|
import { z } from "zod";
|
|
24
26
|
import { GenericDriveExplorer } from "@powerhousedao/powerhouse-vetra-packages/editors";
|
|
27
|
+
import { Outlet, RouterProvider, createBrowserRouter, createRoutesFromChildren, matchRoutes, useLocation, useNavigationType } from "react-router-dom";
|
|
28
|
+
import { redo, undo } from "@powerhousedao/shared/document-model";
|
|
29
|
+
import { useHotkeys } from "react-hotkeys-hook";
|
|
25
30
|
import { createReactorMcpProvider } from "@powerhousedao/reactor-mcp/tools";
|
|
26
31
|
import { ReactorChatFab, createSwitchboardSchemaTool } from "@powerhousedao/reactor-browser/ai";
|
|
27
32
|
import { twMerge } from "tailwind-merge";
|
|
@@ -29,1173 +34,1042 @@ import { mockAdapter } from "@renown/sdk/wallet/mock";
|
|
|
29
34
|
import { privyAdapter } from "@renown/sdk/wallet/privy";
|
|
30
35
|
import { rainbowAdapter } from "@renown/sdk/wallet/rainbow";
|
|
31
36
|
import { arbitrum, base, mainnet, optimism, polygon, sepolia } from "wagmi/chains";
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
function
|
|
35
|
-
|
|
36
|
-
return document.querySelector("base")?.getAttribute("href") || "/";
|
|
37
|
-
}
|
|
38
|
-
//#endregion
|
|
39
|
-
//#region src/utils/document-editor-debug-tools.ts
|
|
40
|
-
var DocumentEditorDebugTools = class {
|
|
41
|
-
document;
|
|
42
|
-
operations = [];
|
|
43
|
-
constructor(document) {
|
|
44
|
-
if (document) this.document = document;
|
|
45
|
-
}
|
|
46
|
-
operationsToTableObject(operations) {
|
|
47
|
-
return operations.map((op) => ({
|
|
48
|
-
...op,
|
|
49
|
-
input: JSON.stringify(op.action.input)
|
|
50
|
-
}));
|
|
51
|
-
}
|
|
52
|
-
setDocument(document) {
|
|
53
|
-
this.document = document;
|
|
54
|
-
}
|
|
55
|
-
getDocument() {
|
|
56
|
-
return this.document;
|
|
57
|
-
}
|
|
58
|
-
getOperations() {
|
|
59
|
-
return this.operations;
|
|
60
|
-
}
|
|
61
|
-
pushOperation(operation) {
|
|
62
|
-
this.operations.push(operation);
|
|
63
|
-
}
|
|
64
|
-
operationsTable() {
|
|
65
|
-
if (!this.document) console.warn("No document");
|
|
66
|
-
const ops = Object.values(this.document?.operations || {}).filter((array) => array !== void 0).flatMap((array) => array).sort((a, b) => a.index - b.index);
|
|
67
|
-
console.table(this.operationsToTableObject(ops));
|
|
68
|
-
}
|
|
69
|
-
scopeOperationsTable(scope) {
|
|
70
|
-
if (!this.document) console.warn("No document");
|
|
71
|
-
const ops = this.document?.operations[scope] || [];
|
|
72
|
-
console.table(this.operationsToTableObject(ops));
|
|
73
|
-
}
|
|
74
|
-
operationsLog() {
|
|
75
|
-
console.log(this.operations);
|
|
76
|
-
}
|
|
77
|
-
operationsLogTable() {
|
|
78
|
-
console.table(this.operationsToTableObject(this.operations));
|
|
79
|
-
}
|
|
80
|
-
clear() {
|
|
81
|
-
this.operations = [];
|
|
82
|
-
this.document = void 0;
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
//#endregion
|
|
86
|
-
//#region src/utils/launch-queue.ts
|
|
87
|
-
let pendingImportFiles = [];
|
|
88
|
-
const pendingListeners = /* @__PURE__ */ new Set();
|
|
89
|
-
function notifyPendingListeners() {
|
|
90
|
-
for (const listener of pendingListeners) listener();
|
|
91
|
-
}
|
|
92
|
-
function getPendingImportFiles() {
|
|
93
|
-
return pendingImportFiles;
|
|
37
|
+
//#region src/components/error-boundary.tsx
|
|
38
|
+
const logger$2 = childLogger(["Connect"]);
|
|
39
|
+
function hasCustomFallback(props) {
|
|
40
|
+
return "fallbackRender" in props;
|
|
94
41
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
return `${file.name}|${file.size}|${file.lastModified}`;
|
|
42
|
+
function SilentFallback() {
|
|
43
|
+
return null;
|
|
98
44
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Simple text-based fallback component.
|
|
47
|
+
* Displays a centered message when an error occurs.
|
|
48
|
+
*/
|
|
49
|
+
function TextFallback({ message = "Something went wrong" }) {
|
|
50
|
+
return /* @__PURE__ */ jsx("div", {
|
|
51
|
+
className: "text-center wrap-break-word text-foreground",
|
|
52
|
+
children: message
|
|
106
53
|
});
|
|
107
|
-
if (fresh.length === 0) return;
|
|
108
|
-
pendingImportFiles = [...pendingImportFiles, ...fresh];
|
|
109
|
-
notifyPendingListeners();
|
|
110
54
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Detailed fallback component showing full error information.
|
|
57
|
+
* Displays error message with a collapsible details section.
|
|
58
|
+
* Useful for development and debugging purposes.
|
|
59
|
+
*/
|
|
60
|
+
function DetailedFallback({ error, resetErrorBoundary }) {
|
|
61
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
62
|
+
const errorDetails = error instanceof Error ? error.stack ?? String(error.cause) : JSON.stringify(error, null, 2);
|
|
63
|
+
return /* @__PURE__ */ jsx("div", {
|
|
64
|
+
className: "z-10 mx-auto flex max-w-[80%] flex-1 items-center justify-center p-6",
|
|
65
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
66
|
+
className: "w-full max-w-lg rounded-lg border border-border bg-card p-6 text-foreground shadow-sm",
|
|
67
|
+
children: [
|
|
68
|
+
/* @__PURE__ */ jsxs("div", {
|
|
69
|
+
className: "mb-3 flex items-center gap-2",
|
|
70
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
71
|
+
name: "Error",
|
|
72
|
+
className: "size-5 shrink-0 text-destructive"
|
|
73
|
+
}), /* @__PURE__ */ jsx("h1", {
|
|
74
|
+
className: "text-lg font-semibold text-foreground",
|
|
75
|
+
children: "Something went wrong"
|
|
76
|
+
})]
|
|
77
|
+
}),
|
|
78
|
+
/* @__PURE__ */ jsx("p", {
|
|
79
|
+
className: "mb-4 text-sm wrap-break-word text-foreground",
|
|
80
|
+
children: errorMessage
|
|
81
|
+
}),
|
|
82
|
+
errorDetails !== "{}" && /* @__PURE__ */ jsxs("details", {
|
|
83
|
+
className: "group",
|
|
84
|
+
children: [/* @__PURE__ */ jsx("summary", {
|
|
85
|
+
className: "cursor-pointer text-sm font-medium text-foreground underline select-none hover:hover-effect",
|
|
86
|
+
children: "Show details"
|
|
87
|
+
}), /* @__PURE__ */ jsx("pre", {
|
|
88
|
+
className: "mt-2 max-h-48 overflow-auto rounded-sm bg-muted p-3 text-xs text-foreground",
|
|
89
|
+
children: errorDetails
|
|
90
|
+
})]
|
|
91
|
+
}),
|
|
92
|
+
/* @__PURE__ */ jsx(PowerhouseButton, {
|
|
93
|
+
type: "button",
|
|
94
|
+
onClick: resetErrorBoundary,
|
|
95
|
+
className: "mt-4 px-3 py-1.5 text-base font-medium",
|
|
96
|
+
children: "Try again"
|
|
97
|
+
})
|
|
98
|
+
]
|
|
99
|
+
})
|
|
100
|
+
});
|
|
115
101
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
102
|
+
/**
|
|
103
|
+
* Centered error message fallback component.
|
|
104
|
+
* Displays the error message in a centered, full-size container.
|
|
105
|
+
* Suitable for use as a custom fallbackRender when you need simple error display.
|
|
106
|
+
*/
|
|
107
|
+
function CenteredErrorMessage({ error }) {
|
|
108
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
109
|
+
return /* @__PURE__ */ jsx("div", {
|
|
110
|
+
className: "flex size-full items-center justify-center p-6",
|
|
111
|
+
children: /* @__PURE__ */ jsx("h3", {
|
|
112
|
+
className: "max-w-lg min-w-0 text-center text-lg font-semibold wrap-break-word text-foreground",
|
|
113
|
+
children: errorMessage
|
|
114
|
+
})
|
|
115
|
+
});
|
|
121
116
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
} catch (error) {
|
|
129
|
-
console.error("Failed to read launched file:", handle.name, error);
|
|
117
|
+
function getFallbackComponent(variant, fallbackMessage) {
|
|
118
|
+
switch (variant) {
|
|
119
|
+
case "silent": return SilentFallback;
|
|
120
|
+
case "text": return () => /* @__PURE__ */ jsx(TextFallback, { message: fallbackMessage });
|
|
121
|
+
case "detailed": return DetailedFallback;
|
|
122
|
+
default: return CenteredErrorMessage;
|
|
130
123
|
}
|
|
131
|
-
if (files.length === 0) return;
|
|
132
|
-
addPendingImportFiles(files);
|
|
133
|
-
showPHModal({ type: "openFileDocuments" });
|
|
134
124
|
}
|
|
135
|
-
function maybeReopenImportModal() {
|
|
136
|
-
if (getPendingImportFiles().length === 0) return;
|
|
137
|
-
if (window.ph?.modal !== void 0) return;
|
|
138
|
-
showPHModal({ type: "openFileDocuments" });
|
|
139
|
-
}
|
|
140
|
-
let initialized = false;
|
|
141
125
|
/**
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
126
|
+
* Unified error boundary component for catching and handling React errors.
|
|
127
|
+
*
|
|
128
|
+
* Built on top of `react-error-boundary`, this component provides:
|
|
129
|
+
* - Automatic error logging with configurable context
|
|
130
|
+
* - Multiple fallback UI variants (silent, text, detailed)
|
|
131
|
+
* - Support for custom fallback render functions
|
|
132
|
+
* - Reset capability via `resetKeys`
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* // Using a predefined variant
|
|
136
|
+
* <ErrorBoundary variant="detailed" loggerContext={["Connect", "Editor"]}>
|
|
137
|
+
* <EditorComponent />
|
|
138
|
+
* </ErrorBoundary>
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* // Using a custom message with the text variant
|
|
142
|
+
* <ErrorBoundary variant="text" fallbackMessage="Failed to load drives">
|
|
143
|
+
* <DrivesList />
|
|
144
|
+
* </ErrorBoundary>
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* // Using a custom fallback render
|
|
148
|
+
* <ErrorBoundary
|
|
149
|
+
* fallbackRender={CenteredErrorMessage}
|
|
150
|
+
* onError={(error) => trackError(error)}
|
|
151
|
+
* >
|
|
152
|
+
* <MyComponent />
|
|
153
|
+
* </ErrorBoundary>
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* // Silent mode for modals (renders null on error)
|
|
157
|
+
* <ErrorBoundary variant="silent" loggerContext={["Connect", "Modals"]}>
|
|
158
|
+
* <ModalContent />
|
|
159
|
+
* </ErrorBoundary>
|
|
147
160
|
*/
|
|
148
|
-
function
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
161
|
+
function ErrorBoundary$1(props) {
|
|
162
|
+
const { children, onError, resetKeys, loggerContext } = props;
|
|
163
|
+
const handleError = (error, info) => {
|
|
164
|
+
if (error.message.includes("Failed to fetch dynamically imported module") && error.message.includes("node_modules/.vite")) {
|
|
165
|
+
console.error(error);
|
|
166
|
+
console.log("Outdated chunk detected, reloading page...");
|
|
167
|
+
window.location.reload();
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
(loggerContext ? childLogger(loggerContext) : logger$2).error("@error @info", error, info);
|
|
171
|
+
onError?.(error, info);
|
|
172
|
+
};
|
|
173
|
+
const fallbackRender = hasCustomFallback(props) ? props.fallbackRender : getFallbackComponent(props.variant, props.fallbackMessage);
|
|
174
|
+
return /* @__PURE__ */ jsx(ErrorBoundary, {
|
|
175
|
+
fallbackRender,
|
|
176
|
+
onError: handleError,
|
|
177
|
+
resetKeys,
|
|
178
|
+
children
|
|
154
179
|
});
|
|
155
180
|
}
|
|
156
181
|
//#endregion
|
|
157
|
-
//#region src/
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
function notifyUploadListeners() {
|
|
161
|
-
for (const listener of listeners$1) listener();
|
|
162
|
-
}
|
|
163
|
-
function getOpenFileUploads() {
|
|
164
|
-
return uploads;
|
|
165
|
-
}
|
|
166
|
-
function subscribeOpenFileUploads(cb) {
|
|
167
|
-
listeners$1.add(cb);
|
|
168
|
-
return () => {
|
|
169
|
-
listeners$1.delete(cb);
|
|
170
|
-
};
|
|
182
|
+
//#region src/components/analytics.tsx
|
|
183
|
+
function gtag(...args) {
|
|
184
|
+
window.dataLayer?.push(...args);
|
|
171
185
|
}
|
|
172
|
-
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
let
|
|
195
|
-
let importChain = Promise.resolve();
|
|
186
|
+
const Analytics = () => {
|
|
187
|
+
const gaTrackingId = connectConfig.gaTrackingId;
|
|
188
|
+
const [{ analytics }] = useAcceptedCookies();
|
|
189
|
+
const useAnalytics = gaTrackingId && analytics;
|
|
190
|
+
useEffect(() => {
|
|
191
|
+
if (useAnalytics) {
|
|
192
|
+
const script = document.createElement("script");
|
|
193
|
+
script.src = `https://www.googletagmanager.com/gtag/js?id=${gaTrackingId}`;
|
|
194
|
+
script.async = true;
|
|
195
|
+
document.head.appendChild(script);
|
|
196
|
+
window.dataLayer = window.dataLayer || [];
|
|
197
|
+
gtag("js", /* @__PURE__ */ new Date());
|
|
198
|
+
gtag("config", gaTrackingId);
|
|
199
|
+
return () => {
|
|
200
|
+
document.head.removeChild(script);
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
}, [useAnalytics, gaTrackingId]);
|
|
204
|
+
return null;
|
|
205
|
+
};
|
|
206
|
+
//#endregion
|
|
207
|
+
//#region src/services/openpanel/client.ts
|
|
208
|
+
let client;
|
|
196
209
|
/**
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
* the
|
|
201
|
-
* were resolved in the picker (rename), so the conflict stage must never
|
|
202
|
-
* fire — this also covers a duplicate appearing between pre-check and import.
|
|
210
|
+
* Returns the cached `OpenPanel` singleton, building it on first call.
|
|
211
|
+
*
|
|
212
|
+
* When `config.clientId` is empty it returns `undefined` without importing
|
|
213
|
+
* `@openpanel/web`, so the bundler can tree-shake the SDK out of production.
|
|
203
214
|
*/
|
|
204
|
-
function
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
patchOpenFileUpload(row.id, {
|
|
214
|
-
status: mapProgressStageToStatus(progress.stage),
|
|
215
|
-
progress: progress.progress,
|
|
216
|
-
...progress.error ? { errorDetails: progress.error } : {},
|
|
217
|
-
...progress.documentType ? { documentType: progress.documentType } : {},
|
|
218
|
-
...progress.fileNode ? { fileNode: progress.fileNode } : {}
|
|
219
|
-
});
|
|
220
|
-
switch (progress.stage) {
|
|
221
|
-
case "complete":
|
|
222
|
-
settle(progress.fileNode);
|
|
223
|
-
break;
|
|
224
|
-
case "failed":
|
|
225
|
-
case "unsupported-document-type":
|
|
226
|
-
settle(void 0);
|
|
227
|
-
break;
|
|
228
|
-
default: break;
|
|
229
|
-
}
|
|
230
|
-
}, documentTypes, "duplicate").catch(() => {
|
|
231
|
-
settle(void 0);
|
|
232
|
-
});
|
|
215
|
+
async function getOpenPanelClient(config) {
|
|
216
|
+
if (!config.clientId) return;
|
|
217
|
+
if (client) return client;
|
|
218
|
+
const { OpenPanel: OpenPanelClass } = await import("@openpanel/web");
|
|
219
|
+
client = new OpenPanelClass({
|
|
220
|
+
clientId: config.clientId,
|
|
221
|
+
...config.apiUrl ? { apiUrl: config.apiUrl } : {},
|
|
222
|
+
trackScreenViews: true,
|
|
223
|
+
trackOutgoingLinks: true
|
|
233
224
|
});
|
|
225
|
+
client.setGlobalProperties({ app: "connect" });
|
|
226
|
+
drainOpenPanelBuffer(client);
|
|
227
|
+
return client;
|
|
234
228
|
}
|
|
235
229
|
/**
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
* single-file batch that succeeds opens its document in the editor.
|
|
230
|
+
* Clears the cached singleton and the pre-init buffer. Call on consent
|
|
231
|
+
* revocation or during tests; buffered events are discarded, not replayed.
|
|
239
232
|
*/
|
|
240
|
-
function
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
const rows = imports.map(({ file, name }) => ({
|
|
244
|
-
id: `open-file-${++uploadCounter}`,
|
|
245
|
-
file,
|
|
246
|
-
name
|
|
247
|
-
}));
|
|
248
|
-
addOpenFileUploads(rows.map((row) => ({
|
|
249
|
-
id: row.id,
|
|
250
|
-
fileName: row.name,
|
|
251
|
-
fileSize: formatFileSize(row.file.size),
|
|
252
|
-
status: "pending",
|
|
253
|
-
progress: 0
|
|
254
|
-
})));
|
|
255
|
-
const run = async () => {
|
|
256
|
-
const results = [];
|
|
257
|
-
for (const row of rows) results.push(await importOne(row, driveId, documentTypes));
|
|
258
|
-
if (rows.length === 1 && results[0]) setSelectedNode(results[0]);
|
|
259
|
-
};
|
|
260
|
-
importChain = importChain.then(run, run);
|
|
261
|
-
return importChain;
|
|
262
|
-
}
|
|
263
|
-
//#endregion
|
|
264
|
-
//#region src/components/migration-status.ts
|
|
265
|
-
let current = null;
|
|
266
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
267
|
-
function setMigrationStatus(status) {
|
|
268
|
-
current = status;
|
|
269
|
-
for (const l of listeners) l();
|
|
270
|
-
}
|
|
271
|
-
function getMigrationStatus() {
|
|
272
|
-
return current;
|
|
273
|
-
}
|
|
274
|
-
function subscribeMigrationStatus(cb) {
|
|
275
|
-
listeners.add(cb);
|
|
276
|
-
return () => {
|
|
277
|
-
listeners.delete(cb);
|
|
278
|
-
};
|
|
233
|
+
function resetOpenPanelClient() {
|
|
234
|
+
client = void 0;
|
|
235
|
+
clearOpenPanelBuffer();
|
|
279
236
|
}
|
|
280
237
|
//#endregion
|
|
281
|
-
//#region src/
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
238
|
+
//#region src/services/openpanel/events.json
|
|
239
|
+
var events_default = [
|
|
240
|
+
{
|
|
241
|
+
"documentType": "powerhouse/document-drive",
|
|
242
|
+
"actionTypes": [
|
|
243
|
+
"ADD_FOLDER",
|
|
244
|
+
"DELETE_NODE",
|
|
245
|
+
"ADD_FILE",
|
|
246
|
+
"UPDATE_FILE",
|
|
247
|
+
"COPY_NODE",
|
|
248
|
+
"MOVE_NODE",
|
|
249
|
+
"SET_DRIVE_NAME",
|
|
250
|
+
"SET_DRIVE_ICON"
|
|
251
|
+
]
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
"documentType": "powerhouse/document-model",
|
|
255
|
+
"actionTypes": [
|
|
256
|
+
"SET_MODEL_NAME",
|
|
257
|
+
"SET_MODEL_ID",
|
|
258
|
+
"ADD_MODULE",
|
|
259
|
+
"DELETE_MODULE",
|
|
260
|
+
"ADD_OPERATION",
|
|
261
|
+
"DELETE_OPERATION"
|
|
262
|
+
]
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
"documentType": "powerhouse/reactor-drive",
|
|
266
|
+
"actionTypes": [
|
|
267
|
+
"ADD_FOLDER",
|
|
268
|
+
"REMOVE_FOLDER",
|
|
269
|
+
"UPDATE_FOLDER"
|
|
270
|
+
]
|
|
313
271
|
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
272
|
+
];
|
|
273
|
+
//#endregion
|
|
274
|
+
//#region src/services/openpanel/events.ts
|
|
275
|
+
const EventMappingSchema = z.object({
|
|
276
|
+
documentType: z.string().min(1),
|
|
277
|
+
actionTypes: z.array(z.string().min(1)).min(1),
|
|
278
|
+
alias: z.string().optional()
|
|
279
|
+
}).strict();
|
|
280
|
+
const EventMappingsSchema = z.array(EventMappingSchema).readonly();
|
|
281
|
+
/**
|
|
282
|
+
* Parses and validates the event mapping table, returning the validated array
|
|
283
|
+
* and an O(1) lookup map. Accepts a `raw` override for tests. Throws on zod
|
|
284
|
+
* failures and on duplicate `(documentType, actionType)` pairs.
|
|
285
|
+
*/
|
|
286
|
+
function loadEvents(raw = events_default) {
|
|
287
|
+
const result = EventMappingsSchema.safeParse(raw);
|
|
288
|
+
if (!result.success) throw new Error(`Invalid OpenPanel events.json: ${result.error.message}`);
|
|
289
|
+
const mappings = result.data;
|
|
290
|
+
const lookupMap = /* @__PURE__ */ new Map();
|
|
291
|
+
for (const mapping of mappings) {
|
|
292
|
+
let inner = lookupMap.get(mapping.documentType);
|
|
293
|
+
if (!inner) {
|
|
294
|
+
inner = /* @__PURE__ */ new Map();
|
|
295
|
+
lookupMap.set(mapping.documentType, inner);
|
|
333
296
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
console.warn(`Failed to delete expired pglite backup ${rec.name}`, err);
|
|
338
|
-
keep.push(rec);
|
|
297
|
+
for (const actionType of mapping.actionTypes) {
|
|
298
|
+
if (inner.has(actionType)) throw new Error(`Duplicate OpenPanel event mapping for ${mapping.documentType}/${actionType}`);
|
|
299
|
+
inner.set(actionType, mapping);
|
|
339
300
|
}
|
|
340
301
|
}
|
|
341
|
-
writeBackupIndex(keep);
|
|
342
|
-
}
|
|
343
|
-
function createPersistentBackup() {
|
|
344
302
|
return {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
await cloneFileData(idbName, backupName);
|
|
348
|
-
registerBackup({
|
|
349
|
-
name: backupName,
|
|
350
|
-
idbName,
|
|
351
|
-
createdAt: Date.now()
|
|
352
|
-
});
|
|
353
|
-
return backupName;
|
|
354
|
-
},
|
|
355
|
-
rollback: async (handle, idbName, cause) => {
|
|
356
|
-
const backupName = handle;
|
|
357
|
-
try {
|
|
358
|
-
await cloneFileData(backupName, idbName);
|
|
359
|
-
} catch (rollbackErr) {
|
|
360
|
-
console.error(`PGlite migration rollback failed for ${idbName}; backup ${backupName} retained. Primary migration error:`, cause, "Rollback error:", rollbackErr);
|
|
361
|
-
return;
|
|
362
|
-
}
|
|
363
|
-
await deleteIdb(backupName).catch(() => void 0);
|
|
364
|
-
forgetBackup(backupName);
|
|
365
|
-
},
|
|
366
|
-
discard: async (handle) => {
|
|
367
|
-
const backupName = handle;
|
|
368
|
-
await deleteIdb(backupName).catch(() => void 0);
|
|
369
|
-
forgetBackup(backupName);
|
|
370
|
-
},
|
|
371
|
-
commit: () => Promise.resolve()
|
|
303
|
+
mappings,
|
|
304
|
+
lookupMap
|
|
372
305
|
};
|
|
373
306
|
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
phase
|
|
380
|
-
}), backup);
|
|
381
|
-
} finally {
|
|
382
|
-
setMigrationStatus(null);
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
async function migrateAllIfNeeded() {
|
|
386
|
-
janitor().catch((err) => console.warn("PGlite backup janitor failed", err));
|
|
387
|
-
if (!(typeof navigator !== "undefined" && "locks" in navigator && typeof navigator.locks.request === "function")) {
|
|
388
|
-
await migrateAllLocked();
|
|
389
|
-
return;
|
|
390
|
-
}
|
|
391
|
-
await navigator.locks.request("ph-pglite-migration", { mode: "exclusive" }, async () => {
|
|
392
|
-
await migrateAllLocked();
|
|
393
|
-
});
|
|
394
|
-
}
|
|
395
|
-
//#endregion
|
|
396
|
-
//#region src/hooks/useFailedInstallations.ts
|
|
397
|
-
const emptyArray$1 = [];
|
|
398
|
-
function useFailedInstallations() {
|
|
399
|
-
const discoveryService = usePackageDiscoveryService();
|
|
400
|
-
return useSyncExternalStore((cb) => discoveryService?.subscribeFailed(cb) ?? (() => {}), () => discoveryService?.getFailedInstallations() ?? emptyArray$1);
|
|
401
|
-
}
|
|
402
|
-
//#endregion
|
|
403
|
-
//#region src/hooks/useInitSentry.ts
|
|
404
|
-
const logger$2 = childLogger(["sentry"]);
|
|
405
|
-
let clientStarted = false;
|
|
406
|
-
async function getSentry() {
|
|
407
|
-
return await import("@sentry/react");
|
|
408
|
-
}
|
|
409
|
-
async function initSentry() {
|
|
410
|
-
const Sentry = await getSentry();
|
|
411
|
-
const integrations = [
|
|
412
|
-
Sentry.httpClientIntegration(),
|
|
413
|
-
Sentry.extraErrorDataIntegration({ depth: 5 }),
|
|
414
|
-
Sentry.replayIntegration(),
|
|
415
|
-
Sentry.captureConsoleIntegration({ levels: ["error"] })
|
|
416
|
-
];
|
|
417
|
-
if (connectConfig.sentry.tracing) integrations.push(Sentry.reactRouterV6BrowserTracingIntegration({
|
|
418
|
-
useEffect: React.useEffect,
|
|
419
|
-
useLocation,
|
|
420
|
-
useNavigationType,
|
|
421
|
-
createRoutesFromChildren,
|
|
422
|
-
matchRoutes
|
|
423
|
-
}));
|
|
424
|
-
Sentry.init({
|
|
425
|
-
release: connectConfig.sentry.release,
|
|
426
|
-
dsn: connectConfig.sentry.dsn ?? void 0,
|
|
427
|
-
environment: connectConfig.sentry.env,
|
|
428
|
-
integrations,
|
|
429
|
-
ignoreErrors: [
|
|
430
|
-
"User is not allowed to create files",
|
|
431
|
-
"User is not allowed to move documents",
|
|
432
|
-
"The user aborted a request."
|
|
433
|
-
],
|
|
434
|
-
sendDefaultPii: true,
|
|
435
|
-
tracesSampleRate: 1,
|
|
436
|
-
replaysSessionSampleRate: .1,
|
|
437
|
-
replaysOnErrorSampleRate: 1,
|
|
438
|
-
beforeSend(event, hint) {
|
|
439
|
-
const error = hint.originalException;
|
|
440
|
-
if (error instanceof TypeError && error.message.includes("Failed to fetch") && !navigator.onLine) return null;
|
|
441
|
-
return event;
|
|
442
|
-
}
|
|
443
|
-
});
|
|
444
|
-
setSentryModule(Sentry);
|
|
445
|
-
clientStarted = true;
|
|
446
|
-
}
|
|
447
|
-
async function closeClient() {
|
|
448
|
-
if (!clientStarted) return;
|
|
449
|
-
const sentry = await getSentry();
|
|
450
|
-
setSentryModule(void 0);
|
|
451
|
-
return sentry.getClient()?.close();
|
|
452
|
-
}
|
|
453
|
-
function useInitSentry() {
|
|
454
|
-
const [acceptedCookies] = useAcceptedCookies();
|
|
455
|
-
const { analytics } = acceptedCookies;
|
|
456
|
-
useEffect(() => {
|
|
457
|
-
if (!analytics) {
|
|
458
|
-
closeClient().catch((error) => logger$2.error("@error", error));
|
|
459
|
-
return;
|
|
460
|
-
}
|
|
461
|
-
if (clientStarted || connectConfig.sentry.dsn === null || connectConfig.sentry.dsn === void 0 || connectConfig.sentry.dsn === "") return;
|
|
462
|
-
initSentry().catch((error) => logger$2.error("@error", error));
|
|
463
|
-
}, [analytics]);
|
|
464
|
-
}
|
|
465
|
-
//#endregion
|
|
466
|
-
//#region src/services/openpanel/buffer.ts
|
|
467
|
-
const buffer = [];
|
|
468
|
-
let errorHandler;
|
|
469
|
-
function defaultOnError(err) {
|
|
470
|
-
console.warn("[useOpenPanelAnalytics] track failed:", err);
|
|
471
|
-
}
|
|
307
|
+
const { mappings: defaultMappings, lookupMap: defaultLookupMap } = loadEvents();
|
|
308
|
+
/** Validated mapping array from the bundled events.json. */
|
|
309
|
+
const eventMappings = defaultMappings;
|
|
310
|
+
/** O(1) lookup map: documentType → actionType → mapping. */
|
|
311
|
+
const eventLookupMap = defaultLookupMap;
|
|
472
312
|
/**
|
|
473
|
-
*
|
|
474
|
-
*
|
|
475
|
-
*
|
|
476
|
-
* inner `.catch()` handles rejected promises. Both are needed because
|
|
477
|
-
* `Promise.resolve(x).catch()` cannot catch a throw from evaluating `x`.
|
|
313
|
+
* Normalizes a document type into a safe event-name segment: lowercased, `/`
|
|
314
|
+
* replaced with `.`, and any character outside `[a-z0-9._-]` stripped.
|
|
315
|
+
* e.g. `powerhouse/document-drive` → `powerhouse.document-drive`.
|
|
478
316
|
*/
|
|
479
|
-
function
|
|
480
|
-
|
|
481
|
-
Promise.resolve(client.track(name, props)).catch((err) => (errorHandler ?? defaultOnError)(err));
|
|
482
|
-
} catch (err) {
|
|
483
|
-
(errorHandler ?? defaultOnError)(err);
|
|
484
|
-
}
|
|
317
|
+
function normalize(documentType) {
|
|
318
|
+
return documentType.toLowerCase().replace(/\//g, ".").replace(/[^a-z0-9._-]/g, "");
|
|
485
319
|
}
|
|
486
320
|
/**
|
|
487
|
-
*
|
|
488
|
-
*
|
|
321
|
+
* Derives the OpenPanel event name: `mapping.alias` when present, otherwise
|
|
322
|
+
* `${normalize(documentType)}.${actionType.toLowerCase()}`.
|
|
489
323
|
*/
|
|
490
|
-
function
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
for (const [name, props] of pending) forward(client, name, props);
|
|
324
|
+
function deriveEventName(mapping, op) {
|
|
325
|
+
if (mapping.alias) return mapping.alias;
|
|
326
|
+
return `${normalize(op.context.documentType)}.${op.operation.action.type.toLowerCase()}`;
|
|
494
327
|
}
|
|
495
328
|
/**
|
|
496
|
-
*
|
|
497
|
-
*
|
|
329
|
+
* Builds the default properties attached to every OpenPanel event. The `app`
|
|
330
|
+
* property is stamped globally by the client, not here.
|
|
498
331
|
*/
|
|
499
|
-
function
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
const discoveryService = usePackageDiscoveryService();
|
|
508
|
-
const cacheRef = useRef(emptyArray);
|
|
509
|
-
return useSyncExternalStore((cb) => discoveryService?.subscribePending(cb) ?? (() => {}), useCallback(() => {
|
|
510
|
-
if (!discoveryService) return emptyArray;
|
|
511
|
-
const next = discoveryService.getPendingInstallations() ?? emptyArray;
|
|
512
|
-
const prev = cacheRef.current;
|
|
513
|
-
if (next === prev || next.length === prev.length && next.every((p, i) => p === prev[i])) return prev;
|
|
514
|
-
cacheRef.current = next;
|
|
515
|
-
return next;
|
|
516
|
-
}, [discoveryService]));
|
|
332
|
+
function buildDefaultProperties(op) {
|
|
333
|
+
return {
|
|
334
|
+
documentType: op.context.documentType,
|
|
335
|
+
actionType: op.operation.action.type,
|
|
336
|
+
documentId: op.context.documentId,
|
|
337
|
+
scope: op.context.scope,
|
|
338
|
+
branch: op.context.branch
|
|
339
|
+
};
|
|
517
340
|
}
|
|
518
341
|
//#endregion
|
|
519
|
-
//#region src/
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
342
|
+
//#region src/services/openpanel/processor.ts
|
|
343
|
+
/**
|
|
344
|
+
* Read-only reactor `IProcessor` that translates matching document operations
|
|
345
|
+
* into OpenPanel analytics events. Operations whose `(documentType, actionType)`
|
|
346
|
+
* pair is absent from the lookup map are skipped; per-operation errors are
|
|
347
|
+
* routed to `onError` and never thrown back to the manager.
|
|
348
|
+
*/
|
|
349
|
+
var OpenPanelProcessor = class {
|
|
350
|
+
client;
|
|
351
|
+
lookupMap;
|
|
352
|
+
onError;
|
|
353
|
+
constructor(client, lookupMap, onError = (err) => console.warn("[OpenPanelProcessor] Error tracking event:", err)) {
|
|
354
|
+
this.client = client;
|
|
355
|
+
this.lookupMap = lookupMap;
|
|
356
|
+
this.onError = onError;
|
|
357
|
+
}
|
|
358
|
+
async onOperations(operations) {
|
|
359
|
+
for (const op of operations) {
|
|
360
|
+
const inner = this.lookupMap.get(op.context.documentType);
|
|
361
|
+
if (!inner) continue;
|
|
362
|
+
const mapping = inner.get(op.operation.action.type);
|
|
363
|
+
if (!mapping) continue;
|
|
364
|
+
const name = deriveEventName(mapping, op);
|
|
365
|
+
const payload = buildDefaultProperties(op);
|
|
366
|
+
try {
|
|
367
|
+
await this.client.track(name, payload);
|
|
368
|
+
} catch (err) {
|
|
369
|
+
this.onError(err, op);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
onDisconnect() {
|
|
374
|
+
this.client.flush?.();
|
|
375
|
+
return Promise.resolve();
|
|
528
376
|
}
|
|
529
|
-
useHotkeys(undoShortcut, (event) => {
|
|
530
|
-
event.preventDefault();
|
|
531
|
-
if (canUndo) undo();
|
|
532
|
-
}, {}, [canUndo, undo]);
|
|
533
|
-
useHotkeys(redoShortcut, (event) => {
|
|
534
|
-
event.preventDefault();
|
|
535
|
-
if (canRedo) redo();
|
|
536
|
-
}, {}, [canRedo, redo]);
|
|
537
|
-
};
|
|
538
|
-
//#endregion
|
|
539
|
-
//#region src/components/app-skeleton.tsx
|
|
540
|
-
const LOADER_DELAY = 250;
|
|
541
|
-
const PHASE_LABEL = {
|
|
542
|
-
clone: "Backing up local database…",
|
|
543
|
-
dump: "Exporting data from previous version…",
|
|
544
|
-
restore: "Restoring data into the new database…"
|
|
545
|
-
};
|
|
546
|
-
const MigrationOverlay = () => {
|
|
547
|
-
const status = useSyncExternalStore(subscribeMigrationStatus, getMigrationStatus, () => null);
|
|
548
|
-
if (!status) return null;
|
|
549
|
-
return /* @__PURE__ */ jsx("div", {
|
|
550
|
-
className: "absolute inset-0 z-20 flex items-center justify-center",
|
|
551
|
-
children: /* @__PURE__ */ jsxs("div", {
|
|
552
|
-
className: "rounded-lg bg-card/90 px-6 py-4 text-sm text-foreground shadow-lg",
|
|
553
|
-
children: [/* @__PURE__ */ jsx("div", {
|
|
554
|
-
className: "font-medium",
|
|
555
|
-
children: "Upgrading local database…"
|
|
556
|
-
}), /* @__PURE__ */ jsx("div", {
|
|
557
|
-
className: "text-foreground",
|
|
558
|
-
children: PHASE_LABEL[status.phase]
|
|
559
|
-
})]
|
|
560
|
-
})
|
|
561
|
-
});
|
|
562
|
-
};
|
|
563
|
-
const Loader = ({ delay = LOADER_DELAY }) => {
|
|
564
|
-
const isSSR = typeof window === "undefined";
|
|
565
|
-
const showInitialLoader = typeof document !== "undefined" && document.body.getAttribute("data-show-loader") === "true";
|
|
566
|
-
if (!isSSR) initTheme();
|
|
567
|
-
const [showLoading, setShowLoading] = useState(!delay || showInitialLoader);
|
|
568
|
-
useEffect(() => {
|
|
569
|
-
const id = setTimeout(() => {
|
|
570
|
-
setShowLoading(true);
|
|
571
|
-
}, delay);
|
|
572
|
-
return () => clearTimeout(id);
|
|
573
|
-
}, []);
|
|
574
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
575
|
-
className: `skeleton-loader absolute inset-0 z-10 flex items-center justify-center ${showLoading ? "" : "hidden"}`,
|
|
576
|
-
children: [/* @__PURE__ */ jsx("div", {
|
|
577
|
-
className: "animate-pulse overflow-hidden rounded-full shadow-lg",
|
|
578
|
-
children: /* @__PURE__ */ jsx(LogoAnimation, {})
|
|
579
|
-
}), isSSR ? /* @__PURE__ */ jsx("script", { dangerouslySetInnerHTML: { __html: `setTimeout(() => {
|
|
580
|
-
document.querySelector('.skeleton-loader')?.classList.remove('hidden');
|
|
581
|
-
document.body.setAttribute('data-show-loader', 'true');
|
|
582
|
-
}, ${delay})` } }) : null]
|
|
583
|
-
});
|
|
584
|
-
};
|
|
585
|
-
const AppSkeleton = (props) => {
|
|
586
|
-
const isSSR = typeof window === "undefined";
|
|
587
|
-
const isHomeScreen = !isSSR && window.location.pathname === getBasePath();
|
|
588
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
589
|
-
className: "flex h-screen overflow-hidden bg-background",
|
|
590
|
-
children: [
|
|
591
|
-
!(!isSSR && getIsEmbedded()) && /* @__PURE__ */ jsx(ConnectSidebar, {
|
|
592
|
-
className: "animate-pulse",
|
|
593
|
-
onLogin: void 0,
|
|
594
|
-
onDisconnect: void 0,
|
|
595
|
-
onClickSettings: void 0,
|
|
596
|
-
address: void 0
|
|
597
|
-
}),
|
|
598
|
-
/* @__PURE__ */ jsx(HomeScreen, {
|
|
599
|
-
containerClassName: isSSR || !isHomeScreen ? "home-screen hidden" : void 0,
|
|
600
|
-
children: props.children ?? null
|
|
601
|
-
}),
|
|
602
|
-
isSSR ? /* @__PURE__ */ jsx("script", { dangerouslySetInnerHTML: { __html: `
|
|
603
|
-
const baseEl = document.querySelector('base');
|
|
604
|
-
const href = baseEl?.getAttribute('href');
|
|
605
|
-
const basePath = href || '/';
|
|
606
|
-
if (window.location.pathname === basePath) {
|
|
607
|
-
document.querySelector('.home-screen')?.classList.remove('hidden')
|
|
608
|
-
}` } }) : null,
|
|
609
|
-
!props.children ? /* @__PURE__ */ jsx(Loader, {}) : null,
|
|
610
|
-
/* @__PURE__ */ jsx(MigrationOverlay, {})
|
|
611
|
-
]
|
|
612
|
-
});
|
|
613
377
|
};
|
|
614
378
|
//#endregion
|
|
615
|
-
//#region src/
|
|
616
|
-
const logger$1 = childLogger(["Connect"]);
|
|
617
|
-
function hasCustomFallback(props) {
|
|
618
|
-
return "fallbackRender" in props;
|
|
619
|
-
}
|
|
620
|
-
function SilentFallback() {
|
|
621
|
-
return null;
|
|
622
|
-
}
|
|
379
|
+
//#region src/services/openpanel/factory.ts
|
|
623
380
|
/**
|
|
624
|
-
*
|
|
625
|
-
*
|
|
381
|
+
* Returns a `ProcessorFactory` that, for each drive, creates a single
|
|
382
|
+
* `OpenPanelProcessor` record whose `filter.documentType` is the union of all
|
|
383
|
+
* document types present in the event mapping table.
|
|
626
384
|
*/
|
|
627
|
-
function
|
|
628
|
-
return
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
385
|
+
function createOpenPanelProcessorFactory(config) {
|
|
386
|
+
return function openPanelProcessorFactory(_driveHeader) {
|
|
387
|
+
const documentType = Array.from(config.events.lookupMap.keys());
|
|
388
|
+
return [{
|
|
389
|
+
processor: new OpenPanelProcessor(config.client, config.events.lookupMap, config.onError),
|
|
390
|
+
filter: { documentType },
|
|
391
|
+
startFrom: config.startFrom ?? "current"
|
|
392
|
+
}];
|
|
393
|
+
};
|
|
632
394
|
}
|
|
395
|
+
//#endregion
|
|
396
|
+
//#region src/components/openpanel-traits.ts
|
|
633
397
|
/**
|
|
634
|
-
*
|
|
635
|
-
*
|
|
636
|
-
*
|
|
398
|
+
* Builds the OpenPanel identity traits from a renown User.
|
|
399
|
+
*
|
|
400
|
+
* Canonical trait schema (shared with Renown and Vetra — each app sends every
|
|
401
|
+
* field it has data for, under these names):
|
|
402
|
+
* - `address`, `did`, `networkId`, `chainId`, `caip2` — wallet/chain facts.
|
|
403
|
+
* - `ensName`, `ensAvatar` — raw ENS facts.
|
|
404
|
+
* - `username`, `userImage`, `profileDocumentId`, `profileCreatedAt` — raw
|
|
405
|
+
* Renown profile facts.
|
|
406
|
+
* - `accountType` — wallet-adapter concept; only Renown has it.
|
|
407
|
+
*
|
|
408
|
+
* Rules:
|
|
409
|
+
* - `credential` (contains a JWT) is **never** forwarded.
|
|
410
|
+
* - Traits carry raw facts only; resolved presentation values (avatar,
|
|
411
|
+
* display name) go in OpenPanel's native identify fields — see
|
|
412
|
+
* {@link buildIdentifyPayload}.
|
|
413
|
+
* - Optional fields (`ens`, `profile`) are only included when their value is
|
|
414
|
+
* non-nullish (guards against `null` from `RenownProfile` fields as well
|
|
415
|
+
* as plain `undefined`).
|
|
416
|
+
*
|
|
417
|
+
* Mirror the Sentry pattern in `store/user.ts`: destructure off `credential`
|
|
418
|
+
* first, then assemble the trait payload from the remainder.
|
|
637
419
|
*/
|
|
638
|
-
function
|
|
639
|
-
const
|
|
640
|
-
const
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
})]
|
|
655
|
-
}),
|
|
656
|
-
/* @__PURE__ */ jsx("p", {
|
|
657
|
-
className: "mb-4 text-sm wrap-break-word text-foreground",
|
|
658
|
-
children: errorMessage
|
|
659
|
-
}),
|
|
660
|
-
errorDetails !== "{}" && /* @__PURE__ */ jsxs("details", {
|
|
661
|
-
className: "group",
|
|
662
|
-
children: [/* @__PURE__ */ jsx("summary", {
|
|
663
|
-
className: "cursor-pointer text-sm font-medium text-foreground underline select-none hover:hover-effect",
|
|
664
|
-
children: "Show details"
|
|
665
|
-
}), /* @__PURE__ */ jsx("pre", {
|
|
666
|
-
className: "mt-2 max-h-48 overflow-auto rounded-sm bg-muted p-3 text-xs text-foreground",
|
|
667
|
-
children: errorDetails
|
|
668
|
-
})]
|
|
669
|
-
}),
|
|
670
|
-
/* @__PURE__ */ jsx(PowerhouseButton, {
|
|
671
|
-
type: "button",
|
|
672
|
-
onClick: resetErrorBoundary,
|
|
673
|
-
className: "mt-4 px-3 py-1.5 text-base font-medium",
|
|
674
|
-
children: "Try again"
|
|
675
|
-
})
|
|
676
|
-
]
|
|
677
|
-
})
|
|
678
|
-
});
|
|
420
|
+
function buildTraits(user) {
|
|
421
|
+
const { credential: _credential, ...rest } = user;
|
|
422
|
+
const traits = {
|
|
423
|
+
address: rest.address,
|
|
424
|
+
did: rest.did,
|
|
425
|
+
networkId: rest.networkId,
|
|
426
|
+
chainId: rest.chainId,
|
|
427
|
+
caip2: `${rest.networkId}:${rest.chainId}`
|
|
428
|
+
};
|
|
429
|
+
if (rest.ens?.name != null) traits.ensName = rest.ens.name;
|
|
430
|
+
if (rest.ens?.avatarUrl != null) traits.ensAvatar = rest.ens.avatarUrl;
|
|
431
|
+
if (rest.profile?.username != null) traits.username = rest.profile.username;
|
|
432
|
+
if (rest.profile?.userImage != null) traits.userImage = rest.profile.userImage;
|
|
433
|
+
if (rest.profile?.documentId != null) traits.profileDocumentId = rest.profile.documentId;
|
|
434
|
+
if (rest.profile?.createdAt != null) traits.profileCreatedAt = rest.profile.createdAt;
|
|
435
|
+
return traits;
|
|
679
436
|
}
|
|
680
437
|
/**
|
|
681
|
-
*
|
|
682
|
-
*
|
|
683
|
-
*
|
|
438
|
+
* Builds the full `identify()` payload:
|
|
439
|
+
* - `profileId` is the wallet address — the cross-app profile key shared with
|
|
440
|
+
* Renown and Vetra.
|
|
441
|
+
* - `avatar` / `firstName` are OpenPanel's native profile fields (they drive
|
|
442
|
+
* the picture and name in the dashboard UI), resolved as
|
|
443
|
+
* `userImage ?? ensAvatar` and `ensName ?? username`.
|
|
444
|
+
* - `properties` are the raw traits from {@link buildTraits}.
|
|
684
445
|
*/
|
|
685
|
-
function
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
}
|
|
694
|
-
function getFallbackComponent(variant, fallbackMessage) {
|
|
695
|
-
switch (variant) {
|
|
696
|
-
case "silent": return SilentFallback;
|
|
697
|
-
case "text": return () => /* @__PURE__ */ jsx(TextFallback, { message: fallbackMessage });
|
|
698
|
-
case "detailed": return DetailedFallback;
|
|
699
|
-
default: return CenteredErrorMessage;
|
|
700
|
-
}
|
|
446
|
+
function buildIdentifyPayload(user) {
|
|
447
|
+
const avatar = user.profile?.userImage ?? user.ens?.avatarUrl;
|
|
448
|
+
const firstName = user.ens?.name ?? user.profile?.username;
|
|
449
|
+
return {
|
|
450
|
+
profileId: user.address,
|
|
451
|
+
...avatar != null ? { avatar } : {},
|
|
452
|
+
...firstName != null ? { firstName } : {},
|
|
453
|
+
properties: buildTraits(user)
|
|
454
|
+
};
|
|
701
455
|
}
|
|
456
|
+
//#endregion
|
|
457
|
+
//#region src/components/openpanel.tsx
|
|
702
458
|
/**
|
|
703
|
-
*
|
|
459
|
+
* `OpenPanel` is a `null`-rendering component that manages the full lifecycle
|
|
460
|
+
* of the OpenPanel analytics subsystem.
|
|
704
461
|
*
|
|
705
|
-
*
|
|
706
|
-
* -
|
|
707
|
-
* -
|
|
708
|
-
* - Support for custom fallback render functions
|
|
709
|
-
* - Reset capability via `resetKeys`
|
|
462
|
+
* Gates:
|
|
463
|
+
* - `useAcceptedCookies().analytics === true` — the existing analytics cookie.
|
|
464
|
+
* - `connectConfig.openPanel.clientId` non-empty — no client ID → no-op.
|
|
710
465
|
*
|
|
711
|
-
*
|
|
712
|
-
*
|
|
713
|
-
*
|
|
714
|
-
*
|
|
715
|
-
*
|
|
466
|
+
* Behaviour when both gates pass:
|
|
467
|
+
* 1. Lazy-imports `@openpanel/web` and builds the singleton via
|
|
468
|
+
* `getOpenPanelClient(connectConfig.openPanel)`.
|
|
469
|
+
* 2. Exposes the client on `window.openPanel` for the card-6
|
|
470
|
+
* `useOpenPanelAnalytics()` hook to consume.
|
|
471
|
+
* 3. If `connectConfig.openPanel.trackOperations`, registers the processor
|
|
472
|
+
* factory against `processorManager` so document operations are forwarded.
|
|
473
|
+
* 4. Calls `client.identify()` when the renown user transitions from
|
|
474
|
+
* `undefined` → defined (login). The profile ID is the wallet address —
|
|
475
|
+
* the cross-app key shared with Renown and Vetra.
|
|
476
|
+
* 5. Calls `client.clear()` when the user transitions from defined →
|
|
477
|
+
* `undefined` (logout).
|
|
716
478
|
*
|
|
717
|
-
*
|
|
718
|
-
*
|
|
719
|
-
*
|
|
720
|
-
*
|
|
721
|
-
* </ErrorBoundary>
|
|
479
|
+
* Teardown (unmount **or** consent revocation):
|
|
480
|
+
* - `unregisterFactory("openpanel")` to remove the processor.
|
|
481
|
+
* - `resetOpenPanelClient()` to clear the singleton.
|
|
482
|
+
* - `window.openPanel` is cleared.
|
|
722
483
|
*
|
|
723
|
-
*
|
|
724
|
-
*
|
|
725
|
-
*
|
|
726
|
-
* fallbackRender={CenteredErrorMessage}
|
|
727
|
-
* onError={(error) => trackError(error)}
|
|
728
|
-
* >
|
|
729
|
-
* <MyComponent />
|
|
730
|
-
* </ErrorBoundary>
|
|
484
|
+
* Mirrors the Sentry pattern in `store/user.ts` for login/logout detection.
|
|
485
|
+
* Analytics failures are caught and forwarded to `console.warn` — they must
|
|
486
|
+
* never throw into the application.
|
|
731
487
|
*
|
|
732
|
-
*
|
|
733
|
-
* // Silent mode for modals (renders null on error)
|
|
734
|
-
* <ErrorBoundary variant="silent" loggerContext={["Connect", "Modals"]}>
|
|
735
|
-
* <ModalContent />
|
|
736
|
-
* </ErrorBoundary>
|
|
488
|
+
* Mounted next to `<Analytics />` in `app.tsx`.
|
|
737
489
|
*/
|
|
738
|
-
function
|
|
739
|
-
const {
|
|
740
|
-
const
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
490
|
+
function OpenPanel() {
|
|
491
|
+
const [{ analytics }] = useAcceptedCookies();
|
|
492
|
+
const user = useUser();
|
|
493
|
+
const module = useReactorClientModule();
|
|
494
|
+
const reactorClientModule = module?.kind === "browser" ? module : void 0;
|
|
495
|
+
const [client, setClient] = useState();
|
|
496
|
+
/**
|
|
497
|
+
* Tracks the previous `user` value so we can detect the two transitions:
|
|
498
|
+
* undefined → defined (login)
|
|
499
|
+
* defined → undefined (logout)
|
|
500
|
+
*/
|
|
501
|
+
const prevUserRef = useRef(void 0);
|
|
502
|
+
const enabled = analytics && !!connectConfig.openPanel.clientId;
|
|
503
|
+
const processorManager = reactorClientModule?.reactorModule?.processorManager;
|
|
504
|
+
useEffect(() => {
|
|
505
|
+
if (!enabled) return;
|
|
506
|
+
let cancelled = false;
|
|
507
|
+
const isCancelled = () => cancelled;
|
|
508
|
+
const setup = async () => {
|
|
509
|
+
let builtClient;
|
|
510
|
+
try {
|
|
511
|
+
builtClient = await getOpenPanelClient(connectConfig.openPanel);
|
|
512
|
+
} catch (err) {
|
|
513
|
+
console.warn("[OpenPanel] Failed to build client:", err);
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
if (isCancelled() || !builtClient) return;
|
|
517
|
+
setClient(builtClient);
|
|
518
|
+
window.openPanel = builtClient;
|
|
519
|
+
if (connectConfig.openPanel.trackOperations && processorManager) try {
|
|
520
|
+
await processorManager.registerFactory("openpanel", createOpenPanelProcessorFactory({
|
|
521
|
+
client: builtClient,
|
|
522
|
+
events: {
|
|
523
|
+
mappings: eventMappings,
|
|
524
|
+
lookupMap: eventLookupMap
|
|
525
|
+
},
|
|
526
|
+
startFrom: "current"
|
|
527
|
+
}));
|
|
528
|
+
if (isCancelled()) await processorManager.unregisterFactory("openpanel").catch((err) => console.warn("[OpenPanel] Failed to unregister factory after cancellation:", err));
|
|
529
|
+
} catch (err) {
|
|
530
|
+
console.warn("[OpenPanel] Failed to register processor factory:", err);
|
|
531
|
+
}
|
|
532
|
+
};
|
|
533
|
+
setup();
|
|
534
|
+
return () => {
|
|
535
|
+
cancelled = true;
|
|
536
|
+
prevUserRef.current = void 0;
|
|
537
|
+
if (connectConfig.openPanel.trackOperations && processorManager) processorManager.unregisterFactory("openpanel").catch((err) => console.warn("[OpenPanel] Failed to unregister processor factory:", err));
|
|
538
|
+
resetOpenPanelClient();
|
|
539
|
+
window.openPanel = void 0;
|
|
540
|
+
setClient(void 0);
|
|
541
|
+
};
|
|
542
|
+
}, [enabled, processorManager]);
|
|
543
|
+
useEffect(() => {
|
|
544
|
+
if (!enabled || !client) return;
|
|
545
|
+
const prev = prevUserRef.current;
|
|
546
|
+
prevUserRef.current = user;
|
|
547
|
+
if (!prev && user) try {
|
|
548
|
+
client.identify(buildIdentifyPayload(user));
|
|
549
|
+
} catch (err) {
|
|
550
|
+
console.warn("[OpenPanel] Failed to identify user:", err);
|
|
746
551
|
}
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
552
|
+
else if (prev && !user) try {
|
|
553
|
+
client.clear();
|
|
554
|
+
} catch (err) {
|
|
555
|
+
console.warn("[OpenPanel] Failed to clear user:", err);
|
|
556
|
+
}
|
|
557
|
+
}, [
|
|
558
|
+
client,
|
|
559
|
+
user,
|
|
560
|
+
enabled
|
|
561
|
+
]);
|
|
562
|
+
return null;
|
|
756
563
|
}
|
|
757
564
|
//#endregion
|
|
758
|
-
//#region src/components/
|
|
759
|
-
function
|
|
760
|
-
|
|
565
|
+
//#region src/components/document-editor-container.tsx
|
|
566
|
+
function DocumentEditorContainer() {
|
|
567
|
+
const [selectedDocument] = useSelectedDocument();
|
|
568
|
+
const parentFolder = useNodeParentFolderById(selectedDocument.header.id);
|
|
569
|
+
useMemo(() => {
|
|
570
|
+
return async () => {};
|
|
571
|
+
}, []);
|
|
572
|
+
useCallback(() => {
|
|
573
|
+
setSelectedNode(parentFolder);
|
|
574
|
+
}, [parentFolder]);
|
|
575
|
+
return /* @__PURE__ */ jsx("div", {
|
|
576
|
+
id: "document-editor-container",
|
|
577
|
+
className: "flex-1",
|
|
578
|
+
"data-document-type": selectedDocument.header.documentType,
|
|
579
|
+
children: /* @__PURE__ */ jsx(DocumentEditor, { document: selectedDocument })
|
|
580
|
+
});
|
|
761
581
|
}
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
const
|
|
582
|
+
//#endregion
|
|
583
|
+
//#region src/components/editor-loader.tsx
|
|
584
|
+
function EditorLoader(props) {
|
|
585
|
+
const [showLoading, setShowLoading] = useState(false);
|
|
766
586
|
useEffect(() => {
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
document.head.removeChild(script);
|
|
777
|
-
};
|
|
778
|
-
}
|
|
779
|
-
}, [useAnalytics, gaTrackingId]);
|
|
780
|
-
return null;
|
|
781
|
-
};
|
|
587
|
+
setTimeout(() => {
|
|
588
|
+
setShowLoading(true);
|
|
589
|
+
}, props.loadingTimeout ?? 200);
|
|
590
|
+
}, [props]);
|
|
591
|
+
if (!showLoading) return null;
|
|
592
|
+
const { customEditorLoader, ...defaultProps } = props;
|
|
593
|
+
if (customEditorLoader) return /* @__PURE__ */ jsx(Fragment, { children: customEditorLoader });
|
|
594
|
+
return /* @__PURE__ */ jsx(DefaultEditorLoader, { ...defaultProps });
|
|
595
|
+
}
|
|
782
596
|
//#endregion
|
|
783
|
-
//#region src/
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
597
|
+
//#region src/components/app-container.tsx
|
|
598
|
+
function AppContainer() {
|
|
599
|
+
const [selectedDrive] = useSelectedDriveSafe();
|
|
600
|
+
const selectedDocumentId = useSelectedDocumentId();
|
|
601
|
+
const app = useAppModuleById(selectedDrive?.header.meta?.preferredEditor);
|
|
602
|
+
const defaultApp = useDefaultAppModule();
|
|
603
|
+
if (!selectedDrive) return /* @__PURE__ */ jsx(EditorLoader, {});
|
|
604
|
+
const AppComponent = app?.Component ?? defaultApp?.Component ?? GenericDriveExplorer.Component;
|
|
605
|
+
if (!AppComponent) throw new Error("No app component found");
|
|
606
|
+
return /* @__PURE__ */ jsx(ErrorBoundary$1, {
|
|
607
|
+
variant: "detailed",
|
|
608
|
+
resetKeys: [selectedDrive.header.id],
|
|
609
|
+
loggerContext: ["Connect", "App"],
|
|
610
|
+
children: /* @__PURE__ */ jsx(Suspense, {
|
|
611
|
+
fallback: /* @__PURE__ */ jsx(EditorLoader, {}),
|
|
612
|
+
children: /* @__PURE__ */ jsx(DropZoneWrapper, {
|
|
613
|
+
className: "flex h-full flex-col overflow-auto",
|
|
614
|
+
children: /* @__PURE__ */ jsx(AppComponent, { children: selectedDocumentId ? /* @__PURE__ */ jsx(DocumentEditorContainer, {}) : null })
|
|
615
|
+
})
|
|
616
|
+
})
|
|
800
617
|
});
|
|
801
|
-
client.setGlobalProperties({ app: "connect" });
|
|
802
|
-
drainOpenPanelBuffer(client);
|
|
803
|
-
return client;
|
|
804
|
-
}
|
|
805
|
-
/**
|
|
806
|
-
* Clears the cached singleton and the pre-init buffer. Call on consent
|
|
807
|
-
* revocation or during tests; buffered events are discarded, not replayed.
|
|
808
|
-
*/
|
|
809
|
-
function resetOpenPanelClient() {
|
|
810
|
-
client = void 0;
|
|
811
|
-
clearOpenPanelBuffer();
|
|
812
618
|
}
|
|
813
619
|
//#endregion
|
|
814
|
-
//#region src/
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
"DELETE_NODE",
|
|
821
|
-
"ADD_FILE",
|
|
822
|
-
"UPDATE_FILE",
|
|
823
|
-
"COPY_NODE",
|
|
824
|
-
"MOVE_NODE",
|
|
825
|
-
"SET_DRIVE_NAME",
|
|
826
|
-
"SET_DRIVE_ICON"
|
|
827
|
-
]
|
|
828
|
-
},
|
|
829
|
-
{
|
|
830
|
-
"documentType": "powerhouse/document-model",
|
|
831
|
-
"actionTypes": [
|
|
832
|
-
"SET_MODEL_NAME",
|
|
833
|
-
"SET_MODEL_ID",
|
|
834
|
-
"ADD_MODULE",
|
|
835
|
-
"DELETE_MODULE",
|
|
836
|
-
"ADD_OPERATION",
|
|
837
|
-
"DELETE_OPERATION"
|
|
838
|
-
]
|
|
839
|
-
},
|
|
840
|
-
{
|
|
841
|
-
"documentType": "powerhouse/reactor-drive",
|
|
842
|
-
"actionTypes": [
|
|
843
|
-
"ADD_FOLDER",
|
|
844
|
-
"REMOVE_FOLDER",
|
|
845
|
-
"UPDATE_FOLDER"
|
|
846
|
-
]
|
|
847
|
-
}
|
|
848
|
-
];
|
|
620
|
+
//#region src/hooks/useFailedInstallations.ts
|
|
621
|
+
const emptyArray$1 = [];
|
|
622
|
+
function useFailedInstallations() {
|
|
623
|
+
const discoveryService = usePackageDiscoveryService();
|
|
624
|
+
return useSyncExternalStore((cb) => discoveryService?.subscribeFailed(cb) ?? (() => {}), () => discoveryService?.getFailedInstallations() ?? emptyArray$1);
|
|
625
|
+
}
|
|
849
626
|
//#endregion
|
|
850
|
-
//#region src/
|
|
851
|
-
const
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
if (
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
627
|
+
//#region src/hooks/useInitSentry.ts
|
|
628
|
+
const logger$1 = childLogger(["sentry"]);
|
|
629
|
+
let clientStarted = false;
|
|
630
|
+
async function getSentry() {
|
|
631
|
+
return await import("@sentry/react");
|
|
632
|
+
}
|
|
633
|
+
async function initSentry() {
|
|
634
|
+
const Sentry = await getSentry();
|
|
635
|
+
const integrations = [
|
|
636
|
+
Sentry.httpClientIntegration(),
|
|
637
|
+
Sentry.extraErrorDataIntegration({ depth: 5 }),
|
|
638
|
+
Sentry.replayIntegration(),
|
|
639
|
+
Sentry.captureConsoleIntegration({ levels: ["error"] })
|
|
640
|
+
];
|
|
641
|
+
if (connectConfig.sentry.tracing) integrations.push(Sentry.reactRouterV6BrowserTracingIntegration({
|
|
642
|
+
useEffect: React.useEffect,
|
|
643
|
+
useLocation,
|
|
644
|
+
useNavigationType,
|
|
645
|
+
createRoutesFromChildren,
|
|
646
|
+
matchRoutes
|
|
647
|
+
}));
|
|
648
|
+
Sentry.init({
|
|
649
|
+
release: connectConfig.sentry.release,
|
|
650
|
+
dsn: connectConfig.sentry.dsn ?? void 0,
|
|
651
|
+
environment: connectConfig.sentry.env,
|
|
652
|
+
integrations,
|
|
653
|
+
ignoreErrors: [
|
|
654
|
+
"User is not allowed to create files",
|
|
655
|
+
"User is not allowed to move documents",
|
|
656
|
+
"The user aborted a request."
|
|
657
|
+
],
|
|
658
|
+
sendDefaultPii: true,
|
|
659
|
+
tracesSampleRate: 1,
|
|
660
|
+
replaysSessionSampleRate: .1,
|
|
661
|
+
replaysOnErrorSampleRate: 1,
|
|
662
|
+
beforeSend(event, hint) {
|
|
663
|
+
const error = hint.originalException;
|
|
664
|
+
if (error instanceof TypeError && error.message.includes("Failed to fetch") && !navigator.onLine) return null;
|
|
665
|
+
return event;
|
|
876
666
|
}
|
|
877
|
-
}
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
lookupMap
|
|
881
|
-
};
|
|
667
|
+
});
|
|
668
|
+
setSentryModule(Sentry);
|
|
669
|
+
clientStarted = true;
|
|
882
670
|
}
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
const
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
/**
|
|
889
|
-
* Normalizes a document type into a safe event-name segment: lowercased, `/`
|
|
890
|
-
* replaced with `.`, and any character outside `[a-z0-9._-]` stripped.
|
|
891
|
-
* e.g. `powerhouse/document-drive` → `powerhouse.document-drive`.
|
|
892
|
-
*/
|
|
893
|
-
function normalize(documentType) {
|
|
894
|
-
return documentType.toLowerCase().replace(/\//g, ".").replace(/[^a-z0-9._-]/g, "");
|
|
671
|
+
async function closeClient() {
|
|
672
|
+
if (!clientStarted) return;
|
|
673
|
+
const sentry = await getSentry();
|
|
674
|
+
setSentryModule(void 0);
|
|
675
|
+
return sentry.getClient()?.close();
|
|
895
676
|
}
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
677
|
+
function useInitSentry() {
|
|
678
|
+
const [acceptedCookies] = useAcceptedCookies();
|
|
679
|
+
const { analytics } = acceptedCookies;
|
|
680
|
+
useEffect(() => {
|
|
681
|
+
if (!analytics) {
|
|
682
|
+
closeClient().catch((error) => logger$1.error("@error", error));
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
685
|
+
if (clientStarted || connectConfig.sentry.dsn === null || connectConfig.sentry.dsn === void 0 || connectConfig.sentry.dsn === "") return;
|
|
686
|
+
initSentry().catch((error) => logger$1.error("@error", error));
|
|
687
|
+
}, [analytics]);
|
|
903
688
|
}
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
689
|
+
//#endregion
|
|
690
|
+
//#region src/hooks/usePendingInstallations.ts
|
|
691
|
+
const emptyArray = [];
|
|
692
|
+
function usePendingInstallations() {
|
|
693
|
+
const discoveryService = usePackageDiscoveryService();
|
|
694
|
+
const cacheRef = useRef(emptyArray);
|
|
695
|
+
const getSnapshot = useCallback(() => {
|
|
696
|
+
if (!discoveryService) return emptyArray;
|
|
697
|
+
const next = discoveryService.getPendingInstallations() ?? emptyArray;
|
|
698
|
+
const prev = cacheRef.current;
|
|
699
|
+
if (next === prev || next.length === prev.length && next.every((p, i) => p === prev[i])) return prev;
|
|
700
|
+
cacheRef.current = next;
|
|
701
|
+
return next;
|
|
702
|
+
}, [discoveryService]);
|
|
703
|
+
return useSyncExternalStore((cb) => discoveryService?.subscribePending(cb) ?? (() => {}), getSnapshot);
|
|
916
704
|
}
|
|
917
705
|
//#endregion
|
|
918
|
-
//#region src/
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
this.client = client;
|
|
928
|
-
this.lookupMap = lookupMap;
|
|
929
|
-
this.onError = onError;
|
|
706
|
+
//#region src/hooks/useUndoRedoShortcuts.ts
|
|
707
|
+
const useUndoRedoShortcuts = (props) => {
|
|
708
|
+
const { undo, redo, canRedo, canUndo } = props;
|
|
709
|
+
const isMac = window.navigator.userAgent.includes("Mac");
|
|
710
|
+
let undoShortcut = "ctrl+z";
|
|
711
|
+
let redoShortcut = "ctrl+y";
|
|
712
|
+
if (isMac) {
|
|
713
|
+
undoShortcut = "mod+z";
|
|
714
|
+
redoShortcut = "mod+shift+z";
|
|
930
715
|
}
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
716
|
+
useHotkeys(undoShortcut, (event) => {
|
|
717
|
+
event.preventDefault();
|
|
718
|
+
if (canUndo) undo();
|
|
719
|
+
}, {}, [canUndo, undo]);
|
|
720
|
+
useHotkeys(redoShortcut, (event) => {
|
|
721
|
+
event.preventDefault();
|
|
722
|
+
if (canRedo) redo();
|
|
723
|
+
}, {}, [canRedo, redo]);
|
|
724
|
+
};
|
|
725
|
+
//#endregion
|
|
726
|
+
//#region src/context/sentry-provider.tsx
|
|
727
|
+
const SentryProvider = ({ children }) => {
|
|
728
|
+
useInitSentry();
|
|
729
|
+
return children;
|
|
730
|
+
};
|
|
731
|
+
//#endregion
|
|
732
|
+
//#region src/utils/document-editor-debug-tools.ts
|
|
733
|
+
var DocumentEditorDebugTools = class {
|
|
734
|
+
document;
|
|
735
|
+
operations = [];
|
|
736
|
+
constructor(document) {
|
|
737
|
+
if (document) this.document = document;
|
|
945
738
|
}
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
739
|
+
operationsToTableObject(operations) {
|
|
740
|
+
return operations.map((op) => ({
|
|
741
|
+
...op,
|
|
742
|
+
input: JSON.stringify(op.action.input)
|
|
743
|
+
}));
|
|
744
|
+
}
|
|
745
|
+
setDocument(document) {
|
|
746
|
+
this.document = document;
|
|
747
|
+
}
|
|
748
|
+
getDocument() {
|
|
749
|
+
return this.document;
|
|
750
|
+
}
|
|
751
|
+
getOperations() {
|
|
752
|
+
return this.operations;
|
|
753
|
+
}
|
|
754
|
+
pushOperation(operation) {
|
|
755
|
+
this.operations.push(operation);
|
|
756
|
+
}
|
|
757
|
+
operationsTable() {
|
|
758
|
+
if (!this.document) console.warn("No document");
|
|
759
|
+
const ops = Object.values(this.document?.operations || {}).filter((array) => array !== void 0).flatMap((array) => array).sort((a, b) => a.index - b.index);
|
|
760
|
+
console.table(this.operationsToTableObject(ops));
|
|
761
|
+
}
|
|
762
|
+
scopeOperationsTable(scope) {
|
|
763
|
+
if (!this.document) console.warn("No document");
|
|
764
|
+
const ops = this.document?.operations[scope] || [];
|
|
765
|
+
console.table(this.operationsToTableObject(ops));
|
|
766
|
+
}
|
|
767
|
+
operationsLog() {
|
|
768
|
+
console.log(this.operations);
|
|
769
|
+
}
|
|
770
|
+
operationsLogTable() {
|
|
771
|
+
console.table(this.operationsToTableObject(this.operations));
|
|
772
|
+
}
|
|
773
|
+
clear() {
|
|
774
|
+
this.operations = [];
|
|
775
|
+
this.document = void 0;
|
|
949
776
|
}
|
|
950
777
|
};
|
|
951
778
|
//#endregion
|
|
952
|
-
//#region src/
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
function
|
|
959
|
-
return
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
779
|
+
//#region src/utils/launch-queue.ts
|
|
780
|
+
let pendingImportFiles = [];
|
|
781
|
+
const pendingListeners = /* @__PURE__ */ new Set();
|
|
782
|
+
function notifyPendingListeners() {
|
|
783
|
+
for (const listener of pendingListeners) listener();
|
|
784
|
+
}
|
|
785
|
+
function getPendingImportFiles() {
|
|
786
|
+
return pendingImportFiles;
|
|
787
|
+
}
|
|
788
|
+
/** Stable identity of a pending file (also the picker's pre-check cache key). */
|
|
789
|
+
function pendingFileKey(file) {
|
|
790
|
+
return `${file.name}|${file.size}|${file.lastModified}`;
|
|
791
|
+
}
|
|
792
|
+
function addPendingImportFiles(files) {
|
|
793
|
+
const seen = new Set(pendingImportFiles.map(pendingFileKey));
|
|
794
|
+
const fresh = files.filter((file) => {
|
|
795
|
+
const key = pendingFileKey(file);
|
|
796
|
+
if (seen.has(key)) return false;
|
|
797
|
+
seen.add(key);
|
|
798
|
+
return true;
|
|
799
|
+
});
|
|
800
|
+
if (fresh.length === 0) return;
|
|
801
|
+
pendingImportFiles = [...pendingImportFiles, ...fresh];
|
|
802
|
+
notifyPendingListeners();
|
|
803
|
+
}
|
|
804
|
+
function clearPendingImportFiles() {
|
|
805
|
+
if (pendingImportFiles.length === 0) return;
|
|
806
|
+
pendingImportFiles = [];
|
|
807
|
+
notifyPendingListeners();
|
|
808
|
+
}
|
|
809
|
+
function subscribePendingImportFiles(cb) {
|
|
810
|
+
pendingListeners.add(cb);
|
|
811
|
+
return () => {
|
|
812
|
+
pendingListeners.delete(cb);
|
|
966
813
|
};
|
|
967
814
|
}
|
|
968
|
-
|
|
969
|
-
|
|
815
|
+
async function handleLaunchParams(params) {
|
|
816
|
+
const handles = params.files.filter((handle) => handle.kind === "file");
|
|
817
|
+
if (handles.length === 0) return;
|
|
818
|
+
const files = [];
|
|
819
|
+
for (const handle of handles) try {
|
|
820
|
+
files.push(await handle.getFile());
|
|
821
|
+
} catch (error) {
|
|
822
|
+
console.error("Failed to read launched file:", handle.name, error);
|
|
823
|
+
}
|
|
824
|
+
if (files.length === 0) return;
|
|
825
|
+
addPendingImportFiles(files);
|
|
826
|
+
showPHModal({ type: "openFileDocuments" });
|
|
827
|
+
}
|
|
828
|
+
function maybeReopenImportModal() {
|
|
829
|
+
if (getPendingImportFiles().length === 0) return;
|
|
830
|
+
if (window.ph?.modal !== void 0) return;
|
|
831
|
+
showPHModal({ type: "openFileDocuments" });
|
|
832
|
+
}
|
|
833
|
+
let initialized = false;
|
|
970
834
|
/**
|
|
971
|
-
*
|
|
972
|
-
*
|
|
973
|
-
*
|
|
974
|
-
*
|
|
975
|
-
*
|
|
976
|
-
* - `ensName`, `ensAvatar` — raw ENS facts.
|
|
977
|
-
* - `username`, `userImage`, `profileDocumentId`, `profileCreatedAt` — raw
|
|
978
|
-
* Renown profile facts.
|
|
979
|
-
* - `accountType` — wallet-adapter concept; only Renown has it.
|
|
980
|
-
*
|
|
981
|
-
* Rules:
|
|
982
|
-
* - `credential` (contains a JWT) is **never** forwarded.
|
|
983
|
-
* - Traits carry raw facts only; resolved presentation values (avatar,
|
|
984
|
-
* display name) go in OpenPanel's native identify fields — see
|
|
985
|
-
* {@link buildIdentifyPayload}.
|
|
986
|
-
* - Optional fields (`ens`, `profile`) are only included when their value is
|
|
987
|
-
* non-nullish (guards against `null` from `RenownProfile` fields as well
|
|
988
|
-
* as plain `undefined`).
|
|
989
|
-
*
|
|
990
|
-
* Mirror the Sentry pattern in `store/user.ts`: destructure off `credential`
|
|
991
|
-
* first, then assemble the trait payload from the remainder.
|
|
835
|
+
* Register the launchQueue consumer that receives files opened with Connect
|
|
836
|
+
* through the OS file association. Idempotent (safe under StrictMode double
|
|
837
|
+
* effects) and a no-op where the File Handling API doesn't exist — Firefox,
|
|
838
|
+
* Safari, and any context without an installed PWA manifest simply never
|
|
839
|
+
* deliver launches.
|
|
992
840
|
*/
|
|
993
|
-
function
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
841
|
+
function initLaunchQueueFileHandling() {
|
|
842
|
+
if (initialized) return;
|
|
843
|
+
initialized = true;
|
|
844
|
+
window.addEventListener("ph:modalUpdated", maybeReopenImportModal);
|
|
845
|
+
window.launchQueue?.setConsumer((params) => {
|
|
846
|
+
handleLaunchParams(params);
|
|
847
|
+
});
|
|
848
|
+
}
|
|
849
|
+
//#endregion
|
|
850
|
+
//#region src/utils/open-file-uploads.ts
|
|
851
|
+
let uploads = [];
|
|
852
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
853
|
+
function notifyUploadListeners() {
|
|
854
|
+
for (const listener of listeners) listener();
|
|
855
|
+
}
|
|
856
|
+
function getOpenFileUploads() {
|
|
857
|
+
return uploads;
|
|
858
|
+
}
|
|
859
|
+
function subscribeOpenFileUploads(cb) {
|
|
860
|
+
listeners.add(cb);
|
|
861
|
+
return () => {
|
|
862
|
+
listeners.delete(cb);
|
|
1001
863
|
};
|
|
1002
|
-
if (rest.ens?.name != null) traits.ensName = rest.ens.name;
|
|
1003
|
-
if (rest.ens?.avatarUrl != null) traits.ensAvatar = rest.ens.avatarUrl;
|
|
1004
|
-
if (rest.profile?.username != null) traits.username = rest.profile.username;
|
|
1005
|
-
if (rest.profile?.userImage != null) traits.userImage = rest.profile.userImage;
|
|
1006
|
-
if (rest.profile?.documentId != null) traits.profileDocumentId = rest.profile.documentId;
|
|
1007
|
-
if (rest.profile?.createdAt != null) traits.profileCreatedAt = rest.profile.createdAt;
|
|
1008
|
-
return traits;
|
|
1009
864
|
}
|
|
865
|
+
function removeOpenFileUpload(id) {
|
|
866
|
+
const next = uploads.filter((upload) => upload.id !== id);
|
|
867
|
+
if (next.length === uploads.length) return;
|
|
868
|
+
uploads = next;
|
|
869
|
+
notifyUploadListeners();
|
|
870
|
+
}
|
|
871
|
+
function clearOpenFileUploads() {
|
|
872
|
+
if (uploads.length === 0) return;
|
|
873
|
+
uploads = [];
|
|
874
|
+
notifyUploadListeners();
|
|
875
|
+
}
|
|
876
|
+
function addOpenFileUploads(rows) {
|
|
877
|
+
uploads = [...uploads, ...rows];
|
|
878
|
+
notifyUploadListeners();
|
|
879
|
+
}
|
|
880
|
+
function patchOpenFileUpload(id, patch) {
|
|
881
|
+
uploads = uploads.map((upload) => upload.id === id ? {
|
|
882
|
+
...upload,
|
|
883
|
+
...patch
|
|
884
|
+
} : upload);
|
|
885
|
+
notifyUploadListeners();
|
|
886
|
+
}
|
|
887
|
+
let uploadCounter = 0;
|
|
888
|
+
let importChain = Promise.resolve();
|
|
1010
889
|
/**
|
|
1011
|
-
*
|
|
1012
|
-
*
|
|
1013
|
-
*
|
|
1014
|
-
*
|
|
1015
|
-
*
|
|
1016
|
-
*
|
|
1017
|
-
* - `properties` are the raw traits from {@link buildTraits}.
|
|
890
|
+
* Import one file and resolve once the flow truly ends. Completion is
|
|
891
|
+
* tracked through the progress stages, NOT the returned promise — the
|
|
892
|
+
* package-discovery retry path resolves early and keeps reporting through
|
|
893
|
+
* the callback. `resolveConflict: "duplicate"` is always passed: duplicates
|
|
894
|
+
* were resolved in the picker (rename), so the conflict stage must never
|
|
895
|
+
* fire — this also covers a duplicate appearing between pre-check and import.
|
|
1018
896
|
*/
|
|
1019
|
-
function
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
897
|
+
function importOne(row, driveId, documentTypes) {
|
|
898
|
+
return new Promise((resolve) => {
|
|
899
|
+
let settled = false;
|
|
900
|
+
const settle = (fileNode) => {
|
|
901
|
+
if (settled) return;
|
|
902
|
+
settled = true;
|
|
903
|
+
resolve(fileNode);
|
|
904
|
+
};
|
|
905
|
+
addFileWithProgress(row.file, driveId, row.name, void 0, (progress) => {
|
|
906
|
+
patchOpenFileUpload(row.id, {
|
|
907
|
+
status: mapProgressStageToStatus(progress.stage),
|
|
908
|
+
progress: progress.progress,
|
|
909
|
+
...progress.error ? { errorDetails: progress.error } : {},
|
|
910
|
+
...progress.documentType ? { documentType: progress.documentType } : {},
|
|
911
|
+
...progress.fileNode ? { fileNode: progress.fileNode } : {}
|
|
912
|
+
});
|
|
913
|
+
switch (progress.stage) {
|
|
914
|
+
case "complete":
|
|
915
|
+
settle(progress.fileNode);
|
|
916
|
+
break;
|
|
917
|
+
case "failed":
|
|
918
|
+
case "unsupported-document-type": settle(void 0);
|
|
919
|
+
}
|
|
920
|
+
}, documentTypes, "duplicate").catch(() => {
|
|
921
|
+
settle(void 0);
|
|
922
|
+
});
|
|
923
|
+
});
|
|
1028
924
|
}
|
|
1029
|
-
//#endregion
|
|
1030
|
-
//#region src/components/openpanel.tsx
|
|
1031
925
|
/**
|
|
1032
|
-
*
|
|
1033
|
-
*
|
|
1034
|
-
*
|
|
1035
|
-
* Gates:
|
|
1036
|
-
* - `useAcceptedCookies().analytics === true` — the existing analytics cookie.
|
|
1037
|
-
* - `connectConfig.openPanel.clientId` non-empty — no client ID → no-op.
|
|
1038
|
-
*
|
|
1039
|
-
* Behaviour when both gates pass:
|
|
1040
|
-
* 1. Lazy-imports `@openpanel/web` and builds the singleton via
|
|
1041
|
-
* `getOpenPanelClient(connectConfig.openPanel)`.
|
|
1042
|
-
* 2. Exposes the client on `window.openPanel` for the card-6
|
|
1043
|
-
* `useOpenPanelAnalytics()` hook to consume.
|
|
1044
|
-
* 3. If `connectConfig.openPanel.trackOperations`, registers the processor
|
|
1045
|
-
* factory against `processorManager` so document operations are forwarded.
|
|
1046
|
-
* 4. Calls `client.identify()` when the renown user transitions from
|
|
1047
|
-
* `undefined` → defined (login). The profile ID is the wallet address —
|
|
1048
|
-
* the cross-app key shared with Renown and Vetra.
|
|
1049
|
-
* 5. Calls `client.clear()` when the user transitions from defined →
|
|
1050
|
-
* `undefined` (logout).
|
|
1051
|
-
*
|
|
1052
|
-
* Teardown (unmount **or** consent revocation):
|
|
1053
|
-
* - `unregisterFactory("openpanel")` to remove the processor.
|
|
1054
|
-
* - `resetOpenPanelClient()` to clear the singleton.
|
|
1055
|
-
* - `window.openPanel` is cleared.
|
|
1056
|
-
*
|
|
1057
|
-
* Mirrors the Sentry pattern in `store/user.ts` for login/logout detection.
|
|
1058
|
-
* Analytics failures are caught and forwarded to `console.warn` — they must
|
|
1059
|
-
* never throw into the application.
|
|
1060
|
-
*
|
|
1061
|
-
* Mounted next to `<Analytics />` in `app.tsx`.
|
|
926
|
+
* Run a confirmed batch of imports into a drive, feeding the floating upload
|
|
927
|
+
* panel. Rows appear immediately (queued), files import sequentially, and a
|
|
928
|
+
* single-file batch that succeeds opens its document in the editor.
|
|
1062
929
|
*/
|
|
1063
|
-
function
|
|
1064
|
-
const
|
|
1065
|
-
|
|
1066
|
-
const
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
const
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
console.warn("[OpenPanel] Failed to register processor factory:", err);
|
|
1104
|
-
}
|
|
1105
|
-
};
|
|
1106
|
-
setup();
|
|
1107
|
-
return () => {
|
|
1108
|
-
cancelled = true;
|
|
1109
|
-
prevUserRef.current = void 0;
|
|
1110
|
-
if (connectConfig.openPanel.trackOperations && processorManager) processorManager.unregisterFactory("openpanel").catch((err) => console.warn("[OpenPanel] Failed to unregister processor factory:", err));
|
|
1111
|
-
resetOpenPanelClient();
|
|
1112
|
-
window.openPanel = void 0;
|
|
1113
|
-
setClient(void 0);
|
|
930
|
+
function runOpenFileImports(args) {
|
|
931
|
+
const { driveId, imports, documentTypes } = args;
|
|
932
|
+
if (imports.length === 0) return importChain;
|
|
933
|
+
const rows = imports.map(({ file, name }) => ({
|
|
934
|
+
id: `open-file-${++uploadCounter}`,
|
|
935
|
+
file,
|
|
936
|
+
name
|
|
937
|
+
}));
|
|
938
|
+
addOpenFileUploads(rows.map((row) => ({
|
|
939
|
+
id: row.id,
|
|
940
|
+
fileName: row.name,
|
|
941
|
+
fileSize: formatFileSize(row.file.size),
|
|
942
|
+
status: "pending",
|
|
943
|
+
progress: 0
|
|
944
|
+
})));
|
|
945
|
+
const run = async () => {
|
|
946
|
+
const results = [];
|
|
947
|
+
for (const row of rows) results.push(await importOne(row, driveId, documentTypes));
|
|
948
|
+
if (rows.length === 1 && results[0]) setSelectedNode(results[0]);
|
|
949
|
+
};
|
|
950
|
+
importChain = importChain.then(run, run);
|
|
951
|
+
return importChain;
|
|
952
|
+
}
|
|
953
|
+
//#endregion
|
|
954
|
+
//#region src/utils/openUrl.ts
|
|
955
|
+
const openBrowserUrl = (url) => window.open(url, "_blank");
|
|
956
|
+
const openUrl = openBrowserUrl;
|
|
957
|
+
//#endregion
|
|
958
|
+
//#region src/utils/pglite-migration.ts
|
|
959
|
+
const BACKUP_PREFIX = "ph-pglite-backup::";
|
|
960
|
+
const BACKUP_INDEX_KEY = "ph:pglite-backups";
|
|
961
|
+
const BACKUP_RETENTION_MS = 2592e6;
|
|
962
|
+
function deleteIdb(name, timeoutMs = 15e3) {
|
|
963
|
+
return new Promise((resolve, reject) => {
|
|
964
|
+
const req = indexedDB.deleteDatabase(name);
|
|
965
|
+
let settled = false;
|
|
966
|
+
const done = (fn) => {
|
|
967
|
+
if (settled) return;
|
|
968
|
+
settled = true;
|
|
969
|
+
fn();
|
|
1114
970
|
};
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
971
|
+
const timer = setTimeout(() => done(() => reject(/* @__PURE__ */ new Error(`IDB delete timed out for ${name} after ${timeoutMs}ms`))), timeoutMs);
|
|
972
|
+
req.onsuccess = () => done(() => {
|
|
973
|
+
clearTimeout(timer);
|
|
974
|
+
resolve();
|
|
975
|
+
});
|
|
976
|
+
req.onerror = () => done(() => {
|
|
977
|
+
clearTimeout(timer);
|
|
978
|
+
reject(idbError(req, `IDB delete failed for ${name}`));
|
|
979
|
+
});
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
function readBackupIndex() {
|
|
983
|
+
try {
|
|
984
|
+
const raw = localStorage.getItem(BACKUP_INDEX_KEY);
|
|
985
|
+
if (!raw) return [];
|
|
986
|
+
const parsed = JSON.parse(raw);
|
|
987
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
988
|
+
} catch {
|
|
989
|
+
return [];
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
function writeBackupIndex(records) {
|
|
993
|
+
try {
|
|
994
|
+
localStorage.setItem(BACKUP_INDEX_KEY, JSON.stringify(records));
|
|
995
|
+
} catch {}
|
|
996
|
+
}
|
|
997
|
+
function registerBackup(rec) {
|
|
998
|
+
writeBackupIndex([...readBackupIndex(), rec]);
|
|
999
|
+
}
|
|
1000
|
+
function forgetBackup(name) {
|
|
1001
|
+
writeBackupIndex(readBackupIndex().filter((r) => r.name !== name));
|
|
1002
|
+
}
|
|
1003
|
+
async function janitor() {
|
|
1004
|
+
const cutoff = Date.now() - BACKUP_RETENTION_MS;
|
|
1005
|
+
const keep = [];
|
|
1006
|
+
for (const rec of readBackupIndex()) {
|
|
1007
|
+
if (rec.createdAt >= cutoff) {
|
|
1008
|
+
keep.push(rec);
|
|
1009
|
+
continue;
|
|
1124
1010
|
}
|
|
1125
|
-
|
|
1126
|
-
|
|
1011
|
+
try {
|
|
1012
|
+
await deleteIdb(rec.name);
|
|
1127
1013
|
} catch (err) {
|
|
1128
|
-
console.warn(
|
|
1014
|
+
console.warn(`Failed to delete expired pglite backup ${rec.name}`, err);
|
|
1015
|
+
keep.push(rec);
|
|
1129
1016
|
}
|
|
1130
|
-
}
|
|
1131
|
-
|
|
1132
|
-
user,
|
|
1133
|
-
enabled
|
|
1134
|
-
]);
|
|
1135
|
-
return null;
|
|
1017
|
+
}
|
|
1018
|
+
writeBackupIndex(keep);
|
|
1136
1019
|
}
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1020
|
+
function createPersistentBackup() {
|
|
1021
|
+
return {
|
|
1022
|
+
snapshot: async (idbName) => {
|
|
1023
|
+
const backupName = `${BACKUP_PREFIX}${idbName}::${(/* @__PURE__ */ new Date()).toISOString()}`;
|
|
1024
|
+
await cloneFileData(idbName, backupName);
|
|
1025
|
+
registerBackup({
|
|
1026
|
+
name: backupName,
|
|
1027
|
+
idbName,
|
|
1028
|
+
createdAt: Date.now()
|
|
1029
|
+
});
|
|
1030
|
+
return backupName;
|
|
1031
|
+
},
|
|
1032
|
+
rollback: async (handle, idbName, cause) => {
|
|
1033
|
+
const backupName = handle;
|
|
1034
|
+
try {
|
|
1035
|
+
await cloneFileData(backupName, idbName);
|
|
1036
|
+
} catch (rollbackErr) {
|
|
1037
|
+
console.error(`PGlite migration rollback failed for ${idbName}; backup ${backupName} retained. Primary migration error:`, cause, "Rollback error:", rollbackErr);
|
|
1038
|
+
return;
|
|
1039
|
+
}
|
|
1040
|
+
await deleteIdb(backupName).catch(() => void 0);
|
|
1041
|
+
forgetBackup(backupName);
|
|
1042
|
+
},
|
|
1043
|
+
discard: async (handle) => {
|
|
1044
|
+
const backupName = handle;
|
|
1045
|
+
await deleteIdb(backupName).catch(() => void 0);
|
|
1046
|
+
forgetBackup(backupName);
|
|
1047
|
+
},
|
|
1048
|
+
commit: () => Promise.resolve()
|
|
1049
|
+
};
|
|
1154
1050
|
}
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
const { customEditorLoader, ...defaultProps } = props;
|
|
1166
|
-
if (customEditorLoader) return /* @__PURE__ */ jsx(Fragment, { children: customEditorLoader });
|
|
1167
|
-
return /* @__PURE__ */ jsx(DefaultEditorLoader, { ...defaultProps });
|
|
1051
|
+
async function migrateAllLocked() {
|
|
1052
|
+
const backup = createPersistentBackup();
|
|
1053
|
+
try {
|
|
1054
|
+
for (const idbName of PRIMARY_IDB_NAMES) await migrateIdb(idbName, (phase) => setMigrationStatus({
|
|
1055
|
+
idbName,
|
|
1056
|
+
phase
|
|
1057
|
+
}), backup);
|
|
1058
|
+
} finally {
|
|
1059
|
+
setMigrationStatus(null);
|
|
1060
|
+
}
|
|
1168
1061
|
}
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
const AppComponent = app?.Component ?? defaultApp?.Component ?? GenericDriveExplorer.Component;
|
|
1178
|
-
if (!AppComponent) throw new Error("No app component found");
|
|
1179
|
-
return /* @__PURE__ */ jsx(ErrorBoundary$1, {
|
|
1180
|
-
variant: "detailed",
|
|
1181
|
-
resetKeys: [selectedDrive.header.id],
|
|
1182
|
-
loggerContext: ["Connect", "App"],
|
|
1183
|
-
children: /* @__PURE__ */ jsx(Suspense, {
|
|
1184
|
-
fallback: /* @__PURE__ */ jsx(EditorLoader, {}),
|
|
1185
|
-
children: /* @__PURE__ */ jsx(DropZoneWrapper, {
|
|
1186
|
-
className: "flex h-full flex-col overflow-auto",
|
|
1187
|
-
children: /* @__PURE__ */ jsx(AppComponent, { children: selectedDocumentId ? /* @__PURE__ */ jsx(DocumentEditorContainer, {}) : null })
|
|
1188
|
-
})
|
|
1189
|
-
})
|
|
1062
|
+
async function migrateAllIfNeeded() {
|
|
1063
|
+
janitor().catch((err) => console.warn("PGlite backup janitor failed", err));
|
|
1064
|
+
if (!(typeof navigator !== "undefined" && "locks" in navigator && typeof navigator.locks.request === "function")) {
|
|
1065
|
+
await migrateAllLocked();
|
|
1066
|
+
return;
|
|
1067
|
+
}
|
|
1068
|
+
await navigator.locks.request("ph-pglite-migration", { mode: "exclusive" }, async () => {
|
|
1069
|
+
await migrateAllLocked();
|
|
1190
1070
|
});
|
|
1191
1071
|
}
|
|
1192
1072
|
//#endregion
|
|
1193
|
-
//#region src/context/sentry-provider.tsx
|
|
1194
|
-
const SentryProvider = ({ children }) => {
|
|
1195
|
-
useInitSentry();
|
|
1196
|
-
return children;
|
|
1197
|
-
};
|
|
1198
|
-
//#endregion
|
|
1199
1073
|
//#region src/components/reactor-chat.tsx
|
|
1200
1074
|
/**
|
|
1201
1075
|
* Resolves the reactor tool descriptors for the chat agent from the
|
|
@@ -1401,11 +1275,12 @@ function PackageInstallPrompt() {
|
|
|
1401
1275
|
const pendingInstallations = usePendingInstallations();
|
|
1402
1276
|
const discoveryService = usePackageDiscoveryService();
|
|
1403
1277
|
if (!discoveryService || pendingInstallations.length === 0) return null;
|
|
1278
|
+
const installations = pendingInstallations.flatMap((p) => p.packageNames.map((packageName) => ({
|
|
1279
|
+
documentType: p.documentType,
|
|
1280
|
+
packageName
|
|
1281
|
+
})));
|
|
1404
1282
|
return /* @__PURE__ */ jsx(PackageInstallModal, {
|
|
1405
|
-
pendingInstallations:
|
|
1406
|
-
documentType: p.documentType,
|
|
1407
|
-
packageName
|
|
1408
|
-
}))),
|
|
1283
|
+
pendingInstallations: installations,
|
|
1409
1284
|
onInstall: (packageName) => discoveryService.approveInstallation(packageName),
|
|
1410
1285
|
onDismiss: (packageName) => discoveryService.dismissInstallation(packageName)
|
|
1411
1286
|
});
|
|
@@ -1533,6 +1408,20 @@ const App = () => {
|
|
|
1533
1408
|
] }) });
|
|
1534
1409
|
};
|
|
1535
1410
|
//#endregion
|
|
1411
|
+
//#region src/components/dots-loader.tsx
|
|
1412
|
+
const DotsLoader = () => {
|
|
1413
|
+
const [dots, setDots] = useState(0);
|
|
1414
|
+
useEffect(() => {
|
|
1415
|
+
const id = setInterval(() => {
|
|
1416
|
+
setDots((dots) => dots === 3 ? 0 : dots + 1);
|
|
1417
|
+
}, 200);
|
|
1418
|
+
return () => {
|
|
1419
|
+
clearInterval(id);
|
|
1420
|
+
};
|
|
1421
|
+
}, []);
|
|
1422
|
+
return /* @__PURE__ */ jsx("span", { children: new Array(dots).fill(".").join("") });
|
|
1423
|
+
};
|
|
1424
|
+
//#endregion
|
|
1536
1425
|
//#region src/components/drive-icon.tsx
|
|
1537
1426
|
function DriveIcon({ drive }) {
|
|
1538
1427
|
const remotes = useSyncList();
|
|
@@ -1597,6 +1486,9 @@ function EditorError({ title, children }) {
|
|
|
1597
1486
|
})
|
|
1598
1487
|
});
|
|
1599
1488
|
}
|
|
1489
|
+
function defaultScope(scopes) {
|
|
1490
|
+
return scopes.includes("global") ? "global" : scopes[0];
|
|
1491
|
+
}
|
|
1600
1492
|
function OpenPackageManagerButton() {
|
|
1601
1493
|
return /* @__PURE__ */ jsx(PowerhouseButton, {
|
|
1602
1494
|
className: "px-3 py-1.5 text-base font-medium",
|
|
@@ -1616,10 +1508,30 @@ const DocumentEditor = (props) => {
|
|
|
1616
1508
|
const documentName = document?.header.name ?? void 0;
|
|
1617
1509
|
const documentType = document?.header.documentType ?? void 0;
|
|
1618
1510
|
const preferredEditor = document?.header.meta?.preferredEditor ?? void 0;
|
|
1619
|
-
const
|
|
1511
|
+
const scopes = useMemo(() => {
|
|
1512
|
+
const keys = Object.keys(document?.header.revision ?? {});
|
|
1513
|
+
return keys.length > 0 ? keys : ["global"];
|
|
1514
|
+
}, [document?.header.revision]);
|
|
1515
|
+
const [operationScope, setOperationScope] = useState(() => defaultScope(scopes));
|
|
1516
|
+
const selectedScope = scopes.includes(operationScope) ? operationScope : defaultScope(scopes);
|
|
1517
|
+
const { operations: historyOperations, isLoading: isLoadingHistory, hasNextPage: historyHasNextPage, fetchNextPage: fetchNextHistoryPage, error: historyError } = useDocumentOperations(documentId, selectedScope, {
|
|
1518
|
+
enabled: revisionHistoryVisible,
|
|
1519
|
+
limit: 500
|
|
1520
|
+
});
|
|
1521
|
+
const { operations: globalOperations, hasNextPage: globalHasNextPage, isLoading: isLoadingGlobal, fetchNextPage: fetchNextGlobalPage, error: globalError } = useDocumentOperations(documentId, "global", {
|
|
1522
|
+
enabled: !!selectedTimelineItem,
|
|
1523
|
+
limit: 500
|
|
1524
|
+
});
|
|
1620
1525
|
useEffect(() => {
|
|
1621
|
-
if (
|
|
1622
|
-
|
|
1526
|
+
if (!globalHasNextPage || isLoadingGlobal || globalError) return;
|
|
1527
|
+
const handle = window.setTimeout(fetchNextGlobalPage, 0);
|
|
1528
|
+
return () => window.clearTimeout(handle);
|
|
1529
|
+
}, [
|
|
1530
|
+
globalHasNextPage,
|
|
1531
|
+
isLoadingGlobal,
|
|
1532
|
+
fetchNextGlobalPage,
|
|
1533
|
+
globalError
|
|
1534
|
+
]);
|
|
1623
1535
|
const globalRevisionNumber = document?.header.revision.global ?? 0;
|
|
1624
1536
|
const localRevisionNumber = document?.header.revision.local ?? 0;
|
|
1625
1537
|
const documentModelModule = useDocumentModelModuleById(documentType);
|
|
@@ -1725,11 +1637,17 @@ const DocumentEditor = (props) => {
|
|
|
1725
1637
|
id: "document-editor-context",
|
|
1726
1638
|
"data-editor": editorModule.config.id,
|
|
1727
1639
|
"data-document-type": documentType,
|
|
1728
|
-
children: revisionHistoryVisible ?
|
|
1640
|
+
children: revisionHistoryVisible ? /* @__PURE__ */ jsx(RevisionHistory, {
|
|
1729
1641
|
documentTitle: documentName ?? "",
|
|
1730
1642
|
documentId: documentId ?? "",
|
|
1731
|
-
|
|
1732
|
-
|
|
1643
|
+
operations: historyOperations,
|
|
1644
|
+
isLoading: isLoadingHistory,
|
|
1645
|
+
hasNextPage: historyHasNextPage,
|
|
1646
|
+
onLoadNextPage: fetchNextHistoryPage,
|
|
1647
|
+
error: historyError,
|
|
1648
|
+
scopes,
|
|
1649
|
+
scope: selectedScope,
|
|
1650
|
+
onScopeChange: setOperationScope,
|
|
1733
1651
|
onClose: () => setRevisionHistoryVisible(false),
|
|
1734
1652
|
documentState: document.state,
|
|
1735
1653
|
onCopyState: () => {
|
|
@@ -1749,7 +1667,7 @@ const DocumentEditor = (props) => {
|
|
|
1749
1667
|
children: !editorError?.error && /* @__PURE__ */ jsx(EditorComponent, {
|
|
1750
1668
|
context: {
|
|
1751
1669
|
readMode: !!selectedTimelineItem,
|
|
1752
|
-
selectedTimelineRevision: getRevisionFromDate(selectedTimelineItem?.startDate, selectedTimelineItem?.endDate, globalOperations)
|
|
1670
|
+
selectedTimelineRevision: (isLoadingGlobal || globalHasNextPage) && !globalError ? void 0 : getRevisionFromDate(selectedTimelineItem?.startDate, selectedTimelineItem?.endDate, globalOperations)
|
|
1753
1671
|
},
|
|
1754
1672
|
documentId: document.header.id
|
|
1755
1673
|
}, `${editorBundleKey}:${documentId}`)
|
|
@@ -1758,8 +1676,35 @@ const DocumentEditor = (props) => {
|
|
|
1758
1676
|
});
|
|
1759
1677
|
};
|
|
1760
1678
|
//#endregion
|
|
1679
|
+
//#region src/components/footer.tsx
|
|
1680
|
+
const Footer$1 = () => {
|
|
1681
|
+
return /* @__PURE__ */ jsxs(Footer, { children: [
|
|
1682
|
+
/* @__PURE__ */ jsx(FooterLink, {
|
|
1683
|
+
onClick: () => setBannerShown(true),
|
|
1684
|
+
children: /* @__PURE__ */ jsx(Trans, { i18nKey: "footer.cookiePolicy" })
|
|
1685
|
+
}),
|
|
1686
|
+
/* @__PURE__ */ jsx(FooterLink, {
|
|
1687
|
+
onClick: () => showPHModal({ type: "disclaimer" }),
|
|
1688
|
+
children: /* @__PURE__ */ jsx(Trans, { i18nKey: "footer.disclaimer" })
|
|
1689
|
+
}),
|
|
1690
|
+
/* @__PURE__ */ jsx(FooterLink, {
|
|
1691
|
+
id: "ph-logo-link",
|
|
1692
|
+
onClick: () => openUrl("https://www.powerhouse.inc/"),
|
|
1693
|
+
children: /* @__PURE__ */ jsx(Trans, {
|
|
1694
|
+
i18nKey: "footer.builtWith",
|
|
1695
|
+
components: { icon: /* @__PURE__ */ jsx(Icon, {
|
|
1696
|
+
name: "PowerhouseLogoSmall",
|
|
1697
|
+
size: 16,
|
|
1698
|
+
className: "mx-1"
|
|
1699
|
+
}) }
|
|
1700
|
+
})
|
|
1701
|
+
})
|
|
1702
|
+
] });
|
|
1703
|
+
};
|
|
1704
|
+
//#endregion
|
|
1761
1705
|
//#region src/components/root.tsx
|
|
1762
1706
|
function Root() {
|
|
1707
|
+
const isEmbedded = useIsEmbedded();
|
|
1763
1708
|
return /* @__PURE__ */ jsx("div", {
|
|
1764
1709
|
className: "h-screen bg-background",
|
|
1765
1710
|
children: /* @__PURE__ */ jsx("div", {
|
|
@@ -1768,7 +1713,7 @@ function Root() {
|
|
|
1768
1713
|
tabIndex: 0,
|
|
1769
1714
|
children: /* @__PURE__ */ jsxs(Suspense, {
|
|
1770
1715
|
name: "Root",
|
|
1771
|
-
children: [!
|
|
1716
|
+
children: [!isEmbedded && /* @__PURE__ */ jsx(Sidebar, {}), /* @__PURE__ */ jsx("div", {
|
|
1772
1717
|
className: "relative flex-1 overflow-auto",
|
|
1773
1718
|
children: /* @__PURE__ */ jsx(Outlet, {})
|
|
1774
1719
|
})]
|
|
@@ -1950,6 +1895,64 @@ const Router = () => {
|
|
|
1950
1895
|
return /* @__PURE__ */ jsx(RouterProvider, { router });
|
|
1951
1896
|
};
|
|
1952
1897
|
//#endregion
|
|
1898
|
+
//#region src/components/search-bar.tsx
|
|
1899
|
+
const defaultFilterItems = [
|
|
1900
|
+
{
|
|
1901
|
+
id: "project",
|
|
1902
|
+
label: ".project",
|
|
1903
|
+
icon: /* @__PURE__ */ jsx(Icon, {
|
|
1904
|
+
name: "Project",
|
|
1905
|
+
color: "#FF6A55",
|
|
1906
|
+
size: 16
|
|
1907
|
+
})
|
|
1908
|
+
},
|
|
1909
|
+
{
|
|
1910
|
+
id: "budget",
|
|
1911
|
+
label: ".budget",
|
|
1912
|
+
icon: /* @__PURE__ */ jsx(Icon, {
|
|
1913
|
+
name: "BarChart",
|
|
1914
|
+
color: "#8E55EA",
|
|
1915
|
+
size: 16
|
|
1916
|
+
})
|
|
1917
|
+
},
|
|
1918
|
+
{
|
|
1919
|
+
id: "profile",
|
|
1920
|
+
label: ".profile",
|
|
1921
|
+
icon: /* @__PURE__ */ jsx(Icon, {
|
|
1922
|
+
name: "Person",
|
|
1923
|
+
color: "#3E90F0",
|
|
1924
|
+
size: 16
|
|
1925
|
+
})
|
|
1926
|
+
},
|
|
1927
|
+
{
|
|
1928
|
+
id: "legal",
|
|
1929
|
+
label: ".legal",
|
|
1930
|
+
icon: /* @__PURE__ */ jsx(Icon, {
|
|
1931
|
+
name: "Briefcase",
|
|
1932
|
+
color: "#4BAB71",
|
|
1933
|
+
size: 16
|
|
1934
|
+
})
|
|
1935
|
+
},
|
|
1936
|
+
{
|
|
1937
|
+
id: "atlas",
|
|
1938
|
+
label: ".Atlas",
|
|
1939
|
+
icon: /* @__PURE__ */ jsx(Icon, {
|
|
1940
|
+
name: "Globe",
|
|
1941
|
+
color: "#FF8A00",
|
|
1942
|
+
size: 16
|
|
1943
|
+
})
|
|
1944
|
+
}
|
|
1945
|
+
];
|
|
1946
|
+
const SearchBar = () => {
|
|
1947
|
+
const { t } = useTranslation();
|
|
1948
|
+
return /* @__PURE__ */ jsx(ConnectSearchBar, {
|
|
1949
|
+
className: "m-4 shrink-0 bg-muted",
|
|
1950
|
+
placeholder: t("searchbar.placeholder"),
|
|
1951
|
+
filterLabel: t("searchbar.filterLabel"),
|
|
1952
|
+
filterItems: defaultFilterItems
|
|
1953
|
+
});
|
|
1954
|
+
};
|
|
1955
|
+
//#endregion
|
|
1953
1956
|
//#region src/components/sidebar.tsx
|
|
1954
1957
|
function Sidebar() {
|
|
1955
1958
|
const user = useUser();
|
|
@@ -2130,20 +2133,20 @@ const MigrationBanner = () => {
|
|
|
2130
2133
|
};
|
|
2131
2134
|
//#endregion
|
|
2132
2135
|
//#region src/components/modal/modals-container.tsx
|
|
2133
|
-
const AddDriveModal$1 = lazy(() => import("./AddDriveModal-
|
|
2134
|
-
const ClearStorageModal = lazy(() => import("./ClearStorageModal-
|
|
2135
|
-
const CookiesPolicyModal = lazy(() => import("./CookiesPolicyModal-
|
|
2136
|
-
const CreateDocumentModal$1 = lazy(() => import("./CreateDocumentModal-
|
|
2137
|
-
const DebugSettingsModal = lazy(() => import("./DebugSettingsModal-
|
|
2138
|
-
const DeleteDriveModal = lazy(() => import("./DeleteDriveModal-
|
|
2139
|
-
const DeleteItemModal = lazy(() => import("./DeleteItemModal-
|
|
2140
|
-
const DisclaimerModal = lazy(() => import("./DisclaimerModal-
|
|
2141
|
-
const DriveSettingsModal$1 = lazy(() => import("./DriveSettingsModal-
|
|
2142
|
-
const DownloadDocumentWithErrorsModal = lazy(() => import("./DownloadDocumentWithErrorsModal-
|
|
2143
|
-
const DocumentVersionUnsupportedModal = lazy(() => import("./DocumentVersionUnsupportedModal-
|
|
2144
|
-
const ConfirmDocumentUpgradeModal = lazy(() => import("./ConfirmDocumentUpgradeModal-
|
|
2145
|
-
const SettingsModal$1 = lazy(() => import("./SettingsModal-
|
|
2146
|
-
const UpgradeDriveModal = lazy(() => import("./UpgradeDriveModal-
|
|
2136
|
+
const AddDriveModal$1 = lazy(() => import("./AddDriveModal-DhNfP94R.js").then((m) => ({ default: m.AddDriveModal })));
|
|
2137
|
+
const ClearStorageModal = lazy(() => import("./ClearStorageModal-DaNmZ8f2.js").then((m) => ({ default: m.ClearStorageModal })));
|
|
2138
|
+
const CookiesPolicyModal = lazy(() => import("./CookiesPolicyModal-BLw4pnhn.js").then((m) => ({ default: m.CookiesPolicyModal })));
|
|
2139
|
+
const CreateDocumentModal$1 = lazy(() => import("./CreateDocumentModal-Bmv0V-kY.js").then((m) => ({ default: m.CreateDocumentModal })));
|
|
2140
|
+
const DebugSettingsModal = lazy(() => import("./DebugSettingsModal-EYgccEiI.js").then((m) => ({ default: m.DebugSettingsModal })));
|
|
2141
|
+
const DeleteDriveModal = lazy(() => import("./DeleteDriveModal-CjGnG0ht.js").then((m) => ({ default: m.DeleteDriveModal })));
|
|
2142
|
+
const DeleteItemModal = lazy(() => import("./DeleteItemModal-BbY_4_xT.js").then((m) => ({ default: m.DeleteItemModal })));
|
|
2143
|
+
const DisclaimerModal = lazy(() => import("./DisclaimerModal-DuglmEwL.js").then((m) => ({ default: m.DisclaimerModal })));
|
|
2144
|
+
const DriveSettingsModal$1 = lazy(() => import("./DriveSettingsModal-d1L0eYof.js").then((m) => ({ default: m.DriveSettingsModal })));
|
|
2145
|
+
const DownloadDocumentWithErrorsModal = lazy(() => import("./DownloadDocumentWithErrorsModal-BsPQ5qgy.js").then((m) => ({ default: m.DownloadDocumentWithErrorsModal })));
|
|
2146
|
+
const DocumentVersionUnsupportedModal = lazy(() => import("./DocumentVersionUnsupportedModal-C4fy7fZ6.js").then((m) => ({ default: m.DocumentVersionUnsupportedModal })));
|
|
2147
|
+
const ConfirmDocumentUpgradeModal = lazy(() => import("./ConfirmDocumentUpgradeModal-DcOZy20m.js").then((m) => ({ default: m.ConfirmDocumentUpgradeModal })));
|
|
2148
|
+
const SettingsModal$1 = lazy(() => import("./SettingsModal-iBBWf4UN.js").then((m) => ({ default: m.SettingsModal })));
|
|
2149
|
+
const UpgradeDriveModal = lazy(() => import("./UpgradeDriveModal-CXX6D5Au.js").then((m) => ({ default: m.UpgradeDriveModal })));
|
|
2147
2150
|
const modalComponents = {
|
|
2148
2151
|
addDrive: AddDriveModal$1,
|
|
2149
2152
|
clearStorage: ClearStorageModal,
|
|
@@ -2157,13 +2160,13 @@ const modalComponents = {
|
|
|
2157
2160
|
downloadDocumentWithErrors: DownloadDocumentWithErrorsModal,
|
|
2158
2161
|
documentVersionUnsupported: DocumentVersionUnsupportedModal,
|
|
2159
2162
|
confirmDocumentUpgrade: ConfirmDocumentUpgradeModal,
|
|
2160
|
-
inspector: lazy(() => import("./InspectorModal-
|
|
2163
|
+
inspector: lazy(() => import("./InspectorModal-Bkry1jv9.js").then((m) => ({ default: m.InspectorModal }))),
|
|
2161
2164
|
settings: SettingsModal$1,
|
|
2162
2165
|
upgradeDrive: UpgradeDriveModal,
|
|
2163
|
-
missingPackage: lazy(() => import("./MissingPackageModal-
|
|
2164
|
-
driveAuthRequired: lazy(() => import("./DriveAuthRequiredModal-
|
|
2165
|
-
openFileDocuments: lazy(() => import("./OpenFileDocumentsModal-
|
|
2166
|
-
login: lazy(() => import("./LoginModal-
|
|
2166
|
+
missingPackage: lazy(() => import("./MissingPackageModal-CjkK_4A7.js").then((m) => ({ default: m.ConnectMissingPackageModal }))),
|
|
2167
|
+
driveAuthRequired: lazy(() => import("./DriveAuthRequiredModal-CtsB0kwH.js").then((m) => ({ default: m.DriveAuthRequiredModal }))),
|
|
2168
|
+
openFileDocuments: lazy(() => import("./OpenFileDocumentsModal-CEFijapC.js").then((m) => ({ default: m.OpenFileDocumentsModal }))),
|
|
2169
|
+
login: lazy(() => import("./LoginModal-CI0ogC2-.js").then((m) => ({ default: m.LoginModal })))
|
|
2167
2170
|
};
|
|
2168
2171
|
const ModalsContainer = lazy(() => {
|
|
2169
2172
|
return Promise.resolve({ default: () => {
|
|
@@ -2201,12 +2204,48 @@ const ServiceWorkerUpdatePrompt = () => {
|
|
|
2201
2204
|
});
|
|
2202
2205
|
};
|
|
2203
2206
|
//#endregion
|
|
2207
|
+
//#region src/components/stored-documents-refused.tsx
|
|
2208
|
+
/** Boot screen for a reactor that refused this browser's stored documents. */
|
|
2209
|
+
function StoredDocumentsRefusedFallback({ error }) {
|
|
2210
|
+
return /* @__PURE__ */ jsx("div", {
|
|
2211
|
+
className: "z-10 mx-auto flex max-w-[80%] flex-1 items-center justify-center p-6",
|
|
2212
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
2213
|
+
role: "alert",
|
|
2214
|
+
className: "w-full max-w-lg rounded-lg border border-border bg-card p-6 text-foreground shadow-sm",
|
|
2215
|
+
children: [
|
|
2216
|
+
/* @__PURE__ */ jsxs("div", {
|
|
2217
|
+
className: "mb-3 flex items-center gap-2",
|
|
2218
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
2219
|
+
name: "Error",
|
|
2220
|
+
className: "size-5 shrink-0 text-destructive"
|
|
2221
|
+
}), /* @__PURE__ */ jsx("h1", {
|
|
2222
|
+
className: "text-lg font-semibold text-foreground",
|
|
2223
|
+
children: "Connect cannot open this browser's documents"
|
|
2224
|
+
})]
|
|
2225
|
+
}),
|
|
2226
|
+
/* @__PURE__ */ jsx("p", {
|
|
2227
|
+
className: "mb-4 text-sm wrap-break-word text-foreground",
|
|
2228
|
+
children: error.message
|
|
2229
|
+
}),
|
|
2230
|
+
/* @__PURE__ */ jsx(PowerhouseButton, {
|
|
2231
|
+
type: "button",
|
|
2232
|
+
onClick: () => {
|
|
2233
|
+
window.location.reload();
|
|
2234
|
+
},
|
|
2235
|
+
className: "px-3 py-1.5 text-base font-medium",
|
|
2236
|
+
children: "Reload"
|
|
2237
|
+
})
|
|
2238
|
+
]
|
|
2239
|
+
})
|
|
2240
|
+
});
|
|
2241
|
+
}
|
|
2242
|
+
//#endregion
|
|
2204
2243
|
//#region src/components/app-loader.tsx
|
|
2205
|
-
const CookieBanner$1 = lazy(() => import("./cookie-banner-
|
|
2244
|
+
const CookieBanner$1 = lazy(() => import("./cookie-banner-BxXvPdIY.js").then((m) => ({ default: m.CookieBanner })));
|
|
2206
2245
|
const AppLoader = (props) => {
|
|
2207
|
-
const Load = lazy(() => import("./load
|
|
2246
|
+
const Load = lazy(() => import("./load--VQTmlAi.js").then((m) => m.loadComponent(props.localPackage)));
|
|
2208
2247
|
return /* @__PURE__ */ jsx(StrictMode, { children: /* @__PURE__ */ jsxs(ErrorBoundary$1, {
|
|
2209
|
-
fallbackRender: (props) => /* @__PURE__ */ jsx(AppSkeleton, { children: /* @__PURE__ */ jsx(DetailedFallback, { ...props }) }),
|
|
2248
|
+
fallbackRender: (props) => /* @__PURE__ */ jsx(AppSkeleton, { children: isStoredDocumentsRefused(props.error) ? /* @__PURE__ */ jsx(StoredDocumentsRefusedFallback, { error: props.error }) : /* @__PURE__ */ jsx(DetailedFallback, { ...props }) }),
|
|
2210
2249
|
resetKeys: [props.localPackage],
|
|
2211
2250
|
loggerContext: ["Connect"],
|
|
2212
2251
|
children: [
|
|
@@ -2238,7 +2277,7 @@ const AppLoader = (props) => {
|
|
|
2238
2277
|
}) });
|
|
2239
2278
|
};
|
|
2240
2279
|
//#endregion
|
|
2241
|
-
export {
|
|
2280
|
+
export { EditorLoader as _, Root as a, Analytics as b, DriveIcon as c, runOpenFileImports as d, clearPendingImportFiles as f, AppContainer as g, subscribePendingImportFiles as h, Router as i, DotsLoader as l, pendingFileKey as m, Sidebar as n, Footer$1 as o, getPendingImportFiles as p, SearchBar as r, DocumentEditor as s, AppLoader as t, App as u, DocumentEditorContainer as v, OpenPanel as y };
|
|
2242
2281
|
|
|
2243
|
-
//# sourceMappingURL=app-loader-
|
|
2244
|
-
//# debugId=
|
|
2282
|
+
//# sourceMappingURL=app-loader-BXd5hsez.js.map
|
|
2283
|
+
//# debugId=dfdd60eb-74cd-51f4-aecf-a38aed5d8193
|