@powerhousedao/connect 6.2.3-dev.2 → 6.2.3-dev.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{AddDriveModal-Q-Ffh5XA.js → AddDriveModal-CW-ZSWkf.js} +6 -21
- package/dist/AddDriveModal-CW-ZSWkf.js.map +1 -0
- package/dist/{ClearStorageModal-CcGmYZTu.js → ClearStorageModal-CoXeVy8Y.js} +5 -5
- package/dist/{ClearStorageModal-CcGmYZTu.js.map → ClearStorageModal-CoXeVy8Y.js.map} +1 -1
- package/dist/{ConfirmDocumentUpgradeModal-FUOhZsk7.js → ConfirmDocumentUpgradeModal-BBrFlHp_.js} +6 -6
- package/dist/{ConfirmDocumentUpgradeModal-FUOhZsk7.js.map → ConfirmDocumentUpgradeModal-BBrFlHp_.js.map} +1 -1
- package/dist/{CookiesPolicyModal-BpyPPyxS.js → CookiesPolicyModal-lKdOuTNm.js} +4 -4
- package/dist/{CookiesPolicyModal-BpyPPyxS.js.map → CookiesPolicyModal-lKdOuTNm.js.map} +1 -1
- package/dist/{CreateDocumentModal-C45W8J0V.js → CreateDocumentModal-HmK-78sB.js} +4 -4
- package/dist/{CreateDocumentModal-C45W8J0V.js.map → CreateDocumentModal-HmK-78sB.js.map} +1 -1
- package/dist/{DebugSettingsModal-Bmfn-T8m.js → DebugSettingsModal-BYm2jPPV.js} +7 -7
- package/dist/{DebugSettingsModal-Bmfn-T8m.js.map → DebugSettingsModal-BYm2jPPV.js.map} +1 -1
- package/dist/{DeleteDriveModal-Dug84t1j.js → DeleteDriveModal-Cyw6hwc2.js} +5 -5
- package/dist/{DeleteDriveModal-Dug84t1j.js.map → DeleteDriveModal-Cyw6hwc2.js.map} +1 -1
- package/dist/{DeleteItemModal-mMzy3V8o.js → DeleteItemModal-CiFwstZx.js} +5 -5
- package/dist/{DeleteItemModal-mMzy3V8o.js.map → DeleteItemModal-CiFwstZx.js.map} +1 -1
- package/dist/{DisclaimerModal-DvpD5dPM.js → DisclaimerModal-DIRsjUvu.js} +4 -4
- package/dist/{DisclaimerModal-DvpD5dPM.js.map → DisclaimerModal-DIRsjUvu.js.map} +1 -1
- package/dist/{DocumentVersionUnsupportedModal-C3Q0V75l.js → DocumentVersionUnsupportedModal-KftC3-jr.js} +4 -4
- package/dist/{DocumentVersionUnsupportedModal-C3Q0V75l.js.map → DocumentVersionUnsupportedModal-KftC3-jr.js.map} +1 -1
- package/dist/{DownloadDocumentWithErrorsModal-IKl0ljQb.js → DownloadDocumentWithErrorsModal-CxsR74d-.js} +4 -4
- package/dist/{DownloadDocumentWithErrorsModal-IKl0ljQb.js.map → DownloadDocumentWithErrorsModal-CxsR74d-.js.map} +1 -1
- package/dist/{DriveAuthRequiredModal-Cw9eCAQ_.js → DriveAuthRequiredModal-BoqnnNKT.js} +19 -7
- package/dist/DriveAuthRequiredModal-BoqnnNKT.js.map +1 -0
- package/dist/{DriveSettingsModal-C6-mRQiv.js → DriveSettingsModal-DRarHRIb.js} +4 -4
- package/dist/{DriveSettingsModal-C6-mRQiv.js.map → DriveSettingsModal-DRarHRIb.js.map} +1 -1
- package/dist/{InspectorModal-PtIbilu_.js → InspectorModal-98Hn3VHb.js} +8 -8
- package/dist/{InspectorModal-PtIbilu_.js.map → InspectorModal-98Hn3VHb.js.map} +1 -1
- package/dist/{LoginModal-CybbOm3N.js → LoginModal-DhQTxsoG.js} +5 -5
- package/dist/{LoginModal-CybbOm3N.js.map → LoginModal-DhQTxsoG.js.map} +1 -1
- package/dist/{MissingPackageModal-nBnExqO0.js → MissingPackageModal-Bar7ErIs.js} +5 -5
- package/dist/{MissingPackageModal-nBnExqO0.js.map → MissingPackageModal-Bar7ErIs.js.map} +1 -1
- package/dist/{OpenFileDocumentsModal-Du-V-3od.js → OpenFileDocumentsModal-Cv6CLGAy.js} +6 -6
- package/dist/{OpenFileDocumentsModal-Du-V-3od.js.map → OpenFileDocumentsModal-Cv6CLGAy.js.map} +1 -1
- package/dist/{SettingsModal-C75UaQE8.js → SettingsModal-D93WeiUe.js} +10 -9
- package/dist/{SettingsModal-C75UaQE8.js.map → SettingsModal-D93WeiUe.js.map} +1 -1
- package/dist/{UpgradeDriveModal-_8t9slxQ.js → UpgradeDriveModal-C8scFkuq.js} +4 -4
- package/dist/{UpgradeDriveModal-_8t9slxQ.js.map → UpgradeDriveModal-C8scFkuq.js.map} +1 -1
- package/dist/{app-loader-4yYa_F0I.js → app-loader-BbuC7lmP.js} +1188 -1117
- package/dist/app-loader-BbuC7lmP.js.map +1 -0
- package/dist/app-loader-DdT4MrfI.js +4 -0
- package/dist/app-skeleton-BQts0IHn.js +4 -0
- package/dist/app-skeleton-C6RjKQuy.js +111 -0
- package/dist/app-skeleton-C6RjKQuy.js.map +1 -0
- package/dist/boot-uobbAyWT.js +210 -0
- package/dist/boot-uobbAyWT.js.map +1 -0
- package/dist/buffer-Bu1eWySI.js +66 -0
- package/dist/buffer-Bu1eWySI.js.map +1 -0
- package/dist/{build-info-B24DIeTL.js → build-info-C24WHQ7L.js} +5 -5
- package/dist/{build-info-B24DIeTL.js.map → build-info-C24WHQ7L.js.map} +1 -1
- package/dist/components-BEG2PFJE.js +5 -0
- package/dist/{connect.config-DaHDEUrw.js → connect.config-BofwIsWJ.js} +4 -3
- package/dist/{connect.config-DaHDEUrw.js.map → connect.config-BofwIsWJ.js.map} +1 -1
- package/dist/{connection-state-3w4liC1X.js → connection-state-DAqW06pk.js} +5 -5
- package/dist/{connection-state-3w4liC1X.js.map → connection-state-DAqW06pk.js.map} +1 -1
- package/dist/{cookie-banner-BH6bIq24.js → cookie-banner-BQescTYk.js} +6 -6
- package/dist/{cookie-banner-BH6bIq24.js.map → cookie-banner-BQescTYk.js.map} +1 -1
- package/dist/{i18n-CWO0vYVd.js → i18n-90Q8hAPL.js} +3 -3
- package/dist/{i18n-CWO0vYVd.js.map → i18n-90Q8hAPL.js.map} +1 -1
- package/dist/{load-B45H0s1X.js → load-DLrFSyLN.js} +8 -8
- package/dist/{load-B45H0s1X.js.map → load-DLrFSyLN.js.map} +1 -1
- package/dist/main.js +8 -8
- package/dist/main.js.map +1 -1
- package/dist/package-manager-CKEdIJGv.js +475 -0
- package/dist/package-manager-CKEdIJGv.js.map +1 -0
- package/dist/{pglite-major-B39aOEiE.js → pglite-major-D3sdYMs2.js} +3 -3
- package/dist/{pglite-major-B39aOEiE.js.map → pglite-major-D3sdYMs2.js.map} +1 -1
- package/dist/{pglite-migrate-core-Boxqqx-c.js → pglite-migrate-core-BIWwtl5e.js} +4 -4
- package/dist/{pglite-migrate-core-Boxqqx-c.js.map → pglite-migrate-core-BIWwtl5e.js.map} +1 -1
- package/dist/{pglite-seed-BqAUvNFw.js → pglite-seed-ChNTfFkc.js} +4 -4
- package/dist/{pglite-seed-BqAUvNFw.js.map → pglite-seed-ChNTfFkc.js.map} +1 -1
- package/dist/{preferences-store-_5Cw4_YV.js → preferences-store-Coa1SHvi.js} +6 -25
- package/dist/preferences-store-Coa1SHvi.js.map +1 -0
- package/dist/{pwa-manifest-link-DIgOSo2Q.js → pwa-manifest-link-B38lBmEu.js} +3 -3
- package/dist/{pwa-manifest-link-DIgOSo2Q.js.map → pwa-manifest-link-B38lBmEu.js.map} +1 -1
- package/dist/{reactor-BMNq8chi.js → reactor-CedYEEQQ.js} +26 -421
- package/dist/reactor-CedYEEQQ.js.map +1 -0
- package/dist/reactor.worker.js +29 -13
- package/dist/reactor.worker.js.map +1 -1
- package/dist/{registerServiceWorker-BSzbNfvz.js → registerServiceWorker-BAbPbSW4.js} +5 -5
- package/dist/{registerServiceWorker-BSzbNfvz.js.map → registerServiceWorker-BAbPbSW4.js.map} +1 -1
- 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 +2060 -0
- package/dist/{toast-BXIGd4Eb.js → toast-CO6ChlzE.js} +3 -3
- package/dist/{toast-BXIGd4Eb.js.map → toast-CO6ChlzE.js.map} +1 -1
- package/dist/{use-renown-login-Cf3va6u_.js → use-renown-login-rS9wfcuG.js} +3 -3
- package/dist/{use-renown-login-Cf3va6u_.js.map → use-renown-login-rS9wfcuG.js.map} +1 -1
- package/dist/useIsEmbedded-B_AIFqBu.js +26 -0
- package/dist/useIsEmbedded-B_AIFqBu.js.map +1 -0
- package/dist/{useRegistryPackages-BnUcL_nZ.js → useRegistryPackages-C2WHmqn4.js} +60 -3
- package/dist/useRegistryPackages-C2WHmqn4.js.map +1 -0
- package/package.json +13 -12
- package/style.css +4 -0
- package/dist/AddDriveModal-Q-Ffh5XA.js.map +0 -1
- package/dist/DriveAuthRequiredModal-Cw9eCAQ_.js.map +0 -1
- package/dist/app-loader-4yYa_F0I.js.map +0 -1
- package/dist/app-loader-e4nqwWF5.js +0 -4
- package/dist/components-Dx56Q8EI.js +0 -4
- package/dist/preferences-store-_5Cw4_YV.js.map +0 -1
- package/dist/reactor-BMNq8chi.js.map +0 -1
- package/dist/useRegistryPackages-BnUcL_nZ.js.map +0 -1
|
@@ -1,27 +1,31 @@
|
|
|
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]="
|
|
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]="4b603cc8-96ef-555a-ad0e-ceb73451bf03")}catch(e){}}();
|
|
3
3
|
import { n as getRuntimeConfig } from "./runtime-config-DL3QjcfM.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { n as
|
|
4
|
+
import { n as drainOpenPanelBuffer, t as clearOpenPanelBuffer } from "./buffer-Bu1eWySI.js";
|
|
5
|
+
import { c as idbError } from "./pglite-major-D3sdYMs2.js";
|
|
6
|
+
import { n as cloneFileData, r as migrateIdb } from "./pglite-migrate-core-BIWwtl5e.js";
|
|
7
|
+
import { n as setMigrationStatus, t as AppSkeleton } from "./app-skeleton-C6RjKQuy.js";
|
|
8
|
+
import { n as useIsEmbedded } from "./useIsEmbedded-B_AIFqBu.js";
|
|
9
|
+
import { a as defaultPHDocumentEditorConfig, i as defaultPHAppConfig, r as connectConfig } from "./connect.config-BofwIsWJ.js";
|
|
10
|
+
import { n as useAcceptedCookies, t as setBannerShown } from "./preferences-store-Coa1SHvi.js";
|
|
9
11
|
import { t as setSentryModule } from "./sentry-QXKgQmr2.js";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { t as
|
|
12
|
+
import { n as dismissToast, r as toast, t as ToastContainer } from "./toast-CO6ChlzE.js";
|
|
13
|
+
import { f as PRIMARY_IDB_NAMES, r as subscribeWorkerConnection, s as getCachedMigrationMajor, t as getWorkerConnectionStatus, u as subscribeMigrationMajor } from "./connection-state-DAqW06pk.js";
|
|
14
|
+
import { n as serviceWorkerManager, r as subscribeServiceWorkerUpdate, t as getServiceWorkerUpdateAvailable } from "./registerServiceWorker-BAbPbSW4.js";
|
|
15
|
+
import { t as useOpenRenownLogin } from "./use-renown-login-rS9wfcuG.js";
|
|
13
16
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
14
|
-
import { useTranslation } from "react-i18next";
|
|
17
|
+
import { Trans, useTranslation } from "react-i18next";
|
|
15
18
|
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";
|
|
19
|
+
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";
|
|
20
|
+
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
21
|
import { Icon, Modal, PowerhouseButton } from "@powerhousedao/design-system";
|
|
22
|
+
import { childLogger } from "document-model";
|
|
22
23
|
import { ErrorBoundary } from "react-error-boundary";
|
|
23
24
|
import { z } from "zod";
|
|
24
25
|
import { GenericDriveExplorer } from "@powerhousedao/powerhouse-vetra-packages/editors";
|
|
26
|
+
import { Outlet, RouterProvider, createBrowserRouter, createRoutesFromChildren, matchRoutes, useLocation, useNavigationType } from "react-router-dom";
|
|
27
|
+
import { redo, undo } from "@powerhousedao/shared/document-model";
|
|
28
|
+
import { useHotkeys } from "react-hotkeys-hook";
|
|
25
29
|
import { createReactorMcpProvider } from "@powerhousedao/reactor-mcp/tools";
|
|
26
30
|
import { ReactorChatFab, createSwitchboardSchemaTool } from "@powerhousedao/reactor-browser/ai";
|
|
27
31
|
import { twMerge } from "tailwind-merge";
|
|
@@ -29,487 +33,663 @@ import { mockAdapter } from "@renown/sdk/wallet/mock";
|
|
|
29
33
|
import { privyAdapter } from "@renown/sdk/wallet/privy";
|
|
30
34
|
import { rainbowAdapter } from "@renown/sdk/wallet/rainbow";
|
|
31
35
|
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;
|
|
36
|
+
//#region src/components/error-boundary.tsx
|
|
37
|
+
const logger$2 = childLogger(["Connect"]);
|
|
38
|
+
function hasCustomFallback(props) {
|
|
39
|
+
return "fallbackRender" in props;
|
|
94
40
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
return `${file.name}|${file.size}|${file.lastModified}`;
|
|
41
|
+
function SilentFallback() {
|
|
42
|
+
return null;
|
|
98
43
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Simple text-based fallback component.
|
|
46
|
+
* Displays a centered message when an error occurs.
|
|
47
|
+
*/
|
|
48
|
+
function TextFallback({ message = "Something went wrong" }) {
|
|
49
|
+
return /* @__PURE__ */ jsx("div", {
|
|
50
|
+
className: "text-center wrap-break-word text-foreground",
|
|
51
|
+
children: message
|
|
106
52
|
});
|
|
107
|
-
if (fresh.length === 0) return;
|
|
108
|
-
pendingImportFiles = [...pendingImportFiles, ...fresh];
|
|
109
|
-
notifyPendingListeners();
|
|
110
53
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Detailed fallback component showing full error information.
|
|
56
|
+
* Displays error message with a collapsible details section.
|
|
57
|
+
* Useful for development and debugging purposes.
|
|
58
|
+
*/
|
|
59
|
+
function DetailedFallback({ error, resetErrorBoundary }) {
|
|
60
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
61
|
+
const errorDetails = error instanceof Error ? error.stack ?? String(error.cause) : JSON.stringify(error, null, 2);
|
|
62
|
+
return /* @__PURE__ */ jsx("div", {
|
|
63
|
+
className: "z-10 mx-auto flex max-w-[80%] flex-1 items-center justify-center p-6",
|
|
64
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
65
|
+
className: "w-full max-w-lg rounded-lg border border-border bg-card p-6 text-foreground shadow-sm",
|
|
66
|
+
children: [
|
|
67
|
+
/* @__PURE__ */ jsxs("div", {
|
|
68
|
+
className: "mb-3 flex items-center gap-2",
|
|
69
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
70
|
+
name: "Error",
|
|
71
|
+
className: "size-5 shrink-0 text-destructive"
|
|
72
|
+
}), /* @__PURE__ */ jsx("h1", {
|
|
73
|
+
className: "text-lg font-semibold text-foreground",
|
|
74
|
+
children: "Something went wrong"
|
|
75
|
+
})]
|
|
76
|
+
}),
|
|
77
|
+
/* @__PURE__ */ jsx("p", {
|
|
78
|
+
className: "mb-4 text-sm wrap-break-word text-foreground",
|
|
79
|
+
children: errorMessage
|
|
80
|
+
}),
|
|
81
|
+
errorDetails !== "{}" && /* @__PURE__ */ jsxs("details", {
|
|
82
|
+
className: "group",
|
|
83
|
+
children: [/* @__PURE__ */ jsx("summary", {
|
|
84
|
+
className: "cursor-pointer text-sm font-medium text-foreground underline select-none hover:hover-effect",
|
|
85
|
+
children: "Show details"
|
|
86
|
+
}), /* @__PURE__ */ jsx("pre", {
|
|
87
|
+
className: "mt-2 max-h-48 overflow-auto rounded-sm bg-muted p-3 text-xs text-foreground",
|
|
88
|
+
children: errorDetails
|
|
89
|
+
})]
|
|
90
|
+
}),
|
|
91
|
+
/* @__PURE__ */ jsx(PowerhouseButton, {
|
|
92
|
+
type: "button",
|
|
93
|
+
onClick: resetErrorBoundary,
|
|
94
|
+
className: "mt-4 px-3 py-1.5 text-base font-medium",
|
|
95
|
+
children: "Try again"
|
|
96
|
+
})
|
|
97
|
+
]
|
|
98
|
+
})
|
|
99
|
+
});
|
|
115
100
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
101
|
+
/**
|
|
102
|
+
* Centered error message fallback component.
|
|
103
|
+
* Displays the error message in a centered, full-size container.
|
|
104
|
+
* Suitable for use as a custom fallbackRender when you need simple error display.
|
|
105
|
+
*/
|
|
106
|
+
function CenteredErrorMessage({ error }) {
|
|
107
|
+
return /* @__PURE__ */ jsx("div", {
|
|
108
|
+
className: "flex size-full items-center justify-center p-6",
|
|
109
|
+
children: /* @__PURE__ */ jsx("h3", {
|
|
110
|
+
className: "max-w-lg min-w-0 text-center text-lg font-semibold wrap-break-word text-foreground",
|
|
111
|
+
children: error instanceof Error ? error.message : String(error)
|
|
112
|
+
})
|
|
113
|
+
});
|
|
121
114
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
} catch (error) {
|
|
129
|
-
console.error("Failed to read launched file:", handle.name, error);
|
|
115
|
+
function getFallbackComponent(variant, fallbackMessage) {
|
|
116
|
+
switch (variant) {
|
|
117
|
+
case "silent": return SilentFallback;
|
|
118
|
+
case "text": return () => /* @__PURE__ */ jsx(TextFallback, { message: fallbackMessage });
|
|
119
|
+
case "detailed": return DetailedFallback;
|
|
120
|
+
default: return CenteredErrorMessage;
|
|
130
121
|
}
|
|
131
|
-
if (files.length === 0) return;
|
|
132
|
-
addPendingImportFiles(files);
|
|
133
|
-
showPHModal({ type: "openFileDocuments" });
|
|
134
122
|
}
|
|
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
123
|
/**
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
124
|
+
* Unified error boundary component for catching and handling React errors.
|
|
125
|
+
*
|
|
126
|
+
* Built on top of `react-error-boundary`, this component provides:
|
|
127
|
+
* - Automatic error logging with configurable context
|
|
128
|
+
* - Multiple fallback UI variants (silent, text, detailed)
|
|
129
|
+
* - Support for custom fallback render functions
|
|
130
|
+
* - Reset capability via `resetKeys`
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* // Using a predefined variant
|
|
134
|
+
* <ErrorBoundary variant="detailed" loggerContext={["Connect", "Editor"]}>
|
|
135
|
+
* <EditorComponent />
|
|
136
|
+
* </ErrorBoundary>
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* // Using a custom message with the text variant
|
|
140
|
+
* <ErrorBoundary variant="text" fallbackMessage="Failed to load drives">
|
|
141
|
+
* <DrivesList />
|
|
142
|
+
* </ErrorBoundary>
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* // Using a custom fallback render
|
|
146
|
+
* <ErrorBoundary
|
|
147
|
+
* fallbackRender={CenteredErrorMessage}
|
|
148
|
+
* onError={(error) => trackError(error)}
|
|
149
|
+
* >
|
|
150
|
+
* <MyComponent />
|
|
151
|
+
* </ErrorBoundary>
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* // Silent mode for modals (renders null on error)
|
|
155
|
+
* <ErrorBoundary variant="silent" loggerContext={["Connect", "Modals"]}>
|
|
156
|
+
* <ModalContent />
|
|
157
|
+
* </ErrorBoundary>
|
|
147
158
|
*/
|
|
148
|
-
function
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
159
|
+
function ErrorBoundary$1(props) {
|
|
160
|
+
const { children, onError, resetKeys, loggerContext } = props;
|
|
161
|
+
const handleError = (error, info) => {
|
|
162
|
+
if (error.message.includes("Failed to fetch dynamically imported module") && error.message.includes("node_modules/.vite")) {
|
|
163
|
+
console.error(error);
|
|
164
|
+
console.log("Outdated chunk detected, reloading page...");
|
|
165
|
+
window.location.reload();
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
(loggerContext ? childLogger(loggerContext) : logger$2).error("@error @info", error, info);
|
|
169
|
+
onError?.(error, info);
|
|
170
|
+
};
|
|
171
|
+
return /* @__PURE__ */ jsx(ErrorBoundary, {
|
|
172
|
+
fallbackRender: hasCustomFallback(props) ? props.fallbackRender : getFallbackComponent(props.variant, props.fallbackMessage),
|
|
173
|
+
onError: handleError,
|
|
174
|
+
resetKeys,
|
|
175
|
+
children
|
|
154
176
|
});
|
|
155
177
|
}
|
|
156
178
|
//#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
|
-
};
|
|
179
|
+
//#region src/components/analytics.tsx
|
|
180
|
+
function gtag(...args) {
|
|
181
|
+
window.dataLayer?.push(...args);
|
|
171
182
|
}
|
|
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();
|
|
183
|
+
const Analytics = () => {
|
|
184
|
+
const gaTrackingId = connectConfig.gaTrackingId;
|
|
185
|
+
const [{ analytics }] = useAcceptedCookies();
|
|
186
|
+
const useAnalytics = gaTrackingId && analytics;
|
|
187
|
+
useEffect(() => {
|
|
188
|
+
if (useAnalytics) {
|
|
189
|
+
const script = document.createElement("script");
|
|
190
|
+
script.src = `https://www.googletagmanager.com/gtag/js?id=${gaTrackingId}`;
|
|
191
|
+
script.async = true;
|
|
192
|
+
document.head.appendChild(script);
|
|
193
|
+
window.dataLayer = window.dataLayer || [];
|
|
194
|
+
gtag("js", /* @__PURE__ */ new Date());
|
|
195
|
+
gtag("config", gaTrackingId);
|
|
196
|
+
return () => {
|
|
197
|
+
document.head.removeChild(script);
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
}, [useAnalytics, gaTrackingId]);
|
|
201
|
+
return null;
|
|
202
|
+
};
|
|
203
|
+
//#endregion
|
|
204
|
+
//#region src/services/openpanel/client.ts
|
|
205
|
+
let client;
|
|
196
206
|
/**
|
|
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.
|
|
207
|
+
* Returns the cached `OpenPanel` singleton, building it on first call.
|
|
208
|
+
*
|
|
209
|
+
* When `config.clientId` is empty it returns `undefined` without importing
|
|
210
|
+
* `@openpanel/web`, so the bundler can tree-shake the SDK out of production.
|
|
203
211
|
*/
|
|
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
|
-
});
|
|
212
|
+
async function getOpenPanelClient(config) {
|
|
213
|
+
if (!config.clientId) return;
|
|
214
|
+
if (client) return client;
|
|
215
|
+
const { OpenPanel: OpenPanelClass } = await import("@openpanel/web");
|
|
216
|
+
client = new OpenPanelClass({
|
|
217
|
+
clientId: config.clientId,
|
|
218
|
+
...config.apiUrl ? { apiUrl: config.apiUrl } : {},
|
|
219
|
+
trackScreenViews: true,
|
|
220
|
+
trackOutgoingLinks: true
|
|
233
221
|
});
|
|
222
|
+
client.setGlobalProperties({ app: "connect" });
|
|
223
|
+
drainOpenPanelBuffer(client);
|
|
224
|
+
return client;
|
|
234
225
|
}
|
|
235
226
|
/**
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
* single-file batch that succeeds opens its document in the editor.
|
|
227
|
+
* Clears the cached singleton and the pre-init buffer. Call on consent
|
|
228
|
+
* revocation or during tests; buffered events are discarded, not replayed.
|
|
239
229
|
*/
|
|
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
|
-
};
|
|
230
|
+
function resetOpenPanelClient() {
|
|
231
|
+
client = void 0;
|
|
232
|
+
clearOpenPanelBuffer();
|
|
279
233
|
}
|
|
280
234
|
//#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
|
-
|
|
235
|
+
//#region src/services/openpanel/events.json
|
|
236
|
+
var events_default = [
|
|
237
|
+
{
|
|
238
|
+
"documentType": "powerhouse/document-drive",
|
|
239
|
+
"actionTypes": [
|
|
240
|
+
"ADD_FOLDER",
|
|
241
|
+
"DELETE_NODE",
|
|
242
|
+
"ADD_FILE",
|
|
243
|
+
"UPDATE_FILE",
|
|
244
|
+
"COPY_NODE",
|
|
245
|
+
"MOVE_NODE",
|
|
246
|
+
"SET_DRIVE_NAME",
|
|
247
|
+
"SET_DRIVE_ICON"
|
|
248
|
+
]
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
"documentType": "powerhouse/document-model",
|
|
252
|
+
"actionTypes": [
|
|
253
|
+
"SET_MODEL_NAME",
|
|
254
|
+
"SET_MODEL_ID",
|
|
255
|
+
"ADD_MODULE",
|
|
256
|
+
"DELETE_MODULE",
|
|
257
|
+
"ADD_OPERATION",
|
|
258
|
+
"DELETE_OPERATION"
|
|
259
|
+
]
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
"documentType": "powerhouse/reactor-drive",
|
|
263
|
+
"actionTypes": [
|
|
264
|
+
"ADD_FOLDER",
|
|
265
|
+
"REMOVE_FOLDER",
|
|
266
|
+
"UPDATE_FOLDER"
|
|
267
|
+
]
|
|
313
268
|
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
269
|
+
];
|
|
270
|
+
//#endregion
|
|
271
|
+
//#region src/services/openpanel/events.ts
|
|
272
|
+
const EventMappingSchema = z.object({
|
|
273
|
+
documentType: z.string().min(1),
|
|
274
|
+
actionTypes: z.array(z.string().min(1)).min(1),
|
|
275
|
+
alias: z.string().optional()
|
|
276
|
+
}).strict();
|
|
277
|
+
const EventMappingsSchema = z.array(EventMappingSchema).readonly();
|
|
278
|
+
/**
|
|
279
|
+
* Parses and validates the event mapping table, returning the validated array
|
|
280
|
+
* and an O(1) lookup map. Accepts a `raw` override for tests. Throws on zod
|
|
281
|
+
* failures and on duplicate `(documentType, actionType)` pairs.
|
|
282
|
+
*/
|
|
283
|
+
function loadEvents(raw = events_default) {
|
|
284
|
+
const result = EventMappingsSchema.safeParse(raw);
|
|
285
|
+
if (!result.success) throw new Error(`Invalid OpenPanel events.json: ${result.error.message}`);
|
|
286
|
+
const mappings = result.data;
|
|
287
|
+
const lookupMap = /* @__PURE__ */ new Map();
|
|
288
|
+
for (const mapping of mappings) {
|
|
289
|
+
let inner = lookupMap.get(mapping.documentType);
|
|
290
|
+
if (!inner) {
|
|
291
|
+
inner = /* @__PURE__ */ new Map();
|
|
292
|
+
lookupMap.set(mapping.documentType, inner);
|
|
333
293
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
console.warn(`Failed to delete expired pglite backup ${rec.name}`, err);
|
|
338
|
-
keep.push(rec);
|
|
294
|
+
for (const actionType of mapping.actionTypes) {
|
|
295
|
+
if (inner.has(actionType)) throw new Error(`Duplicate OpenPanel event mapping for ${mapping.documentType}/${actionType}`);
|
|
296
|
+
inner.set(actionType, mapping);
|
|
339
297
|
}
|
|
340
298
|
}
|
|
341
|
-
writeBackupIndex(keep);
|
|
342
|
-
}
|
|
343
|
-
function createPersistentBackup() {
|
|
344
299
|
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()
|
|
300
|
+
mappings,
|
|
301
|
+
lookupMap
|
|
372
302
|
};
|
|
373
303
|
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
304
|
+
const { mappings: defaultMappings, lookupMap: defaultLookupMap } = loadEvents();
|
|
305
|
+
/** Validated mapping array from the bundled events.json. */
|
|
306
|
+
const eventMappings = defaultMappings;
|
|
307
|
+
/** O(1) lookup map: documentType → actionType → mapping. */
|
|
308
|
+
const eventLookupMap = defaultLookupMap;
|
|
309
|
+
/**
|
|
310
|
+
* Normalizes a document type into a safe event-name segment: lowercased, `/`
|
|
311
|
+
* replaced with `.`, and any character outside `[a-z0-9._-]` stripped.
|
|
312
|
+
* e.g. `powerhouse/document-drive` → `powerhouse.document-drive`.
|
|
313
|
+
*/
|
|
314
|
+
function normalize(documentType) {
|
|
315
|
+
return documentType.toLowerCase().replace(/\//g, ".").replace(/[^a-z0-9._-]/g, "");
|
|
384
316
|
}
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
await migrateAllLocked();
|
|
393
|
-
});
|
|
317
|
+
/**
|
|
318
|
+
* Derives the OpenPanel event name: `mapping.alias` when present, otherwise
|
|
319
|
+
* `${normalize(documentType)}.${actionType.toLowerCase()}`.
|
|
320
|
+
*/
|
|
321
|
+
function deriveEventName(mapping, op) {
|
|
322
|
+
if (mapping.alias) return mapping.alias;
|
|
323
|
+
return `${normalize(op.context.documentType)}.${op.operation.action.type.toLowerCase()}`;
|
|
394
324
|
}
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
return
|
|
325
|
+
/**
|
|
326
|
+
* Builds the default properties attached to every OpenPanel event. The `app`
|
|
327
|
+
* property is stamped globally by the client, not here.
|
|
328
|
+
*/
|
|
329
|
+
function buildDefaultProperties(op) {
|
|
330
|
+
return {
|
|
331
|
+
documentType: op.context.documentType,
|
|
332
|
+
actionType: op.operation.action.type,
|
|
333
|
+
documentId: op.context.documentId,
|
|
334
|
+
scope: op.context.scope,
|
|
335
|
+
branch: op.context.branch
|
|
336
|
+
};
|
|
401
337
|
}
|
|
402
338
|
//#endregion
|
|
403
|
-
//#region src/
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
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;
|
|
339
|
+
//#region src/services/openpanel/processor.ts
|
|
340
|
+
/**
|
|
341
|
+
* Read-only reactor `IProcessor` that translates matching document operations
|
|
342
|
+
* into OpenPanel analytics events. Operations whose `(documentType, actionType)`
|
|
343
|
+
* pair is absent from the lookup map are skipped; per-operation errors are
|
|
344
|
+
* routed to `onError` and never thrown back to the manager.
|
|
345
|
+
*/
|
|
346
|
+
var OpenPanelProcessor = class {
|
|
347
|
+
constructor(client, lookupMap, onError = (err) => console.warn("[OpenPanelProcessor] Error tracking event:", err)) {
|
|
348
|
+
this.client = client;
|
|
349
|
+
this.lookupMap = lookupMap;
|
|
350
|
+
this.onError = onError;
|
|
351
|
+
}
|
|
352
|
+
async onOperations(operations) {
|
|
353
|
+
for (const op of operations) {
|
|
354
|
+
const inner = this.lookupMap.get(op.context.documentType);
|
|
355
|
+
if (!inner) continue;
|
|
356
|
+
const mapping = inner.get(op.operation.action.type);
|
|
357
|
+
if (!mapping) continue;
|
|
358
|
+
const name = deriveEventName(mapping, op);
|
|
359
|
+
const payload = buildDefaultProperties(op);
|
|
360
|
+
try {
|
|
361
|
+
await this.client.track(name, payload);
|
|
362
|
+
} catch (err) {
|
|
363
|
+
this.onError(err, op);
|
|
364
|
+
}
|
|
460
365
|
}
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
366
|
+
}
|
|
367
|
+
onDisconnect() {
|
|
368
|
+
this.client.flush?.();
|
|
369
|
+
return Promise.resolve();
|
|
370
|
+
}
|
|
371
|
+
};
|
|
465
372
|
//#endregion
|
|
466
|
-
//#region src/services/openpanel/
|
|
467
|
-
const buffer = [];
|
|
468
|
-
let errorHandler;
|
|
469
|
-
function defaultOnError(err) {
|
|
470
|
-
console.warn("[useOpenPanelAnalytics] track failed:", err);
|
|
471
|
-
}
|
|
373
|
+
//#region src/services/openpanel/factory.ts
|
|
472
374
|
/**
|
|
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`.
|
|
375
|
+
* Returns a `ProcessorFactory` that, for each drive, creates a single
|
|
376
|
+
* `OpenPanelProcessor` record whose `filter.documentType` is the union of all
|
|
377
|
+
* document types present in the event mapping table.
|
|
478
378
|
*/
|
|
479
|
-
function
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
379
|
+
function createOpenPanelProcessorFactory(config) {
|
|
380
|
+
return function openPanelProcessorFactory(_driveHeader) {
|
|
381
|
+
const documentType = Array.from(config.events.lookupMap.keys());
|
|
382
|
+
return [{
|
|
383
|
+
processor: new OpenPanelProcessor(config.client, config.events.lookupMap, config.onError),
|
|
384
|
+
filter: { documentType },
|
|
385
|
+
startFrom: config.startFrom ?? "current"
|
|
386
|
+
}];
|
|
387
|
+
};
|
|
485
388
|
}
|
|
389
|
+
//#endregion
|
|
390
|
+
//#region src/components/openpanel-traits.ts
|
|
486
391
|
/**
|
|
487
|
-
*
|
|
488
|
-
*
|
|
392
|
+
* Builds the OpenPanel identity traits from a renown User.
|
|
393
|
+
*
|
|
394
|
+
* Canonical trait schema (shared with Renown and Vetra — each app sends every
|
|
395
|
+
* field it has data for, under these names):
|
|
396
|
+
* - `address`, `did`, `networkId`, `chainId`, `caip2` — wallet/chain facts.
|
|
397
|
+
* - `ensName`, `ensAvatar` — raw ENS facts.
|
|
398
|
+
* - `username`, `userImage`, `profileDocumentId`, `profileCreatedAt` — raw
|
|
399
|
+
* Renown profile facts.
|
|
400
|
+
* - `accountType` — wallet-adapter concept; only Renown has it.
|
|
401
|
+
*
|
|
402
|
+
* Rules:
|
|
403
|
+
* - `credential` (contains a JWT) is **never** forwarded.
|
|
404
|
+
* - Traits carry raw facts only; resolved presentation values (avatar,
|
|
405
|
+
* display name) go in OpenPanel's native identify fields — see
|
|
406
|
+
* {@link buildIdentifyPayload}.
|
|
407
|
+
* - Optional fields (`ens`, `profile`) are only included when their value is
|
|
408
|
+
* non-nullish (guards against `null` from `RenownProfile` fields as well
|
|
409
|
+
* as plain `undefined`).
|
|
410
|
+
*
|
|
411
|
+
* Mirror the Sentry pattern in `store/user.ts`: destructure off `credential`
|
|
412
|
+
* first, then assemble the trait payload from the remainder.
|
|
489
413
|
*/
|
|
490
|
-
function
|
|
491
|
-
|
|
492
|
-
const
|
|
493
|
-
|
|
414
|
+
function buildTraits(user) {
|
|
415
|
+
const { credential: _credential, ...rest } = user;
|
|
416
|
+
const traits = {
|
|
417
|
+
address: rest.address,
|
|
418
|
+
did: rest.did,
|
|
419
|
+
networkId: rest.networkId,
|
|
420
|
+
chainId: rest.chainId,
|
|
421
|
+
caip2: `${rest.networkId}:${rest.chainId}`
|
|
422
|
+
};
|
|
423
|
+
if (rest.ens?.name != null) traits.ensName = rest.ens.name;
|
|
424
|
+
if (rest.ens?.avatarUrl != null) traits.ensAvatar = rest.ens.avatarUrl;
|
|
425
|
+
if (rest.profile?.username != null) traits.username = rest.profile.username;
|
|
426
|
+
if (rest.profile?.userImage != null) traits.userImage = rest.profile.userImage;
|
|
427
|
+
if (rest.profile?.documentId != null) traits.profileDocumentId = rest.profile.documentId;
|
|
428
|
+
if (rest.profile?.createdAt != null) traits.profileCreatedAt = rest.profile.createdAt;
|
|
429
|
+
return traits;
|
|
494
430
|
}
|
|
495
431
|
/**
|
|
496
|
-
*
|
|
497
|
-
*
|
|
432
|
+
* Builds the full `identify()` payload:
|
|
433
|
+
* - `profileId` is the wallet address — the cross-app profile key shared with
|
|
434
|
+
* Renown and Vetra.
|
|
435
|
+
* - `avatar` / `firstName` are OpenPanel's native profile fields (they drive
|
|
436
|
+
* the picture and name in the dashboard UI), resolved as
|
|
437
|
+
* `userImage ?? ensAvatar` and `ensName ?? username`.
|
|
438
|
+
* - `properties` are the raw traits from {@link buildTraits}.
|
|
498
439
|
*/
|
|
499
|
-
function
|
|
500
|
-
|
|
501
|
-
|
|
440
|
+
function buildIdentifyPayload(user) {
|
|
441
|
+
const avatar = user.profile?.userImage ?? user.ens?.avatarUrl;
|
|
442
|
+
const firstName = user.ens?.name ?? user.profile?.username;
|
|
443
|
+
return {
|
|
444
|
+
profileId: user.address,
|
|
445
|
+
...avatar != null ? { avatar } : {},
|
|
446
|
+
...firstName != null ? { firstName } : {},
|
|
447
|
+
properties: buildTraits(user)
|
|
448
|
+
};
|
|
502
449
|
}
|
|
503
450
|
//#endregion
|
|
504
|
-
//#region src/
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
451
|
+
//#region src/components/openpanel.tsx
|
|
452
|
+
/**
|
|
453
|
+
* `OpenPanel` is a `null`-rendering component that manages the full lifecycle
|
|
454
|
+
* of the OpenPanel analytics subsystem.
|
|
455
|
+
*
|
|
456
|
+
* Gates:
|
|
457
|
+
* - `useAcceptedCookies().analytics === true` — the existing analytics cookie.
|
|
458
|
+
* - `connectConfig.openPanel.clientId` non-empty — no client ID → no-op.
|
|
459
|
+
*
|
|
460
|
+
* Behaviour when both gates pass:
|
|
461
|
+
* 1. Lazy-imports `@openpanel/web` and builds the singleton via
|
|
462
|
+
* `getOpenPanelClient(connectConfig.openPanel)`.
|
|
463
|
+
* 2. Exposes the client on `window.openPanel` for the card-6
|
|
464
|
+
* `useOpenPanelAnalytics()` hook to consume.
|
|
465
|
+
* 3. If `connectConfig.openPanel.trackOperations`, registers the processor
|
|
466
|
+
* factory against `processorManager` so document operations are forwarded.
|
|
467
|
+
* 4. Calls `client.identify()` when the renown user transitions from
|
|
468
|
+
* `undefined` → defined (login). The profile ID is the wallet address —
|
|
469
|
+
* the cross-app key shared with Renown and Vetra.
|
|
470
|
+
* 5. Calls `client.clear()` when the user transitions from defined →
|
|
471
|
+
* `undefined` (logout).
|
|
472
|
+
*
|
|
473
|
+
* Teardown (unmount **or** consent revocation):
|
|
474
|
+
* - `unregisterFactory("openpanel")` to remove the processor.
|
|
475
|
+
* - `resetOpenPanelClient()` to clear the singleton.
|
|
476
|
+
* - `window.openPanel` is cleared.
|
|
477
|
+
*
|
|
478
|
+
* Mirrors the Sentry pattern in `store/user.ts` for login/logout detection.
|
|
479
|
+
* Analytics failures are caught and forwarded to `console.warn` — they must
|
|
480
|
+
* never throw into the application.
|
|
481
|
+
*
|
|
482
|
+
* Mounted next to `<Analytics />` in `app.tsx`.
|
|
483
|
+
*/
|
|
484
|
+
function OpenPanel() {
|
|
485
|
+
const [{ analytics }] = useAcceptedCookies();
|
|
486
|
+
const user = useUser();
|
|
487
|
+
const module = useReactorClientModule();
|
|
488
|
+
const reactorClientModule = module?.kind === "browser" ? module : void 0;
|
|
489
|
+
const [client, setClient] = useState();
|
|
490
|
+
/**
|
|
491
|
+
* Tracks the previous `user` value so we can detect the two transitions:
|
|
492
|
+
* undefined → defined (login)
|
|
493
|
+
* defined → undefined (logout)
|
|
494
|
+
*/
|
|
495
|
+
const prevUserRef = useRef(void 0);
|
|
496
|
+
const enabled = analytics && !!connectConfig.openPanel.clientId;
|
|
497
|
+
const processorManager = reactorClientModule?.reactorModule?.processorManager;
|
|
498
|
+
useEffect(() => {
|
|
499
|
+
if (!enabled) return;
|
|
500
|
+
let cancelled = false;
|
|
501
|
+
const isCancelled = () => cancelled;
|
|
502
|
+
const setup = async () => {
|
|
503
|
+
let builtClient;
|
|
504
|
+
try {
|
|
505
|
+
builtClient = await getOpenPanelClient(connectConfig.openPanel);
|
|
506
|
+
} catch (err) {
|
|
507
|
+
console.warn("[OpenPanel] Failed to build client:", err);
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
if (isCancelled() || !builtClient) return;
|
|
511
|
+
setClient(builtClient);
|
|
512
|
+
window.openPanel = builtClient;
|
|
513
|
+
if (connectConfig.openPanel.trackOperations && processorManager) try {
|
|
514
|
+
await processorManager.registerFactory("openpanel", createOpenPanelProcessorFactory({
|
|
515
|
+
client: builtClient,
|
|
516
|
+
events: {
|
|
517
|
+
mappings: eventMappings,
|
|
518
|
+
lookupMap: eventLookupMap
|
|
519
|
+
},
|
|
520
|
+
startFrom: "current"
|
|
521
|
+
}));
|
|
522
|
+
if (isCancelled()) await processorManager.unregisterFactory("openpanel").catch((err) => console.warn("[OpenPanel] Failed to unregister factory after cancellation:", err));
|
|
523
|
+
} catch (err) {
|
|
524
|
+
console.warn("[OpenPanel] Failed to register processor factory:", err);
|
|
525
|
+
}
|
|
526
|
+
};
|
|
527
|
+
setup();
|
|
528
|
+
return () => {
|
|
529
|
+
cancelled = true;
|
|
530
|
+
prevUserRef.current = void 0;
|
|
531
|
+
if (connectConfig.openPanel.trackOperations && processorManager) processorManager.unregisterFactory("openpanel").catch((err) => console.warn("[OpenPanel] Failed to unregister processor factory:", err));
|
|
532
|
+
resetOpenPanelClient();
|
|
533
|
+
window.openPanel = void 0;
|
|
534
|
+
setClient(void 0);
|
|
535
|
+
};
|
|
536
|
+
}, [enabled, processorManager]);
|
|
537
|
+
useEffect(() => {
|
|
538
|
+
if (!enabled || !client) return;
|
|
539
|
+
const prev = prevUserRef.current;
|
|
540
|
+
prevUserRef.current = user;
|
|
541
|
+
if (!prev && user) try {
|
|
542
|
+
client.identify(buildIdentifyPayload(user));
|
|
543
|
+
} catch (err) {
|
|
544
|
+
console.warn("[OpenPanel] Failed to identify user:", err);
|
|
545
|
+
}
|
|
546
|
+
else if (prev && !user) try {
|
|
547
|
+
client.clear();
|
|
548
|
+
} catch (err) {
|
|
549
|
+
console.warn("[OpenPanel] Failed to clear user:", err);
|
|
550
|
+
}
|
|
551
|
+
}, [
|
|
552
|
+
client,
|
|
553
|
+
user,
|
|
554
|
+
enabled
|
|
555
|
+
]);
|
|
556
|
+
return null;
|
|
557
|
+
}
|
|
558
|
+
//#endregion
|
|
559
|
+
//#region src/components/document-editor-container.tsx
|
|
560
|
+
function DocumentEditorContainer() {
|
|
561
|
+
const [selectedDocument] = useSelectedDocument();
|
|
562
|
+
const parentFolder = useNodeParentFolderById(selectedDocument.header.id);
|
|
563
|
+
useMemo(() => {
|
|
564
|
+
return async () => {};
|
|
565
|
+
}, []);
|
|
566
|
+
useCallback(() => {
|
|
567
|
+
setSelectedNode(parentFolder);
|
|
568
|
+
}, [parentFolder]);
|
|
569
|
+
return /* @__PURE__ */ jsx("div", {
|
|
570
|
+
id: "document-editor-container",
|
|
571
|
+
className: "flex-1",
|
|
572
|
+
"data-document-type": selectedDocument.header.documentType,
|
|
573
|
+
children: /* @__PURE__ */ jsx(DocumentEditor, { document: selectedDocument })
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
//#endregion
|
|
577
|
+
//#region src/components/editor-loader.tsx
|
|
578
|
+
function EditorLoader(props) {
|
|
579
|
+
const [showLoading, setShowLoading] = useState(false);
|
|
580
|
+
useEffect(() => {
|
|
581
|
+
setTimeout(() => {
|
|
582
|
+
setShowLoading(true);
|
|
583
|
+
}, props.loadingTimeout ?? 200);
|
|
584
|
+
}, [props]);
|
|
585
|
+
if (!showLoading) return null;
|
|
586
|
+
const { customEditorLoader, ...defaultProps } = props;
|
|
587
|
+
if (customEditorLoader) return /* @__PURE__ */ jsx(Fragment, { children: customEditorLoader });
|
|
588
|
+
return /* @__PURE__ */ jsx(DefaultEditorLoader, { ...defaultProps });
|
|
589
|
+
}
|
|
590
|
+
//#endregion
|
|
591
|
+
//#region src/components/app-container.tsx
|
|
592
|
+
function AppContainer() {
|
|
593
|
+
const [selectedDrive] = useSelectedDriveSafe();
|
|
594
|
+
const selectedDocumentId = useSelectedDocumentId();
|
|
595
|
+
const app = useAppModuleById(selectedDrive?.header.meta?.preferredEditor);
|
|
596
|
+
const defaultApp = useDefaultAppModule();
|
|
597
|
+
if (!selectedDrive) return /* @__PURE__ */ jsx(EditorLoader, {});
|
|
598
|
+
const AppComponent = app?.Component ?? defaultApp?.Component ?? GenericDriveExplorer.Component;
|
|
599
|
+
if (!AppComponent) throw new Error("No app component found");
|
|
600
|
+
return /* @__PURE__ */ jsx(ErrorBoundary$1, {
|
|
601
|
+
variant: "detailed",
|
|
602
|
+
resetKeys: [selectedDrive.header.id],
|
|
603
|
+
loggerContext: ["Connect", "App"],
|
|
604
|
+
children: /* @__PURE__ */ jsx(Suspense, {
|
|
605
|
+
fallback: /* @__PURE__ */ jsx(EditorLoader, {}),
|
|
606
|
+
children: /* @__PURE__ */ jsx(DropZoneWrapper, {
|
|
607
|
+
className: "flex h-full flex-col overflow-auto",
|
|
608
|
+
children: /* @__PURE__ */ jsx(AppComponent, { children: selectedDocumentId ? /* @__PURE__ */ jsx(DocumentEditorContainer, {}) : null })
|
|
609
|
+
})
|
|
610
|
+
})
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
//#endregion
|
|
614
|
+
//#region src/hooks/useFailedInstallations.ts
|
|
615
|
+
const emptyArray$1 = [];
|
|
616
|
+
function useFailedInstallations() {
|
|
617
|
+
const discoveryService = usePackageDiscoveryService();
|
|
618
|
+
return useSyncExternalStore((cb) => discoveryService?.subscribeFailed(cb) ?? (() => {}), () => discoveryService?.getFailedInstallations() ?? emptyArray$1);
|
|
619
|
+
}
|
|
620
|
+
//#endregion
|
|
621
|
+
//#region src/hooks/useInitSentry.ts
|
|
622
|
+
const logger$1 = childLogger(["sentry"]);
|
|
623
|
+
let clientStarted = false;
|
|
624
|
+
async function getSentry() {
|
|
625
|
+
return await import("@sentry/react");
|
|
626
|
+
}
|
|
627
|
+
async function initSentry() {
|
|
628
|
+
const Sentry = await getSentry();
|
|
629
|
+
const integrations = [
|
|
630
|
+
Sentry.httpClientIntegration(),
|
|
631
|
+
Sentry.extraErrorDataIntegration({ depth: 5 }),
|
|
632
|
+
Sentry.replayIntegration(),
|
|
633
|
+
Sentry.captureConsoleIntegration({ levels: ["error"] })
|
|
634
|
+
];
|
|
635
|
+
if (connectConfig.sentry.tracing) integrations.push(Sentry.reactRouterV6BrowserTracingIntegration({
|
|
636
|
+
useEffect: React.useEffect,
|
|
637
|
+
useLocation,
|
|
638
|
+
useNavigationType,
|
|
639
|
+
createRoutesFromChildren,
|
|
640
|
+
matchRoutes
|
|
641
|
+
}));
|
|
642
|
+
Sentry.init({
|
|
643
|
+
release: connectConfig.sentry.release,
|
|
644
|
+
dsn: connectConfig.sentry.dsn ?? void 0,
|
|
645
|
+
environment: connectConfig.sentry.env,
|
|
646
|
+
integrations,
|
|
647
|
+
ignoreErrors: [
|
|
648
|
+
"User is not allowed to create files",
|
|
649
|
+
"User is not allowed to move documents",
|
|
650
|
+
"The user aborted a request."
|
|
651
|
+
],
|
|
652
|
+
sendDefaultPii: true,
|
|
653
|
+
tracesSampleRate: 1,
|
|
654
|
+
replaysSessionSampleRate: .1,
|
|
655
|
+
replaysOnErrorSampleRate: 1,
|
|
656
|
+
beforeSend(event, hint) {
|
|
657
|
+
const error = hint.originalException;
|
|
658
|
+
if (error instanceof TypeError && error.message.includes("Failed to fetch") && !navigator.onLine) return null;
|
|
659
|
+
return event;
|
|
660
|
+
}
|
|
661
|
+
});
|
|
662
|
+
setSentryModule(Sentry);
|
|
663
|
+
clientStarted = true;
|
|
664
|
+
}
|
|
665
|
+
async function closeClient() {
|
|
666
|
+
if (!clientStarted) return;
|
|
667
|
+
const sentry = await getSentry();
|
|
668
|
+
setSentryModule(void 0);
|
|
669
|
+
return sentry.getClient()?.close();
|
|
670
|
+
}
|
|
671
|
+
function useInitSentry() {
|
|
672
|
+
const [acceptedCookies] = useAcceptedCookies();
|
|
673
|
+
const { analytics } = acceptedCookies;
|
|
674
|
+
useEffect(() => {
|
|
675
|
+
if (!analytics) {
|
|
676
|
+
closeClient().catch((error) => logger$1.error("@error", error));
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
if (clientStarted || connectConfig.sentry.dsn === null || connectConfig.sentry.dsn === void 0 || connectConfig.sentry.dsn === "") return;
|
|
680
|
+
initSentry().catch((error) => logger$1.error("@error", error));
|
|
681
|
+
}, [analytics]);
|
|
682
|
+
}
|
|
683
|
+
//#endregion
|
|
684
|
+
//#region src/hooks/usePendingInstallations.ts
|
|
685
|
+
const emptyArray = [];
|
|
686
|
+
function usePendingInstallations() {
|
|
687
|
+
const discoveryService = usePackageDiscoveryService();
|
|
688
|
+
const cacheRef = useRef(emptyArray);
|
|
689
|
+
return useSyncExternalStore((cb) => discoveryService?.subscribePending(cb) ?? (() => {}), useCallback(() => {
|
|
690
|
+
if (!discoveryService) return emptyArray;
|
|
691
|
+
const next = discoveryService.getPendingInstallations() ?? emptyArray;
|
|
692
|
+
const prev = cacheRef.current;
|
|
513
693
|
if (next === prev || next.length === prev.length && next.every((p, i) => p === prev[i])) return prev;
|
|
514
694
|
cacheRef.current = next;
|
|
515
695
|
return next;
|
|
@@ -536,666 +716,356 @@ const useUndoRedoShortcuts = (props) => {
|
|
|
536
716
|
}, {}, [canRedo, redo]);
|
|
537
717
|
};
|
|
538
718
|
//#endregion
|
|
539
|
-
//#region src/
|
|
540
|
-
const
|
|
541
|
-
|
|
542
|
-
|
|
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
|
-
});
|
|
719
|
+
//#region src/context/sentry-provider.tsx
|
|
720
|
+
const SentryProvider = ({ children }) => {
|
|
721
|
+
useInitSentry();
|
|
722
|
+
return children;
|
|
584
723
|
};
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
724
|
+
//#endregion
|
|
725
|
+
//#region src/utils/document-editor-debug-tools.ts
|
|
726
|
+
var DocumentEditorDebugTools = class {
|
|
727
|
+
document;
|
|
728
|
+
operations = [];
|
|
729
|
+
constructor(document) {
|
|
730
|
+
if (document) this.document = document;
|
|
731
|
+
}
|
|
732
|
+
operationsToTableObject(operations) {
|
|
733
|
+
return operations.map((op) => ({
|
|
734
|
+
...op,
|
|
735
|
+
input: JSON.stringify(op.action.input)
|
|
736
|
+
}));
|
|
737
|
+
}
|
|
738
|
+
setDocument(document) {
|
|
739
|
+
this.document = document;
|
|
740
|
+
}
|
|
741
|
+
getDocument() {
|
|
742
|
+
return this.document;
|
|
743
|
+
}
|
|
744
|
+
getOperations() {
|
|
745
|
+
return this.operations;
|
|
746
|
+
}
|
|
747
|
+
pushOperation(operation) {
|
|
748
|
+
this.operations.push(operation);
|
|
749
|
+
}
|
|
750
|
+
operationsTable() {
|
|
751
|
+
if (!this.document) console.warn("No document");
|
|
752
|
+
const ops = Object.values(this.document?.operations || {}).filter((array) => array !== void 0).flatMap((array) => array).sort((a, b) => a.index - b.index);
|
|
753
|
+
console.table(this.operationsToTableObject(ops));
|
|
754
|
+
}
|
|
755
|
+
scopeOperationsTable(scope) {
|
|
756
|
+
if (!this.document) console.warn("No document");
|
|
757
|
+
const ops = this.document?.operations[scope] || [];
|
|
758
|
+
console.table(this.operationsToTableObject(ops));
|
|
759
|
+
}
|
|
760
|
+
operationsLog() {
|
|
761
|
+
console.log(this.operations);
|
|
762
|
+
}
|
|
763
|
+
operationsLogTable() {
|
|
764
|
+
console.table(this.operationsToTableObject(this.operations));
|
|
765
|
+
}
|
|
766
|
+
clear() {
|
|
767
|
+
this.operations = [];
|
|
768
|
+
this.document = void 0;
|
|
769
|
+
}
|
|
613
770
|
};
|
|
614
771
|
//#endregion
|
|
615
|
-
//#region src/
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
772
|
+
//#region src/utils/launch-queue.ts
|
|
773
|
+
let pendingImportFiles = [];
|
|
774
|
+
const pendingListeners = /* @__PURE__ */ new Set();
|
|
775
|
+
function notifyPendingListeners() {
|
|
776
|
+
for (const listener of pendingListeners) listener();
|
|
619
777
|
}
|
|
620
|
-
function
|
|
621
|
-
return
|
|
778
|
+
function getPendingImportFiles() {
|
|
779
|
+
return pendingImportFiles;
|
|
622
780
|
}
|
|
623
|
-
/**
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
*/
|
|
627
|
-
function TextFallback({ message = "Something went wrong" }) {
|
|
628
|
-
return /* @__PURE__ */ jsx("div", {
|
|
629
|
-
className: "text-center wrap-break-word text-foreground",
|
|
630
|
-
children: message
|
|
631
|
-
});
|
|
781
|
+
/** Stable identity of a pending file (also the picker's pre-check cache key). */
|
|
782
|
+
function pendingFileKey(file) {
|
|
783
|
+
return `${file.name}|${file.size}|${file.lastModified}`;
|
|
632
784
|
}
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
const errorDetails = error instanceof Error ? error.stack ?? String(error.cause) : JSON.stringify(error, null, 2);
|
|
641
|
-
return /* @__PURE__ */ jsx("div", {
|
|
642
|
-
className: "z-10 mx-auto flex max-w-[80%] flex-1 items-center justify-center p-6",
|
|
643
|
-
children: /* @__PURE__ */ jsxs("div", {
|
|
644
|
-
className: "w-full max-w-lg rounded-lg border border-border bg-card p-6 text-foreground shadow-sm",
|
|
645
|
-
children: [
|
|
646
|
-
/* @__PURE__ */ jsxs("div", {
|
|
647
|
-
className: "mb-3 flex items-center gap-2",
|
|
648
|
-
children: [/* @__PURE__ */ jsx(Icon, {
|
|
649
|
-
name: "Error",
|
|
650
|
-
className: "size-5 shrink-0 text-destructive"
|
|
651
|
-
}), /* @__PURE__ */ jsx("h1", {
|
|
652
|
-
className: "text-lg font-semibold text-foreground",
|
|
653
|
-
children: "Something went wrong"
|
|
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
|
-
})
|
|
785
|
+
function addPendingImportFiles(files) {
|
|
786
|
+
const seen = new Set(pendingImportFiles.map(pendingFileKey));
|
|
787
|
+
const fresh = files.filter((file) => {
|
|
788
|
+
const key = pendingFileKey(file);
|
|
789
|
+
if (seen.has(key)) return false;
|
|
790
|
+
seen.add(key);
|
|
791
|
+
return true;
|
|
678
792
|
});
|
|
793
|
+
if (fresh.length === 0) return;
|
|
794
|
+
pendingImportFiles = [...pendingImportFiles, ...fresh];
|
|
795
|
+
notifyPendingListeners();
|
|
679
796
|
}
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
*/
|
|
685
|
-
function CenteredErrorMessage({ error }) {
|
|
686
|
-
return /* @__PURE__ */ jsx("div", {
|
|
687
|
-
className: "flex size-full items-center justify-center p-6",
|
|
688
|
-
children: /* @__PURE__ */ jsx("h3", {
|
|
689
|
-
className: "max-w-lg min-w-0 text-center text-lg font-semibold wrap-break-word text-foreground",
|
|
690
|
-
children: error instanceof Error ? error.message : String(error)
|
|
691
|
-
})
|
|
692
|
-
});
|
|
797
|
+
function clearPendingImportFiles() {
|
|
798
|
+
if (pendingImportFiles.length === 0) return;
|
|
799
|
+
pendingImportFiles = [];
|
|
800
|
+
notifyPendingListeners();
|
|
693
801
|
}
|
|
694
|
-
function
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
802
|
+
function subscribePendingImportFiles(cb) {
|
|
803
|
+
pendingListeners.add(cb);
|
|
804
|
+
return () => {
|
|
805
|
+
pendingListeners.delete(cb);
|
|
806
|
+
};
|
|
807
|
+
}
|
|
808
|
+
async function handleLaunchParams(params) {
|
|
809
|
+
const handles = params.files.filter((handle) => handle.kind === "file");
|
|
810
|
+
if (handles.length === 0) return;
|
|
811
|
+
const files = [];
|
|
812
|
+
for (const handle of handles) try {
|
|
813
|
+
files.push(await handle.getFile());
|
|
814
|
+
} catch (error) {
|
|
815
|
+
console.error("Failed to read launched file:", handle.name, error);
|
|
700
816
|
}
|
|
817
|
+
if (files.length === 0) return;
|
|
818
|
+
addPendingImportFiles(files);
|
|
819
|
+
showPHModal({ type: "openFileDocuments" });
|
|
820
|
+
}
|
|
821
|
+
function maybeReopenImportModal() {
|
|
822
|
+
if (getPendingImportFiles().length === 0) return;
|
|
823
|
+
if (window.ph?.modal !== void 0) return;
|
|
824
|
+
showPHModal({ type: "openFileDocuments" });
|
|
701
825
|
}
|
|
826
|
+
let initialized = false;
|
|
702
827
|
/**
|
|
703
|
-
*
|
|
704
|
-
*
|
|
705
|
-
*
|
|
706
|
-
*
|
|
707
|
-
*
|
|
708
|
-
* - Support for custom fallback render functions
|
|
709
|
-
* - Reset capability via `resetKeys`
|
|
710
|
-
*
|
|
711
|
-
* @example
|
|
712
|
-
* // Using a predefined variant
|
|
713
|
-
* <ErrorBoundary variant="detailed" loggerContext={["Connect", "Editor"]}>
|
|
714
|
-
* <EditorComponent />
|
|
715
|
-
* </ErrorBoundary>
|
|
716
|
-
*
|
|
717
|
-
* @example
|
|
718
|
-
* // Using a custom message with the text variant
|
|
719
|
-
* <ErrorBoundary variant="text" fallbackMessage="Failed to load drives">
|
|
720
|
-
* <DrivesList />
|
|
721
|
-
* </ErrorBoundary>
|
|
722
|
-
*
|
|
723
|
-
* @example
|
|
724
|
-
* // Using a custom fallback render
|
|
725
|
-
* <ErrorBoundary
|
|
726
|
-
* fallbackRender={CenteredErrorMessage}
|
|
727
|
-
* onError={(error) => trackError(error)}
|
|
728
|
-
* >
|
|
729
|
-
* <MyComponent />
|
|
730
|
-
* </ErrorBoundary>
|
|
731
|
-
*
|
|
732
|
-
* @example
|
|
733
|
-
* // Silent mode for modals (renders null on error)
|
|
734
|
-
* <ErrorBoundary variant="silent" loggerContext={["Connect", "Modals"]}>
|
|
735
|
-
* <ModalContent />
|
|
736
|
-
* </ErrorBoundary>
|
|
828
|
+
* Register the launchQueue consumer that receives files opened with Connect
|
|
829
|
+
* through the OS file association. Idempotent (safe under StrictMode double
|
|
830
|
+
* effects) and a no-op where the File Handling API doesn't exist — Firefox,
|
|
831
|
+
* Safari, and any context without an installed PWA manifest simply never
|
|
832
|
+
* deliver launches.
|
|
737
833
|
*/
|
|
738
|
-
function
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
window.location.reload();
|
|
745
|
-
return;
|
|
746
|
-
}
|
|
747
|
-
(loggerContext ? childLogger(loggerContext) : logger$1).error("@error @info", error, info);
|
|
748
|
-
onError?.(error, info);
|
|
749
|
-
};
|
|
750
|
-
return /* @__PURE__ */ jsx(ErrorBoundary, {
|
|
751
|
-
fallbackRender: hasCustomFallback(props) ? props.fallbackRender : getFallbackComponent(props.variant, props.fallbackMessage),
|
|
752
|
-
onError: handleError,
|
|
753
|
-
resetKeys,
|
|
754
|
-
children
|
|
834
|
+
function initLaunchQueueFileHandling() {
|
|
835
|
+
if (initialized) return;
|
|
836
|
+
initialized = true;
|
|
837
|
+
window.addEventListener("ph:modalUpdated", maybeReopenImportModal);
|
|
838
|
+
window.launchQueue?.setConsumer((params) => {
|
|
839
|
+
handleLaunchParams(params);
|
|
755
840
|
});
|
|
756
841
|
}
|
|
757
842
|
//#endregion
|
|
758
|
-
//#region src/
|
|
759
|
-
|
|
760
|
-
|
|
843
|
+
//#region src/utils/open-file-uploads.ts
|
|
844
|
+
let uploads = [];
|
|
845
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
846
|
+
function notifyUploadListeners() {
|
|
847
|
+
for (const listener of listeners) listener();
|
|
761
848
|
}
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
const [{ analytics }] = useAcceptedCookies();
|
|
765
|
-
const useAnalytics = gaTrackingId && analytics;
|
|
766
|
-
useEffect(() => {
|
|
767
|
-
if (useAnalytics) {
|
|
768
|
-
const script = document.createElement("script");
|
|
769
|
-
script.src = `https://www.googletagmanager.com/gtag/js?id=${gaTrackingId}`;
|
|
770
|
-
script.async = true;
|
|
771
|
-
document.head.appendChild(script);
|
|
772
|
-
window.dataLayer = window.dataLayer || [];
|
|
773
|
-
gtag("js", /* @__PURE__ */ new Date());
|
|
774
|
-
gtag("config", gaTrackingId);
|
|
775
|
-
return () => {
|
|
776
|
-
document.head.removeChild(script);
|
|
777
|
-
};
|
|
778
|
-
}
|
|
779
|
-
}, [useAnalytics, gaTrackingId]);
|
|
780
|
-
return null;
|
|
781
|
-
};
|
|
782
|
-
//#endregion
|
|
783
|
-
//#region src/services/openpanel/client.ts
|
|
784
|
-
let client;
|
|
785
|
-
/**
|
|
786
|
-
* Returns the cached `OpenPanel` singleton, building it on first call.
|
|
787
|
-
*
|
|
788
|
-
* When `config.clientId` is empty it returns `undefined` without importing
|
|
789
|
-
* `@openpanel/web`, so the bundler can tree-shake the SDK out of production.
|
|
790
|
-
*/
|
|
791
|
-
async function getOpenPanelClient(config) {
|
|
792
|
-
if (!config.clientId) return;
|
|
793
|
-
if (client) return client;
|
|
794
|
-
const { OpenPanel: OpenPanelClass } = await import("@openpanel/web");
|
|
795
|
-
client = new OpenPanelClass({
|
|
796
|
-
clientId: config.clientId,
|
|
797
|
-
...config.apiUrl ? { apiUrl: config.apiUrl } : {},
|
|
798
|
-
trackScreenViews: true,
|
|
799
|
-
trackOutgoingLinks: true
|
|
800
|
-
});
|
|
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();
|
|
849
|
+
function getOpenFileUploads() {
|
|
850
|
+
return uploads;
|
|
812
851
|
}
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
"documentType": "powerhouse/document-drive",
|
|
818
|
-
"actionTypes": [
|
|
819
|
-
"ADD_FOLDER",
|
|
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
|
-
];
|
|
849
|
-
//#endregion
|
|
850
|
-
//#region src/services/openpanel/events.ts
|
|
851
|
-
const EventMappingSchema = z.object({
|
|
852
|
-
documentType: z.string().min(1),
|
|
853
|
-
actionTypes: z.array(z.string().min(1)).min(1),
|
|
854
|
-
alias: z.string().optional()
|
|
855
|
-
}).strict();
|
|
856
|
-
const EventMappingsSchema = z.array(EventMappingSchema).readonly();
|
|
857
|
-
/**
|
|
858
|
-
* Parses and validates the event mapping table, returning the validated array
|
|
859
|
-
* and an O(1) lookup map. Accepts a `raw` override for tests. Throws on zod
|
|
860
|
-
* failures and on duplicate `(documentType, actionType)` pairs.
|
|
861
|
-
*/
|
|
862
|
-
function loadEvents(raw = events_default) {
|
|
863
|
-
const result = EventMappingsSchema.safeParse(raw);
|
|
864
|
-
if (!result.success) throw new Error(`Invalid OpenPanel events.json: ${result.error.message}`);
|
|
865
|
-
const mappings = result.data;
|
|
866
|
-
const lookupMap = /* @__PURE__ */ new Map();
|
|
867
|
-
for (const mapping of mappings) {
|
|
868
|
-
let inner = lookupMap.get(mapping.documentType);
|
|
869
|
-
if (!inner) {
|
|
870
|
-
inner = /* @__PURE__ */ new Map();
|
|
871
|
-
lookupMap.set(mapping.documentType, inner);
|
|
872
|
-
}
|
|
873
|
-
for (const actionType of mapping.actionTypes) {
|
|
874
|
-
if (inner.has(actionType)) throw new Error(`Duplicate OpenPanel event mapping for ${mapping.documentType}/${actionType}`);
|
|
875
|
-
inner.set(actionType, mapping);
|
|
876
|
-
}
|
|
877
|
-
}
|
|
878
|
-
return {
|
|
879
|
-
mappings,
|
|
880
|
-
lookupMap
|
|
852
|
+
function subscribeOpenFileUploads(cb) {
|
|
853
|
+
listeners.add(cb);
|
|
854
|
+
return () => {
|
|
855
|
+
listeners.delete(cb);
|
|
881
856
|
};
|
|
882
857
|
}
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
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, "");
|
|
895
|
-
}
|
|
896
|
-
/**
|
|
897
|
-
* Derives the OpenPanel event name: `mapping.alias` when present, otherwise
|
|
898
|
-
* `${normalize(documentType)}.${actionType.toLowerCase()}`.
|
|
899
|
-
*/
|
|
900
|
-
function deriveEventName(mapping, op) {
|
|
901
|
-
if (mapping.alias) return mapping.alias;
|
|
902
|
-
return `${normalize(op.context.documentType)}.${op.operation.action.type.toLowerCase()}`;
|
|
858
|
+
function removeOpenFileUpload(id) {
|
|
859
|
+
const next = uploads.filter((upload) => upload.id !== id);
|
|
860
|
+
if (next.length === uploads.length) return;
|
|
861
|
+
uploads = next;
|
|
862
|
+
notifyUploadListeners();
|
|
903
863
|
}
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
function buildDefaultProperties(op) {
|
|
909
|
-
return {
|
|
910
|
-
documentType: op.context.documentType,
|
|
911
|
-
actionType: op.operation.action.type,
|
|
912
|
-
documentId: op.context.documentId,
|
|
913
|
-
scope: op.context.scope,
|
|
914
|
-
branch: op.context.branch
|
|
915
|
-
};
|
|
864
|
+
function clearOpenFileUploads() {
|
|
865
|
+
if (uploads.length === 0) return;
|
|
866
|
+
uploads = [];
|
|
867
|
+
notifyUploadListeners();
|
|
916
868
|
}
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
* Read-only reactor `IProcessor` that translates matching document operations
|
|
921
|
-
* into OpenPanel analytics events. Operations whose `(documentType, actionType)`
|
|
922
|
-
* pair is absent from the lookup map are skipped; per-operation errors are
|
|
923
|
-
* routed to `onError` and never thrown back to the manager.
|
|
924
|
-
*/
|
|
925
|
-
var OpenPanelProcessor = class {
|
|
926
|
-
constructor(client, lookupMap, onError = (err) => console.warn("[OpenPanelProcessor] Error tracking event:", err)) {
|
|
927
|
-
this.client = client;
|
|
928
|
-
this.lookupMap = lookupMap;
|
|
929
|
-
this.onError = onError;
|
|
930
|
-
}
|
|
931
|
-
async onOperations(operations) {
|
|
932
|
-
for (const op of operations) {
|
|
933
|
-
const inner = this.lookupMap.get(op.context.documentType);
|
|
934
|
-
if (!inner) continue;
|
|
935
|
-
const mapping = inner.get(op.operation.action.type);
|
|
936
|
-
if (!mapping) continue;
|
|
937
|
-
const name = deriveEventName(mapping, op);
|
|
938
|
-
const payload = buildDefaultProperties(op);
|
|
939
|
-
try {
|
|
940
|
-
await this.client.track(name, payload);
|
|
941
|
-
} catch (err) {
|
|
942
|
-
this.onError(err, op);
|
|
943
|
-
}
|
|
944
|
-
}
|
|
945
|
-
}
|
|
946
|
-
onDisconnect() {
|
|
947
|
-
this.client.flush?.();
|
|
948
|
-
return Promise.resolve();
|
|
949
|
-
}
|
|
950
|
-
};
|
|
951
|
-
//#endregion
|
|
952
|
-
//#region src/services/openpanel/factory.ts
|
|
953
|
-
/**
|
|
954
|
-
* Returns a `ProcessorFactory` that, for each drive, creates a single
|
|
955
|
-
* `OpenPanelProcessor` record whose `filter.documentType` is the union of all
|
|
956
|
-
* document types present in the event mapping table.
|
|
957
|
-
*/
|
|
958
|
-
function createOpenPanelProcessorFactory(config) {
|
|
959
|
-
return function openPanelProcessorFactory(_driveHeader) {
|
|
960
|
-
const documentType = Array.from(config.events.lookupMap.keys());
|
|
961
|
-
return [{
|
|
962
|
-
processor: new OpenPanelProcessor(config.client, config.events.lookupMap, config.onError),
|
|
963
|
-
filter: { documentType },
|
|
964
|
-
startFrom: config.startFrom ?? "current"
|
|
965
|
-
}];
|
|
966
|
-
};
|
|
869
|
+
function addOpenFileUploads(rows) {
|
|
870
|
+
uploads = [...uploads, ...rows];
|
|
871
|
+
notifyUploadListeners();
|
|
967
872
|
}
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
* field it has data for, under these names):
|
|
975
|
-
* - `address`, `did`, `networkId`, `chainId`, `caip2` — wallet/chain facts.
|
|
976
|
-
* - `ensName`, `ensAvatar` — raw ENS facts.
|
|
977
|
-
* - `username`, `userImage`, `profileDocumentId`, `profileCreatedAt` — raw
|
|
978
|
-
* Renown profile facts.
|
|
979
|
-
* - `accountType` — wallet-adapter concept; only Renown has it.
|
|
980
|
-
*
|
|
981
|
-
* Rules:
|
|
982
|
-
* - `credential` (contains a JWT) is **never** forwarded.
|
|
983
|
-
* - Traits carry raw facts only; resolved presentation values (avatar,
|
|
984
|
-
* display name) go in OpenPanel's native identify fields — see
|
|
985
|
-
* {@link buildIdentifyPayload}.
|
|
986
|
-
* - Optional fields (`ens`, `profile`) are only included when their value is
|
|
987
|
-
* non-nullish (guards against `null` from `RenownProfile` fields as well
|
|
988
|
-
* as plain `undefined`).
|
|
989
|
-
*
|
|
990
|
-
* Mirror the Sentry pattern in `store/user.ts`: destructure off `credential`
|
|
991
|
-
* first, then assemble the trait payload from the remainder.
|
|
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}`
|
|
1001
|
-
};
|
|
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;
|
|
873
|
+
function patchOpenFileUpload(id, patch) {
|
|
874
|
+
uploads = uploads.map((upload) => upload.id === id ? {
|
|
875
|
+
...upload,
|
|
876
|
+
...patch
|
|
877
|
+
} : upload);
|
|
878
|
+
notifyUploadListeners();
|
|
1009
879
|
}
|
|
880
|
+
let uploadCounter = 0;
|
|
881
|
+
let importChain = Promise.resolve();
|
|
1010
882
|
/**
|
|
1011
|
-
*
|
|
1012
|
-
*
|
|
1013
|
-
*
|
|
1014
|
-
*
|
|
1015
|
-
*
|
|
1016
|
-
*
|
|
1017
|
-
* - `properties` are the raw traits from {@link buildTraits}.
|
|
883
|
+
* Import one file and resolve once the flow truly ends. Completion is
|
|
884
|
+
* tracked through the progress stages, NOT the returned promise — the
|
|
885
|
+
* package-discovery retry path resolves early and keeps reporting through
|
|
886
|
+
* the callback. `resolveConflict: "duplicate"` is always passed: duplicates
|
|
887
|
+
* were resolved in the picker (rename), so the conflict stage must never
|
|
888
|
+
* fire — this also covers a duplicate appearing between pre-check and import.
|
|
1018
889
|
*/
|
|
1019
|
-
function
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
890
|
+
function importOne(row, driveId, documentTypes) {
|
|
891
|
+
return new Promise((resolve) => {
|
|
892
|
+
let settled = false;
|
|
893
|
+
const settle = (fileNode) => {
|
|
894
|
+
if (settled) return;
|
|
895
|
+
settled = true;
|
|
896
|
+
resolve(fileNode);
|
|
897
|
+
};
|
|
898
|
+
addFileWithProgress(row.file, driveId, row.name, void 0, (progress) => {
|
|
899
|
+
patchOpenFileUpload(row.id, {
|
|
900
|
+
status: mapProgressStageToStatus(progress.stage),
|
|
901
|
+
progress: progress.progress,
|
|
902
|
+
...progress.error ? { errorDetails: progress.error } : {},
|
|
903
|
+
...progress.documentType ? { documentType: progress.documentType } : {},
|
|
904
|
+
...progress.fileNode ? { fileNode: progress.fileNode } : {}
|
|
905
|
+
});
|
|
906
|
+
switch (progress.stage) {
|
|
907
|
+
case "complete":
|
|
908
|
+
settle(progress.fileNode);
|
|
909
|
+
break;
|
|
910
|
+
case "failed":
|
|
911
|
+
case "unsupported-document-type":
|
|
912
|
+
settle(void 0);
|
|
913
|
+
break;
|
|
914
|
+
default: break;
|
|
915
|
+
}
|
|
916
|
+
}, documentTypes, "duplicate").catch(() => {
|
|
917
|
+
settle(void 0);
|
|
918
|
+
});
|
|
919
|
+
});
|
|
1028
920
|
}
|
|
1029
|
-
//#endregion
|
|
1030
|
-
//#region src/components/openpanel.tsx
|
|
1031
921
|
/**
|
|
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`.
|
|
922
|
+
* Run a confirmed batch of imports into a drive, feeding the floating upload
|
|
923
|
+
* panel. Rows appear immediately (queued), files import sequentially, and a
|
|
924
|
+
* single-file batch that succeeds opens its document in the editor.
|
|
1062
925
|
*/
|
|
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);
|
|
926
|
+
function runOpenFileImports(args) {
|
|
927
|
+
const { driveId, imports, documentTypes } = args;
|
|
928
|
+
if (imports.length === 0) return importChain;
|
|
929
|
+
const rows = imports.map(({ file, name }) => ({
|
|
930
|
+
id: `open-file-${++uploadCounter}`,
|
|
931
|
+
file,
|
|
932
|
+
name
|
|
933
|
+
}));
|
|
934
|
+
addOpenFileUploads(rows.map((row) => ({
|
|
935
|
+
id: row.id,
|
|
936
|
+
fileName: row.name,
|
|
937
|
+
fileSize: formatFileSize(row.file.size),
|
|
938
|
+
status: "pending",
|
|
939
|
+
progress: 0
|
|
940
|
+
})));
|
|
941
|
+
const run = async () => {
|
|
942
|
+
const results = [];
|
|
943
|
+
for (const row of rows) results.push(await importOne(row, driveId, documentTypes));
|
|
944
|
+
if (rows.length === 1 && results[0]) setSelectedNode(results[0]);
|
|
945
|
+
};
|
|
946
|
+
importChain = importChain.then(run, run);
|
|
947
|
+
return importChain;
|
|
948
|
+
}
|
|
949
|
+
//#endregion
|
|
950
|
+
//#region src/utils/openUrl.ts
|
|
951
|
+
const openBrowserUrl = (url) => window.open(url, "_blank");
|
|
952
|
+
const openUrl = openBrowserUrl;
|
|
953
|
+
//#endregion
|
|
954
|
+
//#region src/utils/pglite-migration.ts
|
|
955
|
+
const BACKUP_PREFIX = "ph-pglite-backup::";
|
|
956
|
+
const BACKUP_INDEX_KEY = "ph:pglite-backups";
|
|
957
|
+
const BACKUP_RETENTION_MS = 720 * 60 * 60 * 1e3;
|
|
958
|
+
function deleteIdb(name, timeoutMs = 15e3) {
|
|
959
|
+
return new Promise((resolve, reject) => {
|
|
960
|
+
const req = indexedDB.deleteDatabase(name);
|
|
961
|
+
let settled = false;
|
|
962
|
+
const done = (fn) => {
|
|
963
|
+
if (settled) return;
|
|
964
|
+
settled = true;
|
|
965
|
+
fn();
|
|
1114
966
|
};
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
967
|
+
const timer = setTimeout(() => done(() => reject(/* @__PURE__ */ new Error(`IDB delete timed out for ${name} after ${timeoutMs}ms`))), timeoutMs);
|
|
968
|
+
req.onsuccess = () => done(() => {
|
|
969
|
+
clearTimeout(timer);
|
|
970
|
+
resolve();
|
|
971
|
+
});
|
|
972
|
+
req.onerror = () => done(() => {
|
|
973
|
+
clearTimeout(timer);
|
|
974
|
+
reject(idbError(req, `IDB delete failed for ${name}`));
|
|
975
|
+
});
|
|
976
|
+
});
|
|
977
|
+
}
|
|
978
|
+
function readBackupIndex() {
|
|
979
|
+
try {
|
|
980
|
+
const raw = localStorage.getItem(BACKUP_INDEX_KEY);
|
|
981
|
+
if (!raw) return [];
|
|
982
|
+
const parsed = JSON.parse(raw);
|
|
983
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
984
|
+
} catch {
|
|
985
|
+
return [];
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
function writeBackupIndex(records) {
|
|
989
|
+
try {
|
|
990
|
+
localStorage.setItem(BACKUP_INDEX_KEY, JSON.stringify(records));
|
|
991
|
+
} catch {}
|
|
992
|
+
}
|
|
993
|
+
function registerBackup(rec) {
|
|
994
|
+
writeBackupIndex([...readBackupIndex(), rec]);
|
|
995
|
+
}
|
|
996
|
+
function forgetBackup(name) {
|
|
997
|
+
writeBackupIndex(readBackupIndex().filter((r) => r.name !== name));
|
|
998
|
+
}
|
|
999
|
+
async function janitor() {
|
|
1000
|
+
const cutoff = Date.now() - BACKUP_RETENTION_MS;
|
|
1001
|
+
const keep = [];
|
|
1002
|
+
for (const rec of readBackupIndex()) {
|
|
1003
|
+
if (rec.createdAt >= cutoff) {
|
|
1004
|
+
keep.push(rec);
|
|
1005
|
+
continue;
|
|
1124
1006
|
}
|
|
1125
|
-
|
|
1126
|
-
|
|
1007
|
+
try {
|
|
1008
|
+
await deleteIdb(rec.name);
|
|
1127
1009
|
} catch (err) {
|
|
1128
|
-
console.warn(
|
|
1010
|
+
console.warn(`Failed to delete expired pglite backup ${rec.name}`, err);
|
|
1011
|
+
keep.push(rec);
|
|
1129
1012
|
}
|
|
1130
|
-
}
|
|
1131
|
-
|
|
1132
|
-
user,
|
|
1133
|
-
enabled
|
|
1134
|
-
]);
|
|
1135
|
-
return null;
|
|
1013
|
+
}
|
|
1014
|
+
writeBackupIndex(keep);
|
|
1136
1015
|
}
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1016
|
+
function createPersistentBackup() {
|
|
1017
|
+
return {
|
|
1018
|
+
snapshot: async (idbName) => {
|
|
1019
|
+
const backupName = `${BACKUP_PREFIX}${idbName}::${(/* @__PURE__ */ new Date()).toISOString()}`;
|
|
1020
|
+
await cloneFileData(idbName, backupName);
|
|
1021
|
+
registerBackup({
|
|
1022
|
+
name: backupName,
|
|
1023
|
+
idbName,
|
|
1024
|
+
createdAt: Date.now()
|
|
1025
|
+
});
|
|
1026
|
+
return backupName;
|
|
1027
|
+
},
|
|
1028
|
+
rollback: async (handle, idbName, cause) => {
|
|
1029
|
+
const backupName = handle;
|
|
1030
|
+
try {
|
|
1031
|
+
await cloneFileData(backupName, idbName);
|
|
1032
|
+
} catch (rollbackErr) {
|
|
1033
|
+
console.error(`PGlite migration rollback failed for ${idbName}; backup ${backupName} retained. Primary migration error:`, cause, "Rollback error:", rollbackErr);
|
|
1034
|
+
return;
|
|
1035
|
+
}
|
|
1036
|
+
await deleteIdb(backupName).catch(() => void 0);
|
|
1037
|
+
forgetBackup(backupName);
|
|
1038
|
+
},
|
|
1039
|
+
discard: async (handle) => {
|
|
1040
|
+
const backupName = handle;
|
|
1041
|
+
await deleteIdb(backupName).catch(() => void 0);
|
|
1042
|
+
forgetBackup(backupName);
|
|
1043
|
+
},
|
|
1044
|
+
commit: () => Promise.resolve()
|
|
1045
|
+
};
|
|
1154
1046
|
}
|
|
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 });
|
|
1047
|
+
async function migrateAllLocked() {
|
|
1048
|
+
const backup = createPersistentBackup();
|
|
1049
|
+
try {
|
|
1050
|
+
for (const idbName of PRIMARY_IDB_NAMES) await migrateIdb(idbName, (phase) => setMigrationStatus({
|
|
1051
|
+
idbName,
|
|
1052
|
+
phase
|
|
1053
|
+
}), backup);
|
|
1054
|
+
} finally {
|
|
1055
|
+
setMigrationStatus(null);
|
|
1056
|
+
}
|
|
1168
1057
|
}
|
|
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
|
-
})
|
|
1058
|
+
async function migrateAllIfNeeded() {
|
|
1059
|
+
janitor().catch((err) => console.warn("PGlite backup janitor failed", err));
|
|
1060
|
+
if (!(typeof navigator !== "undefined" && "locks" in navigator && typeof navigator.locks.request === "function")) {
|
|
1061
|
+
await migrateAllLocked();
|
|
1062
|
+
return;
|
|
1063
|
+
}
|
|
1064
|
+
await navigator.locks.request("ph-pglite-migration", { mode: "exclusive" }, async () => {
|
|
1065
|
+
await migrateAllLocked();
|
|
1190
1066
|
});
|
|
1191
1067
|
}
|
|
1192
1068
|
//#endregion
|
|
1193
|
-
//#region src/context/sentry-provider.tsx
|
|
1194
|
-
const SentryProvider = ({ children }) => {
|
|
1195
|
-
useInitSentry();
|
|
1196
|
-
return children;
|
|
1197
|
-
};
|
|
1198
|
-
//#endregion
|
|
1199
1069
|
//#region src/components/reactor-chat.tsx
|
|
1200
1070
|
/**
|
|
1201
1071
|
* Resolves the reactor tool descriptors for the chat agent from the
|
|
@@ -1533,6 +1403,20 @@ const App = () => {
|
|
|
1533
1403
|
] }) });
|
|
1534
1404
|
};
|
|
1535
1405
|
//#endregion
|
|
1406
|
+
//#region src/components/dots-loader.tsx
|
|
1407
|
+
const DotsLoader = () => {
|
|
1408
|
+
const [dots, setDots] = useState(0);
|
|
1409
|
+
useEffect(() => {
|
|
1410
|
+
const id = setInterval(() => {
|
|
1411
|
+
setDots((dots) => dots === 3 ? 0 : dots + 1);
|
|
1412
|
+
}, 200);
|
|
1413
|
+
return () => {
|
|
1414
|
+
clearInterval(id);
|
|
1415
|
+
};
|
|
1416
|
+
}, []);
|
|
1417
|
+
return /* @__PURE__ */ jsx("span", { children: new Array(dots).fill(".").join("") });
|
|
1418
|
+
};
|
|
1419
|
+
//#endregion
|
|
1536
1420
|
//#region src/components/drive-icon.tsx
|
|
1537
1421
|
function DriveIcon({ drive }) {
|
|
1538
1422
|
const remotes = useSyncList();
|
|
@@ -1597,6 +1481,9 @@ function EditorError({ title, children }) {
|
|
|
1597
1481
|
})
|
|
1598
1482
|
});
|
|
1599
1483
|
}
|
|
1484
|
+
function defaultScope(scopes) {
|
|
1485
|
+
return scopes.includes("global") ? "global" : scopes[0];
|
|
1486
|
+
}
|
|
1600
1487
|
function OpenPackageManagerButton() {
|
|
1601
1488
|
return /* @__PURE__ */ jsx(PowerhouseButton, {
|
|
1602
1489
|
className: "px-3 py-1.5 text-base font-medium",
|
|
@@ -1616,10 +1503,30 @@ const DocumentEditor = (props) => {
|
|
|
1616
1503
|
const documentName = document?.header.name ?? void 0;
|
|
1617
1504
|
const documentType = document?.header.documentType ?? void 0;
|
|
1618
1505
|
const preferredEditor = document?.header.meta?.preferredEditor ?? void 0;
|
|
1619
|
-
const
|
|
1506
|
+
const scopes = useMemo(() => {
|
|
1507
|
+
const keys = Object.keys(document?.header.revision ?? {});
|
|
1508
|
+
return keys.length > 0 ? keys : ["global"];
|
|
1509
|
+
}, [document?.header.revision]);
|
|
1510
|
+
const [operationScope, setOperationScope] = useState(() => defaultScope(scopes));
|
|
1511
|
+
const selectedScope = scopes.includes(operationScope) ? operationScope : defaultScope(scopes);
|
|
1512
|
+
const { operations: historyOperations, isLoading: isLoadingHistory, hasNextPage: historyHasNextPage, fetchNextPage: fetchNextHistoryPage, error: historyError } = useDocumentOperations(documentId, selectedScope, {
|
|
1513
|
+
enabled: revisionHistoryVisible,
|
|
1514
|
+
limit: 500
|
|
1515
|
+
});
|
|
1516
|
+
const { operations: globalOperations, hasNextPage: globalHasNextPage, isLoading: isLoadingGlobal, fetchNextPage: fetchNextGlobalPage, error: globalError } = useDocumentOperations(documentId, "global", {
|
|
1517
|
+
enabled: !!selectedTimelineItem,
|
|
1518
|
+
limit: 500
|
|
1519
|
+
});
|
|
1620
1520
|
useEffect(() => {
|
|
1621
|
-
if (
|
|
1622
|
-
|
|
1521
|
+
if (!globalHasNextPage || isLoadingGlobal || globalError) return;
|
|
1522
|
+
const handle = window.setTimeout(fetchNextGlobalPage, 0);
|
|
1523
|
+
return () => window.clearTimeout(handle);
|
|
1524
|
+
}, [
|
|
1525
|
+
globalHasNextPage,
|
|
1526
|
+
isLoadingGlobal,
|
|
1527
|
+
fetchNextGlobalPage,
|
|
1528
|
+
globalError
|
|
1529
|
+
]);
|
|
1623
1530
|
const globalRevisionNumber = document?.header.revision.global ?? 0;
|
|
1624
1531
|
const localRevisionNumber = document?.header.revision.local ?? 0;
|
|
1625
1532
|
const documentModelModule = useDocumentModelModuleById(documentType);
|
|
@@ -1725,11 +1632,17 @@ const DocumentEditor = (props) => {
|
|
|
1725
1632
|
id: "document-editor-context",
|
|
1726
1633
|
"data-editor": editorModule.config.id,
|
|
1727
1634
|
"data-document-type": documentType,
|
|
1728
|
-
children: revisionHistoryVisible ?
|
|
1635
|
+
children: revisionHistoryVisible ? /* @__PURE__ */ jsx(RevisionHistory, {
|
|
1729
1636
|
documentTitle: documentName ?? "",
|
|
1730
1637
|
documentId: documentId ?? "",
|
|
1731
|
-
|
|
1732
|
-
|
|
1638
|
+
operations: historyOperations,
|
|
1639
|
+
isLoading: isLoadingHistory,
|
|
1640
|
+
hasNextPage: historyHasNextPage,
|
|
1641
|
+
onLoadNextPage: fetchNextHistoryPage,
|
|
1642
|
+
error: historyError,
|
|
1643
|
+
scopes,
|
|
1644
|
+
scope: selectedScope,
|
|
1645
|
+
onScopeChange: setOperationScope,
|
|
1733
1646
|
onClose: () => setRevisionHistoryVisible(false),
|
|
1734
1647
|
documentState: document.state,
|
|
1735
1648
|
onCopyState: () => {
|
|
@@ -1749,7 +1662,7 @@ const DocumentEditor = (props) => {
|
|
|
1749
1662
|
children: !editorError?.error && /* @__PURE__ */ jsx(EditorComponent, {
|
|
1750
1663
|
context: {
|
|
1751
1664
|
readMode: !!selectedTimelineItem,
|
|
1752
|
-
selectedTimelineRevision: getRevisionFromDate(selectedTimelineItem?.startDate, selectedTimelineItem?.endDate, globalOperations)
|
|
1665
|
+
selectedTimelineRevision: (isLoadingGlobal || globalHasNextPage) && !globalError ? void 0 : getRevisionFromDate(selectedTimelineItem?.startDate, selectedTimelineItem?.endDate, globalOperations)
|
|
1753
1666
|
},
|
|
1754
1667
|
documentId: document.header.id
|
|
1755
1668
|
}, `${editorBundleKey}:${documentId}`)
|
|
@@ -1758,6 +1671,32 @@ const DocumentEditor = (props) => {
|
|
|
1758
1671
|
});
|
|
1759
1672
|
};
|
|
1760
1673
|
//#endregion
|
|
1674
|
+
//#region src/components/footer.tsx
|
|
1675
|
+
const Footer$1 = () => {
|
|
1676
|
+
return /* @__PURE__ */ jsxs(Footer, { children: [
|
|
1677
|
+
/* @__PURE__ */ jsx(FooterLink, {
|
|
1678
|
+
onClick: () => setBannerShown(true),
|
|
1679
|
+
children: /* @__PURE__ */ jsx(Trans, { i18nKey: "footer.cookiePolicy" })
|
|
1680
|
+
}),
|
|
1681
|
+
/* @__PURE__ */ jsx(FooterLink, {
|
|
1682
|
+
onClick: () => showPHModal({ type: "disclaimer" }),
|
|
1683
|
+
children: /* @__PURE__ */ jsx(Trans, { i18nKey: "footer.disclaimer" })
|
|
1684
|
+
}),
|
|
1685
|
+
/* @__PURE__ */ jsx(FooterLink, {
|
|
1686
|
+
id: "ph-logo-link",
|
|
1687
|
+
onClick: () => openUrl("https://www.powerhouse.inc/"),
|
|
1688
|
+
children: /* @__PURE__ */ jsx(Trans, {
|
|
1689
|
+
i18nKey: "footer.builtWith",
|
|
1690
|
+
components: { icon: /* @__PURE__ */ jsx(Icon, {
|
|
1691
|
+
name: "PowerhouseLogoSmall",
|
|
1692
|
+
size: 16,
|
|
1693
|
+
className: "mx-1"
|
|
1694
|
+
}) }
|
|
1695
|
+
})
|
|
1696
|
+
})
|
|
1697
|
+
] });
|
|
1698
|
+
};
|
|
1699
|
+
//#endregion
|
|
1761
1700
|
//#region src/components/root.tsx
|
|
1762
1701
|
function Root() {
|
|
1763
1702
|
return /* @__PURE__ */ jsx("div", {
|
|
@@ -1778,25 +1717,98 @@ function Root() {
|
|
|
1778
1717
|
}
|
|
1779
1718
|
//#endregion
|
|
1780
1719
|
//#region src/components/use-drive-auth-gate.ts
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1720
|
+
/**
|
|
1721
|
+
* Decides the gate for the drive the user selected, and only that drive. A
|
|
1722
|
+
* refusal on any other drive must not hide the rest of Connect.
|
|
1723
|
+
*
|
|
1724
|
+
* Connection states are keyed by remote name, which is a random uuid, so the
|
|
1725
|
+
* caller supplies the remote -> drive mapping.
|
|
1726
|
+
*/
|
|
1727
|
+
function computeAuthGate(isAuthenticated, connectionStates, selection) {
|
|
1728
|
+
const { selectedDriveId, remotes } = selection;
|
|
1729
|
+
if (!selectedDriveId) return null;
|
|
1730
|
+
let refused = false;
|
|
1731
|
+
for (const remote of remotes) {
|
|
1732
|
+
if (remote.driveId !== selectedDriveId) continue;
|
|
1733
|
+
const snapshot = connectionStates.get(remote.name);
|
|
1734
|
+
if (snapshot?.state === "error" && snapshot.requiresAuth) {
|
|
1735
|
+
refused = true;
|
|
1736
|
+
break;
|
|
1737
|
+
}
|
|
1786
1738
|
}
|
|
1787
|
-
if (!
|
|
1739
|
+
if (!refused) return null;
|
|
1788
1740
|
return isAuthenticated ? "unauthorized" : "login";
|
|
1789
1741
|
}
|
|
1790
|
-
|
|
1742
|
+
const hiddenDriveIds = /* @__PURE__ */ new Set();
|
|
1743
|
+
let hiddenDriveIdsSnapshot = [];
|
|
1744
|
+
const hiddenDriveListeners = /* @__PURE__ */ new Set();
|
|
1745
|
+
function publishHiddenDrives() {
|
|
1746
|
+
hiddenDriveIdsSnapshot = [...hiddenDriveIds];
|
|
1747
|
+
for (const listener of [...hiddenDriveListeners]) listener();
|
|
1748
|
+
}
|
|
1749
|
+
function subscribeHiddenDrives(listener) {
|
|
1750
|
+
hiddenDriveListeners.add(listener);
|
|
1751
|
+
return () => {
|
|
1752
|
+
hiddenDriveListeners.delete(listener);
|
|
1753
|
+
};
|
|
1754
|
+
}
|
|
1755
|
+
function getHiddenDriveIds() {
|
|
1756
|
+
return hiddenDriveIdsSnapshot;
|
|
1757
|
+
}
|
|
1758
|
+
/** Hides a drive from Connect's drive lists until the page reloads. */
|
|
1759
|
+
function hideDriveForSession(driveId) {
|
|
1760
|
+
if (hiddenDriveIds.has(driveId)) return;
|
|
1761
|
+
hiddenDriveIds.add(driveId);
|
|
1762
|
+
publishHiddenDrives();
|
|
1763
|
+
}
|
|
1764
|
+
/** Restores every drive hidden this session. */
|
|
1765
|
+
function clearHiddenDrives() {
|
|
1766
|
+
if (hiddenDriveIds.size === 0) return;
|
|
1767
|
+
hiddenDriveIds.clear();
|
|
1768
|
+
publishHiddenDrives();
|
|
1769
|
+
}
|
|
1770
|
+
function useHiddenDriveIds() {
|
|
1771
|
+
return useSyncExternalStore(subscribeHiddenDrives, getHiddenDriveIds, getHiddenDriveIds);
|
|
1772
|
+
}
|
|
1773
|
+
/** `useDrives()` minus the drives dismissed from the auth gate this session. */
|
|
1774
|
+
function useVisibleDrives() {
|
|
1775
|
+
const drives = useDrives();
|
|
1776
|
+
const hidden = useHiddenDriveIds();
|
|
1777
|
+
return useMemo(() => {
|
|
1778
|
+
if (!drives || hidden.length === 0) return drives;
|
|
1779
|
+
return drives.filter((drive) => !hidden.includes(drive.header.id));
|
|
1780
|
+
}, [drives, hidden]);
|
|
1781
|
+
}
|
|
1782
|
+
/** Live wrapper over {@link computeAuthGate}, plus the dismiss action. */
|
|
1791
1783
|
function useDriveAuthGate() {
|
|
1792
1784
|
const user = useUser();
|
|
1793
1785
|
const connectionStates = useConnectionStates();
|
|
1794
|
-
|
|
1786
|
+
const syncManager = useSync();
|
|
1787
|
+
const selectedDriveId = useSelectedDriveId();
|
|
1788
|
+
const remotes = useMemo(() => (syncManager?.list() ?? []).map((remote) => ({
|
|
1789
|
+
name: remote.meta.name,
|
|
1790
|
+
driveId: remote.meta.collectionId.driveId
|
|
1791
|
+
})), [syncManager, connectionStates]);
|
|
1792
|
+
const address = user?.address;
|
|
1793
|
+
useEffect(() => {
|
|
1794
|
+
clearHiddenDrives();
|
|
1795
|
+
}, [address]);
|
|
1796
|
+
const dismiss = useCallback(() => {
|
|
1797
|
+
if (selectedDriveId) hideDriveForSession(selectedDriveId);
|
|
1798
|
+
setSelectedDrive(void 0);
|
|
1799
|
+
}, [selectedDriveId]);
|
|
1800
|
+
return {
|
|
1801
|
+
gate: computeAuthGate(Boolean(user), connectionStates, {
|
|
1802
|
+
selectedDriveId,
|
|
1803
|
+
remotes
|
|
1804
|
+
}),
|
|
1805
|
+
dismiss
|
|
1806
|
+
};
|
|
1795
1807
|
}
|
|
1796
1808
|
//#endregion
|
|
1797
1809
|
//#region src/pages/content.tsx
|
|
1798
1810
|
function Content() {
|
|
1799
|
-
const { gate } = useDriveAuthGate();
|
|
1811
|
+
const { gate, dismiss } = useDriveAuthGate();
|
|
1800
1812
|
const openLogin = useOpenRenownLogin();
|
|
1801
1813
|
const [selectedDrive] = useSelectedDriveSafe();
|
|
1802
1814
|
const selectedFolder = useSelectedFolder();
|
|
@@ -1812,7 +1824,8 @@ function Content() {
|
|
|
1812
1824
|
children: /* @__PURE__ */ jsx(DriveAuthGate, {
|
|
1813
1825
|
mode: gate,
|
|
1814
1826
|
onLogin: openLogin,
|
|
1815
|
-
onLogout: () => void logout()
|
|
1827
|
+
onLogout: () => void logout(),
|
|
1828
|
+
onClose: dismiss
|
|
1816
1829
|
})
|
|
1817
1830
|
}) : !selectedDocumentId && !selectedDrive && !selectedFolder ? /* @__PURE__ */ jsx(HomeScreenContainer, {}) : /* @__PURE__ */ jsx(AppContainer, {}) });
|
|
1818
1831
|
}
|
|
@@ -1833,7 +1846,7 @@ function DriveItem({ drive }) {
|
|
|
1833
1846
|
}, drive.header.id);
|
|
1834
1847
|
}
|
|
1835
1848
|
function HomeScreenContainer() {
|
|
1836
|
-
const drives =
|
|
1849
|
+
const drives = useVisibleDrives();
|
|
1837
1850
|
const isAddDriveEnabled = useIsAddDriveEnabled();
|
|
1838
1851
|
const homeBackground = getRuntimeConfig().connect?.branding?.homeBackground;
|
|
1839
1852
|
return /* @__PURE__ */ jsxs(HomeScreen, {
|
|
@@ -1876,11 +1889,69 @@ const Router = () => {
|
|
|
1876
1889
|
return /* @__PURE__ */ jsx(RouterProvider, { router });
|
|
1877
1890
|
};
|
|
1878
1891
|
//#endregion
|
|
1892
|
+
//#region src/components/search-bar.tsx
|
|
1893
|
+
const defaultFilterItems = [
|
|
1894
|
+
{
|
|
1895
|
+
id: "project",
|
|
1896
|
+
label: ".project",
|
|
1897
|
+
icon: /* @__PURE__ */ jsx(Icon, {
|
|
1898
|
+
name: "Project",
|
|
1899
|
+
color: "#FF6A55",
|
|
1900
|
+
size: 16
|
|
1901
|
+
})
|
|
1902
|
+
},
|
|
1903
|
+
{
|
|
1904
|
+
id: "budget",
|
|
1905
|
+
label: ".budget",
|
|
1906
|
+
icon: /* @__PURE__ */ jsx(Icon, {
|
|
1907
|
+
name: "BarChart",
|
|
1908
|
+
color: "#8E55EA",
|
|
1909
|
+
size: 16
|
|
1910
|
+
})
|
|
1911
|
+
},
|
|
1912
|
+
{
|
|
1913
|
+
id: "profile",
|
|
1914
|
+
label: ".profile",
|
|
1915
|
+
icon: /* @__PURE__ */ jsx(Icon, {
|
|
1916
|
+
name: "Person",
|
|
1917
|
+
color: "#3E90F0",
|
|
1918
|
+
size: 16
|
|
1919
|
+
})
|
|
1920
|
+
},
|
|
1921
|
+
{
|
|
1922
|
+
id: "legal",
|
|
1923
|
+
label: ".legal",
|
|
1924
|
+
icon: /* @__PURE__ */ jsx(Icon, {
|
|
1925
|
+
name: "Briefcase",
|
|
1926
|
+
color: "#4BAB71",
|
|
1927
|
+
size: 16
|
|
1928
|
+
})
|
|
1929
|
+
},
|
|
1930
|
+
{
|
|
1931
|
+
id: "atlas",
|
|
1932
|
+
label: ".Atlas",
|
|
1933
|
+
icon: /* @__PURE__ */ jsx(Icon, {
|
|
1934
|
+
name: "Globe",
|
|
1935
|
+
color: "#FF8A00",
|
|
1936
|
+
size: 16
|
|
1937
|
+
})
|
|
1938
|
+
}
|
|
1939
|
+
];
|
|
1940
|
+
const SearchBar = () => {
|
|
1941
|
+
const { t } = useTranslation();
|
|
1942
|
+
return /* @__PURE__ */ jsx(ConnectSearchBar, {
|
|
1943
|
+
className: "m-4 shrink-0 bg-muted",
|
|
1944
|
+
placeholder: t("searchbar.placeholder"),
|
|
1945
|
+
filterLabel: t("searchbar.filterLabel"),
|
|
1946
|
+
filterItems: defaultFilterItems
|
|
1947
|
+
});
|
|
1948
|
+
};
|
|
1949
|
+
//#endregion
|
|
1879
1950
|
//#region src/components/sidebar.tsx
|
|
1880
1951
|
function Sidebar() {
|
|
1881
1952
|
const user = useUser();
|
|
1882
1953
|
const openLogin = useOpenRenownLogin();
|
|
1883
|
-
const drives =
|
|
1954
|
+
const drives = useVisibleDrives();
|
|
1884
1955
|
const isAddDriveEnabled = useIsAddDriveEnabled();
|
|
1885
1956
|
const [selectedDrive] = useSelectedDriveSafe();
|
|
1886
1957
|
const connectDebug = localStorage.getItem("CONNECT_DEBUG") === "true";
|
|
@@ -1912,12 +1983,12 @@ function Sidebar() {
|
|
|
1912
1983
|
variant: "text",
|
|
1913
1984
|
fallbackMessage: "There was an error loading drives",
|
|
1914
1985
|
loggerContext: ["Connect", "Sidebar"],
|
|
1915
|
-
children: [drives?.map((drive
|
|
1986
|
+
children: [drives?.map((drive) => /* @__PURE__ */ jsx(SidebarItem, {
|
|
1916
1987
|
title: drive.header.name,
|
|
1917
1988
|
onClick: () => setSelectedDrive(drive),
|
|
1918
1989
|
active: selectedDrive?.header.id === drive.header.id,
|
|
1919
1990
|
icon: /* @__PURE__ */ jsx(DriveIcon, { drive })
|
|
1920
|
-
},
|
|
1991
|
+
}, drive.header.id)), isAddDriveEnabled && /* @__PURE__ */ jsx(SidebarAddDriveItem, { onClick: onAddDriveClick })]
|
|
1921
1992
|
})
|
|
1922
1993
|
}) });
|
|
1923
1994
|
}
|
|
@@ -2056,20 +2127,20 @@ const MigrationBanner = () => {
|
|
|
2056
2127
|
};
|
|
2057
2128
|
//#endregion
|
|
2058
2129
|
//#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-
|
|
2130
|
+
const AddDriveModal$1 = lazy(() => import("./AddDriveModal-CW-ZSWkf.js").then((m) => ({ default: m.AddDriveModal })));
|
|
2131
|
+
const ClearStorageModal = lazy(() => import("./ClearStorageModal-CoXeVy8Y.js").then((m) => ({ default: m.ClearStorageModal })));
|
|
2132
|
+
const CookiesPolicyModal = lazy(() => import("./CookiesPolicyModal-lKdOuTNm.js").then((m) => ({ default: m.CookiesPolicyModal })));
|
|
2133
|
+
const CreateDocumentModal$1 = lazy(() => import("./CreateDocumentModal-HmK-78sB.js").then((m) => ({ default: m.CreateDocumentModal })));
|
|
2134
|
+
const DebugSettingsModal = lazy(() => import("./DebugSettingsModal-BYm2jPPV.js").then((m) => ({ default: m.DebugSettingsModal })));
|
|
2135
|
+
const DeleteDriveModal = lazy(() => import("./DeleteDriveModal-Cyw6hwc2.js").then((m) => ({ default: m.DeleteDriveModal })));
|
|
2136
|
+
const DeleteItemModal = lazy(() => import("./DeleteItemModal-CiFwstZx.js").then((m) => ({ default: m.DeleteItemModal })));
|
|
2137
|
+
const DisclaimerModal = lazy(() => import("./DisclaimerModal-DIRsjUvu.js").then((m) => ({ default: m.DisclaimerModal })));
|
|
2138
|
+
const DriveSettingsModal$1 = lazy(() => import("./DriveSettingsModal-DRarHRIb.js").then((m) => ({ default: m.DriveSettingsModal })));
|
|
2139
|
+
const DownloadDocumentWithErrorsModal = lazy(() => import("./DownloadDocumentWithErrorsModal-CxsR74d-.js").then((m) => ({ default: m.DownloadDocumentWithErrorsModal })));
|
|
2140
|
+
const DocumentVersionUnsupportedModal = lazy(() => import("./DocumentVersionUnsupportedModal-KftC3-jr.js").then((m) => ({ default: m.DocumentVersionUnsupportedModal })));
|
|
2141
|
+
const ConfirmDocumentUpgradeModal = lazy(() => import("./ConfirmDocumentUpgradeModal-BBrFlHp_.js").then((m) => ({ default: m.ConfirmDocumentUpgradeModal })));
|
|
2142
|
+
const SettingsModal$1 = lazy(() => import("./SettingsModal-D93WeiUe.js").then((m) => ({ default: m.SettingsModal })));
|
|
2143
|
+
const UpgradeDriveModal = lazy(() => import("./UpgradeDriveModal-C8scFkuq.js").then((m) => ({ default: m.UpgradeDriveModal })));
|
|
2073
2144
|
const modalComponents = {
|
|
2074
2145
|
addDrive: AddDriveModal$1,
|
|
2075
2146
|
clearStorage: ClearStorageModal,
|
|
@@ -2083,13 +2154,13 @@ const modalComponents = {
|
|
|
2083
2154
|
downloadDocumentWithErrors: DownloadDocumentWithErrorsModal,
|
|
2084
2155
|
documentVersionUnsupported: DocumentVersionUnsupportedModal,
|
|
2085
2156
|
confirmDocumentUpgrade: ConfirmDocumentUpgradeModal,
|
|
2086
|
-
inspector: lazy(() => import("./InspectorModal-
|
|
2157
|
+
inspector: lazy(() => import("./InspectorModal-98Hn3VHb.js").then((m) => ({ default: m.InspectorModal }))),
|
|
2087
2158
|
settings: SettingsModal$1,
|
|
2088
2159
|
upgradeDrive: UpgradeDriveModal,
|
|
2089
|
-
missingPackage: lazy(() => import("./MissingPackageModal-
|
|
2090
|
-
driveAuthRequired: lazy(() => import("./DriveAuthRequiredModal-
|
|
2091
|
-
openFileDocuments: lazy(() => import("./OpenFileDocumentsModal-
|
|
2092
|
-
login: lazy(() => import("./LoginModal-
|
|
2160
|
+
missingPackage: lazy(() => import("./MissingPackageModal-Bar7ErIs.js").then((m) => ({ default: m.ConnectMissingPackageModal }))),
|
|
2161
|
+
driveAuthRequired: lazy(() => import("./DriveAuthRequiredModal-BoqnnNKT.js").then((m) => ({ default: m.DriveAuthRequiredModal }))),
|
|
2162
|
+
openFileDocuments: lazy(() => import("./OpenFileDocumentsModal-Cv6CLGAy.js").then((m) => ({ default: m.OpenFileDocumentsModal }))),
|
|
2163
|
+
login: lazy(() => import("./LoginModal-DhQTxsoG.js").then((m) => ({ default: m.LoginModal })))
|
|
2093
2164
|
};
|
|
2094
2165
|
const ModalsContainer = lazy(() => {
|
|
2095
2166
|
return Promise.resolve({ default: () => {
|
|
@@ -2128,9 +2199,9 @@ const ServiceWorkerUpdatePrompt = () => {
|
|
|
2128
2199
|
};
|
|
2129
2200
|
//#endregion
|
|
2130
2201
|
//#region src/components/app-loader.tsx
|
|
2131
|
-
const CookieBanner$1 = lazy(() => import("./cookie-banner-
|
|
2202
|
+
const CookieBanner$1 = lazy(() => import("./cookie-banner-BQescTYk.js").then((m) => ({ default: m.CookieBanner })));
|
|
2132
2203
|
const AppLoader = (props) => {
|
|
2133
|
-
const Load = lazy(() => import("./load-
|
|
2204
|
+
const Load = lazy(() => import("./load-DLrFSyLN.js").then((m) => m.loadComponent(props.localPackage)));
|
|
2134
2205
|
return /* @__PURE__ */ jsx(StrictMode, { children: /* @__PURE__ */ jsxs(ErrorBoundary$1, {
|
|
2135
2206
|
fallbackRender: (props) => /* @__PURE__ */ jsx(AppSkeleton, { children: /* @__PURE__ */ jsx(DetailedFallback, { ...props }) }),
|
|
2136
2207
|
resetKeys: [props.localPackage],
|
|
@@ -2164,7 +2235,7 @@ const AppLoader = (props) => {
|
|
|
2164
2235
|
}) });
|
|
2165
2236
|
};
|
|
2166
2237
|
//#endregion
|
|
2167
|
-
export {
|
|
2238
|
+
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
2239
|
|
|
2169
|
-
//# sourceMappingURL=app-loader-
|
|
2170
|
-
//# debugId=
|
|
2240
|
+
//# sourceMappingURL=app-loader-BbuC7lmP.js.map
|
|
2241
|
+
//# debugId=4b603cc8-96ef-555a-ad0e-ceb73451bf03
|