@powerhousedao/connect 6.2.3-dev.3 → 6.2.3-dev.31
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-Q-Ffh5XA.js → AddDriveModal-DhNfP94R.js} +6 -21
- package/dist/AddDriveModal-DhNfP94R.js.map +1 -0
- package/dist/{ClearStorageModal-DJXGvVAy.js → ClearStorageModal-a7dk64ub.js} +5 -5
- package/dist/{ClearStorageModal-DJXGvVAy.js.map → ClearStorageModal-a7dk64ub.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-BomehG-z.js → DebugSettingsModal-D_S1LnBH.js} +7 -7
- package/dist/{DebugSettingsModal-BomehG-z.js.map → DebugSettingsModal-D_S1LnBH.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-Cw9eCAQ_.js → DriveAuthRequiredModal-CtsB0kwH.js} +19 -7
- package/dist/DriveAuthRequiredModal-CtsB0kwH.js.map +1 -0
- 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-CEV4kwcd.js → InspectorModal-sOCQEpKA.js} +12 -10
- package/dist/{InspectorModal-CEV4kwcd.js.map → InspectorModal-sOCQEpKA.js.map} +1 -1
- 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-HFUPQMML.js} +5 -5
- package/dist/{MissingPackageModal-nBnExqO0.js.map → MissingPackageModal-HFUPQMML.js.map} +1 -1
- package/dist/{OpenFileDocumentsModal-EhXtaNVb.js → OpenFileDocumentsModal-tCrGCLLF.js} +8 -7
- package/dist/{OpenFileDocumentsModal-EhXtaNVb.js.map → OpenFileDocumentsModal-tCrGCLLF.js.map} +1 -1
- package/dist/{SettingsModal-Celp-x5H.js → SettingsModal-BnQVmt3Z.js} +17 -15
- package/dist/{SettingsModal-Celp-x5H.js.map → SettingsModal-BnQVmt3Z.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-wq-dOkb0.js → app-loader-D5-KfjU4.js} +1213 -1136
- package/dist/app-loader-D5-KfjU4.js.map +1 -0
- package/dist/app-loader-DmJ10OyR.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-Bc36ZmXD.js → build-info-B31oFKR6.js} +5 -5
- package/dist/{build-info-Bc36ZmXD.js.map → build-info-B31oFKR6.js.map} +1 -1
- package/dist/components-e-CRRtTY.js +5 -0
- package/dist/{connect.config-DaHDEUrw.js → connect.config-Dgs13R1s.js} +7 -6
- package/dist/{connect.config-DaHDEUrw.js.map → connect.config-Dgs13R1s.js.map} +1 -1
- package/dist/{connection-state-3w4liC1X.js → connection-state-Cy8xRCm_.js} +6 -6
- package/dist/{connection-state-3w4liC1X.js.map → connection-state-Cy8xRCm_.js.map} +1 -1
- package/dist/{cookie-banner-BH6bIq24.js → cookie-banner-CSF930bl.js} +6 -6
- package/dist/{cookie-banner-BH6bIq24.js.map → cookie-banner-CSF930bl.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-CognkhXK.js → load-B7_AbI5f.js} +13 -11
- package/dist/{load-CognkhXK.js.map → load-B7_AbI5f.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-BbmMK26m.js} +3 -3
- package/dist/{pglite-major-B39aOEiE.js.map → pglite-major-BbmMK26m.js.map} +1 -1
- package/dist/{pglite-migrate-core-Boxqqx-c.js → pglite-migrate-core-o88cWesm.js} +8 -6
- package/dist/{pglite-migrate-core-Boxqqx-c.js.map → pglite-migrate-core-o88cWesm.js.map} +1 -1
- package/dist/{pglite-seed-BqAUvNFw.js → pglite-seed-D6fqQApT.js} +4 -4
- package/dist/{pglite-seed-BqAUvNFw.js.map → pglite-seed-D6fqQApT.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-Bekp7tv-.js} +6 -25
- package/dist/preferences-store-Bekp7tv-.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-CSAxliEy.js → reactor-BmQPQNmi.js} +56 -435
- package/dist/reactor-BmQPQNmi.js.map +1 -0
- package/dist/reactor.worker.d.ts +2 -1
- package/dist/reactor.worker.js +48 -20
- package/dist/reactor.worker.js.map +1 -1
- package/dist/{registerServiceWorker-BSzbNfvz.js → registerServiceWorker-Cy1G2rCq.js} +5 -5
- package/dist/{registerServiceWorker-BSzbNfvz.js.map → registerServiceWorker-Cy1G2rCq.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 +2910 -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-DuoU75ap.js} +73 -10
- package/dist/useRegistryPackages-DuoU75ap.js.map +1 -0
- package/package.json +19 -19
- package/style.css +7 -5
- package/dist/AddDriveModal-Q-Ffh5XA.js.map +0 -1
- package/dist/DriveAuthRequiredModal-Cw9eCAQ_.js.map +0 -1
- package/dist/app-loader-BslURZCB.js +0 -4
- package/dist/app-loader-wq-dOkb0.js.map +0 -1
- package/dist/components-ChVjT238.js +0 -4
- package/dist/preferences-store-_5Cw4_YV.js.map +0 -1
- package/dist/reactor-CSAxliEy.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]="75440a3c-d037-561c-a267-a1ca53a8d755")}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 } from "./pglite-major-BbmMK26m.js";
|
|
6
|
+
import { n as cloneFileData, r as migrateIdb } from "./pglite-migrate-core-o88cWesm.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-Dgs13R1s.js";
|
|
11
|
+
import { n as useAcceptedCookies, t as setBannerShown } from "./preferences-store-Bekp7tv-.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-Cy8xRCm_.js";
|
|
15
|
+
import { n as serviceWorkerManager, r as subscribeServiceWorkerUpdate, t as getServiceWorkerUpdateAvailable } from "./registerServiceWorker-Cy1G2rCq.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;
|
|
776
|
+
}
|
|
777
|
+
};
|
|
778
|
+
//#endregion
|
|
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);
|
|
813
|
+
};
|
|
814
|
+
}
|
|
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);
|
|
949
823
|
}
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
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;
|
|
953
834
|
/**
|
|
954
|
-
*
|
|
955
|
-
*
|
|
956
|
-
*
|
|
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.
|
|
957
840
|
*/
|
|
958
|
-
function
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
}];
|
|
966
|
-
};
|
|
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
|
+
});
|
|
967
848
|
}
|
|
968
849
|
//#endregion
|
|
969
|
-
//#region src/
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
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.
|
|
992
|
-
*/
|
|
993
|
-
function buildTraits(user) {
|
|
994
|
-
const { credential: _credential, ...rest } = user;
|
|
995
|
-
const traits = {
|
|
996
|
-
address: rest.address,
|
|
997
|
-
did: rest.did,
|
|
998
|
-
networkId: rest.networkId,
|
|
999
|
-
chainId: rest.chainId,
|
|
1000
|
-
caip2: `${rest.networkId}:${rest.chainId}`
|
|
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
|
})]
|
|
@@ -1778,25 +1723,98 @@ function Root() {
|
|
|
1778
1723
|
}
|
|
1779
1724
|
//#endregion
|
|
1780
1725
|
//#region src/components/use-drive-auth-gate.ts
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1726
|
+
/**
|
|
1727
|
+
* Decides the gate for the drive the user selected, and only that drive. A
|
|
1728
|
+
* refusal on any other drive must not hide the rest of Connect.
|
|
1729
|
+
*
|
|
1730
|
+
* Connection states are keyed by remote name, which is a random uuid, so the
|
|
1731
|
+
* caller supplies the remote -> drive mapping.
|
|
1732
|
+
*/
|
|
1733
|
+
function computeAuthGate(isAuthenticated, connectionStates, selection) {
|
|
1734
|
+
const { selectedDriveId, remotes } = selection;
|
|
1735
|
+
if (!selectedDriveId) return null;
|
|
1736
|
+
let refused = false;
|
|
1737
|
+
for (const remote of remotes) {
|
|
1738
|
+
if (remote.driveId !== selectedDriveId) continue;
|
|
1739
|
+
const snapshot = connectionStates.get(remote.name);
|
|
1740
|
+
if (snapshot?.state === "error" && snapshot.requiresAuth) {
|
|
1741
|
+
refused = true;
|
|
1742
|
+
break;
|
|
1743
|
+
}
|
|
1786
1744
|
}
|
|
1787
|
-
if (!
|
|
1745
|
+
if (!refused) return null;
|
|
1788
1746
|
return isAuthenticated ? "unauthorized" : "login";
|
|
1789
1747
|
}
|
|
1790
|
-
|
|
1748
|
+
const hiddenDriveIds = /* @__PURE__ */ new Set();
|
|
1749
|
+
let hiddenDriveIdsSnapshot = [];
|
|
1750
|
+
const hiddenDriveListeners = /* @__PURE__ */ new Set();
|
|
1751
|
+
function publishHiddenDrives() {
|
|
1752
|
+
hiddenDriveIdsSnapshot = [...hiddenDriveIds];
|
|
1753
|
+
for (const listener of [...hiddenDriveListeners]) listener();
|
|
1754
|
+
}
|
|
1755
|
+
function subscribeHiddenDrives(listener) {
|
|
1756
|
+
hiddenDriveListeners.add(listener);
|
|
1757
|
+
return () => {
|
|
1758
|
+
hiddenDriveListeners.delete(listener);
|
|
1759
|
+
};
|
|
1760
|
+
}
|
|
1761
|
+
function getHiddenDriveIds() {
|
|
1762
|
+
return hiddenDriveIdsSnapshot;
|
|
1763
|
+
}
|
|
1764
|
+
/** Hides a drive from Connect's drive lists until the page reloads. */
|
|
1765
|
+
function hideDriveForSession(driveId) {
|
|
1766
|
+
if (hiddenDriveIds.has(driveId)) return;
|
|
1767
|
+
hiddenDriveIds.add(driveId);
|
|
1768
|
+
publishHiddenDrives();
|
|
1769
|
+
}
|
|
1770
|
+
/** Restores every drive hidden this session. */
|
|
1771
|
+
function clearHiddenDrives() {
|
|
1772
|
+
if (hiddenDriveIds.size === 0) return;
|
|
1773
|
+
hiddenDriveIds.clear();
|
|
1774
|
+
publishHiddenDrives();
|
|
1775
|
+
}
|
|
1776
|
+
function useHiddenDriveIds() {
|
|
1777
|
+
return useSyncExternalStore(subscribeHiddenDrives, getHiddenDriveIds, getHiddenDriveIds);
|
|
1778
|
+
}
|
|
1779
|
+
/** `useDrives()` minus the drives dismissed from the auth gate this session. */
|
|
1780
|
+
function useVisibleDrives() {
|
|
1781
|
+
const drives = useDrives();
|
|
1782
|
+
const hidden = useHiddenDriveIds();
|
|
1783
|
+
return useMemo(() => {
|
|
1784
|
+
if (!drives || hidden.length === 0) return drives;
|
|
1785
|
+
return drives.filter((drive) => !hidden.includes(drive.header.id));
|
|
1786
|
+
}, [drives, hidden]);
|
|
1787
|
+
}
|
|
1788
|
+
/** Live wrapper over {@link computeAuthGate}, plus the dismiss action. */
|
|
1791
1789
|
function useDriveAuthGate() {
|
|
1792
1790
|
const user = useUser();
|
|
1793
1791
|
const connectionStates = useConnectionStates();
|
|
1794
|
-
|
|
1792
|
+
const syncManager = useSync();
|
|
1793
|
+
const selectedDriveId = useSelectedDriveId();
|
|
1794
|
+
const remotes = useMemo(() => (syncManager?.list() ?? []).map((remote) => ({
|
|
1795
|
+
name: remote.meta.name,
|
|
1796
|
+
driveId: remote.meta.collectionId.driveId
|
|
1797
|
+
})), [syncManager, connectionStates]);
|
|
1798
|
+
const address = user?.address;
|
|
1799
|
+
useEffect(() => {
|
|
1800
|
+
clearHiddenDrives();
|
|
1801
|
+
}, [address]);
|
|
1802
|
+
const dismiss = useCallback(() => {
|
|
1803
|
+
if (selectedDriveId) hideDriveForSession(selectedDriveId);
|
|
1804
|
+
setSelectedDrive(void 0);
|
|
1805
|
+
}, [selectedDriveId]);
|
|
1806
|
+
return {
|
|
1807
|
+
gate: computeAuthGate(Boolean(user), connectionStates, {
|
|
1808
|
+
selectedDriveId,
|
|
1809
|
+
remotes
|
|
1810
|
+
}),
|
|
1811
|
+
dismiss
|
|
1812
|
+
};
|
|
1795
1813
|
}
|
|
1796
1814
|
//#endregion
|
|
1797
1815
|
//#region src/pages/content.tsx
|
|
1798
1816
|
function Content() {
|
|
1799
|
-
const { gate } = useDriveAuthGate();
|
|
1817
|
+
const { gate, dismiss } = useDriveAuthGate();
|
|
1800
1818
|
const openLogin = useOpenRenownLogin();
|
|
1801
1819
|
const [selectedDrive] = useSelectedDriveSafe();
|
|
1802
1820
|
const selectedFolder = useSelectedFolder();
|
|
@@ -1812,7 +1830,8 @@ function Content() {
|
|
|
1812
1830
|
children: /* @__PURE__ */ jsx(DriveAuthGate, {
|
|
1813
1831
|
mode: gate,
|
|
1814
1832
|
onLogin: openLogin,
|
|
1815
|
-
onLogout: () => void logout()
|
|
1833
|
+
onLogout: () => void logout(),
|
|
1834
|
+
onClose: dismiss
|
|
1816
1835
|
})
|
|
1817
1836
|
}) : !selectedDocumentId && !selectedDrive && !selectedFolder ? /* @__PURE__ */ jsx(HomeScreenContainer, {}) : /* @__PURE__ */ jsx(AppContainer, {}) });
|
|
1818
1837
|
}
|
|
@@ -1833,7 +1852,7 @@ function DriveItem({ drive }) {
|
|
|
1833
1852
|
}, drive.header.id);
|
|
1834
1853
|
}
|
|
1835
1854
|
function HomeScreenContainer() {
|
|
1836
|
-
const drives =
|
|
1855
|
+
const drives = useVisibleDrives();
|
|
1837
1856
|
const isAddDriveEnabled = useIsAddDriveEnabled();
|
|
1838
1857
|
const homeBackground = getRuntimeConfig().connect?.branding?.homeBackground;
|
|
1839
1858
|
return /* @__PURE__ */ jsxs(HomeScreen, {
|
|
@@ -1876,11 +1895,69 @@ const Router = () => {
|
|
|
1876
1895
|
return /* @__PURE__ */ jsx(RouterProvider, { router });
|
|
1877
1896
|
};
|
|
1878
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
|
|
1879
1956
|
//#region src/components/sidebar.tsx
|
|
1880
1957
|
function Sidebar() {
|
|
1881
1958
|
const user = useUser();
|
|
1882
1959
|
const openLogin = useOpenRenownLogin();
|
|
1883
|
-
const drives =
|
|
1960
|
+
const drives = useVisibleDrives();
|
|
1884
1961
|
const isAddDriveEnabled = useIsAddDriveEnabled();
|
|
1885
1962
|
const [selectedDrive] = useSelectedDriveSafe();
|
|
1886
1963
|
const connectDebug = localStorage.getItem("CONNECT_DEBUG") === "true";
|
|
@@ -1912,12 +1989,12 @@ function Sidebar() {
|
|
|
1912
1989
|
variant: "text",
|
|
1913
1990
|
fallbackMessage: "There was an error loading drives",
|
|
1914
1991
|
loggerContext: ["Connect", "Sidebar"],
|
|
1915
|
-
children: [drives?.map((drive
|
|
1992
|
+
children: [drives?.map((drive) => /* @__PURE__ */ jsx(SidebarItem, {
|
|
1916
1993
|
title: drive.header.name,
|
|
1917
1994
|
onClick: () => setSelectedDrive(drive),
|
|
1918
1995
|
active: selectedDrive?.header.id === drive.header.id,
|
|
1919
1996
|
icon: /* @__PURE__ */ jsx(DriveIcon, { drive })
|
|
1920
|
-
},
|
|
1997
|
+
}, drive.header.id)), isAddDriveEnabled && /* @__PURE__ */ jsx(SidebarAddDriveItem, { onClick: onAddDriveClick })]
|
|
1921
1998
|
})
|
|
1922
1999
|
}) });
|
|
1923
2000
|
}
|
|
@@ -2056,20 +2133,20 @@ const MigrationBanner = () => {
|
|
|
2056
2133
|
};
|
|
2057
2134
|
//#endregion
|
|
2058
2135
|
//#region src/components/modal/modals-container.tsx
|
|
2059
|
-
const AddDriveModal$1 = lazy(() => import("./AddDriveModal-
|
|
2060
|
-
const ClearStorageModal = lazy(() => import("./ClearStorageModal-
|
|
2061
|
-
const CookiesPolicyModal = lazy(() => import("./CookiesPolicyModal-
|
|
2062
|
-
const CreateDocumentModal$1 = lazy(() => import("./CreateDocumentModal-
|
|
2063
|
-
const DebugSettingsModal = lazy(() => import("./DebugSettingsModal-
|
|
2064
|
-
const DeleteDriveModal = lazy(() => import("./DeleteDriveModal-
|
|
2065
|
-
const DeleteItemModal = lazy(() => import("./DeleteItemModal-
|
|
2066
|
-
const DisclaimerModal = lazy(() => import("./DisclaimerModal-
|
|
2067
|
-
const DriveSettingsModal$1 = lazy(() => import("./DriveSettingsModal-
|
|
2068
|
-
const DownloadDocumentWithErrorsModal = lazy(() => import("./DownloadDocumentWithErrorsModal-
|
|
2069
|
-
const DocumentVersionUnsupportedModal = lazy(() => import("./DocumentVersionUnsupportedModal-
|
|
2070
|
-
const ConfirmDocumentUpgradeModal = lazy(() => import("./ConfirmDocumentUpgradeModal-
|
|
2071
|
-
const SettingsModal$1 = lazy(() => import("./SettingsModal-
|
|
2072
|
-
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-a7dk64ub.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-D_S1LnBH.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-BnQVmt3Z.js").then((m) => ({ default: m.SettingsModal })));
|
|
2149
|
+
const UpgradeDriveModal = lazy(() => import("./UpgradeDriveModal-CXX6D5Au.js").then((m) => ({ default: m.UpgradeDriveModal })));
|
|
2073
2150
|
const modalComponents = {
|
|
2074
2151
|
addDrive: AddDriveModal$1,
|
|
2075
2152
|
clearStorage: ClearStorageModal,
|
|
@@ -2083,13 +2160,13 @@ const modalComponents = {
|
|
|
2083
2160
|
downloadDocumentWithErrors: DownloadDocumentWithErrorsModal,
|
|
2084
2161
|
documentVersionUnsupported: DocumentVersionUnsupportedModal,
|
|
2085
2162
|
confirmDocumentUpgrade: ConfirmDocumentUpgradeModal,
|
|
2086
|
-
inspector: lazy(() => import("./InspectorModal-
|
|
2163
|
+
inspector: lazy(() => import("./InspectorModal-sOCQEpKA.js").then((m) => ({ default: m.InspectorModal }))),
|
|
2087
2164
|
settings: SettingsModal$1,
|
|
2088
2165
|
upgradeDrive: UpgradeDriveModal,
|
|
2089
|
-
missingPackage: lazy(() => import("./MissingPackageModal-
|
|
2090
|
-
driveAuthRequired: lazy(() => import("./DriveAuthRequiredModal-
|
|
2091
|
-
openFileDocuments: lazy(() => import("./OpenFileDocumentsModal-
|
|
2092
|
-
login: lazy(() => import("./LoginModal-
|
|
2166
|
+
missingPackage: lazy(() => import("./MissingPackageModal-HFUPQMML.js").then((m) => ({ default: m.ConnectMissingPackageModal }))),
|
|
2167
|
+
driveAuthRequired: lazy(() => import("./DriveAuthRequiredModal-CtsB0kwH.js").then((m) => ({ default: m.DriveAuthRequiredModal }))),
|
|
2168
|
+
openFileDocuments: lazy(() => import("./OpenFileDocumentsModal-tCrGCLLF.js").then((m) => ({ default: m.OpenFileDocumentsModal }))),
|
|
2169
|
+
login: lazy(() => import("./LoginModal-CI0ogC2-.js").then((m) => ({ default: m.LoginModal })))
|
|
2093
2170
|
};
|
|
2094
2171
|
const ModalsContainer = lazy(() => {
|
|
2095
2172
|
return Promise.resolve({ default: () => {
|
|
@@ -2128,9 +2205,9 @@ const ServiceWorkerUpdatePrompt = () => {
|
|
|
2128
2205
|
};
|
|
2129
2206
|
//#endregion
|
|
2130
2207
|
//#region src/components/app-loader.tsx
|
|
2131
|
-
const CookieBanner$1 = lazy(() => import("./cookie-banner-
|
|
2208
|
+
const CookieBanner$1 = lazy(() => import("./cookie-banner-CSF930bl.js").then((m) => ({ default: m.CookieBanner })));
|
|
2132
2209
|
const AppLoader = (props) => {
|
|
2133
|
-
const Load = lazy(() => import("./load-
|
|
2210
|
+
const Load = lazy(() => import("./load-B7_AbI5f.js").then((m) => m.loadComponent(props.localPackage)));
|
|
2134
2211
|
return /* @__PURE__ */ jsx(StrictMode, { children: /* @__PURE__ */ jsxs(ErrorBoundary$1, {
|
|
2135
2212
|
fallbackRender: (props) => /* @__PURE__ */ jsx(AppSkeleton, { children: /* @__PURE__ */ jsx(DetailedFallback, { ...props }) }),
|
|
2136
2213
|
resetKeys: [props.localPackage],
|
|
@@ -2164,7 +2241,7 @@ const AppLoader = (props) => {
|
|
|
2164
2241
|
}) });
|
|
2165
2242
|
};
|
|
2166
2243
|
//#endregion
|
|
2167
|
-
export {
|
|
2244
|
+
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 };
|
|
2168
2245
|
|
|
2169
|
-
//# sourceMappingURL=app-loader-
|
|
2170
|
-
//# debugId=
|
|
2246
|
+
//# sourceMappingURL=app-loader-D5-KfjU4.js.map
|
|
2247
|
+
//# debugId=75440a3c-d037-561c-a267-a1ca53a8d755
|